Deny Policies (Guardrails)

Preventive Controls — Azure · AWS · GCP — Side-by-Side Reference

Concept Overview
Policy Types
Real-World Examples
Step-by-Step Setup
Concept Mapping

What Are Deny Policies?

Deny policies are preventive guardrails — they block actions even if an identity has allow permissions. Unlike allow policies (which grant access), deny policies override everything. They're the "seatbelt" of cloud security — you can have a driver's license, but the car won't start if the seatbelt isn't fastened.

Why Use Deny Policies?

01 Prevent Mistakes

Block accidental deletion of production resources

Prevent public exposure of storage buckets

Enforce encryption on all storage accounts

02 Enforce Compliance

Restrict VM creation to approved regions only

Block creation of resources without required tags

Prevent disabling of audit logging

03 Limit Blast Radius

Even if an admin account is compromised, certain destructive actions are blocked

Organization-wide guardrails cannot be bypassed by project owners

Deny vs Allow — How Overrides Work

ScenarioAllow PolicyDeny PolicyResult
User has Storage Admin✅ Yes❌ Deny: No public bucketsDENIED
User has Org Admin✅ Yes❌ Deny: No deletion of audit logsDENIED
User has no permissions❌ No— (none)DENIED
User has Storage Admin✅ Yes— (none)ALLOWED

Key insight: Even Organization Admins cannot override a deny policy. Deny always wins.

Scope & Inheritance

AzureAWSGCP
Top-level scopeManagement GroupOrganization (SCPs)Organization (Org Policies)
Mid-level scopeSubscriptionOU / AccountFolder
Low-level scopeResource GroupAccount / Permission BoundaryProject
InheritanceTop-down (Management Group → Subscription → RG)Top-down (Org → OU → Account)Top-down (Org → Folder → Project)
Can lower-level override?NoNoNo

Available Deny Policy Types — All 3 Clouds

Az Azure

  • Azure Policy (Deny effect) — blocks non-compliant resource creation/updates
  • Azure Policy (DeployIfNotExists) — auto-remediation (not strictly deny but guardrail-adjacent)
  • Management Group scoped — applies to all subscriptions underneath
  • Built-in policies: 500+ pre-built by Microsoft
  • Custom policies: JSON-based with conditions

AW AWS

  • Service Control Policies (SCPs) — guardrails at Org/OU/Account level
  • IAM Permission Boundaries — limits max permissions a role/user can have
  • Resource Control Policies (RCPs) — NEW (2024), limits external access to resources
  • Declarative Policies — NEW (2024), enforce desired state (e.g., block public AMIs)
  • No built-in library — all are custom JSON policy documents

GC GCP

  • Organization Policy Constraints — boolean or list-based restrictions
  • IAM Deny Policies — NEW (2023), deny specific permissions across org/folder/project
  • VPC Service Controls — data exfiltration prevention (network-level guardrail)
  • 50+ built-in constraints (e.g., constraints/compute.restrictProtocolForwardingCreationForTypes)
  • Custom constraints — YAML-based with CEL expressions

Policy Evaluation Order

Evaluation StepAzureAWSGCP
1AuthenticationAuthenticationAuthentication
2RBAC check (allow)SCP check (DENY)IAM Deny check (DENY)
3Azure Policy check (DENY)Permission Boundary check (DENY)Org Policy check (DENY)
4Request forwarded to Resource ProviderIAM Policy check (ALLOW)IAM Allow check (ALLOW)
5Resource-based policy check (ALLOW)VPC Service Controls (DENY)

Common pattern: All three check DENY first, then ALLOW. If deny fires, the request stops immediately.

Example 1: Block Public Storage

Az Azure

{
  "if": {
    "allOf": [{
      "field": "type",
      "equals": "Microsoft.Storage/storageAccounts"
    }, {
      "field": "Microsoft.Storage/storageAccounts/allowBlobPublicAccess",
      "equals": true
    }]
  },
  "then": {
    "effect": "deny"
  }
}

