> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kavachos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Terraform provider

> Manage KavachOS agents, permissions, API keys, and organizations as Terraform resources.

## Why IaC for auth

Auth config drifts in ways application code doesn't. An agent spun up by hand in a dashboard has no peer review, no version history, and no automated rollback. When the production incident happens and you need to know why an agent had write access to the deploy tool, "someone added it last Tuesday" is not an audit trail.

Treating agents and permissions as Terraform resources fixes this. Every grant goes through a pull request. Every change is versioned in git. Destroying a staging environment tears down the access alongside the infrastructure, no orphaned tokens floating around.

## Installation

The provider requires Go 1.21 to build.

<Steps>
  <Step>
    Clone the repository and build the binary:

    ```bash theme={"system"}
    git clone https://github.com/kavachos/terraform-provider-kavachos
    cd terraform-provider-kavachos/sdks/terraform
    go build -o terraform-provider-kavachos .
    ```
  </Step>

  <Step>
    Install into the local plugin cache:

    ```bash theme={"system"}
    OS=$(go env GOOS)
    ARCH=$(go env GOARCH)
    PLUGIN_DIR=~/.terraform.d/plugins/registry.terraform.io/kavachos/kavachos/0.1.0/${OS}_${ARCH}
    mkdir -p "$PLUGIN_DIR"
    mv terraform-provider-kavachos "$PLUGIN_DIR/"
    ```
  </Step>

  <Step>
    Declare the provider in your Terraform configuration:

    ```hcl theme={"system"}
    terraform {
      required_version = ">= 1.5"
      required_providers {
        kavachos = {
          source  = "kavachos/kavachos"
          version = "~> 0.1"
        }
      }
    }
    ```
  </Step>
</Steps>

## Provider setup

```hcl theme={"system"}
provider "kavachos" {
  base_url = "https://your-app.com/api/kavach"
  token    = var.kavachos_token
}
```

Both arguments can be set via environment variables, which is preferred in CI:

```bash theme={"system"}
export KAVACHOS_BASE_URL=https://your-app.com/api/kavach
export KAVACHOS_TOKEN=kv_live_...
```

<ParamField path="base_url" type="string" default="KAVACHOS_BASE_URL env var">Base URL of your KavachOS deployment.</ParamField>
<ParamField path="token" type="string" default="KAVACHOS_TOKEN env var">API token for authenticating with KavachOS.</ParamField>

## Resources

### kavachos\_agent

Manages an agent identity, the primary entity in KavachOS.

```hcl theme={"system"}
resource "kavachos_agent" "github_reader" {
  owner_id = "user-123"
  name     = "github-reader"
  type     = "autonomous"

  permission {
    resource = "mcp:github:*"
    actions  = ["read"]
  }

  permission {
    resource = "mcp:deploy:production"
    actions  = ["execute"]
    constraints {
      require_approval    = true
      max_calls_per_hour = 10
      ip_allowlist        = ["10.0.0.0/8"]
    }
  }

  expires_at = "2026-12-31T23:59:59Z"
}
```

The `token` attribute is computed on creation and marked sensitive. Read it with:

```bash theme={"system"}
terraform output -raw github_reader_token
```

<Warning>
  The raw token is only returned once, at creation time. KavachOS does not store it in recoverable form. If you lose it, rotate the agent's token via the API or dashboard.
</Warning>

<ParamField path="owner_id" type="string" required>ID of the user who owns this agent.</ParamField>
<ParamField path="name" type="string" required>Human-readable name.</ParamField>
<ParamField path="type" type={`"autonomous" | "delegated" | "service"`} required>Agent type: autonomous, delegated, or service.</ParamField>
<ParamField path="permission" type="block[]">One or more permission grant blocks.</ParamField>
<ParamField path="expires_at" type="string">RFC 3339 expiry timestamp.</ParamField>

**Permission block arguments**

<ParamField path="resource" type="string" required>Resource pattern, e.g. mcp:github:\* or mcp:deploy:production.</ParamField>
<ParamField path="actions" type="string[]" required>Allowed actions, e.g. \["read"] or \["execute"].</ParamField>
<ParamField path="constraints" type="block">Optional block limiting usage.</ParamField>

**Constraints block arguments**

<ParamField path="require_approval" type="bool" default="false">Require human approval before the action executes.</ParamField>
<ParamField path="max_calls_per_hour" type="number">Rate limit: maximum calls allowed per hour.</ParamField>
<ParamField path="allowed_arg_patterns" type="string[]">Glob patterns restricting allowed argument values.</ParamField>
<ParamField path="ip_allowlist" type="string[]">CIDR blocks from which this permission may be used.</ParamField>

***

### kavachos\_permission

Grants a single permission to an existing agent from a separate module. If you control both the agent and all its permissions in one place, use inline `permission` blocks on `kavachos_agent` instead.

