HSM, 암호화 관련 테스트 수행 중 수정
This commit is contained in:
@@ -7,10 +7,12 @@ import java.lang.reflect.Method;
|
||||
import java.nio.file.Files;
|
||||
import java.security.KeyStore;
|
||||
import java.security.Provider;
|
||||
import java.security.PublicKey;
|
||||
import java.security.Security;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.Base64;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
@@ -52,11 +54,18 @@ public class HsmManager implements Lifecycle {
|
||||
private static final String PROP_PIN = "PIN";
|
||||
|
||||
private Provider pkcs11Provider;
|
||||
private KeyStore keyStore;
|
||||
private volatile KeyStore keyStore;
|
||||
private boolean started;
|
||||
|
||||
private final LifecycleSupport lifecycle = new LifecycleSupport(this);
|
||||
|
||||
private volatile char[] pin;
|
||||
|
||||
// 재로드 주기 (분 단위). 필요시 PropManager로 외부화 가능.
|
||||
private static final long RELOAD_INTERVAL_MINUTES = 1;
|
||||
private ScheduledExecutorService scheduler;
|
||||
private ScheduledFuture<?> reloadFuture;
|
||||
|
||||
private HsmManager() {
|
||||
}
|
||||
|
||||
@@ -73,6 +82,7 @@ public class HsmManager implements Lifecycle {
|
||||
|
||||
try {
|
||||
init();
|
||||
startReloadScheduler();
|
||||
} catch (Exception e) {
|
||||
throw new LifecycleException(ExceptionUtil.getErrorCode(e, "RECEAIHSM002"));
|
||||
}
|
||||
@@ -85,7 +95,7 @@ public class HsmManager implements Lifecycle {
|
||||
EncryptionManager encManager = EncryptionManager.getInstance();
|
||||
|
||||
String configContent = encManager.decryptDBData(PropManager.getInstance().getProperty(GROUP_NAME, PROP_CONFIG));
|
||||
String pin = encManager.decryptDBData(PropManager.getInstance().getProperty(GROUP_NAME, PROP_PIN));
|
||||
String pinStr = encManager.decryptDBData(PropManager.getInstance().getProperty(GROUP_NAME, PROP_PIN));
|
||||
|
||||
if (configContent == null || configContent.trim().isEmpty()) {
|
||||
logger.warn("HsmManager] PKCS11_CONFIG 가 설정되지 않았습니다. HSM 초기화를 건너뜁니다.");
|
||||
@@ -102,8 +112,8 @@ public class HsmManager implements Lifecycle {
|
||||
Security.addProvider(pkcs11Provider);
|
||||
|
||||
keyStore = KeyStore.getInstance("PKCS11", pkcs11Provider);
|
||||
char[] pinChars = (pin != null) ? pin.toCharArray() : null;
|
||||
keyStore.load(null, pinChars);
|
||||
this.pin = (pinStr != null) ? pinStr.toCharArray() : null;
|
||||
keyStore.load(null, pin);
|
||||
|
||||
logger.warn("HsmManager] 초기화 완료. Provider=" + pkcs11Provider.getName());
|
||||
|
||||
@@ -128,6 +138,66 @@ public class HsmManager implements Lifecycle {
|
||||
}
|
||||
logger.warn("HsmManager] HSM 키 목록: [" + aliasList + "]");
|
||||
}
|
||||
|
||||
/**
|
||||
* 별도 스레드에서 주기적으로 KeyStore.load() 를 다시 호출하여
|
||||
* HSM 에 새로 생성/추가된 키를 인식하도록 한다.
|
||||
*/
|
||||
private void startReloadScheduler() {
|
||||
scheduler = Executors.newSingleThreadScheduledExecutor(r -> {
|
||||
Thread t = new Thread(r, "hsm-keystore-reloader");
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
});
|
||||
|
||||
reloadFuture = scheduler.scheduleWithFixedDelay(
|
||||
this::reloadKeyStoreSafely,
|
||||
RELOAD_INTERVAL_MINUTES,
|
||||
RELOAD_INTERVAL_MINUTES,
|
||||
TimeUnit.MINUTES
|
||||
);
|
||||
|
||||
logger.warn("HsmManager] KeyStore 주기적 재로드 스케줄러 시작. interval=" + RELOAD_INTERVAL_MINUTES + "분");
|
||||
}
|
||||
|
||||
/**
|
||||
* 스케줄러에서 호출되는 래퍼. 예외가 스케줄러 스레드를 죽이지 않도록 반드시 catch 한다.
|
||||
* (ScheduledExecutorService 는 task 에서 예외가 던져지면 이후 스케줄을 자동으로 중단시킨다)
|
||||
*/
|
||||
private void reloadKeyStoreSafely() {
|
||||
try {
|
||||
reloadKeyStoreIfNeeded();
|
||||
} catch (Throwable t) {
|
||||
logger.warn("HsmManager] KeyStore 주기적 재로드 실패: " + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* KeyStore 를 다시 로드한다. 외부(getSecretKey 등)에서 키 미스 발생 시
|
||||
* 즉시 재시도용으로 직접 호출할 수도 있다.
|
||||
*/
|
||||
public synchronized void reloadKeyStoreIfNeeded() throws Exception {
|
||||
if (pkcs11Provider == null) {
|
||||
return; // HSM 비활성화 상태
|
||||
}
|
||||
|
||||
KeyStore ks = KeyStore.getInstance("PKCS11", pkcs11Provider);
|
||||
ks.load(null, pin);
|
||||
this.keyStore = ks; // volatile 필드 교체 - 다른 스레드에서 즉시 가시성 확보
|
||||
|
||||
logger.warn("HsmManager] KeyStore 재로드 완료.");
|
||||
logAliases(ks);
|
||||
}
|
||||
|
||||
private void logAliases(KeyStore ks) throws Exception {
|
||||
java.util.Enumeration<String> aliases = ks.aliases();
|
||||
StringBuilder aliasList = new StringBuilder();
|
||||
while (aliases.hasMoreElements()) {
|
||||
if (aliasList.length() > 0) aliasList.append(", ");
|
||||
aliasList.append(aliases.nextElement());
|
||||
}
|
||||
logger.warn("HsmManager] HSM 키 목록: [" + aliasList + "]");
|
||||
}
|
||||
|
||||
/**
|
||||
* JDK 버전에 따라 SunPKCS11 Provider 를 생성한다.
|
||||
@@ -164,6 +234,13 @@ public class HsmManager implements Lifecycle {
|
||||
}
|
||||
lifecycle.fireLifecycleEvent(STOPING_EVENT, this);
|
||||
|
||||
if (reloadFuture != null) {
|
||||
reloadFuture.cancel(false);
|
||||
}
|
||||
if (scheduler != null) {
|
||||
scheduler.shutdown();
|
||||
}
|
||||
|
||||
if (pkcs11Provider != null) {
|
||||
Security.removeProvider(pkcs11Provider.getName());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user