Pulumi CrossGuard doesn’t just check your infrastructure for compliance; it actively prevents non-compliant infrastructure from being deployed in the first place.
Let’s see this in action with a common policy: ensuring all S3 buckets are private.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
// Define a policy that denies public access to S3 buckets
const privateS3BucketPolicy = new pulumi.policy.PolicyPack("private-s3-bucket-policy", {
policies: [{
name: "restrict-public-read",
description: "Ensures S3 buckets do not allow public read access.",
enforcementLevel: "mandatory",
policy: (args: pulumi.policy.PolicyArgs) => {
// This is where the logic lives. We're checking resources.
if (args.resource.type === "aws:s3/bucket:Bucket") {
const bucket = args.resource as aws.s3.Bucket;
// Check for public ACLs or bucket policies that grant public access
const publicReadAcl = bucket.acl === "public-read" || bucket.acl === "public-read-write";
const publicReadPolicy = bucket.policy?.apply(policyString => {
try {
const policy = JSON.parse(policyString);
return policy.Statement.some((stmt: any) =>
stmt.Effect === "Allow" &&
stmt.Principal === "*" &&
(stmt.Action === "s3:GetObject" || (Array.isArray(stmt.Action) && stmt.Action.includes("s3:GetObject")))
);
} catch (e) {
return false; // Invalid JSON, not public
}
});
if (publicReadAcl || publicReadPolicy) {
// If the policy is violated, report an error.
// This will cause the deployment to fail.
pulumi.fail(`S3 bucket '${bucket.urn}' is configured for public read access. This is not allowed.`);
}
}
},
}],
});
When you run pulumi up with this policy pack enabled, Pulumi doesn’t just tell you if a bucket would be public; it stops the pulumi up command dead in its tracks if the proposed change violates the rule.
The core of CrossGuard is the pulumi policy command and the PolicyPack resource. A PolicyPack is a collection of policies you define. Each policy has a name, a description, and crucially, an enforcementLevel. mandatory means the deployment fails if the policy is violated. advisory means it just logs a warning.
The policy function within each policy definition is where the magic happens. It receives PolicyArgs, which contains information about the resource being created, updated, or deleted. You inspect args.resource.type and args.resource.props (which are the arguments you’d pass to the Pulumi resource constructor) to determine compliance. If you find a violation, you call pulumi.fail() with a descriptive message, and Pulumi halts the deployment.
To enable this policy pack, you’d typically configure it in your Pulumi project settings or directly in your code. For example, in Pulumi.yaml:
name: my-aws-project
runtime: nodejs
description: My basic AWS project
config:
aws:region: us-east-1
policyPacks:
- private-s3-bucket-policy # This name refers to the exported PolicyPack
Or, if you’re defining it programmatically as shown above, ensure the PolicyPack is exported from your index.ts file. Pulumi automatically discovers and loads exported PolicyPack resources.
The real power comes from integrating this into your CI/CD pipelines. You can run pulumi preview --policy-code-provider=local (or point to a remote policy provider) in your pipeline before pulumi up. This ensures that only compliant infrastructure changes make it to production.
One of the most subtle but powerful aspects of CrossGuard is its ability to act on proposed changes. It doesn’t just audit your existing infrastructure; it intercepts your deployment plan. This means you can catch issues before they are deployed, preventing drift and ensuring that your infrastructure always aligns with your desired state, not just after the fact. This proactive stance is what truly differentiates policy as code from simple auditing tools.
The next step is to explore how to manage more complex policies, like those involving network ingress rules or IAM permissions, and to integrate CrossGuard with Pulumi Service for centralized policy management.