Pulumi CrossGuard: Policy as Code for IaC at Scale
Sources
In the era of hyper-scale cloud deployments, the "security review" is a bottleneck. Waiting for a security architect to manually approve a Terraform plan or a CloudFormation template is an operational failure.
Pulumi CrossGuard shifts this paradigm by implementing Policy as Code (PaC). Instead of a PDF of guidelines, you maintain a version-controlled repository of executable rules that intercept every infrastructure change *before* it hits the cloud provider.The Technical Mechanics of CrossGuard
CrossGuard does not wrap the cloud provider's API; it hooks into the Pulumi Engine. When you run `pulumi preview` or `pulumi up`, the engine generates a resource graph (the "plan"). Before the engine sends these requests to the provider (AWS, GCP, Azure), it invokes the loaded Policy Packs.
The Enforcement Loop
[ Developer ] --( pulumi up )--> [ Pulumi Engine ]
|
v
[ Loaded Policy Packs (CrossGuard) ]
|
+----------------------------+----------------------------+
| | |
[ Resource Validation ] [ Stack Validation ] [ Remediations ]
(Check individual props) (Check graph relations) (Auto-fix violations)
| | |
+----------------------------+----------------------------+
|
v
[ Enforcement Level Decision ]
|
+----------------------------+----------------------------+
| | |
( Advisory ) ( Mandatory ) ( Remediate )
Warn & Proceed Block & Fail Fix & Proceed
|
v
[ Cloud Provider API (AWS/Azure/GCP) ]
Resource Validation vs. Stack Validation
One of the most common mistakes in PaC is using the wrong validation scope. CrossGuard provides two distinct modes.
1. Resource Validation
Resource validation policies run for every single resource registered in the program. They are highly efficient and ideal for "low-hanging fruit" security checks.
Use Case: "Every S3 bucket must have `publicAccessBlock` enabled."2. Stack Validation
Stack validation runs once per update, after the entire resource graph has been constructed but before the apply phase. This allows the policy to examine relationships between resources.
Use Case: "Any RDS instance tagged as `production` must be associated with a subnet that has no route to the Internet Gateway (IGW)."| Feature | Resource Validation | Stack Validation |
|---|---|---|
| Execution Frequency | Per Resource | Once per Stack |
| Context | Single Resource Properties | Full Resource Graph |
| Performance | Fast, O(n) | Slower, O(graph) |
| Primary Goal | Property Compliance | Architectural Integrity |
| Best For | Encryption, Tagging, Sizing | Network Isolation, Dependency Checks |
Production-Grade Implementation
Below is a complete implementation of a security-focused policy pack. This example enforces encryption for RDS and prevents the creation of public S3 buckets.
import * as aws from "@pulumi/aws";
import { PolicyPack, validateResourceOfType } from "@pulumi/policy";
new PolicyPack("platform-monkey-security-baseline", {
policies: [
{
name: "s3-no-public-read",
description: "Prevents S3 buckets from having public read access.",
enforcementLevel: "mandatory",
validateResource: validateResourceOfType(aws.s3.Bucket, (bucket, args, reportViolation) => {
if (bucket.acl === "public-read" || bucket.acl === "public-read-write") {
reportViolation("S3 bucket cannot have public-read or public-read-write ACLs.");
}
}),
},
{
name: "rds-storage-encryption",
description: "Requires RDS instances to have storage encryption enabled.",
enforcementLevel: "mandatory",
validateResource: validateResourceOfType(aws.rds.Instance, (instance, args, reportViolation) => {
if (!instance.storageEncrypted) {
reportViolation("RDS instances must have storage encryption enabled for compliance (SOC2/HIPAA).");
}
}),
},
{
name: "vpc-no-igw-in-private-subnets",
description: "Ensures private subnets do not have a direct route to an Internet Gateway.",
enforcementLevel: "mandatory",
validateResource: validateResourceOfType(aws.ec2.Route, (route, args, reportViolation) => {
if (route.gatewayId && route.gatewayId.includes("igw-") && route.destinationCidrBlock === "0.0.0.0/0") {
if (args.resourceTags?.["Tier"] === "Private") {
reportViolation("Private subnets cannot have a direct route to an Internet Gateway.");
}
}
}),
},
],
});
Mapping to Regulatory Frameworks
CrossGuard allows you to map code directly to auditor-friendly controls.
SOC2 (Security & Confidentiality)
- Control: "All data at rest must be encrypted."
- CrossGuard Implementation: Use `validateResourceOfType` for `aws.rds.Instance`, `aws.s3.Bucket`, and `aws.ebs.Volume` to assert `storageEncrypted: true`.
HIPAA (Technical Safeguards)
- Control: "Access to ePHI must be restricted to authorized users."
- CrossGuard Implementation: Enforce that all `aws.iam.Role` policies do not contain `Action: "*"` or `Resource: "*"`.
PCI DSS (Network Security)
- Control: "Restrict traffic to the Cardholder Data Environment (CDE)."
- CrossGuard Implementation: A Stack Validation policy that ensures no `aws.ec2.SecurityGroup` associated with a CDE-tagged instance allows ingress from `0.0.0.0/0` on non-standard ports.
Production Realities: The "Security Theater"
Implementing Policy as Code is not a silver bullet. In high-growth environments, several patterns emerge that undermine the system:
1. The "Advisory" Trap: Teams often set policies to `advisory` to avoid blocking developers. In practice, this becomes "security theater"—warnings are ignored in CI logs, and non-compliant infrastructure is deployed anyway.
2. The Local Bypass: If policy enforcement is only configured locally (`--policy-pack`), a developer can simply omit the flag. True enforcement requires Pulumi Cloud server-side policy groups.
3. The "Unknown" Value Problem: During `pulumi preview`, some values (like an AWS-generated ID) are unknown. Writing policies that depend on these values requires careful handling of `pulumi.Output` and may result in policies that pass in preview but fail in apply.
4. Operational Toil: As the policy pack grows to 100+ rules, `pulumi preview` times can increase significantly. Modularizing policy packs by "domain" (e.g., `network-policies`, `data-policies`) is essential.
Who Should Skip This
Do not implement a full CrossGuard architecture if:
- You have a tiny team (< 5 engineers): A few well-defined IAM boundaries and a simple peer-review process are more efficient than maintaining a policy SDK.
- You are not using Pulumi: While Pulumi can analyze Terraform, the operational overhead of introducing the Pulumi CLI just for policy is rarely worth it compared to using OPA/Rego directly via `terraform plan -json`.
- Your environment is static: If you deploy once a quarter, manual reviews are fine. PaC is for teams shipping infrastructure daily.