--- title: "BYOK(키 주입) 키 준비" slug: "hsm-byok-key-prep" updated: 2026-10-22T09:08:02Z published: 2026-10-22T09:08:02Z canonical: "guide-gov.ncloud-docs.com/hsm-byok-key-prep" --- > ## Documentation Index > Fetch the complete documentation index at: https://guide-gov.ncloud-docs.com/llms.txt > Use this file to discover all available pages before exploring further. # BYOK(키 주입) 키 준비 VPC 환경에서 이용 가능합니다. 이 문서는 BYOK(키 주입)에 사용할 키를 준비하는 방법을 안내합니다. 애플리케이션은 보통 키를 파일이 아니라 Java 키 객체로 다룹니다. 여기서는 애플리케이션 코드에서 키 객체가 흔히 등장하는 지점을 예로 들고, 그 객체에서 주입 입력 파일을 꺼내는 방법을 설명합니다. 고객마다 코드 구성이 다르므로 대표적인 경우만 예로 듭니다. :::(info) (참고) 이 문서에서 만든 파일은 [BYOK(키 주입) Java 예제](/docs/hsm-byok-java-guide) 또는 [BYOK(키 주입) CLI 예제](/docs/hsm-byok-cli-guide)의 주입 절차에 그대로 입력합니다. 주입 원리와 지원 범위는 [BYOK(키 주입) 개요](/docs/hsm-byok-overview)를 참고해 주십시오. 이 문서의 작업은 모두 **키를 보유한 시스템**에서 수행합니다. HSM 클라이언트 서버나 LunaProvider는 필요하지 않습니다. ::: ## 주입 입력 형식 | 키 유형 | 키 객체 | 주입 입력 형식 | 꺼내는 방법 | | --- | --- | --- | --- | | AES-256 대칭키 | `SecretKey` | 원시 32바이트 (`.bin`) | `key.getEncoded()` | | RSA/EC 개인키 | `PrivateKey` | PKCS#8 DER (`.pk8.der`) | `privateKey.getEncoded()` | | RSA/EC 공개키 | `PublicKey` | X.509 PEM (`.pub.pem`) | `publicKey.getEncoded()`를 Base64로 인코딩해 PEM으로 감쌈 | :::(warning) (주의) - `getEncoded()`가 `null`을 돌려주는 키는 **추출할 수 없는 키**입니다. 다른 HSM이나 운영체제 키 저장소 안에서 생성되어 밖으로 꺼낼 수 없게 만든 키가 여기에 해당하며, BYOK 대상이 아닙니다. - 꺼낸 `.bin`과 `.pk8.der`는 **키 평문**입니다. 키를 보유한 시스템에서만 다루고, 아래 예시처럼 소유자만 읽고 쓸 수 있는 권한(600)으로 만든 뒤 주입이 끝나면 즉시 삭제하십시오. ::: ## 파일 이름 이 문서의 예시는 주입 가이드와 같은 `/tmp/sample-{유형}-$TS.{확장자}` 형식으로 파일을 저장합니다. `TS`는 파일 이름이 겹치지 않도록 붙이는 타임스탬프입니다. 주입 가이드의 실행 공통값([Java](/docs/hsm-byok-java-guide#%EC%8B%A4%ED%96%89%EA%B3%B5%ED%86%B5%EA%B0%92), [CLI](/docs/hsm-byok-cli-guide#%EC%8B%A4%ED%96%89%EA%B3%B5%ED%86%B5%EA%B0%92))에서도 `TS`를 정하는데, 이 문서를 먼저 진행했다면 그때 `TS`를 새로 정하지 말고 여기서 정한 값을 그대로 사용하십시오. 그러면 주입 절차의 명령을 파일 경로 수정 없이 그대로 사용할 수 있습니다. ```bash export TS=${TS:-$(date +%Y%m%d%H%M%S)}; echo "TS=$TS" ``` 이미 `TS`가 설정되어 있으면 그 값을 그대로 사용합니다. 출력된 값을 기록해 두고, 셸을 새로 열거나 HSM 클라이언트 서버에서 주입 절차를 진행할 때 `export TS=<기록한 값>`으로 같은 값을 지정하십시오. 아래 Java 예시는 이 값을 환경변수에서 읽어 파일 이름에 씁니다. 예시 코드는 JDK 11 이상의 API(`Path.of`, `Files.writeString`)를 사용합니다. ```java String ts = System.getenv("TS"); // 위에서 export 한 TS ``` 평문 키 파일은 처음부터 소유자만 읽고 쓸 수 있는 권한으로 만들도록, 아래 예시들은 다음 메서드로 파일을 씁니다(Linux 기준). 같은 이름의 파일이 이미 있으면 덮어쓰지 않고 오류를 냅니다. ```java // 평문 키 파일을 권한 600(rw-------)으로 새로 만들어 씁니다. static void writeSecret(Path path, byte[] data) throws IOException { Files.write(Files.createFile(path, PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rw-------"))), data); } ``` ## AES-256 키 — AES-GCM 암호화 코드 애플리케이션에 다음과 같은 암호화 코드가 있다면, `cipher.init`에 넘기는 `key`가 주입할 AES 키입니다. ```java SecretKey key = ...; // 애플리케이션이 쓰던 AES-256 키 // Provider를 지정하지 않으면 JDK 기본 Provider(SunJCE)를 사용합니다. // Cipher.getInstance("AES/GCM/NoPadding", "BC")처럼 다른 Provider를 지정해도 아래 꺼내는 방법은 같습니다. Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(128, iv)); ``` 같은 `key` 객체에서 원시 32바이트를 꺼내 저장합니다. ```java byte[] raw = key.getEncoded(); // 32바이트. null이면 추출할 수 없는 키입니다. writeSecret(Path.of("/tmp/sample-aes-" + ts + ".bin"), raw); ``` ## RSA·EC 키쌍 — 서명 코드 애플리케이션에 다음과 같은 서명 코드가 있다면, `keyPair`가 주입할 키쌍입니다. ```java KeyPair keyPair = ...; // 애플리케이션이 쓰던 RSA 또는 EC 키쌍 // Provider에 관한 내용은 위 AES 예시와 같습니다. Signature signer = Signature.getInstance("SHA256withRSA"); // RSA 키 // Signature signer = Signature.getInstance("SHA256withECDSA"); // EC 키 signer.initSign(keyPair.getPrivate()); ``` 개인키는 PKCS#8 DER로, 공개키는 PEM으로 저장합니다. EC 키라면 파일 이름의 `rsa`를 `ec`로 바꾸십시오. ```java // 개인키 → PKCS#8 DER writeSecret(Path.of("/tmp/sample-rsa-" + ts + ".pk8.der"), keyPair.getPrivate().getEncoded()); // 공개키 → X.509 PEM String pem = "-----BEGIN PUBLIC KEY-----\n" + Base64.getMimeEncoder(64, "\n".getBytes(StandardCharsets.US_ASCII)) .encodeToString(keyPair.getPublic().getEncoded()) + "\n-----END PUBLIC KEY-----\n"; Files.writeString(Path.of("/tmp/sample-rsa-" + ts + ".pub.pem"), pem); ``` ## KeyStore에 보관한 키 키를 KeyStore 파일에 보관하고 있다면, `getKey`로 꺼낸 객체가 주입할 키입니다. KeyStore 형식에 맞게 `getInstance`의 인자를 지정하십시오. AES 키는 PKCS12 또는 JCEKS에 보관할 수 있고, JKS에는 보관할 수 없습니다. ```java KeyStore ks = KeyStore.getInstance("PKCS12"); // JCEKS라면 "JCEKS", JKS라면 "JKS" try (FileInputStream in = new FileInputStream("my.p12")) { ks.load(in, password); } Key key = ks.getKey(alias, password); // AES 키면 SecretKey, RSA/EC 키면 PrivateKey if (key instanceof PrivateKey) { // RSA/EC 키는 함께 저장된 인증서에서 공개키를 꺼냅니다. AES 키에는 인증서가 없습니다. PublicKey publicKey = ks.getCertificate(alias).getPublicKey(); } ``` 꺼낸 `key`가 `SecretKey`이면 [AES 예시](/docs/hsm-byok-key-prep#AESGCM%EC%BD%94%EB%93%9C%EC%97%90%EC%84%9C%EA%BA%BC%EB%82%B4%EA%B8%B0)와 같이, `PrivateKey`이면 [RSA·EC 예시](/docs/hsm-byok-key-prep#%EC%84%9C%EB%AA%85%EC%BD%94%EB%93%9C%EC%97%90%EC%84%9C%EA%BA%BC%EB%82%B4%EA%B8%B0)와 같이 저장합니다. 공개키는 위 `publicKey`를 같은 방법으로 PEM으로 저장합니다. ## 파일 대신 화면 출력으로 옮기기 애플리케이션이 실행되는 곳에서 파일을 바로 쓰기 어렵다면, 값을 Base64로 출력한 뒤 복사해 키 보유 측 작업 시스템에서 파일로 저장할 수 있습니다. ```java // AES 키 System.out.println(Base64.getEncoder().encodeToString(key.getEncoded())); // 개인키 System.out.println(Base64.getMimeEncoder(64, "\n".getBytes(StandardCharsets.US_ASCII)) .encodeToString(keyPair.getPrivate().getEncoded())); // 공개키는 위 RSA·EC 예시의 pem 문자열을 그대로 출력합니다. System.out.println(pem); ``` **실행 위치 — 키 보유 측 작업** 출력된 값을 복사한 뒤 다음 명령을 실행하고, 붙여넣은 다음 `Enter`와 `Ctrl+D`를 차례로 입력합니다. ```bash umask 077 # 이 셸에서 만드는 파일을 소유자만 읽고 쓸 수 있게 함 # AES 키: Base64를 디코딩해 저장 base64 -d > "/tmp/sample-aes-$TS.bin" # 개인키: Base64를 디코딩해 저장 (EC 키라면 rsa 를 ec 로) base64 -d > "/tmp/sample-rsa-$TS.pk8.der" # 공개키: PEM을 그대로 저장 (EC 키라면 rsa 를 ec 로) cat > "/tmp/sample-rsa-$TS.pub.pem" ``` 옮길 값마다 해당하는 명령 하나를 실행하고 붙여넣으십시오. :::(warning) (주의) 화면에 출력한 키 값은 터미널 스크롤 기록, 클립보드, 애플리케이션 로그에 남을 수 있습니다. 옮긴 뒤에는 출력 코드를 제거하고 터미널 기록과 클립보드를 지우십시오. 키 값을 명령행 인자(`echo '...'` 등)로 넘기면 셸 기록에 남으므로 위처럼 표준입력으로 붙여넣으십시오. ::: ## Java 코드 없이 PKCS#12 파일에서 꺼내기 키를 PKCS#12 파일로 보관하고 있다면 Java 코드 없이 OpenSSL로 꺼낼 수도 있습니다. PKCS#12 파일에 개인키가 하나만 들어 있는 경우의 예입니다. **실행 위치 — 키 보유 측 작업** ```bash umask 077 # 개인키 → PKCS#8 DER openssl pkcs12 -in my.p12 -nocerts -nodes \ | openssl pkcs8 -topk8 -nocrypt -outform DER -out "/tmp/sample-rsa-$TS.pk8.der" # 인증서의 공개키 → X.509 PEM openssl pkcs12 -in my.p12 -clcerts -nokeys \ | openssl x509 -pubkey -noout > "/tmp/sample-rsa-$TS.pub.pem" ``` OpenSSL 3에서 오래된 방식(RC2, 3DES 등)으로 암호화된 PKCS#12 파일을 열면 `unsupported` 오류가 날 수 있습니다. 이 경우 두 `openssl pkcs12` 명령에 `-legacy`를 붙여 다시 실행하십시오. ## 다음 단계 - 준비한 키를 파티션에 주입하려면 → [BYOK(키 주입) Java 예제](/docs/hsm-byok-java-guide) 또는 [BYOK(키 주입) CLI 예제](/docs/hsm-byok-cli-guide) - 주입 원리와 지원 범위를 확인하려면 → [BYOK(키 주입) 개요](/docs/hsm-byok-overview)