Skip to content
Back to skills

Terraform Sdk

ASecurity

Integrates with Terraform and OpenTofu via the HCP Terraform API (pyTFE),

  • 4 stars
  • 0 votes
  • 1 copy
  • 5 views
  • Added June 12, 2026
devopspythongodockerkubernetesawsterraformdebugginggitapidatabase

Works with

  • terminal
  • cli
  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned June 12, 2026

npx -y skills add paulpas/agent-skill-router --skill terraform-sdk --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Terraform Sdk?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Terraform Sdk
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/paulpas-terraform-sdk/badge)](https://www.skillsdirectory.com/skills/paulpas-terraform-sdk)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---




name: terraform-sdk
description: Integrates with Terraform and OpenTofu via the HCP Terraform API (pyTFE),
  CDKTF Python bindings, and the Terraform Cloud API to manage providers, resources,
  state, and modules.
license: MIT
compatibility: opencode
metadata:
  version: "1.0.0"
  domain: coding
  triggers: terraform api, terraform cloud, cdktf python, terraform provider, opentofu,
    terraform state, terraform modules, hcp terraform
  archetypes:
  - tactical
  - generation
  anti_triggers:
  - brainstorming
  - vague ideation
  - code golf
  - over-engineering
  response_profile:
    verbosity: low
    directive_strength: high
    abstraction_level: operational
  role: implementation
  scope: implementation
  output-format: code
  content-types:
  - code
  - guidance
  - do-dont
  - examples
  related-skills: coding-kubernetes-api, coding-pulumi, coding-ansible-api




---




# Terraform/OpenTofu SDK & API Integration

Integrates with Terraform and OpenTofu using the HCP Terraform API (via `pyTFE`), the CDKTF Python SDK, and the Terraform Cloud/Enterprise REST API to programmatically manage providers, resources, state, workspaces, and modules.

## TL;DR for Code Generation

- [ ] Use `pyTFE` (`pytfe.TFEClient`) for HCP Terraform and Terraform Enterprise API operations
- [ ] For infrastructure-as-code in Python, prefer the CDKTF — `cdktf` with `cdktf get` to generate provider bindings
- [ ] Manage state via the Terraform Cloud API `workspaces` and `state-versions` endpoints
- [ ] Use the `tfe` Terraform provider if you need to manage Terraform Cloud resources in HCL
- [ ] Authenticate with a `TFE_TOKEN` environment variable or explicit `TFEConfig(token=...)`
- [ ] Use `Pulumi` (see `coding-pulumi` skill) as an alternative when you prefer native IaC over Terraform wrappers

---

## When to Use

Use this skill when:

- Automating workspace creation, runs, and state management in HCP Terraform or Terraform Enterprise
- Writing Python code that provisions infrastructure using Terraform providers (via CDKTF)
- Building CI/CD pipelines that trigger Terraform plans and applies
- Implementing policy-as-code with Sentinel or OPA policies applied to Terraform runs
- Managing Terraform state versions, outputs, and variables programmatically
- Extending Terraform with custom providers using the Terraform Plugin Framework

---

## When NOT to Use

Avoid this skill for:

- Writing declarative HCL (use standard Terraform/OpenTofu CLI workflows instead)
- Low-level cloud API calls (use provider-specific SDKs like `boto3` for AWS)
- Docker container management (use `coding-docker-api`)

---

## Core Workflow

1. **Authenticate to Terraform Cloud/Enterprise** — Create a `TFEClient` with a `TFEConfig` containing the address and API token. **Checkpoint:** Call `client.organizations.list()` to verify connectivity and permissions.

2. **Create or Select Workspace** — Use `client.workspaces.create()` for new workspaces or `client.workspaces.list()` to find existing ones. **Checkpoint:** Verify workspace ID and that the execution mode matches your intent (local vs. remote).

3. **Set Variables and Configuration** — Use `client.variables.create()` for terraform variables and environment variables. **Checkpoint:** Confirm variable values are correct (mark sensitive variables as sensitive).

4. **Trigger a Run** — Create a new run via `client.runs.create()` with a configuration version. Monitor the run through its state machine: pending → planning → applying → applied. **Checkpoint:** Poll `run.status` and handle planning errors or apply failures.

5. **Retrieve Outputs and State** — Use `client.state_versions.current()` to get the current state and `client.run.outputs()` to extract terraform output values. **Checkpoint:** Validate outputs match expected schema.

---

## Implementation Patterns

### Pattern 1: CDKTF Python — Create AWS S3 Bucket

```python
from constructs import Construct
from cdktf import App, TerraformStack, TerraformOutput
from cdktf_cdktf_provider_aws.s3_bucket import S3Bucket
from cdktf_cdktf_provider_aws.provider import AwsProvider


class S3BucketStack(TerraformStack):
    """Define an S3 bucket using CDKTF Python bindings."""

    def __init__(self, scope: Construct, id: str, bucket_name: str):
        super().__init__(scope, id)

        AwsProvider(self, "aws", region="us-east-1")

        bucket = S3Bucket(
            self,
            "my-bucket",
            bucket=bucket_name,
            versioning={
                "enabled": True,
            },
            tags={
                "Name": bucket_name,
                "ManagedBy": "CDKTF",
            },
        )

        TerraformOutput(self, "bucket_arn", value=bucket.arn)
        TerraformOutput(self, "bucket_id", value=bucket.id)


def deploy_s3_bucket(bucket_name: str) -> None:
    """Deploy an S3 bucket programmatically using CDKTF.

    Requires: pip install cdktf cdktf-cdktf-provider-aws

    Run with: python app.py && cdktf deploy
    """
    app = App()
    S3BucketStack(app, "s3-bucket-stack", bucket_name)
    app.synth()
```

### Pattern 2: HCP Terraform Workspace Management (pyTFE)

```python
import os
import time
from pytfe import TFEClient, TFEConfig
from pytfe.exceptions import TFEException


def create_workspace_and_run(
    organization: str,
    workspace_name: str,
    working_directory: str = "",
    variables: dict | None = None,
    auto_apply: bool = True,
    wait_for_completion: bool = True,
) -> dict:
    """Create a Terraform Cloud workspace and trigger a run.

    Args:
        organization: HCP Terraform organization name.
        workspace_name: Name for the new workspace.
        working_directory: Relative path to terraform config.
        variables: Terraform variables to set.
        auto_apply: Whether to auto-apply on plan success.
        wait_for_completion: Wait for the run to finish.

    Returns:
        Dict with workspace ID, run ID, and run status.

    Raises:
        TFEException: If API operations fail.
        TimeoutError: If the run doesn't complete.
    """
    config = TFEConfig(
        address=os.environ.get("TFE_ADDRESS", "https://app.terraform.io"),
        token=os.environ["TFE_TOKEN"],
    )
    client = TFEClient(config)

    # Create or find the workspace
    try:
        workspace = client.workspaces.create(
            organization=organization,
            name=workspace_name,
            auto_apply=auto_apply,
            working_directory=working_directory or None,
        )
    except TFEException as exc:
        # Workspace might already exist
        if "already exists" in str(exc):
            for ws in client.workspaces.list(organization).items:
                if ws.name == workspace_name:
                    workspace = ws
                    break
        else:
            raise

    # Set variables
    for key, value in (variables or {}).items():
        client.variables.create(
            workspace_id=workspace.id,
            key=key,
            value=str(value),
            category="terraform",
        )

    # Create a new configuration version (upload source)
    cv = client.configuration_versions.create(
        workspace_id=workspace.id,
        auto_queue_runs=True,
    )

    # Trigger the run
    run = client.runs.create(workspace_id=workspace.id)

    if wait_for_completion:
        _wait_for_run(client, run.id)

    return {
        "workspace_id": workspace.id,
        "workspace_name": workspace.name,
        "run_id": run.id,
        "status": run.status,
    }


def _wait_for_run(client: TFEClient, run_id: str, timeout: int = 600) -> None:
    """Poll a Terraform Cloud run until it completes or errors."""
    terminal_states = {"applied", "planned_and_finished", "errored", "canceled"}
    start = time.monotonic()

    while time.monotonic() - start < timeout:
        run = client.runs.read(run_id)
        if run.status in terminal_states:
            if run.status == "errored":
                raise RuntimeError(
                    f"Terraform run {run_id} failed with status: {run.status}"
                )
            return
        if run.status == "planning":
            _check_run_errors(run)
        time.sleep(5)

    raise TimeoutError(f"Terraform run {run_id} did not complete in {timeout}s.")
```

### Pattern 3: Terraform Cloud State Version Retrieval

```python
import os
from pytfe import TFEClient, TFEConfig
from pytfe.exceptions import TFEException


def get_workspace_outputs(
    organization: str,
    workspace_name: str,
) -> dict:
    """Retrieve Terraform outputs from a Cloud workspace's current state.

    Args:
        organization: HCP Terraform organization.
        workspace_name: Workspace name.

    Returns:
        Dict of output names to their values.

    Raises:
        RuntimeError: If workspace or state is not found.
    """
    config = TFEConfig(
        address=os.environ.get("TFE_ADDRESS", "https://app.terraform.io"),
        token=os.environ["TFE_TOKEN"],
    )
    client = TFEClient(config)

    # Find the workspace
    workspace = None
    for ws in client.workspaces.list(organization).items:
        if ws.name == workspace_name:
            workspace = ws
            break

    if workspace is None:
        raise RuntimeError(
            f"Workspace '{workspace_name}' not found in organization '{organization}'."
        )

    # Get current state version
    try:
        state_version = client.state_versions.current(workspace_id=workspace.id)
    except TFEException as exc:
        raise RuntimeError(
            f"Failed to retrieve current state for '{workspace_name}': {exc}"
        ) from exc

    # Parse and return outputs
    outputs: dict = {}
    if state_version and state_version.outputs:
        for output_name, output_data in state_version.outputs.items():
            outputs[output_name] = output_data.get("value")

    return outputs
```

### BAD vs GOOD: Terraform API Error Handling

```python
# ❌ BAD — silent pass, no state awareness
def get_workspace_bad(client, org):
    try:
        ws = client.workspaces.create(organization=org, name="my-ws")
        return ws
    except Exception:
        pass  # Ignores "already exists" and other failures

# ✅ GOOD — idempotent create-or-find with explicit error handling
def get_or_create_workspace(
    client: TFEClient,
    organization: str,
    name: str,
) -> dict:
    """Retrieve or create a Terraform Cloud workspace.

    Args:
        client: Authenticated TFEClient instance.
        organization: Organization name.
        name: Workspace name.

    Returns:
        Workspace object.

    Raises:
        RuntimeError: If creation fails for reasons other than conflict.
    """
    try:
        workspace = client.workspaces.create(organization=organization, name=name)
        return {"id": workspace.id, "name": workspace.name, "created": True}
    except TFEException as exc:
        if "already exists" in str(exc):
            for ws in client.workspaces.list(organization).items:
                if ws.name == name:
                    return {"id": ws.id, "name": ws.name, "created": False}
        raise RuntimeError(
            f"Failed to create workspace '{name}': {exc}"
        ) from exc
```

## MUST DO

- Use environment variables (`TFE_TOKEN`, `TFE_ADDRESS`) for authentication — never hardcode tokens
- Implement idempotent create-or-find patterns for workspaces and resources
- Use `category="terraform"` for Terraform variables and `category="env"` for environment variables
- Poll run status with a timeout and handle all terminal states (applied, errored, canceled)
- Set `auto_apply=True` for workspaces where manual approval is not needed in CI/CD

## MUST NOT DO

- Never store Terraform state management credentials in code — they provide full access to infrastructure
- Do not create workspaces without setting the execution mode explicitly
- Avoid hardcoding organization names — read them from environment configuration
- Never ignore variables that should be `sensitive=true` (e.g., database passwords, API keys)
- Do not assume workspaces are deletable — check for attached resources first

---

## Constraints

### MUST DO
- Validate all inputs at function boundaries before processing — guard clauses should fail early with descriptive errors
- Implement proper error handling that distinguishes between recoverable and unrecoverable failures
- Add comprehensive logging with structured context (correlation IDs, operation names, timing) for debugging and monitoring
- Write unit tests covering normal operations, edge cases, and error conditions before integrating the component

### MUST NOT DO
- Do not silently swallow exceptions — always log or propagate errors with meaningful context
- Avoid unbounded resource allocation without limits (connection pools, memory buffers, thread counts)
- Never use hardcoded credentials, API keys, or secrets in source code
- Do not bypass input validation for perceived performance gains


## Live References

- [pyTFE (HCP Terraform Python Client) Documentation](https://github.com/hashicorp/python-tfe)
- [CDK for Terraform (CDKTF) Python API Reference](https://developer.hashicorp.com/terraform/cdktf/api-reference/python)
- [HCP Terraform API Documentation](https://developer.hashicorp.com/terraform/cloud-docs/api-docs)
- [Terraform Plugin Framework Documentation](https://developer.hashicorp.com/terraform/plugin/framework)
- [OpenTofu Documentation](https://opentofu.org/docs/)
- [Terraform Registry — Providers](https://registry.terraform.io/browse/providers)
- [Terraform Cloud State Versions API](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/state-versions)

## Related Skills

| Skill | Purpose |
|---|---|
| `coding-pulumi` | Pulumi Automation API for Python-native IaC |
| `coding-kubernetes-api` | Kubernetes provider via Terraform or client-python |
| `coding-ansible-api` | Ansible for configuration management with provisioned infrastructure |

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.