Terraform Policy
HashiCorpOfficialPublished by HashiCorp
- Skill
- Tool integration
- Cloud and DevOps
- MPL-2.0
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill serves as a central interface for managing Terraform Policy files, including .policy.hcl and .policytest.hcl formats. It routes requests to specialized sub-skills for authoring policies or writing test suites, while providing version-specific guidance for the tfpolicy CLI. It supports the creation of new policies, the conversion of legacy Sentinel policies, and the development of test mocks to ensure policy compliance.
What it does
- Routes requests to specialized sub-skills for policy authoring and testing.
- Provides version-aware guidance for tfpolicy CLI versions 0.3.x, 0.4.x, and 0.5.x.
- Assists in converting existing Sentinel policies to the Terraform Policy format.
- Facilitates the creation of .policy.hcl files from natural-language requirements.
- Supports the development of .policytest.hcl files to validate policy logic.
When to use it
- When you need to write a new Terraform Policy.
- When you are migrating legacy Sentinel policies to Terraform Policy.
- When you need to create or debug test files for your policies.
- When you require guidance on tfpolicy CLI features or syntax.
Advantages
- Centralized management of policy authoring and testing workflows.
- Version-specific instructions ensure compatibility with different CLI releases.
- Streamlined conversion process for legacy Sentinel codebases.
- Clear separation of concerns between policy definition and test validation.
Usage examples
- “Block EC2 instances without encryption”
- The skill routes the request to the authoring sub-skill to generate the appropriate resource_policy block.
- “Convert this Sentinel policy to tfpolicy”
- The skill translates the Sentinel logic into an idiomatic .policy.hcl file.
- “Write a policytest for my EBS policy”
- The skill routes the request to the testing sub-skill to generate a .policytest.hcl file with necessary mocks.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/hashicorp/terraform-policy/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip terraform-policy.zip -d .agents/skills
Documentation by HashiCorp
terraform-policy
UTILITY SKILL — INVOKES: tfpolicy-author | tfpolicy-test
USE FOR:
Writing a new
.policy.hclpolicy from a description or requirementConverting a
.sentinelpolicy to Terraform PolicyWriting or debugging a
.policytest.hcltest fileMigrating a Sentinel policy library to Terraform Policy
Before giving authoring or testing instructions, check the installed tfpolicy CLI version and tailor guidance accordingly. This skill maintains guidance for the two most recent minor lines, 0.4.x and 0.5.x. The 0.3.x bullet below is baseline guidance that applies to every supported line. When a new minor ships, drop the oldest line and add the new one. Inline notes for versions earlier than 0.3.0 are retained only for older CLIs.
If the CLI is
0.3.x(baseline), include a top-levelpolicy { required_providers { ... } }block when authoring.policy.hclfiles containing resource or provider policies. It is mandatory fortfpolicy validate; version-range validation is best effort, and wildcard targets such asresource_policy "*"are not schema-validated. Every mockresource {}block in.policytest.hclfiles must declareattrsorprior_attrs; if both evaluate to empty, the test case is skipped (provider {}andmodule {}mocks are unaffected) (see tfpolicy-test).tfpolicy testreuses the target.policy.hcl's existing top-levelpolicy { required_providers { ... } }block (there is no separate.policytest.hcl-level declaration) to validate provider, resource, and data-source policies andcore::getdatasource()/core::getresources()arguments against resolved provider schemas before any test runs, failing the whole run on a schema mismatch (see tfpolicy-test).core::alltrue(list)andcore::anytrue(list)are available — prefer them over thecore::length()list-comprehension workaround (see tfpolicy-author).meta.tfe_stackandmeta.tfe_workspace.tagsare available to resource, provider, and module policies; Stack fields are empty strings outside Stack evaluations on 0.3.x and 0.4.x (nullon 0.5.x+, see below). On 0.3.x only, theno-opoperation does not exist: resource policies evaluate only resources that the run creates, updates, or deletes, and the defaultoperationsis["create", "update"].If the CLI is
0.4.xor newer, all0.3.xguidance still applies except theoperationsdefault, plus theno-opoperation, which evaluates resources that the run leaves unchanged (the entire state).operationsaccepts"create","update","delete", and"no-op". For policies that do not referenceprior_attrs, the defaultoperationsis now["create", "update", "no-op"], so omitting it evaluates every resource in state. Useoperations = ["create", "update"]to evaluate only changed resources.no-opexposes the existing values throughattrs, andprior_attrsis unavailable.deletecannot be combined withcreateorno-op(["update", "delete"]is valid), andprior_attrspolicies must setoperationsexplicitly. Attrs-only policies (noprior_attrs) callingcore::getresourceswhoseoperationsomitno-opload with a warning; do not addno-opto aprior_attrspolicy, which fails validation. In tests, setmeta.operation = "no-op"explicitly because it is never inferred (see tfpolicy-author and tfpolicy-test).If the CLI is
0.5.xor newer, all0.4.xguidance still applies, with two changes. (1) Absentmetaattributes are exposed asnullinstead of an empty string:meta.alias(no alias),meta.version(no version specified, including modules), andmeta.tfe_stack.deployment_group/deployment_name/stack_name(workspace evaluations or not set).meta.tfe_workspace.tagsis still an empty map. Passingnullto a function such ascore::semverconstraint, or interpolating it into a string such aserror_message, fails, and&&does not short-circuit, so guard with a conditional:meta.version != null ? core::semverconstraint(meta.version, ">= 2.0.0") : false. Equality checks are null-safe (meta.alias == "secondary"isfalsewhen there is no alias), but checks likemeta.tfe_stack.stack_name == ""no longer match (use== null). (2)prior_attrsis rejected at parse time inprovider_policyandmodule_policyblocks; it is valid only inresource_policy(update and delete operations). Useattrs.for provider attributes (see tfpolicy-author).If the CLI version is unknown, ask the user to check it first or provide guidance that clearly distinguishes the
0.3.x,0.4.x, and0.5.xpaths.
DO NOT USE FOR:
Writing
.tftest.hclfiles for Terraform modules — useterraform-testGeneral Terraform HCL authoring — use
terraform-style-guide
Routing
| Task | Sub-skill |
|---|---|
Write or convert a .policy.hcl policy | tfpolicy-author |
Write or debug a .policytest.hcl test | tfpolicy-test |
Examples
"Block EC2 instances without encryption" → tfpolicy-author
"Convert this Sentinel policy to tfpolicy" → tfpolicy-author
"Write a policytest for my EBS policy" → tfpolicy-test
Troubleshooting
Wrong skill triggered? Load the sub-skill directly from the routing table above.
npx skills add hashicorp/agent-skills/terraform/terraform-policy/skills/tfpolicy-author
npx skills add hashicorp/agent-skills/terraform/terraform-policy/skills/tfpolicy-testFiles
- .gitignore29 B
- ATTRIBUTION.mdAdded by AutoGineer865 B
- LICENSELicence file added by AutoGineer16.3 KiB
- README.md2.8 KiB
- SKILL.md6.3 KiB
- examples/README.md2.5 KiB
- examples/conversion/cloudfront-associated-with-waf/README.md871 B
- examples/conversion/cloudfront-associated-with-waf/cloudfront-associated-with-waf.policy.hcl589 B
- examples/conversion/cloudfront-associated-with-waf/cloudfront-associated-with-waf.sentinel1.6 KiB
- examples/conversion/cloudtrail-server-side-encryption-enabled/README.md846 B
- examples/conversion/cloudtrail-server-side-encryption-enabled/cloudtrail-server-side-encryption-enabled.policy.hcl512 B
- examples/conversion/cloudtrail-server-side-encryption-enabled/cloudtrail-server-side-encryption-enabled.sentinel1.4 KiB
- examples/conversion/dms-endpoint-should-be-ssl-configured/README.md872 B
- examples/conversion/dms-endpoint-should-be-ssl-configured/dms-endpoint-should-be-ssl-configured.policy.hcl516 B
- examples/conversion/dms-endpoint-should-be-ssl-configured/dms-endpoint-should-be-ssl-configured.sentinel1.5 KiB
- examples/conversion/dms-endpoints-should-use-ssl/README.md800 B
- examples/conversion/dms-endpoints-should-use-ssl/dms-endpoints-should-use-ssl.policy.hcl579 B
- examples/conversion/dms-endpoints-should-use-ssl/dms-endpoints-should-use-ssl.sentinel1.4 KiB
- examples/conversion/ec2-network-acl-should-have-subnet-ids/README.md970 B
- examples/conversion/ec2-network-acl-should-have-subnet-ids/ec2-network-acl-should-have-subnet-ids.policy.hcl1.0 KiB
- examples/conversion/ec2-network-acl-should-have-subnet-ids/ec2-network-acl-should-have-subnet-ids.sentinel2.9 KiB
- examples/conversion/ec2-vpc-default-security-group-no-traffic/README.md1.1 KiB
- examples/conversion/ec2-vpc-default-security-group-no-traffic/ec2-vpc-default-security-group-no-traffic.policy.hcl865 B
- examples/conversion/ec2-vpc-default-security-group-no-traffic/ec2-vpc-default-security-group-no-traffic.sentinel3.6 KiB
- examples/conversion/efs-access-point-should-enforce-user-identity/README.md727 B
- examples/conversion/efs-access-point-should-enforce-user-identity/efs-access-point-should-enforce-user-identity.policy.hcl448 B
- examples/conversion/efs-access-point-should-enforce-user-identity/efs-access-point-should-enforce-user-identity.sentinel1.3 KiB
- examples/conversion/elasticache-redis-replication-group-encryption-at-transit-enabled/README.md777 B
- examples/conversion/elasticache-redis-replication-group-encryption-at-transit-enabled/elasticache-redis-replication-group-encryption-at-transit-enabled.policy.hcl547 B
- examples/conversion/elasticache-redis-replication-group-encryption-at-transit-enabled/elasticache-redis-replication-group-encryption-at-transit-enabled.sentinel1.5 KiB
- examples/conversion/elasticsearch-encrypted-at-rest/README.md734 B
- examples/conversion/elasticsearch-encrypted-at-rest/elasticsearch-encrypted-at-rest.policy.hcl584 B
- examples/conversion/elasticsearch-encrypted-at-rest/elasticsearch-encrypted-at-rest.sentinel1.5 KiB
- examples/conversion/elasticsearch-https-required/README.md904 B
- examples/conversion/elasticsearch-https-required/elasticsearch-https-required.policy.hcl1.1 KiB
- examples/conversion/elasticsearch-https-required/elasticsearch-https-required.sentinel2.3 KiB
- examples/conversion/elasticsearch-in-vpc-only/README.md890 B
- examples/conversion/elasticsearch-in-vpc-only/elasticsearch-in-vpc-only.policy.hcl589 B
- examples/conversion/elasticsearch-in-vpc-only/elasticsearch-in-vpc-only.sentinel1.9 KiB
- examples/conversion/eventbridge-custom-event-bus-should-have-attached-policy/README.md1.1 KiB
- examples/conversion/eventbridge-custom-event-bus-should-have-attached-policy/eventbridge-custom-event-bus-should-have-attached-policy.policy.hcl845 B
- examples/conversion/eventbridge-custom-event-bus-should-have-attached-policy/eventbridge-custom-event-bus-should-have-attached-policy.sentinel2.1 KiB
- examples/conversion/s3-block-public-access-bucket-level/README.md1.1 KiB
- examples/conversion/s3-block-public-access-bucket-level/s3-block-public-access-bucket-level.policy.hcl1.2 KiB
- examples/conversion/s3-block-public-access-bucket-level/s3-block-public-access-bucket-level.sentinel3.2 KiB
- examples/conversion/s3-bucket-should-have-object-lock-enabled/README.md975 B
- examples/conversion/s3-bucket-should-have-object-lock-enabled/s3-bucket-should-have-object-lock-enabled.policy.hcl1.0 KiB
- examples/conversion/s3-bucket-should-have-object-lock-enabled/s3-bucket-should-have-object-lock-enabled.sentinel2.8 KiB
- examples/conversion/secretsmanager-auto-rotation-enabled-check/README.md955 B
- examples/conversion/secretsmanager-auto-rotation-enabled-check/secretsmanager-auto-rotation-enabled-check.policy.hcl867 B
- examples/conversion/secretsmanager-auto-rotation-enabled-check/secretsmanager-auto-rotation-enabled-check.sentinel2.2 KiB
- examples/conversion/step-functions-state-machine-logging-enabled/README.md778 B
- examples/conversion/step-functions-state-machine-logging-enabled/step-functions-state-machine-logging-enabled.policy.hcl724 B
- examples/conversion/step-functions-state-machine-logging-enabled/step-functions-state-machine-logging-enabled.sentinel1.6 KiB
- references/tfpolicy-author.md102.1 KiB
- references/tfpolicy-test.md46.5 KiB
- references/verified-syntax.md101.2 KiB
examples/conversion/elasticsearch-https-required/elasticsearch-https-required.sentinel
# This policy requires resources of type `aws_elasticsearch_domain` have the `tls_security_policy` set to latest policy that is 'Policy-Min-TLS-1-2-PFS-2023-10' and 'enforce_https' set to true for `domain_endpoint_options` attribute.
# Copyright IBM Corp. 2025, 2026
# SPDX-License-Identifier: BUSL-1.1
# Import
import "tfplan/v2" as tfplan
import "tfresources" as tf
import "report" as report
import "collection" as collection
import "collection/maps" as maps
# Params
param master_count_value default 3
# Constants
const = {
"policy_name": "elasticsearch-https-required",
"message": "Attribute 'tls_security_policy' must be set to latest policy that is 'Policy-Min-TLS-1-2-PFS-2023-10' and 'enforce_https' set to true for the attribute 'domain_endpoint_options' for 'aws_elasticsearch_domain' resources. Refer to https://docs.aws.amazon.com/securityhub/latest/userguide/es-controls.html#es-8 for more details.",
"resource_aws_elasticsearch_domain": "aws_elasticsearch_domain",
"enforce_https": "enforce_https",
"tls_security_policy": "tls_security_policy",
"allowed_tls_latest_policy": "Policy-Min-TLS-1-2-PFS-2023-10",
}
# Functions
get_violations = func(resources) {
return collection.reject(resources, func(res) {
domain_endpoint_options_values = maps.get(res, "values.domain_endpoint_options", [])
if domain_endpoint_options_values is empty {
return false
}
tls_security_policy_value = maps.get(domain_endpoint_options_values[0], const.tls_security_policy, null)
enforce_https_value = maps.get(domain_endpoint_options_values[0], const.enforce_https, true)
if tls_security_policy_value is null {
return false
}
return enforce_https_value is true and tls_security_policy_value == const.allowed_tls_latest_policy
})
}
# Variables
elasticsearch_resources = tf.plan(tfplan.planned_values.resources).type(const.resource_aws_elasticsearch_domain).resources
violations = get_violations(elasticsearch_resources)
summary = {
"policy_name": const.policy_name,
"violations": map violations as _, v {
{
"address": v.address,
"module_address": v.module_address,
"message": const.message,
}
},
}
# Outputs
print(report.generate_policy_report(summary))
# Rules
main = rule {
violations is empty
}
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs Node.js
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- HashiCorp
- Publisher
- HashiCorp (Official)
- Source
- hashicorp/agent-skills · plugins/terraform/skills/terraform-policy · commit 5e30fa5
- Licence
- Mozilla Public License 2.0 (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by HashiCorp or HashiCorp.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download terraform-policy.zip