# Step 4: Governance Constraints - PCI DSS Gateway

> This document captures the governance constraints and Azure Policy requirements that must be addressed in the Bicep implementation for the PCI-DSS Level 1 payment gateway.

- Skill: `tools-only/step-4-governance-constraints-pci-dss-gateway` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add tools-only/step-4-governance-constraints-pci-dss-gateway`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tools-only/step-4-governance-constraints-pci-dss-gateway/raw
- Safety review: pending (external: skill-scanner PASS, skillspector CAUTION)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: tools-only (https://skillmd.com/u/tools-only)
- Updated: 2026-09-29
- Page: https://skillmd.com/skills/tools-only/step-4-governance-constraints-pci-dss-gateway

---

# 🔒 Step 4: Governance Constraints - PCI DSS Gateway

![Step](https://img.shields.io/badge/Step--4-blue?style=for-the-badge)
![Status](https://img.shields.io/badge/Status-Complete-green?style=for-the-badge)
![Agent](https://img.shields.io/badge/Agent-Bicep--Planner-teal?style=for-the-badge)

<details open>
<summary><strong>📑 Governance Constraints</strong></summary>

- [🔍 Discovery Source](#-discovery-source)
- [📋 Azure Policy Compliance](#-azure-policy-compliance)
- [🔄 Plan Adaptations Based on Policies](#-plan-adaptations-based-on-policies)
- [🚫 Deployment Blockers](#-deployment-blockers)
- [🏷️ Required Tags](#️-required-tags)
- [🔐 Security Policies](#-security-policies)
- [💰 Cost Policies](#-cost-policies)
- [🌐 Network Policies](#-network-policies)

</details>

> Generated by @bicep-plan agent | 2026-02-11

| ⬅️ Previous                                        | 📑 Index            | Next ➡️                                                |
| -------------------------------------------------- | ------------------- | ------------------------------------------------------ |
| [03-des-cost-estimate.md](03-des-cost-estimate.md) | [README](README.md) | [04-implementation-plan.md](04-implementation-plan.md) |

> [!NOTE]
> 📚 See [SKILL.md](../../.github/skills/azure-artifacts/SKILL.md) for visual standards.

This document captures the governance constraints and Azure Policy requirements
that must be addressed in the Bicep implementation for the PCI-DSS Level 1 payment gateway.

## 🔍 Discovery Source

> [!IMPORTANT]
> Governance constraints discovered via **REST API** including management group-inherited policies.
> Previous `az policy assignment list` discovery missed 16 of 21 policies.

| Query              | Result                       | Timestamp            |
| ------------------ | ---------------------------- | -------------------- |
| REST API Total     | **21 assignments**           | 2026-02-11T12:00:00Z |
| Subscription-scope | 5 direct assignments         | 2026-02-11T12:00:00Z |
| RG-scoped          | 7 resource group assignments | 2026-02-11T12:00:00Z |
| MG-inherited       | 9 inherited policies         | 2026-02-11T12:00:00Z |
| Deny-effect        | 3 blockers found             | 2026-02-11T12:00:00Z |
| Tag Policies       | 9 tags required (Deny)       | 2026-02-11T12:00:00Z |

**Discovery Method**: REST API
(`GET /subscriptions/{id}/providers/Microsoft.Authorization/policyAssignments?api-version=2022-06-01`)

**Subscription**: noalz (`00858ffc-dded-4f0f-8bbf-e17fff0d47d9`)

**Tenant**: `2d04cb4c-999b-4e60-a3a7-e8993edc768b`

**Scope**: All effective (subscription + resource group + management group inherited)

> [!CAUTION]
> Previous discovery using `az policy assignment list` only returned 5 subscription-scoped policies.
> REST API revealed 16 additional policies including **critical Deny blockers**.

---

## 📋 Azure Policy Compliance

| Category               | Constraint                         | Source                    | Implementation                               |
| ---------------------- | ---------------------------------- | ------------------------- | -------------------------------------------- |
| **Tags (Deny)**        | 9 lowercase tags required on RGs   | JV-Enforce RG Tags v3     | All Bicep RG deployments include all 9       |
| **Tags (Modify)**      | 9 tags auto-inherited to children  | JV-Inherit Tags           | No Bicep action — policy handles it          |
| **VM SKUs (Deny)**     | H, M, N series blocked             | MCAPSGov Deny             | Using D-series — compliant                   |
| **AKS Pools (Deny)**   | Max 10 agent pool profiles         | MCAPSGov Deny             | Using 2 pools — compliant                    |
| **Classic (Deny)**     | All Classic resource types blocked | MCAPSGov Deny + Block ARM | Using ARM — compliant                        |
| **SQL Auth (Deny)**    | Azure SQL requires AAD-only        | MCAPSGov Deny             | Using PostgreSQL — N/A                       |
| **HSM Purge (Deny)**   | Purge protection required          | MCAPSGov Deny             | Enable purge protection in Bicep             |
| **Compliance (Audit)** | PCI DSS v4 (269 controls)          | Subscription policy       | Architecture designed for PCI-DSS L1         |
| **Compliance (Audit)** | GDPR (285 controls)                | Subscription policy       | EU regions: swedencentral/germanywestcentral |
| **Security (Audit)**   | Azure Security Baseline (224)      | MG policy                 | Cloud security benchmark posture             |
| **Security (Audit)**   | MCAPSGov Audit (44)                | MG policy                 | Tenant baseline compliance                   |
| **MFA (Audit)**        | MFA for write/delete operations    | MG policy (×2)            | Deploying user must have MFA enabled         |
| **Naming**             | No naming policy discovered        | —                         | Follow CAF conventions from azure-defaults   |
| **Location**           | No location restriction found      | —                         | EU regions: swedencentral/germanywestcentral |

---

### Complete Policy Inventory

### Management Group-Inherited Policies (9)

| #   | Display Name                                   | Type       | Effect                   | Sub-Policies | Impact                                   |
| --- | ---------------------------------------------- | ---------- | ------------------------ | ------------ | ---------------------------------------- |
| 1   | **JV-Enforce Resource Group Tags v3**          | Policy     | **Deny**                 | 1            | 🚫 BLOCKER — 9 lowercase tags required   |
| 2   | **MCAPSGov Deny Policies**                     | Initiative | **Deny**                 | 11           | ⚠️ VM SKU + AKS pool + HSM constraints   |
| 3   | **Block Azure RM Resource Creation**           | Policy     | **Deny**                 | 1            | ✅ Classic resources only — no impact    |
| 4   | MCAPSGov Deploy and Modify Policies            | Initiative | DeployIfNotExists/Modify | 27           | Auto-deploys security agents             |
| 5   | MCAPSGov Audit Policies                        | Initiative | Audit                    | 44           | Compliance reporting only                |
| 6   | Azure Security Baseline                        | Initiative | Audit                    | 224          | Microsoft cloud security benchmark       |
| 7   | JV - Inherit Multiple Tags from Resource Group | Policy     | Modify                   | 1            | Auto-inherits 9 tags from RG to children |
| 8   | MFA Enforcement for Resource Write Actions     | Policy     | Audit                    | 1            | MFA required for write operations        |
| 9   | MFA Enforcement for Resource Delete Actions    | Policy     | Audit                    | 1            | MFA required for delete operations       |

### Subscription-Scoped Policies (5)

| #   | Display Name                                | Type                      | Effect            | Impact                                    |
| --- | ------------------------------------------- | ------------------------- | ----------------- | ----------------------------------------- |
| 10  | PCI DSS v4                                  | Initiative (269 controls) | Audit             | Architecture must align with PCI DSS      |
| 11  | EU GDPR 2016/679                            | Initiative (285 controls) | Audit             | EU data residency validation              |
| 12  | ASC DataProtection                          | Initiative                | DeployIfNotExists | Auto-deploys data protection monitoring   |
| 13  | ASC OpenSourceRelationalDatabasesProtection | Initiative                | DeployIfNotExists | Auto-deploys Defender for PostgreSQL      |
| 14  | Defender for SQL Servers on Machines        | Initiative                | DeployIfNotExists | SQL Defender (not applicable — PaaS only) |

### Resource Group-Scoped Policies (7)

All scoped to `rg-arcbox-swc01` — a different resource group. **No impact on this project.**

| #   | Display Name                                                          | Scope           |
| --- | --------------------------------------------------------------------- | --------------- |
| 15  | (ArcBox) Enable SSH Posture Control audit                             | rg-arcbox-swc01 |
| 16  | (ArcBox) Enable Azure Update Manager for Arc-enabled Windows machines | rg-arcbox-swc01 |
| 17  | (ArcBox) Tag resources (unnamed)                                      | rg-arcbox-swc01 |
| 18  | (ArcBox) Azure Monitor (unnamed)                                      | rg-arcbox-swc01 |
| 19  | (ArcBox) Enable Azure Update Manager for Arc-enabled Linux machines   | rg-arcbox-swc01 |
| 20  | (ArcBox) Enable Azure Update Manager for Azure Windows machines       | rg-arcbox-swc01 |
| 21  | (ArcBox) Enable Azure Update Manager for Azure Linux machines         | rg-arcbox-swc01 |

---

## 🔄 Plan Adaptations Based on Policies

### Tag Schema (Updated — CRITICAL)

```bicep
// Resource Group tags — ALL 9 REQUIRED by JV-Enforce Resource Group Tags v3 (Deny)
// Case-sensitive: ALL lowercase
@description('Deployment environment')
@allowed(['dev', 'staging', 'prod'])
param environment string

