The hashicorp/vault Terraform provider and the community.hashi_vault Ansible collection work with the HashiCorp Vault API. Stronghold is API-compatible with Vault, so these tools can be pointed at Stronghold by setting its address.
Terraform
The hashicorp/vault provider (also works in OpenTofu) lets you describe Stronghold mounts, policies, auth methods, and roles as code.
Connecting to Stronghold
Create a dedicated AppRole role for Terraform with a policy sufficient to manage the required paths (sys/mounts/*, sys/policies/acl/*, sys/auth/*, auth/*). Example provider configuration:
terraform {
required_providers {
vault = {
source = "hashicorp/vault"
}
}
}
variable "role_id" {
type = string
}
variable "secret_id" {
type = string
sensitive = true
}
provider "vault" {
address = "https://stronghold.example.com"
auth_login {
path = "auth/approle/login"
parameters = {
role_id = var.role_id
secret_id = var.secret_id
}
}
}Alternative authentication options:
- a token from the
VAULT_TOKENenvironment variable (address fromVAULT_ADDR) if noauth_loginblock is set; auth_login_jwtfor runs from CI/CD with a job OIDC token (see CI/CD).
By default, the provider creates a short-lived child token, so the policy needs update on auth/token/create. If this is undesirable, set skip_child_token = true in the provider block.
To work in a namespace, set the namespace parameter in the provider block or in individual resources.
Example: KV, policy, and Kubernetes role
The configuration enables KV version 2 and the Kubernetes auth method, creates a policy, and creates a role for the application:
resource "vault_mount" "kv" {
path = "secret"
type = "kv"
options = { version = "2" }
description = "KV v2 for applications"
}
resource "vault_policy" "myapp_read" {
name = "myapp-read"
policy = <<-EOT
path "secret/data/myapp/*" {
capabilities = ["read"]
}
EOT
}
resource "vault_auth_backend" "kubernetes" {
type = "kubernetes"
}
resource "vault_kubernetes_auth_backend_config" "this" {
backend = vault_auth_backend.kubernetes.path
kubernetes_host = "https://kubernetes.example.com:6443"
}
resource "vault_kubernetes_auth_backend_role" "myapp" {
backend = vault_auth_backend.kubernetes.path
role_name = "myapp"
bound_service_account_names = ["myapp"]
bound_service_account_namespaces = ["myapp"]
token_policies = [vault_policy.myapp_read.name]
token_ttl = 3600
}Apply:
terraform init
terraform plan -out=tfplan
terraform apply tfplanSecret values written by resources (for example, vault_kv_secret_v2) or read by data sources are stored in the Terraform state file in plaintext. Keep the state in a protected, encrypted backend with restricted access. If secret values are written to Stronghold outside Terraform, they do not reach the state file.
To manage Stronghold configuration from Git without Terraform, you can use the built-in GitOps secrets engine.
Ansible
The community.hashi_vault collection provides lookup plugins and modules for reading secrets.
Install the collection and the
hvaclibrary:ansible-galaxy collection install community.hashi_vault pip install hvacSet the Stronghold address and authentication parameters via environment variables:
export ANSIBLE_HASHI_VAULT_ADDR=https://stronghold.example.com export ANSIBLE_HASHI_VAULT_AUTH_METHOD=approle export ANSIBLE_HASHI_VAULT_ROLE_ID=<ROLE_ID> export ANSIBLE_HASHI_VAULT_SECRET_ID=<SECRET_ID><ROLE_ID>and<SECRET_ID>are therole_idandsecret_idof the AppRole role for Ansible.Read a KV version 2 secret in a playbook:
- name: Configure application hosts: app tasks: - name: Read database credentials from Stronghold ansible.builtin.set_fact: db: "{{ lookup('community.hashi_vault.vault_kv2_get', 'myapp/db', engine_mount_point='secret').secret }}" no_log: true - name: Render application config ansible.builtin.template: src: app.conf.j2 dest: /etc/myapp/app.conf mode: "0600" no_log: true
To get dynamic credentials, use the community.hashi_vault.vault_read lookup, for example for the database/creds/my-role path (database secrets engine).
Recommendations:
- Set
no_log: truefor tasks that handle secrets. - Use a dedicated AppRole role for Ansible with read-only access to the required paths and a short
token_ttl. - Do not store
secret_idin the inventory. Pass it via CI/CD environment variables or get it using response wrapping.