Transit 키 가져오기를 위한 키 래핑

Transit 키 가져오기를 위한 키 래핑

transit 시크릿 엔진의 "bring your own key"(BYOK) 기능은 사용자가 Vault 밖에서 생성된 키를 transit 시크릿 엔진으로 가져올 수 있게 해요.

이 문서는 외부에서 생성된 키(대상 키)를 Vault로 가져오기 위해 래핑하는 과정을 설명해요. Golang을 사용한 소프트웨어 저장 키 가져오기와 HSM에 저장된 키 가져오기 과정을 모두 설명해요.

출처: 문서

본문

시크릿 엔진 마운트하기

$ vault secrets enable transit
Success! Enabled the transit secrets engine at: transit/

Transit 래핑 키 가져오기

$ vault read transit/wrapping_key

이것은 4096비트 RSA 키를 반환해요.

이후 단계는 키가 소프트웨어 솔루션으로 저장되어 있는지 HSM에 있는지에 따라 달라져요.

소프트웨어 예시 (Go)

이 예시는 키가 key라는 변수 이름을 사용해 소프트웨어에 저장되어 있다고 가정해요. Golang crypto 라이브러리로 대상 키를 래핑하는 방법을 보여 줘요.

래핑 키를 얻으면 encoding/pemcrypto/x509 라이브러리로 파싱할 수 있어요(아래 예시 코드는 래핑 키가 wrappingKeyString이라는 변수에 쓰였다고 가정해요).

keyBlock, _ := pem.Decode([]byte(wrappingKeyString))
parsedKey, err := x509.ParsePKIXPublicKey(keyBlock.Bytes)
if err != nil {
    return err
}

그런 다음 대상 키를 래핑할 일회성 AES 키를 생성해요. 이 예시는 키 생성에 Golang의 crypto/rand 라이브러리를 사용해요.

ephemeralAESKey := make([]byte, 32)
_, err := rand.Read(ephemeralAESKey)
if err != nil {
        return err
}

참고: 일회성 AES 키는 사용 후 반드시 안전하게 삭제하세요!

Google의 tink 라이브러리는 키 래핑 작업을 수행하는 함수를 제공해요.

wrapKWP, err := subtle.NewKWP(aesKey)
if err != nil {
        return err
}
wrappedTargetKey, err := wrapKWP.Wrap(key)
if err != nil {
        return err
}

그런 다음 transit 래핑 키를 사용해 일회성 AES 키를 암호화해요.

wrappedAESKey, err := rsa.EncryptOAEP(
        sha256.New(),
        rand.Reader,
        wrappingKey,
        ephemeralAESKey,
        []byte{},
)
if err != nil {
        return err
}

이 예시가 SHA256을 사용하지만 Vault는 SHA1, SHA384, SHA512 사용도 지원한다는 점을 기억하세요. 이 단계에서 사용한 해시 함수는 키를 가져올 때 파라미터로 제공해야 해요.

마지막으로 래핑된 키들을 단일 바이트 문자열로 연결해요. 문자열의 가장 왼쪽 4096비트는 래핑된 AES 키여야 하고, 나머지 비트는 래핑된 대상 키여야 해요. 그런 다음 결과 바이트를 base64로 인코딩해요.

combinedCiphertext := append(wrappedAESKey, wrappedTargetKey...)
base64Ciphertext := base64.StdEncoding.EncodeToString(combinedCiphertext)

이것이 transit 시크릿 엔진에 키를 가져올 때 Vault에 제공해야 하는 암호문이에요.

$ vault write transit/keys/test-key/import ciphertext=$CIPHERTEXT hash_function=SHA256 type=$KEY_TYPE

AWS CloudHSM 예시

이 예시는 AWS CloudHSM 클러스터에서 transit 시크릿 엔진으로 키를 가져오는 방법을 보여 줘요. 과정과 사용 메커니즘은 일반적으로 HSM에서 키를 가져오는 데 적용되지만, 구체적 세부 사항은 HSM마다 다를 거예요.

AWS CloudHSM 클러스터 생성과 통신에 대한 정보는 AWS CloudHSM 문서의 Getting Started 가이드를 참고하세요.

HSM과의 통신은 AWS의 key_mgmt_util 도구를 사용해요. 설정에 대한 도움은 key_mgmt_util의 Getting Started 페이지를 참고하세요.

첫 단계는 transit 래핑 키를 HSM에 쓰는 것이에요. 이는 transit의 wrapping_key 엔드포인트가 반환한 키로 새 RSA 공개 키 객체를 만드는 것을 포함해요.

$ importPubKey -f wrapping_key.pem -l "vault-transit-wrapping-key"

이렇게 하면 필요한 모든 권한과 함께 HSM에 공개 키가 생성돼요. 다른 도구를 사용한다면 래핑 키의 용도(usage)에 CKA_WRAP 속성이 포함되어 있는지 확인하세요.

다음 단계는 래핑 키를 사용해 대상 키를 래핑하는 것이에요. 대상 키의 ID가 1이고 래핑 키가 2라면 명령은 다음과 같아요.

$ wrapKey -noheader -k 1 -w 2 -t 3 -m 7 -out ciphertext.key

-m 7 플래그는 키 래핑에 사용할 메커니즘을 지정해요. AWS CloudHSM의 경우 7은 PKCS11 메커니즘 CKM_AES_RSA_KEY_WRAP에 해당해요(자세한 내용은 AWS 문서 참고). -t 3 플래그는 해시 함수로 SHA256을 지정해요. 결과는 ciphertext.key라는 파일에 써져요. noheader 플래그는 암호문에 AWS 특정 헤더가 포함되지 않도록 보장해요.

이 출력은 바이너리 파일이며, Vault에 제공할 때 base64로 인코딩해야 해요.

$ export CIPHERTEXT=$(base64 ciphertext.key)
$ vault write transit/keys/test-key/import ciphertext=$CIPHERTEXT hash_function=SHA256 type=$KEY_TYPE

키를 가져온 후에는 다른 transit 키처럼 사용할 수 있어요.

더 알아보기 (Learn more)