@description('Team or individual owner')
param owner string

@description('Cost center code')
param costCenter string

@description('Technical contact email')
param technicalContact string

var requiredRgTags = {
  environment: environment
  owner: owner
  costcenter: costCenter
  application: 'pci-dss-gw'
  workload: 'payment-gateway'
  sla: '99.99'
  'backup-policy': 'daily'
  'maint-window': 'Sun:02:00-06:00'
  'technical-contact': technicalContact
}

// Additional project-standard tags (not policy-enforced but recommended)
var allTags = union(requiredRgTags, {
  ManagedBy: 'Bicep'
  Project: 'pci-dss-gw'
})
```

> [!IMPORTANT]
> Resource groups require ALL 9 tags from `JV-Enforce Resource Group Tags v3`.
> Child resources auto-inherit these 9 tags via `JV - Inherit Multiple Tags from Resource Group`
> (Modify effect). Additional tags (ManagedBy, Project) can be appended but are NOT required.

### Architectural Constraints

| Original Design       | Blocking Policy                | Effect | Required Adaptation                               |
| --------------------- | ------------------------------ | ------ | ------------------------------------------------- |
| 4 PascalCase tags     | JV-Enforce RG Tags v3          | Deny   | **9 lowercase tags** on all resource groups       |
| Key Vault Premium HSM | MCAPSGov Deny (HSM purge)      | Deny   | `enablePurgeProtection: true` required            |
| AKS 2 node pools      | MCAPSGov Deny (AKS pool limit) | Deny   | ✅ Compliant (2 < 10 limit) — document constraint |
| D8s_v5 / D4s_v5 VMs   | MCAPSGov Deny (VM SKU)         | Deny   | ✅ Compliant — D-series not blocked               |

### Auto-Applied Configurations

| Policy                                                | Effect                   | What Gets Auto-Applied                       |
| ----------------------------------------------------- | ------------------------ | -------------------------------------------- |
| JV - Inherit Multiple Tags from Resource Group        | Modify                   | 9 RG tags auto-copied to all child resources |
| MCAPSGov Deploy and Modify Policies (27 sub-policies) | DeployIfNotExists/Modify | Security agents, diagnostic settings         |
| ASC DataProtection                                    | DeployIfNotExists        | Data protection monitoring agents            |
| ASC OpenSourceRelationalDatabasesProtection           | DeployIfNotExists        | Defender for PostgreSQL monitoring           |
| Defender for SQL on Machines                          | DeployIfNotExists        | SQL Defender agents (N/A — PaaS)             |

---

## 🚫 Deployment Blockers

> [!CAUTION]
> **CRITICAL**: Policies that BLOCK deployment. Resolution is REQUIRED before proceeding.

### Blocker 1: JV-Enforce Resource Group Tags v3 (DENY)

**Assignment**: `b1ad1a690a5148ec8707ff17`

**Scope**: Management Group (Tenant Root `2d04cb4c-999b-4e60-a3a7-e8993edc768b`)

**Enforcement Mode**: Default (enabled)

**Effect**: Deny

**Policy Definition**: `27833bcf-5909-4a37-891c-16a3cb06856d`

**Policy Rule**:

- Applies to: `Microsoft.Resources/subscriptions/resourceGroups`
- Excludes RG names matching: `AzureBackupRG*`, `ResourceMover*`, `databricks-rg*`,
  `NetworkWatcherRG`, `microsoft-network`, `LogAnalyticsDefaultResources`, `rg-amba-*`,
  `DynamicsDeployments*`, `MC_myResourceGroup*`
- **Denies creation if ANY of 9 tags are missing** (case-sensitive, all lowercase)

| #   | Tag Name            | Required | Case      |
| --- | ------------------- | -------- | --------- |
| 1   | `environment`       | Yes      | lowercase |
| 2   | `owner`             | Yes      | lowercase |
| 3   | `costcenter`        | Yes      | lowercase |
| 4   | `application`       | Yes      | lowercase |
| 5   | `workload`          | Yes      | lowercase |
| 6   | `sla`               | Yes      | lowercase |
| 7   | `backup-policy`     | Yes      | lowercase |
| 8   | `maint-window`      | Yes      | lowercase |
| 9   | `technical-contact` | Yes      | lowercase |

> [!WARNING]
> **Our original plan only had 4 tags (Environment, ManagedBy, Project, Owner) with PascalCase.**
> This policy requires **9 tags** with **lowercase** names. Resource group creation will be
> **DENIED** without all 9 tags present.

**Resolution**: Update all Bicep resource group deployments to include all 9 required tags
with correct lowercase casing. The `ManagedBy` and `Project` tags from our defaults are
supplementary but NOT required by policy.

### Blocker 2: MCAPSGov Deny Policies (11 sub-policies)

**Assignment**: `MCAPSGovDenyPolicies`

**Scope**: Management Group (Tenant Root `2d04cb4c-999b-4e60-a3a7-e8993edc768b`)

**Enforcement Mode**: Default (enabled)

**Effect**: Deny (initiative with 11 policies)

| #   | Reference ID                                     | Policy Definition                                | Effect | Impact on This Project                                       |
| --- | ------------------------------------------------ | ------------------------------------------------ | ------ | ------------------------------------------------------------ |
| 1   | BlockVMSKUs_H                                    | VirtualMachine_SKU_Deny                          | Deny   | ✅ Safe — we use D-series, not H-series (17 blocked SKUs)    |
| 2   | BlockVMSKUs_M                                    | VirtualMachine_SKU_Deny                          | Deny   | ✅ Safe — we use D-series, not M-series (44 blocked SKUs)    |
| 3   | BlockVMSKUs_N                                    | VirtualMachine_SKU_Deny                          | Deny   | ✅ Safe — we use D-series, not N-series (64 blocked SKUs)    |
| 4   | AKS_LimitNodeCount                               | AKS_LimitNodeCount_Deny                          | Deny   | ✅ Safe — our plan uses 2 pools (system + CDE), limit is 10  |
| 5   | VMSS_LimitNodesCount                             | VMSS_LimitNodesCount_Deny                        | Deny   | ⚠️ Verify — AKS uses VMSS internally, check node count limit |
| 6   | OpenAI_BlockProvisionedCapacity                  | AzureOpenAI_ProvisionedCapacity_Deny             | Deny   | ✅ N/A — not in our architecture                             |
| 7   | Sentinel_Commitment_Deny                         | Sentinel_Commitment_Deny                         | Deny   | ✅ N/A — not in our architecture                             |
| 8   | AzureSQL_WithoutAzureADOnlyAuthentication_Deny   | AzureSQL_WithoutAzureADOnlyAuthentication_Deny   | Deny   | ✅ N/A — we use PostgreSQL, not Azure SQL                    |
| 9   | AzureSQLMI_WithoutAzureADOnlyAuthentication_Deny | AzureSQLMI_WithoutAzureADOnlyAuthentication_Deny | Deny   | ✅ N/A — not in our architecture                             |
| 10  | NotAllowedResourceTypes                          | 6c112d4e-5bc7-47ae-a041-ea2d9dccd749             | Deny   | ✅ Safe — blocks 57 Classic (ASM) resource types only        |
| 11  | KeyVaultManagedHSM_PurgeProtectionEnabled        | KeyVaultManagedHSM_PurgeProtectionEnabled_Deny   | Deny   | ⚠️ Ensure — Key Vault HSM must have purge protection enabled |

**Resolutions**:

1. **AKS agent pool limit**: Architecture uses 2 pools — compliant. Document constraint.
2. **VMSS node count**: Verify the exact limit parameter and ensure AKS autoscaler max
   does not exceed it.
3. **Key Vault HSM purge protection**: Set `enablePurgeProtection: true` on Key Vault.
4. **VM SKUs**: Only D-series VMs used — compliant. Document blocked families.

### Non-Blocker: Block Azure RM Resource Creation (DENY)

**Scope**: Management Group (Tenant Root)

**Assessment**: This policy ONLY blocks Classic (ASM) resource types:
`Microsoft.ClassicCompute/*`, `Microsoft.ClassicStorage/*`, `Microsoft.ClassicNetwork/*`.

**Impact**: None — our Bicep templates use ARM resources exclusively.

---

## 🏷️ Required Tags

### Resource Group Tags (MANDATORY — Deny enforced)

```bicep
// These 9 tags are REQUIRED by JV-Enforce Resource Group Tags v3 (Deny)
// ALL lowercase, case-sensitive — deployment will FAIL without them
var requiredRgTags = {
  environment: environment          // 'dev' | 'staging' | 'prod'
  owner: owner                      // Team or individual
  costcenter: costCenter            // Cost center code
  application: 'pci-dss-gw'          // Application name
  workload: 'payment-gateway'      // Workload type
  sla: '99.99'                     // SLA target
  'backup-policy': 'daily'         // Backup policy
  'maint-window': 'Sun:02:00-06:00' // Maintenance window
  'technical-contact': techContact  // Technical contact email
}
```

### Resource Tags (Project standard + auto-inherited)

```bicep
// Child resources auto-inherit 9 RG tags via JV-Inherit policy (Modify)
// These additional tags are project convention, not policy-enforced
var additionalTags = {
  ManagedBy: 'Bicep'
  Project: 'pci-dss-gw'
}

var allTags = union(requiredRgTags, additionalTags)
```

---

## 🔐 Security Policies

| Area                    | Requirement                    | Source                          |
| ----------------------- | ------------------------------ | ------------------------------- |
| HTTPS Only              | TLS 1.2+ on all services       | PCI Req 4 (proactive)           |
| Public Access           | Disabled via private endpoints | PCI Req 1 (proactive)           |
| Managed Identity        | All service-to-service auth    | PCI Req 8 (proactive)           |
| Key Vault HSM           | Purge protection required      | MCAPSGov Deny + PCI Req 3       |
| AAD-Only Auth           | Required for all databases     | MCAPSGov Deny (SQL) + PCI Req 8 |
| Network Segmentation    | Hub-spoke with Firewall IDPS   | PCI Req 1 (proactive)           |
| Container Security      | Defender auto-enabled          | MCAPSGov Deploy (auto)          |
| Logging                 | 1-year retention, tamper-proof | PCI Req 10 (proactive)          |
| Defender for PostgreSQL | Auto-enabled                   | ASC policy (auto)               |
| Defender for Cloud      | Enhanced posture               | PCI Req 11 (proactive)          |
| MFA Enforcement         | Write/delete operations        | MG policy (Audit)               |
| Security Baseline       | 224 controls                   | MG policy (Audit)               |

---

## 💰 Cost Policies

| Constraint                          | Source                     | Impact                                                  |
| ----------------------------------- | -------------------------- | ------------------------------------------------------- |
| H/M/N VM SKUs blocked               | MCAPSGov Deny (3 policies) | Prevents expensive HPC/GPU VMs                          |
| OpenAI provisioned capacity blocked | MCAPSGov Deny              | Prevents AI spend                                       |
| Sentinel commitment tier blocked    | MCAPSGov Deny              | Prevents commitment over-provisioning                   |
| No budget policy found              | —                          | Recommend Azure Cost Management alert at $20,000/mo     |
| No reservations policy              | —                          | Recommend 1-year RI for AKS + PostgreSQL (~35% savings) |

---

## 🌐 Network Policies

| Policy                  | Constraint                           | Impact                                              |
| ----------------------- | ------------------------------------ | --------------------------------------------------- |
| No location restriction | No Deny policy on allowed locations  | Using EU regions: swedencentral/germanywestcentral  |
| No naming policy        | No Deny policy on naming conventions | Following CAF conventions from azure-defaults skill |
| NSG flow logs           | MCAPSGov Deploy auto-enables         | Auto-applied via DeployIfNotExists                  |

> [!NOTE]
> No network-specific Deny policies found. Architecture follows PCI-DSS network
> segmentation requirements proactively (hub-spoke, private endpoints, Azure Firewall IDPS).

---

<div align="center">

_Generated by **Azure Agentic InfraOps** | [GitHub](https://github.com/jonathan-vella/azure-agentic-infraops)_

</div>

---

## References

| Topic                    | Link                                                                                                        |
| ------------------------ | ----------------------------------------------------------------------------------------------------------- |
| Azure Policy effects     | [Policy effects](https://learn.microsoft.com/azure/governance/policy/concepts/effects)                      |
| Tag enforcement patterns | [Tag policies](https://learn.microsoft.com/azure/azure-resource-manager/management/tag-policies)            |
| PCI-DSS on Azure         | [PCI compliance](https://learn.microsoft.com/azure/compliance/offerings/offering-pci-dss)                   |
| Azure Policy exemptions  | [Exemption structure](https://learn.microsoft.com/azure/governance/policy/concepts/exemption-structure)     |
| Tag inheritance          | [Inherit a tag from RG](https://learn.microsoft.com/azure/governance/policy/samples/built-in-policies#tags) |
| MCAPSGov policies        | Tenant Root management group (internal)                                                                     |
| REST API discovery       | [Policy assignments API](https://learn.microsoft.com/rest/api/policy/policy-assignments/list)               |

---

_Governance constraints discovered via REST API on subscription `noalz` (`00858ffc-dded-4f0f-8bbf-e17fff0d47d9`)._
_All 21 assignments verified including 9 management group-inherited policies._
_See [governance-discovery.instructions.md](../../.github/instructions/governance-discovery.instructions.md) for discovery methodology._

