kavachOS

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.

Clone the repository and build the binary:

git clone https://github.com/kavachos/terraform-provider-kavachos
cd terraform-provider-kavachos/sdks/terraform
go build -o terraform-provider-kavachos .

Install into the local plugin cache:

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/"

Declare the provider in your Terraform configuration:

terraform {
  required_version = ">= 1.5"
  required_providers {
    kavachos = {
      source  = "kavachos/kavachos"
      version = "~> 0.1"
    }
  }
}

Provider setup

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:

export KAVACHOS_BASE_URL=https://your-app.com/api/kavach
export KAVACHOS_TOKEN=kv_live_...

Prop

Type

Resources

kavachos_agent

Manages an agent identity — the primary entity in KavachOS.

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:

terraform output -raw github_reader_token

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.

Prop

Type

Permission block arguments

Prop

Type

Constraints block arguments

Prop

Type


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.

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

Prop

Type


kavachos_api_key

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

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.

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.


kavachos_organization

Manages an organization for multi-tenant isolation.

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.

data "kavachos_agent" "legacy" {
  id = "agent-id-from-dashboard"
}

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

kavachos_agents

Lists agents, optionally filtered.

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:

# 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.

Importing an API key restores the ID and metadata but not the raw key value — that was only available at creation time.


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:

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.

On this page