Terraform으로 Vault 리소스를 프로그래매틱하게 관리
Terraform으로 Vault 리소스를 프로그래매틱하게 관리
Terraform을 사용해 Vault의 정책, namespace, 플러그인을 관리하세요.
출처: 문서
본문
시작하기 전에
- Terraform이 설치되어 있어야 합니다.
- Terraform Vault provider가 구성되어 있어야 합니다.
- Terraform을 실행할 충분한 접근 권한이 있어야 합니다.
- Vault 서버가 실행 중이어야 합니다.
1단계: namespace용 리소스 파일 만들기
Terraform Vault provider는 Vault namespace를 관리하기 위한 vault_namespace 리소스 유형을 지원합니다:
resource "vault_namespace" "<TERRAFORM_RESOURCE_NAME>" {
path = "<VAULT_NAMESPACE>"
}
Terraform에서 Vault namespace를 관리하려면:
vault namespace list명령을 사용해 마이그레이션해야 하는 관리되지 않는 namespace를 식별합니다. 예를 들어:
$ vault namespace list
Keys
----
admin/
- 관리할 새 namespace 또는 기존 namespace 각각에 대해
vault_namespace리소스를 정의하는vault_namespaces.tf라는 새 Terraform Vault Provider 리소스 파일을 만듭니다.
예를 들어 예시의 admin namespace를 마이그레이션하고 새 dev namespace를 만들려면:
resource "vault_namespace" "admin_ns" {
path = "admin"
}
resource "vault_namespace" "dev_ns" {
path = "dev"
}
2단계: secret engine용 리소스 파일 만들기
Terraform Vault provider는 Vault의 다양한 auth, secret, database 플러그인 유형에 대해 개별 유형을 지원합니다.
secret engine을 마이그레이션하려면 vault_mount 리소스 유형을 사용합니다:
resource "vault_mount" "<TERRAFORM_RESOURCE_NAME>" {
path = "<VAULT_NAMESPACE>"
type = "<VAULT_PLUGIN_TYPE>"
}
Terraform에서 Vault secret engine을 관리하려면:
vault secret list명령을 사용해 마이그레이션해야 하는 관리되지 않는 secret engine을 식별합니다. 예를 들어:
$ vault secrets list | grep -vEw '(cubbyhole|identity|sys)'
Path Type Accessor Description
---- ---- -------- -----------
transit/ transit transit_8291b949 n/a
- 이전 단계에서 식별한 namespace 아래의 관리되지 않는 secret engine을 확인하려면
-namespace플래그를 사용합니다. 예를 들어adminnamespace 아래의 secret engine을 확인하려면:
$ vault secrets list -namespace=admin | grep -vEw '(cubbyhole|identity|sys)'
Path Type Accessor Description
---- ---- -------- -----------
admin_keys/ kv kv_87edfc65 n/a
- 관리할 새 secret engine 또는 기존 secret engine 각각에 대해
vault_mount리소스를 정의하는vault_secrets.tf라는 새 Terraform Vault Provider 리소스 파일을 만듭니다.
예를 들어 예시의 transit 및 admin_keys secret engine을 마이그레이션하고 새 dev namespace 아래에 dev_keys라는 새 kv engine을 활성화하려면:
resource "vault_mount" "transit_plugin" {
path = "transit"
type = "transit"
}
resource "vault_mount" "admin_keys_plugin" {
namespace = vault_namespace.admin_ns.path
path = "admin_keys"
type = "kv"
options = {
version = "2"
}
}
resource "vault_mount" "dev_keys_plugin" {
namespace = vault_namespace.dev_ns.path
path = "dev_keys"
type = "kv"
options = {
version = "2"
}
}
3단계: 정책용 리소스 파일 만들기
Terraform Vault provider는 Vault 정책을 관리하기 위한 vault_policy 리소스 유형을 지원합니다:
resource "vault_policy" "<TERRAFORM_RESOURCE_NAME>" {
name = "<VAULT_POLICY_NAME>"
policy = <<EOT
<VAULT_POLICY_DEFINITION>
EOT
}
Terraform에서 Vault 정책을 관리하려면:
vault policy list명령을 사용해 마이그레이션해야 하는 관리되지 않는 정책을 식별합니다. 예를 들어:
$ vault policy list | grep -vEw 'root'
default
- Terraform에서 관리하려는 각 정책 리소스에 대해
vault_mount리소스를 정의하는vault_policies.tf라는 Terraform Vault Provider 리소스 파일을 만듭니다. 다음bash코드를 사용해 기존의 root가 아닌 모든 정책을 파일에 쓸 수 있습니다:
for vpolicy in $(vault policy list | grep -vw root) ; do
echo "resource \"vault_policy\" \"vault_$vpolicy\" {"
echo " name = \"$vpolicy\""
echo " policy = <<EOT"
vault policy read $vpolicy
echo "EOT"
echo "}"
echo ""
done > vault_policies.tf
- 추가하려는 새 정책으로
vault_policies.tf파일을 갱신합니다. 예를 들어 예시dev_keyssecret engine에 대한 정책을 만들려면:
resource "vault_policy" "dev_team_policy" {
name = "dev_team"
policy = <<EOT
path vault_mount.dev_keys_plugin.path {
capabilities = ["create", "update"]
}
EOT
}
4단계: Terraform 구성 갱신
- Terraform용 배포 구성 파일을 두는 곳에
vault디렉터리를 만듭니다. - 새 리소스 파일을 새 Vault 구성 디렉터리에 저장합니다.
terraform fmt를 사용해(필요한 경우) 새 구성 파일의 형식을 조정합니다:
$ terraform fmt
vault_namespaces.tf
vault_secrets.tf
vault_policies.tf
terraform validate를 사용해 새 구성이 유효한지 확인합니다:
$ terraform validate
Success! The configuration is valid.
5단계: 기존 root-level 리소스 가져오기
terraform import 명령을 사용해 기존 root-level 리소스를 가져옵니다.
예를 들어 이전 단계에서 이어서 admin namespace를 가져옵니다:
$ terraform import vault_namespace.admin_ns admin
vault_namespace.admin_ns: Importing from ID "admin"...
vault_namespace.admin_ns: Import prepared!
Prepared vault_namespace for import
vault_namespace.admin_ns: Refreshing state... [id=admin]
Import successful!
The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.
default 정책을 가져옵니다:
$ terraform import vault_policy.default_policy default
vault_policy.default_policy: Importing from ID "default"...
vault_policy.default_policy: Import prepared!
Prepared vault_policy for import
vault_policy.default_policy: Refreshing state... [id=default]
Import successful!
The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.
transit 플러그인을 가져옵니다:
$ terraform import vault_mount.transit_plugin transit
vault_mount.transit_plugin: Importing from ID "transit"...
vault_mount.transit_plugin: Import prepared!
Prepared vault_mount for import
vault_mount.transit_plugin: Refreshing state... [id=transit]
Import successful!
The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.
6단계: 기존 중첩(nested) 리소스 가져오기
이전에 관리되지 않은 namespace에 속한 리소스를 가져오려면 가져오기 전에 TERRAFORM_VAULT_NAMESPACE_IMPORT 환경 변수를 설정해야 합니다.
예를 들어 admin namespace에서 admin_keys secret engine을 가져오려면:
TERRAFORM_VAULT_NAMESPACE_IMPORT를adminVault namespace로 설정합니다:
$ export TERRAFORM_VAULT_NAMESPACE_IMPORT="admin"
vault_mount리소스admin_keys를 가져옵니다:
$ terraform import vault_mount.admin_keys_plugin admin_keys
vault_mount.admin_keys_plugin: Importing from ID "admin_keys"...
vault_mount.admin_keys_plugin: Import prepared!
Prepared vault_mount for import
vault_mount.admin_keys_plugin: Refreshing state... [id=admin_keys]
Import successful!
The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.
- 자식 리소스 가져오기를 마치면
TERRAFORM_VAULT_NAMESPACE_IMPORT변수를 해제합니다:
$ unset TERRAFORM_VAULT_NAMESPACE_IMPORT
6단계: 가져오기 확인
terraform state show명령을 사용해 Terraform state 파일을 확인하고 리소스가 성공적으로 가져왔는지 검증합니다. 예를 들어admin_keys리소스를 확인하려면:
$ terraform state show vault_mount.admin_keys_plugin
# vault_mount.admin_keys_plugin:
resource "vault_mount" "admin_keys" {
accessor = "kv_87edfc65"
allowed_managed_keys = []
audit_non_hmac_request_keys = []
audit_non_hmac_response_keys = []
default_lease_ttl_seconds = 0
description = null
external_entropy_access = false
id = "admin_keys"
local = false
max_lease_ttl_seconds = 0
namespace = "admin"
options = {
"version" = "2"
}
path = "admin_keys"
seal_wrap = false
type = "kv"
- 각 마이그레이션된 리소스에 대해 Terraform state의
accessor값을 Vault의 accessor 값과 비교합니다. 예를 들어admin_keys의 accessor를 확인하려면:
$ vault secrets list -namespace="admin" | grep -vEw '(cubbyhole|identity|sys)'
Path Type Accessor Description
---- ---- -------- -----------
admin_keys/ kv kv_87edfc65 n/a
7단계: 새 Vault 리소스 추가
terraform plan을 실행해 Terraform이 관리할 새 리소스를 확인합니다:
$ terraform plan
vault_policy.default_policy: Refreshing state... [id=default]
vault_namespace.admin_ns: Refreshing state... [id=admin/]
vault_mount.transit_plugin: Refreshing state... [id=transit]
vault_mount.admin_keys_plugin: Refreshing state... [id=admin_keys]
Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# vault_mount.dev_keys_plugin will be created
+ resource "vault_mount" "dev_keys" {
+ accessor = (known after apply)
+ audit_non_hmac_request_keys = (known after apply)
+ audit_non_hmac_response_keys = (known after apply)
+ default_lease_ttl_seconds = (known after apply)
+ external_entropy_access = false
+ id = (known after apply)
+ max_lease_ttl_seconds = (known after apply)
+ namespace = "dev"
+ options = {
+ "version" = "2"
}
+ path = "dev_keys"
+ seal_wrap = (known after apply)
+ type = "kv"
}
# vault_namespace.dev_ns will be created
+ resource "vault_namespace" "dev" {
+ custom_metadata = (known after apply)
+ id = (known after apply)
+ namespace_id = (known after apply)
+ path = "dev"
+ path_fq = (known after apply)
}
# vault_policy.dev_team will be created
+ resource "vault_policy" "dev_team" {
+ id = (known after apply)
+ name = "dev_team"
+ policy = <<-EOT
path vault_mount.dev_keys_plugin.path {
capabilities = ["create", "update"]
}
EOT
}
Plan: 3 to add, 0 to change, 0 to destroy.
terraform apply를 실행해 새 리소스를 만듭니다:
$ terraform apply
vault_namespace.dev_ns: Creating...
vault_namespace.dev_ns: Creation complete after 0s [id=dev/]
vault_mount.dev_keys_plugin: Creating...
vault_mount.dev_keys_plugin: Creation complete after 0s [id=dev_keys]
vault_policy.dev_team: Creating...
vault_policy.dev_team: Creation complete after 0s [id=dev_team]
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
terraform state show명령을 사용해 Terraform state 파일을 확인하고 새 리소스가 성공적으로 생성되었는지 검증합니다. 예를 들어dev_keys리소스를 확인하려면:
$ terraform state show vault_mount.dev_keys_plugin
# vault_mount.dev_keys_plugin:
resource "vault_mount" "dev_keys" {
accessor = "kv_b3d2dd6f"
allowed_managed_keys = []
audit_non_hmac_request_keys = []
audit_non_hmac_response_keys = []
default_lease_ttl_seconds = 0
description = null
external_entropy_access = false
id = "dev_keys"
local = false
max_lease_ttl_seconds = 0
namespace = "dev"
options = {
"version" = "2"
}
path = "dev_keys"
seal_wrap = false
type = "kv"
}
- Vault 인스턴스가 새 리소스를 사용할 수 있는지 확인합니다. 예를 들어
dev_keys리소스를 확인하려면:
$ vault secrets list -namespace="dev" | grep -vEw '(cubbyhole|identity|sys)'
Path Type Accessor Description
---- ---- -------- -----------
dev_keys/ kv kv_b3d2dd6f n/a
추가 가이드 추가 지침은 프로그래매틱 Vault 관리를 위한 모범 사례를 검토하세요.