AW AWS

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Deny",
    "Action": ["s3:PutBucketPublicAccessBlock"],
    "Resource": "*",
    "Condition": {
      "StringNotEquals": {
        "s3:PublicAccessBlockConfiguration": "true"
      }
    }
  }]
}

GC GCP

# Org Policy Constraint (Console)
Constraint: storage.uniformBucketLevelAccess
Policy: Enforce
Scope: Organization / Folder / Project

# OR — IAM Deny Policy (gcloud)
gcloud iam policies create deny-public-buckets \
  --attachment-point=organizations/ORG_ID \
  --deny-rule=storage.buckets.setIamPolicy

Example 2: Restrict VM Types (Block Expensive SKUs)

Az Azure

{
  "if": {
    "allOf": [{
      "field": "type",
      "equals": "Microsoft.Compute/virtualMachines"
    }, {
      "not": {
        "field": "Microsoft.Compute/virtualMachines/sku.name",
        "in": ["Standard_B2s", "Standard_D2s_v5"]
      }
    }]
  },
  "then": { "effect": "deny" }
}

AW AWS

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "BlockExpensiveEC2",
    "Effect": "Deny",
    "Action": ["ec2:RunInstances"],
    "Resource": "arn:aws:ec2:*:*:\instance/*",
    "Condition": {
      "StringNotEquals": {
        "ec2:InstanceType": ["t3.micro", "t3.small"]
      }
    }
  }]
}

GC GCP

# Org Policy: restrict machine types
Constraint: compute.restrictMachineTypes
Policy: Allow List
Allowed values:
  - n2-standard-2
  - n2-standard-4
  - e2-medium
  - e2-standard-2

Example 3: Block Resource Deletion (Accidental Delete Protection)

Az Azure

Azure Resource Locks:

# CLI:
az lock create --name ProdNoDelete \
  --resource-group prod-rg \
  --lock-type CanNotDelete
# CanNotDelete = authorized users can read/modify but NOT delete
# ReadOnly = authorized users can read but NOT modify/delete

AW AWS

SCP: Deny deletion of production resources

{
  "Sid": "DenyDeleteProd",
  "Effect": "Deny",
  "Action": [
    "ec2:TerminateInstances",
    "s3:DeleteBucket",
    "rds:DeleteDBInstance"
  ],
  "Resource": "*",
  "Condition": {
    "StringEquals": {
      "aws:ResourceTag/env": "prod"
    }
  }
}

GC GCP

IAM Deny Policy (new):

# Deny specific destructive actions
gcloud iam policies create no-delete-prod \
  --attachment-point=cloudresourcemanager.googleapis.com/folders/PROD_FOLDER_ID \
  --kind=denypolicies \
  --deny-rule=compute.instances.delete \
  --deny-rule=compute.disks.delete \
  --deny-rule=storage.buckets.delete

Step-by-Step Setup — All 3 Clouds

Step 1

Navigate to the Guardrail Console

AzureAWSGCP
Console: Policy → Definitions
Or: Management Groups → select MG → Policies
Console: AWS Organizations → Policies → SCPs
Or: IAM → Policies → Create Policy (Permission Boundaries)
Console: IAM & Admin → Organization Policies
Or: IAM & Admin → IAM → Deny (for new IAM Deny Policies)
Step 2

Create the Policy Definition

AzureAWSGCP
+ Create Policy Definition
Location: Management Group or Subscription
Name: e.g., "Deny Public Storage"
Category: Storage or Custom
Policy rule: Paste JSON with "effect": "deny"
+ Create Policy
Type: Service Control Policy
Name: e.g., "Block-S3-Public-Access"
Description: Prevents public S3 buckets
Policy: Paste JSON with "Effect": "Deny"
+ Select Constraint (for org policies)
Filter: Search by service (e.g., "storage")
Select: e.g., storage.uniformBucketLevelAccess
Custom Constraint (optional): YAML with CEL
OR: + Create Deny Policy (for IAM Deny)
Step 3

Assign to Scope

AzureAWSGCP
Assign Policy → Select Scope
• Management Group
• Subscription
• Resource Group

