Migrate unmanaged Vault namespace to Terraform-managed infrastructure
This topic describes importing unmanaged resources into Terraform, with an example focused on importing a namespace and secrets engine.
Overview
When using a Vault cluster to secure, store, and access secrets, we recommend using Terraform to manage administrative resources such as auth methods, secrets engines, namespaces, and policies. Terraform allows you to apply policy and governance at scale using an infrastructure as code (IaC) approach.
When an organization creates new Vault namespaces, they may have specific ACL or Sentinel policies which must be applied to the namespaces. However, if a Vault namespace administrator creates a child namespace directly from the Vault CLI or API, these policies must be manually applied by the cluster's administrator. When you create these namespaces with Terraform, you can ensure security controls are applied automatically to every single cluster. As a result, Terraform can automatically apply updates to managed namespaces when changes to governance policies are required.
Use the following workflow to move an unmanaged Vault namespace to a managed namespace in Terraform:
- Update the Terraform code to include the namespace and mount resources.
- Import the namespace and KV store to the Terraform state.
- Verify that the import was successful.
Example environment
This topic describes the process using the following example environment:
- One Vault instance managed with Terraform.
- One Vault child namespace, which a Vault namespace administrator manages outside of Terraform.
The following diagram depicts the current state of these managed and unmanaged Vault namespaces. The Vault Admin NS
namespace manages three Vault Top NS
namespaces. One of the Vault Top NS
namespaces manages a child namespace, testnamespace
, which contains a KV secrets engine named testkv
.
Requirements
- Vault Enterprise
- Terraform
Update the Terraform code
Add resource blocks to the Terraform code for the unmanaged namespace testnamespace
and KV store testkv
. Add these resource blocks to the same Terraform code that manages the existing managed namespaces.
The following defines resource blocks for testnamespace
and the testkv
KV store so that Terraform can manage them.
resource "vault_namespace" "testnamespace" {
path = "testnamespace"
}
resource "vault_mount" "testkv" {
namespace = vault_namespace.testnamespace.path
path = "testkv"
options = {
version = "2"
}
type = "kv"
}
Import namespace and KV into the Terraform state
After you update the Terraform configuration with the namespace and KV store resource blocks, you can import the existing namespace and KV store into the Terraform state file. You can do this with the Terraform import command or by adding import blocks into the configuration file. The following example uses the terraform import
command.
First, import the unmanaged testnamespace
into the state file and map it to the vault_namespace.testnamespace
resource you created.
$ terraform import vault_namespace.testnamespace testnamespace
vault_namespace.testnamespace: Importing from ID "testnamespace"...
vault_namespace.testnamespace: Import prepared!
Prepared vault_namespace for import
vault_namespace.testnamespace: Refreshing state... [id=testnamespace]
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.
After Terraform imports the testnamespace
namespace, you can import the KV testkv
namespace resource. When importing a resource within an unmanaged namespace, you must set the TERRAFORM_VAULT_NAMESPACE_IMPORT
environment variable to the value of the namespace that testkv
resides in. In the example, this namespace is testnamespace
.
$ export TERRAFORM_VAULT_NAMESPACE_IMPORT=”testnamespace”
Then import the testkv
namespace resource to the vault_mount.testkv
resource in the Terraform state file.
$ terraform import vault_mount.testkv testkv
vault_mount.testkv: Importing from ID "testkv"...
vault_mount.testkv: Import prepared!
Prepared vault_mount for import
vault_mount.testkv: Refreshing state... [id=testkv]
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.
Validate import success
Run the terraform state show
command to view the newly created and imported namespace and namespace resources.
$ terraform state show vault_namespace.testnamespace
# vault_namespace.testnamespace:
resource "vault_namespace" "testnamespace" {
id = "testnamespace/"
namespace_id = "aJc64"
path = "testnamespace"
path_fq = "testnamespace"
}
$ terraform state show vault_mount.testkv
# vault_mount.testkv:
resource "vault_mount" "testkv" {
accessor = "kv_2ff74bf1"
allowed_managed_keys = []
audit_non_hmac_request_keys = []
audit_non_hmac_response_keys = []
default_lease_ttl_seconds = 0
external_entropy_access = false
id = "testkv"
local = false
max_lease_ttl_seconds = 0
namespace = "testnamespace"
options = {
"version" = "2"
}
path = "testkv"
seal_wrap = false
type = "kv"
}
If you run the vault secrets list -ns=testnamespace
command on the Vault instance, the accessor value for testkv/
path will match the accessor value kv_2ff74bf1
in the terraform state show vault_mount.testkv
command.
$ vault secrets list -ns=testnamespace
Path Type Accessor Description
---- ---- -------- -----------
cubbyhole/ ns_cubbyhole ns_cubbyhole_1ce89dcf per-token private secret storage
identity/ ns_identity ns_identity_441533c1 identity store
sys/ ns_system ns_system_857f09ea system endpoints used for control, policy and debugging
testkv/ kv kv_2ff74bf1 n/a
Verify that running terraform plan
does not create duplicate resources. Unset the TERRAFORM_VAULT_NAMESPACE_IMPORT environment variable.
$ unset TERRAFORM_VAULT_NAMESPACE_IMPORT
Finally, run terraform plan
.
$ terraform plan
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration and found no differences, so no
changes are needed.
Terraform now manages the previously unmanaged namespace testnamespace
and resource testkv
. Terraform can now apply the governance policies to the testnamespace
namespace.
Next steps
In this usage document, you learned how to import an unmanaged Vault namespace and resource into a Terraform managed environment.
To learn more about managing you resources with Terraform, visit the following resources:
- Best practices for managing Vault with Terraform
- Learn how to use the import block to import existing resources into your Terraform state
- Read how to codify management of Vault using Terraform