Files
Panama/user/agents/skills/infisical-terraform/references/resources-and-data-sources.md
T
Gabriel Brown 89761a7da3 Keep the personal half of the desktop in one place, and ask before installing it
Agent instructions, skills, SSH host aliases and expansion triggers are worth
having identical on every machine one person owns, and belong in none of the
shared configuration. They live in user/ now, with a manifest saying where each
piece goes and a link-user stage that puts it there.

That stage does nothing unless the machine said yes. Somebody who clones Panama
to try the desktop keeps their own ~/.claude/CLAUDE.md exactly where it was;
the question names the destinations and defaults to no. Anything displaced goes
to config/old rather than being deleted.

~/.claude/CLAUDE.md and ~/.codex/AGENTS.md were byte-identical copies of one
file, which is the drift this exists to prevent.

Also adds the vitals toggles for the battery and Claude usage readouts, which
had preferences and no way to reach them.
2026-08-22 08:54:43 -04:00

9.7 KiB

Resources & Data Sources

Guide to Infisical Terraform resources and data sources for managing secrets, roles, and access policies.

Ephemeral Resource: infisical_secret

The ephemeral resource is the recommended way to fetch secrets in Terraform 1.10+. Secret values are never stored in state.

Key Benefit: Prevents secrets from being persisted in your Terraform state files, reducing security risk.

Requires: Terraform 1.10 or later.

Configuration

ephemeral "infisical_secret" "example" {
  workspace_id = "your-workspace-id"
  env_slug     = "prod"
  secret_key   = "DATABASE_PASSWORD"
  folder_path  = "/" # Optional, defaults to "/"
}

output "db_password" {
  value     = ephemeral.infisical_secret.example.value
  sensitive = true
}

Attributes

Attribute Type Description
workspace_id string ID of the Infisical workspace
env_slug string Environment slug (e.g., "dev", "staging", "prod")
secret_key string Name of the secret to retrieve
folder_path string Path within the environment (optional, defaults to "/")
value string (computed) The secret value (only available during apply, never stored in state)

JSON Secrets

For JSON-formatted secrets, use jsondecode() to parse the value:

ephemeral "infisical_secret" "api_config" {
  workspace_id = "your-workspace-id"
  env_slug     = "prod"
  secret_key   = "API_CONFIG"
}

locals {
  config = jsondecode(ephemeral.infisical_secret.api_config.value)
}

output "api_key" {
  value     = local.config.api_key
  sensitive = true
}

output "api_url" {
  value = local.config.api_url
}

Usage with Resources

# Fetch secret and use it to configure a provider
ephemeral "infisical_secret" "aws_access_key" {
  workspace_id = "your-workspace-id"
  env_slug     = "prod"
  secret_key   = "AWS_ACCESS_KEY_ID"
}

ephemeral "infisical_secret" "aws_secret_key" {
  workspace_id = "your-workspace-id"
  env_slug     = "prod"
  secret_key   = "AWS_SECRET_ACCESS_KEY"
}

provider "aws" {
  access_key = ephemeral.infisical_secret.aws_access_key.value
  secret_key = ephemeral.infisical_secret.aws_secret_key.value
  region     = "us-east-1"
}

Data Source: infisical_secrets

The data source retrieves all secrets from a specific environment and folder. ⚠️ Warning: Secret values ARE stored in Terraform state. Use ephemeral instead when possible.

Configuration

data "infisical_secrets" "all_secrets" {
  workspace_id = "your-workspace-id"
  env_slug     = "prod"
  folder_path  = "/" # Optional, defaults to "/"
}

output "all_secrets" {
  value     = data.infisical_secrets.all_secrets.secrets
  sensitive = true
}

Attributes

Attribute Type Description
workspace_id string ID of the Infisical workspace
env_slug string Environment slug
folder_path string Path within the environment (optional, defaults to "/")
secrets map(string) Map of all secrets in the folder (key → value)

Usage Example

data "infisical_secrets" "all_secrets" {
  workspace_id = "your-workspace-id"
  env_slug     = "prod"
}

# Access individual secrets
output "database_password" {
  value     = data.infisical_secrets.all_secrets.secrets["DB_PASSWORD"]
  sensitive = true
}

# Use secrets in resource configuration
resource "aws_db_instance" "main" {
  allocated_storage    = 100
  engine               = "postgres"
  engine_version       = "15.2"
  instance_class       = "db.t3.micro"
  username             = "admin"
  password             = data.infisical_secrets.all_secrets.secrets["DB_PASSWORD"]
  skip_final_snapshot  = true
}

Resource: infisical_project_role

Create and manage custom project roles with granular permissions.

Use permissions_v2 for modern, flexible permission definitions with subject-action structure.

resource "infisical_project_role" "developer" {
  project_id = "your-project-id"
  name       = "Developer"

  permissions_v2 = [
    {
      subject = "secrets"
      actions = ["read", "create", "edit"]
    },
    {
      subject = "secret-folders"
      actions = ["read", "create", "edit"]
    },
    {
      subject = "secret-imports"
      actions = ["read"]
    },
    {
      subject = "dynamic-secrets"
      actions = ["read", "lease"]
    }
  ]
}

