TerraformPilot

Terraform

Terraform with HashiCorp Vault - Secrets Management

Integrate Terraform with HashiCorp Vault for secrets management. Read secrets, dynamic credentials, AWS/database secret engines, and AppRole authentication.

LLuca Berton1 min read

Quick Answer

#
provider "vault" {
  address = "https://vault.example.com"
}
 
data "vault_generic_secret" "db" {
  path = "secret/data/myapp/database"
}
 
resource "aws_db_instance" "main" {
  username = data.vault_generic_secret.db.data["username"]
  password = data.vault_generic_secret.db.data["password"]
}

Vault Provider Configuration

#
provider "vault" {
  address = var.vault_address
 
  # AppRole auth (recommended for CI/CD)
  auth_login {
    path = "auth/approle/login"
    parameters = {
      role_id   = var.vault_role_id
      secret_id = var.vault_secret_id
    }
  }
}

Read KV Secrets

#
# KV v2 secret engine
data "vault_kv_secret_v2" "app" {
  mount = "secret"
  name  = "myapp/${var.environment}"
}
 
resource "aws_ssm_parameter" "api_key" {
  name  = "/${var.project}/api-key"
  type  = "SecureString"
  value = data.vault_kv_secret_v2.app.data["api_key"]
}

Dynamic AWS Credentials

#
# Vault generates temporary AWS credentials on demand
data "vault_aws_access_credentials" "deploy" {
  backend = "aws"
  role    = "deploy-role"
  type    = "sts"
}
 
provider "aws" {
  access_key = data.vault_aws_access_credentials.deploy.access_key
  secret_key = data.vault_aws_access_credentials.deploy.secret_key
  token      = data.vault_aws_access_credentials.deploy.security_token
  region     = var.region
}

Dynamic Database Credentials

#
data "vault_database_credentials" "app" {
  backend = "database"
  role    = "app-role"
}
 
resource "kubernetes_secret" "db_creds" {
  metadata {
    name      = "db-credentials"
    namespace = "app"
  }
  data = {
    username = data.vault_database_credentials.app.username
    password = data.vault_database_credentials.app.password
  }
}

Manage Vault with Terraform

#
# Create secrets in Vault
resource "vault_kv_secret_v2" "app" {
  mount = vault_mount.kv.path
  name  = "myapp/production"
 
  data_json = jsonencode({
    api_key     = var.api_key
    db_password = random_password.db.result
  })
}
 
# Configure secret engines
resource "vault_mount" "kv" {
  path    = "secret"
  type    = "kv-v2"
}
 
# Configure AWS secret engine
resource "vault_aws_secret_backend" "aws" {
  access_key = var.vault_aws_access_key
  secret_key = var.vault_aws_secret_key
  region     = var.region
}
 
resource "vault_aws_secret_backend_role" "deploy" {
  backend         = vault_aws_secret_backend.aws.path
  name            = "deploy-role"
  credential_type = "iam_user"
 
  policy_document = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect   = "Allow"
      Action   = ["ec2:*", "s3:*"]
      Resource = "*"
    }]
  })
}
 
# Configure policies
resource "vault_policy" "app" {
  name   = "app-policy"
  policy = <<-EOT
    path "secret/data/myapp/*" {
      capabilities = ["read"]
    }
    path "database/creds/app-role" {
      capabilities = ["read"]
    }
  EOT
}

Authentication Methods

#
MethodUse CaseConfig
TokenQuick testingVAULT_TOKEN env var
AppRoleCI/CD pipelinesRole ID + Secret ID
KubernetesK8s workloadsService account JWT
AWS IAMEC2/LambdaInstance role
OIDCGitHub ActionsID token
#

Conclusion

#

Use Vault's dynamic secrets (AWS, database) to eliminate long-lived credentials. AppRole for CI/CD, Kubernetes auth for K8s workloads, and KV v2 for static secrets. Manage Vault configuration itself with Terraform for full infrastructure-as-code.

#Terraform#Vault#HashiCorp#Security#Infrastructure as Code

Share this article