Skip to content
Back to skills

3005 Terraform Policy Complianceinstructions 6827f5c2

ASecurity

MANDATORY Azure Policy compliance rules for Terraform code generation. Azure Policy always wins.

  • 9 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added June 1, 2026
devopsrustgosqlkubernetesazureterraformgitdatabasebackendsecurity

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned June 1, 2026

npx -y skills add tools-only/X-Skills --skill 3005-terraform-policy-complianceinstructions_6827f5c2 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 3005 Terraform Policy Complianceinstructions 6827f5c2?

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

Security grade badge for 3005 Terraform Policy Complianceinstructions 6827f5c2
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-3005-terraform-policy-complianceinstructions-6827f/badge)](https://www.skillsdirectory.com/skills/tools-only-3005-terraform-policy-complianceinstructions-6827f)

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
---
description: "MANDATORY Azure Policy compliance rules for Terraform code generation. Azure Policy always wins."
applyTo: "**/*.tf, **/*.agent.md"
---

# Terraform Policy Compliance Instructions

**First Principle: Azure Policy always wins.** Current Azure Policy
implementation cannot be changed. Code MUST adapt to policy, never
the reverse.

## Mandate

ALL Terraform code generation MUST cross-reference
`04-governance-constraints.md` and `04-governance-constraints.json`
before writing templates. These artifacts contain the discovered
Azure Policy constraints for the target subscription.

## Dynamic Tag List

Tags MUST come from governance constraints, not hardcoded defaults.
The 4 baseline defaults in `terraform-code-best-practices.instructions.md`
(`Environment`, `ManagedBy`, `Project`, `Owner`) are a **MINIMUM** —
discovered policies always win. If governance constraints specify
9 tags, the Terraform code MUST include all 9.

### Example

```text
Defaults (azure-defaults skill):  4 tags
Governance constraints discovered: 9 tags (environment, owner,
  costcenter, application, workload, sla, backup-policy,
  maint-window, tech-contact)
Required in Terraform code:       9 tags (governance wins)
```

```hcl
# locals.tf — all 9 tags when governance requires them
locals {
  tags = merge(var.tags, {
    environment      = var.environment
    owner            = var.owner
    costcenter       = var.costcenter
    application      = var.application
    workload         = var.workload
    sla              = var.sla
    backup-policy    = var.backup_policy
    maint-window     = var.maint_window
    tech-contact     = var.tech_contact
  })
}
```

## `azurePropertyPath` Translation

For each Deny or Modify policy in `04-governance-constraints.json`,
read the `azurePropertyPath` field and translate it to the
corresponding `azurerm_*` resource argument:

### Translation Pattern

1. Split `azurePropertyPath` on `.` → `[resourceType, "properties", ...rest]`
2. Map `resourceType` to the correponding `azurerm_*` resource using the table below
3. Map the `properties.` path to the Terraform argument name (snake_case)

### Resource Type Mapping

| `azurePropertyPath` prefix | Terraform resource                                  |
| -------------------------- | --------------------------------------------------- |
| `storageAccount`           | `azurerm_storage_account`                           |
| `keyVault`                 | `azurerm_key_vault`                                 |
| `sqlServer`                | `azurerm_mssql_server`                              |
| `sqlDatabase`              | `azurerm_mssql_database`                            |
| `cosmosDbAccount`          | `azurerm_cosmosdb_account`                          |
| `webApp`                   | `azurerm_linux_web_app` / `azurerm_windows_web_app` |
| `appServicePlan`           | `azurerm_service_plan`                              |
| `containerRegistry`        | `azurerm_container_registry`                        |
| `aksCluster`               | `azurerm_kubernetes_cluster`                        |
| `serviceBusNamespace`      | `azurerm_servicebus_namespace`                      |
| `eventHubNamespace`        | `azurerm_eventhub_namespace`                        |
| `logAnalyticsWorkspace`    | `azurerm_log_analytics_workspace`                   |

### Property Path Mapping Examples

| `azurePropertyPath`                                  | Terraform Argument                        |
| ---------------------------------------------------- | ----------------------------------------- |
| `storageAccount.properties.minimumTlsVersion`        | `min_tls_version`                         |
| `storageAccount.properties.allowBlobPublicAccess`    | `allow_nested_items_to_be_public`         |
| `storageAccount.properties.supportsHttpsTrafficOnly` | `https_traffic_only_enabled`              |
| `sqlServer.properties.minimalTlsVersion`             | `minimum_tls_version`                     |
| `sqlServer.properties.publicNetworkAccess`           | `public_network_access_enabled`           |
| `keyVault.properties.enableSoftDelete`               | `soft_delete_retention_days` (> 0 = true) |
| `keyVault.properties.enablePurgeProtection`          | `purge_protection_enabled`                |
| `containerRegistry.properties.publicNetworkAccess`   | `public_network_access_enabled`           |
| `webApp.properties.httpsOnly`                        | `https_only`                              |

## Policy Compliance Checklist

For every policy in `04-governance-constraints.json`:

### Deny Policies

- [ ] Read `azurePropertyPath` and `requiredValue` from JSON
- [ ] Translate `azurePropertyPath` to `azurerm_*` resource argument using the table above
- [ ] Verify the generated Terraform code sets the argument to the required value
- [ ] If the argument is missing, add it
- [ ] If the argument value conflicts, change it to match policy

### Modify Policies

- [ ] Document expected auto-modifications in the implementation reference
- [ ] Do NOT set values that Modify policies auto-apply (avoid conflicts)

### DeployIfNotExists Policies

- [ ] Document auto-deployed resources in the implementation reference
- [ ] Include expected resources in cost estimates

### Audit Policies

- [ ] Add a comment in the resource block for awareness
- [ ] Set compliant values where feasible (best effort)

### Audit Policy Comment Pattern

```hcl
resource "azurerm_storage_account" "this" {
  # AUDIT: Policy "Require diagnostic settings" — compliant if Log Analytics configured
  # ...
}
```

## Enforcement Rule

> [!CAUTION]
> **Azure Policy always wins.** Current Azure Policy implementation
> cannot be changed. Code MUST adapt to policy, never the reverse.
> A governance compliance failure is a HARD GATE — the Terraform Code
> Generator MUST NOT proceed past Phase 1.5 with unresolved
> policy violations.

## HCP Terraform Cloud Guardrail

> [!CAUTION]
> **NEVER** use HCP Terraform Cloud (`terraform { cloud {} }`) or
> reference `TFE_TOKEN` in generated code. State backend MUST be
> Azure Storage Account. See
> `terraform-code-best-practices.instructions.md` § State Backend.

## Anti-Patterns

| Anti-Pattern                                                        | Why It Fails                                                                              | Correct Approach                                        |
| ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------- |
| Use `terraform { cloud {} }` or `TFE_TOKEN`                         | Vendor lock-in; violates Azure-only backend policy                                        | Use `backend "azurerm"` with Azure Storage Account      |
| Assume 4 tags are sufficient                                        | Azure Policy may enforce 9+ tags                                                          | Read `04-governance-constraints.md` for actual tag list |
| Ignore `public_network_access_enabled` constraints                  | Deny policy blocks deployment                                                             | Check network policies in governance constraints        |
| Skip constraints reading ("trust artifact chain")                   | Trusting the chain means accepting architecture decisions, NOT skipping compliance checks | Always read and enforce governance constraints          |
| Hardcode security settings without checking policy                  | Policy may require stricter values                                                        | Cross-reference `04-governance-constraints.json`        |
| Use `bicepPropertyPath` for Terraform translation                   | Bicep path format is ARM-only                                                             | Use `azurePropertyPath` for Terraform argument mapping  |
| Generate Terraform without reading `04-governance-constraints.json` | Governance-blind code fails deployment                                                    | Phase 1.5 is a HARD GATE                                |

## Cross-References

- **Governance constraints artifact**: `agent-output/{project}/04-governance-constraints.md`
- **Governance constraints JSON**: `agent-output/{project}/04-governance-constraints.json`
- **Governance discovery instructions**: `.github/instructions/governance-discovery.instructions.md`
- **Azure defaults (baseline tags)**: `.github/skills/azure-defaults/SKILL.md`
- **Terraform best practices**: `.github/instructions/terraform-code-best-practices.instructions.md`

Files in this skill

  • README.md1 KB
  • skill.md8.5 KB

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.