```hcl theme={"system"}
resource "kavachos_permission" "staging_deploy" {
  agent_id           = kavachos_agent.deploy_bot.id
  resource           = "mcp:deploy:staging"
  actions            = ["execute"]
  max_calls_per_hour = 20
}
```

<ParamField path="agent_id" type="string" required>ID of the target agent.</ParamField>
<ParamField path="resource" type="string" required>Resource pattern.</ParamField>
<ParamField path="actions" type="string[]" required>Allowed actions.</ParamField>
<ParamField path="require_approval" type="bool" default="false">Require human approval.</ParamField>
<ParamField path="max_calls_per_hour" type="number">Rate limit per hour.</ParamField>
<ParamField path="allowed_arg_patterns" type="string[]">Glob patterns for argument values.</ParamField>
<ParamField path="ip_allowlist" type="string[]">CIDR blocks allowed to exercise the permission.</ParamField>

***

### kavachos\_api\_key

Manages an API key for server-to-server requests.

```hcl theme={"system"}
resource "kavachos_api_key" "ci_pipeline" {
  name   = "ci-pipeline"
  scopes = ["agents:read", "agents:write"]
}

output "ci_key" {
  value     = kavachos_api_key.ci_pipeline.key
  sensitive = true
}
```

Valid scopes: `agents:read`, `agents:write`, `audit:read`, `delegation:read`, `delegation:write`, `organizations:read`, `organizations:write`, `admin`.

<Info>
  The `key` attribute is only populated immediately after creation. Read it with `terraform output -raw ci_key` and store it in your secret manager before the session ends.
</Info>

***

### kavachos\_organization

Manages an organization for multi-tenant isolation.

```hcl theme={"system"}
resource "kavachos_organization" "engineering" {
  name = "Engineering"
  slug = "engineering"
  plan = "pro"
}
```

`slug` is immutable after creation. Change it by deleting and recreating the organization.

***

## Data sources

### kavachos\_agent

Reads an agent that was not created by this Terraform configuration.

```hcl theme={"system"}
data "kavachos_agent" "legacy" {
  id = "agent-id-from-dashboard"
}

output "status" {
  value = data.kavachos_agent.legacy.status
}
```

### kavachos\_agents

Lists agents, optionally filtered.

```hcl theme={"system"}
data "kavachos_agents" "active_bots" {
  owner_id = "user-123"
  status   = "active"
  type     = "autonomous"
}

output "bot_count" {
  value = length(data.kavachos_agents.active_bots.agents)
}
```

Filter arguments: `owner_id`, `status` (`active` | `revoked` | `expired`), `type` (`autonomous` | `delegated` | `service`).

***

## Import existing state

Resources provisioned outside Terraform can be brought under management:

```bash theme={"system"}
# Import an agent
terraform import kavachos_agent.my_bot agent-abc123

# Import an API key
terraform import kavachos_api_key.ci kv_key_abc123

# Import an organization
terraform import kavachos_organization.eng org-xyz789
```

After importing, run `terraform plan`. Terraform will show a diff for any attributes that differ from your configuration. Update the HCL to match, or let Terraform converge.

<Warning>
  Importing an API key restores the ID and metadata but not the raw key value, that was only available at creation time.
</Warning>

***

## GitOps workflow

Manage KavachOS configuration alongside your application infrastructure:

```
infra/
├── main.tf           # Provider and state backend
├── organizations.tf  # kavachos_organization resources
├── agents.tf         # Agent definitions
├── api_keys.tf       # API keys for CI and services
└── variables.tf
```

A minimal GitHub Actions workflow:

```yaml theme={"system"}
name: Terraform

on:
  push:
    branches: [main]
    paths: ['infra/**']
  pull_request:
    paths: ['infra/**']

jobs:
  terraform:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: actions/checkout@v4

      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: "1.8"

      - run: terraform -chdir=infra init

      - name: Plan
        id: plan
        env:
          KAVACHOS_BASE_URL: ${{ secrets.KAVACHOS_BASE_URL }}
          KAVACHOS_TOKEN: ${{ secrets.KAVACHOS_TOKEN }}
        run: terraform -chdir=infra plan -out=tfplan -no-color

      - name: Apply
        if: github.ref == 'refs/heads/main' && github.event_name == 'push'
        env:
          KAVACHOS_BASE_URL: ${{ secrets.KAVACHOS_BASE_URL }}
          KAVACHOS_TOKEN: ${{ secrets.KAVACHOS_TOKEN }}
        run: terraform -chdir=infra apply tfplan
```

Every permission change ships as a pull request diff. The plan output shows exactly what will change before it's applied. The apply only runs on merge to main.

This means the same controls you use for code changes, required reviewers, branch protection, signed commits, apply to auth config changes too.