Exclusions: You can exclude specific subscriptions or RGs
Attach SCP:
• Root (entire org)
• Specific OU (e.g., prod OU)
• Specific Account

Note: SCPs don't apply to the management account
Set Policy:
• Organization
• Folder
• Project

Policy value: Enforce (block) or Allow List (allow only listed)
Step 4

Test and Verify

AzureAWSGCP
• Use Policy Compliance tab
• Create a test resource that violates policy → see denied
Azure Activity Log shows the deny evaluation
az policy state list for CLI audit
• Use IAM Policy Simulator
• Try restricted action → AccessDenied
CloudTrail logs show explicit deny
aws iam simulate-principal-policy
• Use Policy Analyzer to test permissions
• Try restricted action → PERMISSION_DENIED
Cloud Audit Logs show policy denial
gcloud org-policies describe to verify

CLI Quick Reference

Az Azure CLI

# Create policy definition
az policy definition create \
  --name deny-public-storage \
  --rules policy.json

# Assign to subscription
az policy assignment create \
  --policy deny-public-storage \
  --scope /subscriptions/SUB_ID

# Check compliance
az policy state list \
  --policy-assignment deny-public-storage

AW AWS CLI

# Create SCP
aws organizations create-policy \
  --name BlockPublicBuckets \
  --type SERVICE_CONTROL_POLICY \
  --content file://scp.json

# Attach to OU
aws organizations attach-policy \
  --policy-id p-xxxxx \
  --target-id ou-xxxxx

# Simulate
aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::... \
  --action-names s3:CreateBucket

GC GCP CLI

# Set org policy constraint
gcloud org-policies set-policy policy.yaml \
  --organization=ORG_ID

# Describe constraint
gcloud org-policies describe \
  constraints/storage.uniformBucketLevelAccess \
  --organization=ORG_ID

# Create IAM deny policy
gcloud iam policies create deny-prod-delete \
  --attachment-point=folders/PROD_FOLDER \
  --kind=denypolicies \
  --deny-rule=compute.instances.delete

Concept Mapping — Guardrails & Deny Policies

Primary Deny
Mechanism
Azure Policy
(Deny / DeployIfNotExists)
SCPs
(Service Control Policies)
Org Policy Constraints +
IAM Deny Policies
Policy Language
JSON (ARM policy rule)
JSON (IAM policy document)
YAML (org policies) + CEL (custom constraints)
Override Possible?
No
No
No
Sub-resource
Scope
Permission Boundaries
(limits max perms of IAM roles)
IAM Permission Boundaries
(caps IAM role permissions)
IAM Deny Policies
(deny specific permissions)
Network-level
Guardrail
Azure Firewall Policy /
NSG Rules
VPC Endpoint Policies
+ AWS Network Firewall
VPC Service Controls
(data exfiltration prevention)
Accidental
Delete Lock
Azure Resource Locks
(CanNotDelete / ReadOnly)
SCP + Tag-based Conditions
(no native lock concept)
Deletion Protection flags
(per-resource) + IAM Deny
Remediation
DeployIfNotExists
(auto-fix non-compliant resources)
AWS Config Rules
(detect + auto-remediate)
Org Policy Dry Run
(audit mode — log violations only)

When to Use Which

GoalAzureAWSGCP
Block all public buckets Azure Policy (Deny) SCP (Deny s3:PutBucketAcl) Org Policy (storage.uniformBucketLevelAccess)
Restrict regions Azure Policy (allowedLocations) SCP (Condition: aws:RequestedRegion) Org Policy (constraints/gcp.resourceLocations)
Enforce resource tags Azure Policy (require tag + deny) SCP (Condition: aws:RequestTag) Org Policy (custom constraint + CEL)
Prevent IAM changes Azure Policy (Deny Action) SCP (Deny iam:*) IAM Deny Policy
Block VM deletion Resource Lock (CanNotDelete) SCP + Tag condition IAM Deny Policy + Deletion Protection
Prevent data exfiltration Azure Firewall / Private Endpoints VPC Endpoint Policies VPC Service Controls