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 플래그를 사용합니다. 예를 들어 admin namespace 아래의 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 리소스 파일을 만듭니다.

예를 들어 예시의 transitadmin_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_keys secret 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_IMPORTadmin Vault 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 관리를 위한 모범 사례를 검토하세요.

더 알아보기