Terraform provider
Manage EvalGuard projects, API keys, firewall rules, eval schedules and gateway policies as code. Published on the Terraform Registry as EvalGuardAi/evalguard.
v1.1.0 — five resources with real CRUD against the EvalGuard /api/v1 surface, pinned by contract tests.
Security posture
base_url is https-only — the API key is a Bearer token, so a plaintext endpoint is a hard error. Credential fields (api_key, the created key) are marked sensitive. Retries are bounded and idempotency-safe: 429 is always retried; 5xx is retried only on idempotent verbs — never a double-create. Releases are signed, multi-platform GoReleaser builds; CI runs gosec (SAST), govulncheck, and terraform validate on every example.
Provider setup
Pin the provider and configure auth. The API key is read from the EVALGUARD_API_KEY environment variable by default — keep it out of version control.
terraform {
required_providers {
evalguard = {
source = "EvalGuardAi/evalguard"
version = "~> 1.1"
}
}
}
provider "evalguard" {
# api_key defaults to $EVALGUARD_API_KEY.
# base_url defaults to https://evalguard.ai (self-hosters override — https only).
}Resources
Five resources, each backed by real HTTP against /api/v1 (schema-only stubs were removed in v1.1.0).
evalguard_projectPOST /api/v1/projects + GET|PATCH|DELETE /api/v1/projects/{id}A project — the tenancy boundary evals, scans, traces and firewall rules attach to.
evalguard_api_keyPOST /api/v1/api-keys, GET ?orgId, DELETE /api/v1/api-keys/{id} (soft revoke)A scoped API key. The plaintext `key` is returned once, on create, as a sensitive attribute — capture it in an output or a secret store.
evalguard_firewall_rulePOST /api/v1/firewall/rules (upsert), GET ?projectId, DELETE ?ruleId&projectIdA runtime firewall rule (regex / classifier / policy) with a priority and a block/allow/flag action.
evalguard_eval_schedulePOST /api/v1/eval-schedules, GET ?projectId, PATCH, DELETE ?idA cron-scheduled regression eval — model + scorers run on a schedule so quality doesn't silently drift.
evalguard_gateway_policy/api/v1/gateway/policies (create-rule + list + delete; update = delete+create)An agent-gateway egress policy (allow/deny tools, endpoints) enforced at proxy time.
Complete example
A project with a CI-scoped key, a prompt-injection firewall rule, a nightly regression eval, and a gateway egress policy. This is the config CI runs terraform validate against.
variable "evalguard_org_id" {
type = string
description = "Organization that owns these resources."
}
resource "evalguard_project" "example" {
org_id = var.evalguard_org_id
name = "checkout-assistant"
slug = "checkout-assistant"
settings = jsonencode({
retention_days = 30
})
}
resource "evalguard_api_key" "ci" {
org_id = var.evalguard_org_id
name = "ci-firewall-check"
scopes = ["firewall:check"]
}
resource "evalguard_firewall_rule" "block_injection" {
project_id = evalguard_project.example.id
name = "block-prompt-injection"
type = "regex"
priority = 10
condition = jsonencode({
pattern = "(?i)ignore (all )?previous instructions"
})
action = jsonencode({
type = "block"
})
}
resource "evalguard_eval_schedule" "nightly" {
project_id = evalguard_project.example.id
name = "nightly-regression"
cron_expression = "0 3 * * *"
config = jsonencode({
model = "gpt-4"
scorers = ["exact-match"]
})
}
resource "evalguard_gateway_policy" "deny_external_http" {
project_id = evalguard_project.example.id
name = "deny-external-http"
effect = "deny"
priority = 50
conditions = jsonencode({
tools = ["http.get"]
})
}
# The plaintext key is returned once, on create.
output "ci_api_key" {
value = evalguard_api_key.ci.key
sensitive = true
}Apply it
export EVALGUARD_API_KEY="eg_live_..." terraform init terraform plan -var "evalguard_org_id=$ORG_ID" terraform apply -var "evalguard_org_id=$ORG_ID" # Read the CI key back out (sensitive): terraform output -raw ci_api_key
Notes
evalguard_gateway_policyhas no in-place update path on the API (create + delete only), so a change to an existing policy is a replace (delete-then-create) — expect-/+in the plan.- Deleting an
evalguard_api_keyis a soft revoke — the key stops authenticating but the audit row is retained. - Self-hosters set
base_urlon the provider block to their instance (https only).