When using with Terraform with Keeper Secrets Manager (KSM) a provider is needed to be configured, the Keeper documentation details how this can be configured. Keeper: Terraform Provider Documentation. However, a short version can be found below.
https://docs.keeper.io/en/keeperpam/secrets-manager/integrations/terraform
You need to have already created a Keeper Secrets Manager (KSM) profile which you can use for authentication, this you’ll be exporting to JSON so it can be used by Terraform.
Convert Profiles to Terraform Compatible
We want to get these Applications (profiles) in a format in which we can use them with Terraform, we can export each of the Applications (profiles) to their own JSON file. The recommendation for using this with Terraform is to use a JSON file.
If your KSM profile is ever updated, you’ll need to run and update to export an updated JSON file.
Ensure you have entered the Python Virtual Environment where KSM is installed, before you start to administer or run your Terraform:
source ~/virtualenvs/keeper/bin/activate
Then we can export, in my example I have two KSM profiles which have access to different sets of Secrets, so I’ll create both of these.
cd ~/.keeper/ksm/
ksm profile export --plain --file-format json ids-imt-net-development > account1-development.json
ksm profile export --plain --file-format json ids-imt-net-staging > account2-staging.json
Now fix the permissions on the files:
chmod 0600 account1-development.json
chmod 0600 account2-staging.json
You now have your JSON files ready for use with Terraform.
Prepare Terraform Environment
We’re going to show a basic setup of our two Terraform environments which use their own JSON file with the corresponding profile from KSM.
- account1-development.json
- account2-staging.json
Example 1 – account1-development.json
We add to the providers block the “secretsmanager” provider an example is given below (providers.tf):
terraform {
# Terraform Version
required_version = ">= 1.8.2"
# Terraform State and Lock Location
backend "s3" {
bucket = "account1-development-tgw"
dynamodb_table = "account1-development-tgw"
key = "account1-development-tgw-state"
region = "eu-west-2"
}
# Terraform Providers (with version constraints)
required_providers {
aws = {
source = "hashicorp/aws"
version = "~>6.11.0"
}
secretsmanager = {
source = "keeper-security/secretsmanager"
version = ">= 1.0.0"
}
}
}
Next we need to specify within the same file (below) the provider “runtime”, which specifies where this Terraform environment can find the JSON file containing the credentials to access KSM (Keeper Secrets Manager) to be able to download the secrets we need (using their UID).
...
provider "secretsmanager" {
credential = file("~/.keeper/ksm/account1-development.json")
}
Once you have added the new provider (KSM – secretsmanager) you’ll likely need to run a “terraform init” to load this provider into your Terraform environment.
terraform init -upgrade

This Terraform environment is now ready to use the variables, let’s look at a second one.
Example 2 – account2-staging.json
We add to the providers block the “secretsmanager” provider an example is given below (providers.tf):
terraform {
# Terraform Version
required_version = ">= 1.8.2"
# Terraform State and Lock Location
backend "s3" {
bucket = "account2-staging-tgw"
dynamodb_table = "account2-staging-tgw"
key = "account2-staging-tgw-state"
region = "eu-west-2"
}
# Terraform Providers (with version constraints)
required_providers {
aws = {
source = "hashicorp/aws"
version = "~>6.11.0"
}
secretsmanager = {
source = "keeper-security/secretsmanager"
version = ">= 1.0.0"
}
}
}
Next we need to specify within the same file (below) the provider “runtime”, which specifies where this Terraform environment can find the JSON file containing the credentials to access KSM (Keeper Secrets Manager) to be able to download the secrets we need (using their UID).
...
provider "secretsmanager" {
credential = file("~/.config/ksm/account2-staging.json")
}
That’s it, that’s both of the Terraform environments ready for use. We can now start retrieving some secrets from KSM within our templates.
Once you have added the new provider (KSM – secretsmanager) you’ll likely need to run a “terraform init” to load this provider into your Terraform environment.
terraform init -upgrade

