docs/integrations/frameworks/terraform.mdx
{/* This guide demonstrates how to use Infisical to manage secrets in your Terraform infrastructure code, supporting both traditional data sources and ephemeral resources for enhanced security. It uses:
Before you begin, make sure you have:
First, specify the Infisical provider in your Terraform configuration:
terraform {
required_providers {
infisical = {
source = "infisical/infisical"
}
}
}
Configure the provider using one of these authentication methods:
Using a Machine Identity, you can authenticate your Terraform provider using either OIDC Auth or Universal Auth methods.
provider "infisical" {
host = "https://app.infisical.com" # Optional for cloud, required for self-hosted
auth {
universal { # or use oidc authentication method by providing an identity_id
client_id = var.infisical_client_id
client_secret = var.infisical_client_secret
}
}
}
Learn more about machine identities.
provider "infisical" {
host = "https://app.infisical.com"
service_token = var.infisical_service_token
}
Infisical provides two methods to fetch and use secrets in your Terraform configurations:
Ephemeral resources, introduced in Terraform v1.10, provide enhanced security by ensuring sensitive values are never persisted in state files. This is the recommended approach for handling secrets in your infrastructure code.
# Fetch database credentials ephemerally
ephemeral "infisical_secret" "db_creds" {
name = "DB_CREDENTIALS"
env_slug = "prod"
workspace_id = var.infisical_workspace_id
folder_path = "/database"
}
# Use the credentials to configure a provider
provider "postgresql" {
host = data.aws_db_instance.example.address
port = data.aws_db_instance.example.port
username = jsondecode(ephemeral.infisical_secret.db_creds.value)["username"]
password = jsondecode(ephemeral.infisical_secret.db_creds.value)["password"]
}
Key benefits:
For backwards compatibility or when working with older Terraform versions, you can use the traditional data source approach:
# Fetch all secrets in a folder
data "infisical_secrets" "my_secrets" {
env_slug = "dev"
workspace_id = var.infisical_workspace_id
folder_path = "/api"
}
# Use individual secrets
resource "aws_db_instance" "example" {
username = data.infisical_secrets.my_secrets.secrets["DB_USER"]
password = data.infisical_secrets.my_secrets.secrets["DB_PASS"]
}
Manage database credentials securely without exposing sensitive information in your state files:
# Fetch database credentials securely
ephemeral "infisical_secret" "db_creds" {
name = "DB_CREDENTIALS"
env_slug = "prod"
workspace_id = var.infisical_workspace_id
folder_path = "/database"
}
# Use the credentials in your database instance
resource "aws_db_instance" "example" {
identifier = "my-database"
allocated_storage = 20
engine = "postgres"
engine_version = "14.0"
instance_class = "db.t3.micro"
# Securely inject credentials from Infisical
username = jsondecode(ephemeral.infisical_secret.db_creds.value)["username"]
password = jsondecode(ephemeral.infisical_secret.db_creds.value)["password"]
}
To eliminate the need for static credentials, you can authenticate your workflow using OpenID Connect (OIDC) through providers like the Infisical Secrets GitHub Action. Once authenticated, you can securely access secrets through the Infisical provider:
provider "infisical" {
# Auth credentials automatically injected from the environment
}
# Fetch deployment credentials
ephemeral "infisical_secret" "deploy_token" {
name = "DEPLOY_TOKEN"
env_slug = "prod"
workspace_id = var.infisical_workspace_id
folder_path = "/deployment"
}
For detailed instructions on setting up OIDC authentication with GitHub Actions, refer to our GitHub Actions OIDC guide.
Use Ephemeral Resources: Whenever possible, use ephemeral resources instead of data sources for improved security.
Organize Secrets: Structure your secrets in Infisical using folders to maintain clean separation:
ephemeral "infisical_secret" "db_secret" {
folder_path = "/databases/postgresql" # Organized by service
# ...
}
Variable Usage: Use Terraform variables for workspace IDs and environment slugs:
variable "environment" {
description = "Environment (dev, staging, prod)"
type = string
}
ephemeral "infisical_secret" "secret" {
env_slug = var.environment
# ...
}
Error Handling: Add lifecycle blocks for critical secrets:
ephemeral "infisical_secret" "critical_secret" {
# ...
lifecycle {
postcondition {
condition = length(self.value) > 0
error_message = "Critical secret must not be empty"
}
}
}
Better yet, use ephemeral resources to avoid storing sensitive values in state entirely.
</Accordion>
See also: