Vault Transit Secret Engine란?
Vault의 Transit Secret Engine은 데이터를 암호화하고 복호화하는 데 사용되는 서비스로, 키 관리와 암호화 서비스를 중앙화하여 제공한다. Transit Secret Engine은 전송 중인 데이터에 대한 암호화/복호화를 처리하고, 데이터를 저장하지 않는다는 특징이 있다.
즉 애플리케이션 외부에서 암호화하고, 애플리케이션은 암호화된 형태로 데이터를 처리하게 되기 때문에 데이터 유출 위험이 감소하게 되고, 애플리케이션 개발자의 암호화/복호화에 대한 부담을 덜어준다는 장점이 있다.
Transit의 암호화/복호화 동작 과정은 다음과 같다.
글 작성 기준 Transit Secret Engine은 다음 키 유형을 지원한다.
- aes128-gcm96
- aes256-gcm96 (기본값)
- chacha20-poly1305
- ed25519
- ecdsa-p256
- ecdsa-p384
- ecdsa-p521
- rsa-2048
- rsa-3072
- rsa-4096
- hmac
- managed_key
- 키 관리 솔루션에 따라 다양한 작업을 지원
참고: https://developer.hashicorp.com/vault/docs/secrets/transit#key-types
이번 글에서는 실습을 통해 Vault의 Transit Secret Engine 기능을 통해 평문을 암호화/복호화하고, 암호문(ciphertext) 키를 간단하게 순환(rotate), 재암호화(rewrap)하는 실습을 다룬다.
실습 환경
- Amazon EKS 1.27.7
- Helm Cli v3.8.2
- Vault 1.15.2 (Vault 설치 참고: [Vault 설치])
실습 절차
1. Transit 사용을 위한 유저 생성 및 정책 설정2. Transit Secret Engine 암호화/복호화
3. Transit Secret Engine 암호화 키 순환 (rotate)
4. Transit Secret Engine 암호화 키 재암호화 (rewrap)
5. Transit Secret Engine 기존 암호화 키 파기
참고
Vault의 Auto unseal 기능을 사용하지 않으면, Unseal 후 실습을 진행해야 한다.
1. Transit 사용을 위한 유저 생성 및 정책 설정
먼저, Vault 서버에 접근한다.
$ kubectl exec -it -n vault sts/vault -- /bin/sh
초기 Secret Engine 활성화 및 정책 생성을 위해 "root token"권한이 필요하므로 환경변수를 설정한다.
# ROOT TOKEN 환경변수 설정
$ export VAULT_TOKEN=<ROOT_TOKEN>
transit secret engine을 활성화한다.
참고
이미 transit secret engine이 활성화되어 있으면 해당 과정은 진행하지 않아도 된다.
# transit secrets engine 활성화
$ vault secrets enable -path=transit transit
Success! Enabled the transit secrets engine at: transit/
transit 관리 권한을 위해 "transit-test"라는 이름의 정책을 생성한다.
$ vault policy write transit-test -<<EOF
path "sys/mounts/transit" {
capabilities = [ "create", "read", "update", "delete", "list" ]
}
path "sys/mounts" {
capabilities = [ "read" ]
}
path "transit/*" {
capabilities = [ "create", "read", "update", "delete", "list" ]
}
Success! Uploaded policy: transit-test
유저 생성을 위해 "Username & Password" 인증 방법을 활성화한다.
$ vault auth enable userpass
앞전에 생성한 "transit-test" 정책을 사용할 수 있는 "transit-test" 이름으로 유저를 생성한다.
$ vault write auth/userpass/users/transit-test \
password=<비밀번호 입력> \
policies=transit-test
Success! Data written to: auth/userpass/users/transit-test
생성한 유저로 로그인한다.
$ vault login -method userpass username=transit-test password=<비밀번호 입력>
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.
Key Value
--- -----
token hvs.VBcTlMRVk4bUlDSTQ
token_accessor UaO2Ri64YggpyjtZQBbH
token_duration 768h
token_renewable true
token_policies ["default" "transit-test"]
identity_policies []
policies ["default" "transit-test"]
token_meta_username transit-test
2. Transit Secret Engine 암호화/복호화
test라는 이름의 암호화 키를 생성한다.
$ vault write -f transit/keys/test
Key Value
--- -----
allow_plaintext_backup false
auto_rotate_period 0s
deletion_allowed false
derived false
exportable false
imported_key false
keys map[1:1711941597]
latest_version 1
min_available_version 0
min_decryption_version 1
min_encryption_version 0
name test
supports_decryption true
supports_derivation true
supports_encryption true
supports_signing false
type aes256-gcm96
test 키로 "hello"라는 평문을 암호화한다.
$ vault write transit/encrypt/test \
plaintext=$(echo "hello" | base64)
Key Value
--- -----
ciphertext vault:v1:gh+XRqymJFiBtYXJJaTAiZAJ7QilXXGgL4B+O75awvLqQA==
key_version 1
앞전에 나온 ciphertext의 값으로 복호화하여 plaintext 내용을 확인한다.
$ vault write transit/decrypt/test \
ciphertext="vault:v1:gh+XRqymJFiBtYXJJaTAiZAJ7QilXXGgL4B+O75awvLqQA=="
Key Value
--- -----
plaintext aGVsbG8K
복호화하여 나온 plaintext의 값으로 base64 디코딩하여 메세지를 확인한다.
$ echo "aGVsbG8K" | base64 -d
hello
위 과정을 다음과 같이 한 번에 입력하여 복호화할 수 있다.
$ vault write -field=plaintext transit/decrypt/test ciphertext="vault:v1:gh+XR
qymJFiBtYXJJaTAiZAJ7QilXXGgL4B+O75awvLqQA==" | base64 -d
hello
3. Transit Secret Engine 암호화 키 순환 (rotate)
"rotate" 기능은 암호화 키의 새로운 버전을 생성하는 데 사용된다. 이 기능은 기존의 암호화 키를 새로운 것으로 교체하는 과정을 단순화하여, 키 관리를 더 안전하고 효율적으로 만든다.
다음 명령을 통해 암호화 키를 순환한다.
$ vault write -f transit/keys/test/rotate
Key Value
--- -----
allow_plaintext_backup false
auto_rotate_period 0s
deletion_allowed false
derived false
exportable false
imported_key false
keys map[1:1711941597 2:1711950639]
latest_version 2
min_available_version 0
min_decryption_version 1
min_encryption_version 0
name test
supports_decryption true
supports_derivation true
supports_encryption true
supports_signing false
type aes256-gcm96
keys 값이 2개로 늘어나고, latest_version이 2로 변경된 것을 확인할 수 있다.
다시 "hello"라는 평문을 암호화하면 ciphertext 값이 변경되고, "key_version"이 2로 보이는 것을 확인할 수 있다.
$ vault write transit/encrypt/test \
plaintext=$(echo "hello" | base64)
Key Value
--- -----
ciphertext vault:v2:Ycy/4en8B/S/z8O5pGG7NecK4XjOd+3+yeN8FRMqnHKz0w==
key_version 2
이제 v2의 ciphertext 값과 v1의 ciphertext 값으로 복호화를 진행할 수 있다.
# v1 ciphertext 사용
$ vault write -field=plaintext transit/decrypt/test ciphertext="vault:v1:gh+XRqymJFiBtYXJJaTAiZAJ7QilXXGgL4B+O75awvLqQA==" | base64 -d
hello
# v2 ciphertext 사용
$ vault write -field=plaintext transit/decrypt/test ciphertext="vault:v2:Ycy/4en8B/S/z8O5pGG7NecK4XjOd+3+yeN8FRMqnHKz0w==" | base64 -d
hello
4. Transit Secret Engine 암호화 키 재암호화 (rewrap)
시간이 지남에 따라 암호화 키를 새로운 버전으로 업데이트해야 할 필요가 있을 수 있다. 이런 경우, "rewrap" 기능을 사용하여 이미 암호화된 데이터를 새로운 키 버전으로 다시 암호화할 수 있다.
다음 명령을 통해 맨 처음 만들었던 v1 ciphertext 값을 재암호화하여 v2로 만든다.
$ vault write transit/rewrap/test \
ciphertext="vault:v1:gh+XRqymJFiBtYXJJaTAiZAJ7QilXXGgL4B+O75awvLqQA=="
Key Value
--- -----
ciphertext vault:v2:XwqAnrt5BjftO4nNG3QaSHLMDb/0Gem4PGURj/gHE9hfMA==
key_version 2
기존 v1 ciphertext 값이 rewrap 되어 "vault:v2:xxxxx"로 변경되고, key_version도 2로 변경된 것을 확인할 수 있다.
이제 v1의 ciphertext 값과 rewrap을 통해 v2가 된 ciphertext 값 두 개로 복호화를 진행한다.
# v1의 ciphertext 값
$ vault write -field=plaintext transit/decrypt/test ciphertext="vault:v1:gh+XRqymJFiBtYXJJaTAiZAJ7QilXXGgL4B+O75awvLqQA==" | base64 -d
hello
# v1를 rewrap한 v2 ciphertext 값
$ vault write -field=plaintext transit/decrypt/test ciphertext="vault:v2:XwqAnrt5BjftO4nNG3QaSHLMDb/0Gem4PGURj/gHE9hfMA==" | base64 -d
hello
동일한 결과가 나오는 것을 확인할 수 있다.
5. Transit Secret Engine 기존 암호화 키 파기
test라는 transit key를 조회해 보면 "min_decryption_version"이 1인 것을 확인할 수 있다.
$ vault read transit/keys/test
Key Value
--- -----
allow_plaintext_backup false
auto_rotate_period 0s
deletion_allowed false
derived false
exportable false
imported_key false
keys map[1:1711941597 2:1711950639]
latest_version 2
min_available_version 0
min_decryption_version 1
min_encryption_version 0
name test
supports_decryption true
supports_derivation true
supports_encryption true
supports_signing false
type aes256-gcm96
"min_decryption_version" 값을 2로 올리면 기존 v1에 사용했던 ciphertext 값을 통해 복호화를 진행할 수 없다.
다음 명령을 통해 "min_decryption_version" 값을 2로 설정한다.
$ vault write transit/keys/test/config min_decryption_version=2
Key Value
--- -----
allow_plaintext_backup false
auto_rotate_period 0s
deletion_allowed false
derived false
exportable false
imported_key false
keys map[2:1711950639]
latest_version 2
min_available_version 0
min_decryption_version 2
min_encryption_version 0
name test
supports_decryption true
supports_derivation true
supports_encryption true
supports_signing false
type aes256-gcm96
keys의 값에 [1:xxxx]는 사라지고, "min_decryption_version" 값이 2로 변경된 것을 확인할 수 있다.
이제 v1 ciphertext 값으로 복호화를 진행해 보자.
$ vault write -field=plaintext transit/decrypt/test ciphertext="vault:v1:gh+XRqymJFiBtYXJJaTAiZAJ7QilXXGgL4B+O75awvLqQA==" | base64 -d
Error writing data to transit/decrypt/test: Error making API request.
URL: PUT http://127.0.0.1:8200/v1/transit/decrypt/test
Code: 400. Errors:
* ciphertext or signature version is disallowed by policy (too old)
오래된 버전으로 허용되지 않는다는 메세지와 함께 실패하게 된다.
v2 ciphertext 값으로 복호화가 되는지 확인한다.
$ vault write -field=plaintext transit/decrypt/test ciphertext="vault:v2:XwqAnrt5BjftO4nNG3QaSHLMDb/0Gem4PGURj/gHE9hfMA==" | base64 -d
hello
정상적으로 되는 것을 확인할 수 있다.
첫 번째 rewrap을 통해 생성된 v2 ciphertext 값으로 다시 rewrap을 진행해 보자. (두 번째 rewrap 진행)
$ vault write transit/rewrap/test \
ciphertext="vault:v2:XwqAnrt5BjftO4nNG3QaSHLMDb/0Gem4PGURj/gHE9hfMA=="
Key Value
--- -----
ciphertext vault:v2:+P0b8WahrnbBqvGP/bTk/9F/ufxVRzIlsNmsyLT2qqXR3Q==
key_version 2
두 번째 rewrap으로 생성된 ciphertext 값으로 복호화를 진행한다.
$ vault write -field=plaintext transit/decrypt/test ciphertext="vault:v2:+P0b8WahrnbBqvGP/bTk/9F/ufxVRzIlsNmsyLT2qqXR3Q==" | base64 -d
hello
첫 번째 rewarp 진행한 ciphertext 값도 복호화가 되는지 확인한다.
$ vault write -field=plaintext transit/decrypt/test ciphertext="vault:v2:XwqAnrt5BjftO4nNG3QaSHLMDb/0Gem4PGURj/gHE9hfMA==" | base64 -d
hello
"min_decryption_version" 값이 2이기 때문에 v2 ciphertext 값으로 복호화가 되는 것을 확인할 수 있다.
'Security > Vault' 카테고리의 다른 글
HashiCorp Vault Auto Unseal 기능 사용하여 구성하기 (AWS KMS) (0) | 2024.04.03 |
---|---|
Vault Secrets Operator(VSO)를 활용한 Kubernetes secrets 관리 (PKI 동적 시크릿) (0) | 2024.02.28 |
Vault Secrets Operator(VSO)를 활용한 Kubernetes secrets 관리 (정적 시크릿) (0) | 2024.02.26 |
HashiCorp Vault 란? 개념부터 설치까지 (0) | 2023.04.08 |
댓글