This Terraform environment is now ready to use the variables, let’s look at a second one.
Terraform Example using account1-development.json
Now we have the two Terraform environments setup, we can actually start using KSM to obtain the secrets and interpolate them into our Terraform templates at runtime.
We are just going to use a simple example here to obtain one of the shared keys that is stored in KSM for the ids-imt-net-development profile.
Get the Path UID for the Tunnel 1 Secret
Run the following to show up the secrets:
(keeper) user@machine:~/vscode/aws-transit-gateway-development$ ksm secrets list
UID Record Type Title
----------------------- ----------- -------------------------------------------------------
ECxfDDZa123456VorEaQ login account2 - AWS VPN Preshared Keys (Tunnel 1)
_V7SH123456WS6YB5F_w login account2 - AWS VPN Preshared Keys (Tunnel 2)
We want the first one, the one with the UID of: ECxfDDZa123456VorEaQ
Add the data definition which refers to the UID, so that Terraform can access KSM and retrieve the secret within the variables.tf file:
# Keeper Secrets Manager
data "secretsmanager_login" "TUNNEL1_PRESHARED_KEY" {
path = "ECxfDDZa123456VorEaQ"
}
Now we have the data resource within Terraform, we can use it to populate a value (i.e. interpolate) in the preshared key for the VPN which is stored in that KSM Secret at runtime, for example see the below, on line 16, the line:
tunnel1_preshared_key = data.secretsmanager_login.TUNNEL1_PRESHARED_KEY.password
Here you can see the use of the variable in action, we first refer to it as a data resource, then the secretsmanager_login then the name of the variable you defined above, i.e. TUNNEL1_PRESHARED_KEY and finally the actual attribute where the secret is held, in this example password.
At the time of writing you can’t use/access “Custom Fields”, so all values must be stored in the allowed list of attributes: https://registry.terraform.io/providers/keeper-security/secretsmanager/latest/docs/data-sources/login
So an example AWS VPN configuration within Terraform that uses a KSM obtained secret can be seen below:
resource "aws_vpn_connection" "TGW-VPN-1" {
customer_gateway_id = aws_customer_gateway.CGW-WTGC-1.id
transit_gateway_id = aws_ec2_transit_gateway.TGW.id
type = "ipsec.1"
tunnel_inside_ip_version = "ipv4"
tunnel1_ike_versions = ["ikev2"]
tunnel2_ike_versions = ["ikev2"]
tunnel1_dpd_timeout_action = "clear"
tunnel2_dpd_timeout_action = "clear"
tunnel1_dpd_timeout_seconds = 30
tunnel2_dpd_timeout_seconds = 30
tunnel1_preshared_key = data.secretsmanager_login.TUNNEL1_PRESHARED_KEY.password
tunnel2_preshared_key = data.secretsmanager_login.TUNNEL2_PRESHARED_KEY.password
tunnel1_inside_cidr = var.tunnel1_inside_cidr
tunnel2_inside_cidr = var.tunnel2_inside_cidr
# IPSEC Phase1 Settings (IKE)
tunnel1_phase1_encryption_algorithms = ["AES256"]
tunnel2_phase1_encryption_algorithms = ["AES256"]
tunnel1_phase1_integrity_algorithms = ["SHA2-256", "SHA2-512"]
tunnel2_phase1_integrity_algorithms = ["SHA2-256", "SHA2-512"]
tunnel1_phase1_dh_group_numbers = [14, 21]
tunnel2_phase1_dh_group_numbers = [14, 21]
tunnel1_phase1_lifetime_seconds = 14400
tunnel2_phase1_lifetime_seconds = 14400
# IPSEC Phase2 Settings
tunnel1_phase2_encryption_algorithms = ["AES256"]
tunnel2_phase2_encryption_algorithms = ["AES256"]
tunnel1_phase2_integrity_algorithms = ["SHA2-256", "SHA2-512"]
tunnel2_phase2_integrity_algorithms = ["SHA2-256", "SHA2-512"]
tunnel1_phase2_dh_group_numbers = [14, 21]
tunnel2_phase2_dh_group_numbers = [14, 21]
tunnel1_phase2_lifetime_seconds = 3600
tunnel2_phase2_lifetime_seconds = 3600
tunnel1_log_options {
cloudwatch_log_options {
log_enabled = true
log_group_arn = aws_cloudwatch_log_group.VPN_Tunnel1_Log_Group.arn
log_output_format = "text"
}
}
tunnel2_log_options {
cloudwatch_log_options {
log_enabled = true
log_group_arn = aws_cloudwatch_log_group.VPN_Tunnel2_Log_Group.arn
log_output_format = "text"
}
}
tags = {
name = "TGW-VPN-1",
environment = var.environment
wsi_owner = var.wsi_owner
project_code = var.project_code
budget_code = var.budget_code
function = "VPN"
}
}
You can find a list of the different types of value you can store in Keeper Secrets Manager with: https://docs.keeper.io/en/keeperpam/secrets-manager/integrations/terraform