Vault
Manage Vault resources programmatically with Terraform
Use Terraform to manage policies, namespaces, and plugins in Vault.
Before you start
- You must have Terraform installed.
- You must have the Terraform Vault provider configured.
- You must have sufficient access to run Terraform.
- You must have a Vault server running.
Step 1: Create a resource file for namespaces
Terraform Vault provider supports a vault_namespace resource type for
managing Vault namespaces:
resource "vault_namespace" "<TERRAFORM_RESOURCE_NAME>" {
path = "<VAULT_NAMESPACE>"
}
To manage your Vault namespaces in Terraform:
Use the
vault namespace listcommand to identify any unmanaged namespaces that you need to migrate. For example:$ vault namespace list Keys ---- admin/Create a new Terraform Vault Provider resource file called
vault_namespaces.tfthat definesvault_namespaceresources for each of the new or existing namespaces resources you want to manage.For example, to migrate the
adminnamespace in the example and create a newdevnamespace:resource "vault_namespace" "admin_ns" { path = "admin" } resource "vault_namespace" "dev_ns" { path = "dev" }
Step 2: Create a resource file for secret engines
Terraform Vault provider supports discrete types for the different auth, secret, and database plugin types in Vault.
To migrate a secret engine, use the vault_mount resource type:
resource "vault_mount" "<TERRAFORM_RESOURCE_NAME>" {
path = "<VAULT_NAMESPACE>"
type = "<VAULT_PLUGIN_TYPE>"
}
To manage your Vault secret engines in Terraform:
Use the
vault secret listcommand to identify any unmanaged secret engines that you need to migrate. For example:$ vault secrets list | grep -vEw '(cubbyhole|identity|sys)' Path Type Accessor Description ---- ---- -------- ----------- transit/ transit transit_8291b949 n/aUse the
-namespaceflag to check for unmanaged secret engines under any namespaces you identified in the previous step. For example, to check for secret engines under theadminnamespace:$ vault secrets list -namespace=admin | grep -vEw '(cubbyhole|identity|sys)' Path Type Accessor Description ---- ---- -------- ----------- admin_keys/ kv kv_87edfc65 n/aCreate a new Terraform Vault Provider resource file called
vault_secrets.tfthat definesvault_mountresources for each of the new or existing secret engines you want to manage.For example, to migrate the
transitandadmin_keyssecret engines in the example and enable a newkvengine under the newdevnamespace calleddev_keys: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" } }
Step 3: Create a resource file for policies
Terraform Vault provider supports a vault_policy resource type for
managing Vault policies:
resource "vault_policy" "<TERRAFORM_RESOURCE_NAME>" {
name = "<VAULT_POLICY_NAME>"
policy = <<EOT
<VAULT_POLICY_DEFINITION>
EOT
}
To manage your Vault policies in Terraform:
Use the
vault policy listcommand to identify any unmanaged policies that you need to migrate. For example:$ vault policy list | grep -vEw 'root' defaultCreate a Terraform Vault Provider resource file called
vault_policies.tfthat definesvault_mountresources for each policy resource you want to manage in Terraform. You can use the followingbashcode to write all your existing, non-root policies to the file: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.tfUpdate the
vault_policies.tffile with any new policies you want to add. For example, to create a policy for the exampledev_keyssecret engine:resource "vault_policy" "dev_team_policy" { name = "dev_team" policy = <<EOT path vault_mount.dev_keys_plugin.path { capabilities = ["create", "update"] } EOT }
Step 4: Update your Terraform configuration
Create a
vaultdirectory wherever you keep your deployment configuration files for Terraform.Save your new resource files to your new Vault configuration directory.
Use
terraform fmtto adjust the formatting (if needed) of your new configuration files:$ terraform fmt vault_namespaces.tf vault_secrets.tf vault_policies.tfUse
terraform validateto confirm the new configuration is valid:$ terraform validate Success! The configuration is valid.
Step 5: Import preexisting root-level resources
Use the terraform import command to import the preexisting root-level resources.
For example, continue from the previous steps, and import the 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.
Import the default policy:
$ 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.
Import the transit plugin:
$ 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.
Step 6: Import preexisting nested resources
To import resources that belong to a previously unmanaged namespace, you must
set the TERRAFORM_VAULT_NAMESPACE_IMPORT environment variable before importing.
For example, to import the admin_keys secret engine from the admin namespace:
Set
TERRAFORM_VAULT_NAMESPACE_IMPORTto theadminVault namespace:$ export TERRAFORM_VAULT_NAMESPACE_IMPORT="admin"Import the
vault_mountresourceadmin_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.Unset the
TERRAFORM_VAULT_NAMESPACE_IMPORTvariable when you finish importing child resources:$ unset TERRAFORM_VAULT_NAMESPACE_IMPORT
Step 6: Verify the import
Use the
terraform state showcommand to check your Terraform state file and verify the resources imported successfully. For example, to check theadmin_keysresource:$ 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"For each of the migrated resources, compare the
accessorvalue from your Terraform state to the accessor value in Vault. For example, to confirm the accessor foradmin_keys:$ vault secrets list -namespace="admin" | grep -vEw '(cubbyhole|identity|sys)' Path Type Accessor Description ---- ---- -------- ----------- admin_keys/ kv kv_87edfc65 n/a
Step 7: Add new Vault resources
Run
terraform planto confirm the new resources that Terraform will manage:$ 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.Run
terraform applyto create the new resources:$ 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.Use the
terraform state showcommand to check your Terraform state file and verify the new resources created successfully. For example, to check thedev_keysresource:$ 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" }Confirm that your Vault instance can use the new resources. For example, to confirm the
dev_keysresources:$ vault secrets list -namespace="dev" | grep -vEw '(cubbyhole|identity|sys)' Path Type Accessor Description ---- ---- -------- ----------- dev_keys/ kv kv_b3d2dd6f n/a
Additional guide
Review the best practices for programmatic Vault management for additional guidance.