Permissions v2 Subjects & Actions

Subject Available Actions
secrets read, create, edit, delete, read-metadata
secret-folders read, create, edit, delete
secret-imports read, create, edit, delete
dynamic-secrets read, read-root-credential, create-root-credential, edit-root-credential, delete-root-credential, lease

Permissions v1 Format (Deprecated)

The old permissions attribute uses inverted logic (denying actions). It's deprecated—always prefer permissions_v2.

# ⚠️ DEPRECATED — Do not use in new code
resource "infisical_project_role" "viewer" {
  project_id = "your-project-id"
  name       = "Viewer"

  permissions = [
    {
      action   = "create"
      inverted = true
    },
    {
      action   = "edit"
      inverted = true
    },
    {
      action   = "delete"
      inverted = true
    }
  ]
}

Complete Example with Multiple Roles

resource "infisical_project_role" "admin" {
  project_id = "your-project-id"
  name       = "Admin"

  permissions_v2 = [
    {
      subject = "secrets"
      actions = ["read", "create", "edit", "delete"]
    },
    {
      subject = "secret-folders"
      actions = ["read", "create", "edit", "delete"]
    },
    {
      subject = "secret-imports"
      actions = ["read", "create", "edit", "delete"]
    },
    {
      subject = "dynamic-secrets"
      actions = ["read", "read-root-credential", "create-root-credential", "edit-root-credential", "delete-root-credential", "lease"]
    }
  ]
}

resource "infisical_project_role" "ops" {
  project_id = "your-project-id"
  name       = "Ops"

  permissions_v2 = [
    {
      subject = "secrets"
      actions = ["read"]
    },
    {
      subject = "dynamic-secrets"
      actions = ["read", "lease"]
    }
  ]
}

Resource: infisical_access_approval_policy

Enforce approval workflows for sensitive secret operations.

Configuration

resource "infisical_access_approval_policy" "prod_secrets" {
  project_id      = "your-project-id"
  name            = "Production Secrets Approval"
  environment_slug = "prod"
  secret_path     = "/" # Optional, specific path or "/" for all

  approvers = [
    {
      type     = "username"
      username = "[email protected]"
    },
    {
      type     = "username"
      username = "[email protected]"
    }
  ]

  required_approvals = 1
  enforcement_level  = "hard" # "soft" (warning) or "hard" (blocking)
}

Attributes

Attribute Type Description
project_id string ID of the Infisical project
name string Policy name for identification
environment_slug string Environment to apply policy (e.g., "prod")
secret_path string Secret path (optional, "/" for all secrets)
approvers list(object) List of approvers with type and username
required_approvals number Number of approvals required before access granted
enforcement_level string "soft" (warning) or "hard" (blocking access without approval)

Example: Multiple Approval Policies

# Require approval for all production secrets
resource "infisical_access_approval_policy" "prod_all" {
  project_id       = "your-project-id"
  name             = "Production - All Secrets"
  environment_slug = "prod"
  secret_path      = "/"

  approvers = [
    {
      type     = "username"
      username = "[email protected]"
    },
    {
      type     = "username"
      username = "[email protected]"
    }
  ]

  required_approvals = 2
  enforcement_level  = "hard"
}

# Require approval for database secrets only
resource "infisical_access_approval_policy" "prod_database" {
  project_id       = "your-project-id"
  name             = "Production - Database Secrets"
  environment_slug = "prod"
  secret_path      = "/database"

  approvers = [
    {
      type     = "username"
      username = "[email protected]"
    }
  ]

  required_approvals = 1
  enforcement_level  = "hard"
}

Complete Example: Secrets + Roles + Approvals

terraform {
  required_providers {
    infisical = {
      source  = "infisical/infisical"
      version = "~> 0.13"
    }
  }
}

provider "infisical" {
  client_id     = var.infisical_client_id
  client_secret = var.infisical_client_secret
}

variable "infisical_client_id" {
  type      = string
  sensitive = true
}

variable "infisical_client_secret" {
  type      = string
  sensitive = true
}

# Fetch production database password (never in state)
ephemeral "infisical_secret" "db_password" {
  workspace_id = "ws-abc123"
  env_slug     = "prod"
  secret_key   = "DATABASE_PASSWORD"
}

# Define developer role with permission to read secrets
resource "infisical_project_role" "developer" {
  project_id = "proj-xyz789"
  name       = "Developer"

  permissions_v2 = [
    {
      subject = "secrets"
      actions = ["read"]
    }
  ]
}

# Require approval for production secret access
resource "infisical_access_approval_policy" "prod_approval" {
  project_id       = "proj-xyz789"
  name             = "Production Approval"
  environment_slug = "prod"
  secret_path      = "/"

  approvers = [
    {
      type     = "username"
      username = "[email protected]"
    }
  ]

  required_approvals = 1
  enforcement_level  = "hard"
}

output "database_password" {
  value     = ephemeral.infisical_secret.db_password.value
  sensitive = true
}