vault/website/content/docs/configuration/programmatic-management.mdx
Sarah Chavis 53ec4d5f7b
[DOCS] Manage resources with TF (#27171)
---------

Co-authored-by: CJ <105300705+cjobermaier@users.noreply.github.com>
Co-authored-by: Brian Shumate <brianshumate@users.noreply.github.com>
2024-05-24 09:55:27 -07:00

463 lines
15 KiB
Plaintext

---
layout: docs
page_title: Manage Vault resources programmatically
description: >-
Step-by-step instructions for managing Vault resources programmatically with
Terraform
---
# Manage Vault resources programmatically with Terraform
Use Terraform to manage policies, namespaces, and plugins in Vault.
## Before you start
- **You must have [Terraform installed](/terraform/install)**.
- **You must have the [Terraform Vault provider](https://registry.terraform.io/providers/hashicorp/vault/latest) configured**.
- **You must have admin access to your Terraform installation**. If you do not
have admin access, you can still generate the relevant configuration files,
but you will need to have someone else apply the changes.
- **You must have a [Vault server running](/vault/tutorials/getting-started/getting-started-dev-server)**.
## Step 1: Create a resource file for namespaces
Terraform Vault provider supports a `vault_namespace` resource type for
managing Vault namespaces:
```hcl
resource "vault_namespace" "<TERRAFORM_RESOURCE_NAME>" {
path = "<VAULT_NAMESPACE>"
}
```
To manage your Vault namespaces in Terraform:
1. Use the `vault namespace list` command to identify any unmanaged namespaces
that you need to migrate. For example:
```shell-session
$ vault namespace list
Keys
----
admin/
```
1. Create a new Terraform Vault Provider resource file called
`vault_namespaces.tf` that defines `vault_namespace` resources for each of
the new or existing namespaces resources you want to manage.
For example, to migrate the `admin` namespace in the example and create a new
`dev` namespace:
```hcl
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](https://registry.terraform.io/providers/hashicorp/vault/latest/docs#vault-authentication-configuration-options),
[secret](https://registry.terraform.io/providers/hashicorp/vault/latest/docs/resources/mount),
and [database](https://registry.terraform.io/providers/hashicorp/vault/latest/docs/resources/database_secrets_mount)
plugin types in Vault.
To migrate a secret engine, use the `vault_mount` resource type:
```hcl
resource "vault_mount" "<TERRAFORM_RESOURCE_NAME>" {
path = "<VAULT_NAMESPACE>"
type = "<VAULT_PLUGIN_TYPE>"
}
```
To manage your Vault secret engines in Terraform:
1. Use the `vault secret list` command to identify any unmanaged secret engines
that you need to migrate. For example:
```shell-session
$ vault secrets list | grep -vEw '(cubbyhole|identity|sys)'
Path Type Accessor Description
---- ---- -------- -----------
transit/ transit transit_8291b949 n/a
```
1. Use the `-namespace` flag to check for unmanaged secret engines under any
namespaces you identified in the previous step. For example, to check for
secret engines under the `admin` namespace:
```shell-session
$ vault secrets list -namespace=admin | grep -vEw '(cubbyhole|identity|sys)'
Path Type Accessor Description
---- ---- -------- -----------
admin_keys/ kv kv_87edfc65 n/a
```
1. Create a new Terraform Vault Provider resource file called `vault_secrets.tf`
that defines `vault_mount` resources for each of the new or existing secret
engines you want to manage.
For example, to migrate the `transit` and `admin_keys` secret engines in the
example and enable a new `kv` engine under the new `dev` namespace called
`dev_keys`:
```hcl
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:
```hcl
resource "vault_policy" "<TERRAFORM_RESOURCE_NAME>" {
name = "<VAULT_POLICY_NAME>"
policy = <<EOT
<VAULT_POLICY_DEFINITION>
EOT
}
```
To manage your Vault policies in Terraform:
1. Use the `vault policy list` command to identify any unmanaged policies that
you need to migrate. For example:
```shell-session
$ vault policy list | grep -vEw 'root'
default
```
1. Create a Terraform Vault Provider resource file called `vault_policies.tf`
that defines `vault_mount` resources for each policy resource you want to
manage in Terraform. You can use the following `bash` code to write all
your existing, non-root policies to the file:
```shell-session
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
```
1. Update the `vault_policies.tf` file with any new policies you want to add.
For example, to create a policy for the example `dev_keys` secret engine:
```hcl
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
1. Create a `vault` directory wherever you keep your deployment configuration
files for Terraform.
1. Save your new resource files to your new Vault configuration directory.
1. Use `terraform fmt` to adjust the formatting (if needed) of your new
configuration files:
```shell-session
$ terraform fmt
vault_namespaces.tf
vault_secrets.tf
vault_policies.tf
```
1. Use `terraform validate` to confirm the new configuration is valid:
```shell-session
$ 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, import the `admin` namespace, `default` policy, and `transit`
plugin from the previous steps:
```shell-session
$ 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.
```
```shell-session
$ 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.
```
```shell-session
$ 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:
1. Set `TERRAFORM_VAULT_NAMESPACE_IMPORT` to the `admin` Vault namespace:
```shell-session
$ export TERRAFORM_VAULT_NAMESPACE_IMPORT="admin"
```
1. Import the `vault_mount` resource `admin_keys`:
```shell-session
$ 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.
```
1. Unset the `TERRAFORM_VAULT_NAMESPACE_IMPORT` variable when you finish
importing child resources:
```shell-session
$ unset TERRAFORM_VAULT_NAMESPACE_IMPORT
```
## Step 6: Verify the import
1. Use the `terraform state show` command to check your Terraform state file and
verify the resources imported successfully. For example, to check the
`admin_keys` resource:
```shell-session
$ 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"
```
1. For each of the migrated resources, compare the `accessor` value from your
Terraform state to the accessor value in Vault. For example, to confirm the
accessor for `admin_keys`:
```shell-session
$ 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
1. Run `terraform plan` to confirm the new resources that Terraform will manage:
```shell-session
$ 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.
```
1. Run `terraform apply` to create the new resources:
```shell-session
$ 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.
```
1. Use the `terraform state show` command to check your Terraform state file and
verify the new resources created successfully. For example, to check the
`dev_keys` resource:
```shell-session
$ 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"
}
```
1. Confirm that your Vault instance can use the new resources. For example, to
confirm the `dev_keys` resources:
```shell-session
$ vault secrets list -namespace="dev" | grep -vEw '(cubbyhole|identity|sys)'
Path Type Accessor Description
---- ---- -------- -----------
dev_keys/ kv kv_b3d2dd6f n/a
```
## Next steps
1. Review the [best practices for programmatic Vault management](/vault/docs/configuration/programmatic-best-practices).