Policy Groups
Policy groups organize one or more policy packs and apply them to specific stacks or cloud accounts. They determine when and where policies are enforced across your organization.
Types of policy groups
Pulumi Policies provides two types of policy groups, each designed for a different enforcement pattern:
Preventative policy groups apply to Pulumi stacks and run before any resource is deployed. They act as guardrails during
pulumi previewandpulumi up, evaluating the resources your program declares and reporting violations in the same command the developer was already running. Because they run ahead of the deployment, a policy set tomandatoryenforcement stops a non-compliant change before it reaches your cloud provider. They see only the resources Pulumi manages.Audit policy groups continuously monitor compliance for both Pulumi stacks and cloud accounts. For stacks, they evaluate the latest state each time the stack updates. For cloud accounts, they scan on a schedule and cover every resource in the account, including resources created by hand, by another tool, or by a cloud service itself. Audit groups report violations rather than blocking them, which makes them the safest place to measure a new policy’s impact before you enforce it anywhere.
At a glance:
| Preventative | Audit | |
|---|---|---|
| Applies to | Pulumi stacks | Pulumi stacks and cloud accounts |
| When it runs | During pulumi preview and pulumi up | On stack updates, and on a schedule for cloud accounts |
| What it sees | Resources Pulumi manages | Stack state, plus every resource in a connected cloud account |
| Blocks deployments | Yes, with mandatory enforcement | No, findings are reported for you to act on |
For guidance on which type to use, how to set enforcement levels, and how to roll policies out across an organization, see Best practices.
Default policy groups
Every organization has two policy groups that Pulumi creates and maintains for you, one of each type:
| Policy group | Type | Joins automatically |
|---|---|---|
default-policy-group | Preventative | Every stack in the organization |
default-accounts-policy-group | Audit | Every cloud account connected to Insights |
New stacks and newly connected cloud accounts join the matching default group as they are created. You can remove a stack or account from its default group at any time, the same way you would with any other policy group. Because default-accounts-policy-group is an audit group, you can also add stacks to it, though none are added automatically.
In the Pulumi Cloud console, the Policy Groups tab lists both default groups with a badge marking them as defaults. From the CLI, pulumi policy enable and pulumi policy disable act on the default policy group when you omit --policy-group.
Adding policy packs to the default preventative group
default-policy-group is a preventative group that contains every stack in your organization. A policy pack added there takes effect on the next pulumi preview or pulumi up for every stack, and any policy set to mandatory starts blocking deployments immediately. There is no gradual rollout, and you cannot soften the impact afterward by converting the group to an audit group. The pack’s runtime also becomes a requirement for everyone: because Pulumi’s pre-built policy packs all run on Node.js, adding one means every machine that runs Pulumi needs Node.js installed.To roll out a new policy pack safely, add it to a purpose-built audit policy group first, review the findings, then move it to default-policy-group once you understand its impact. See Best practices.
Adding a policy pack to default-policy-group also makes that pack’s runtime a prerequisite for everyone who runs Pulumi against any stack in your organization. Pulumi’s pre-built policy packs all run on Node.js, so enabling one for every stack means every developer machine and CI runner needs Node.js installed, whatever language the Pulumi programs themselves are written in.
Managing the default policy groups programmatically
The default groups are fixed in identity and mutable only in membership. You can change what is in them; you cannot change what they are. These limits apply no matter how you make the change, including from the Pulumi Cloud console.
| Operation | REST API | Pulumi Cloud provider |
|---|---|---|
| Add or remove stacks | Yes: addStack and removeStack | Yes: PolicyGroupStackAttachment |
| Add or remove cloud accounts | Yes: addInsightsAccount and removeInsightsAccount | Yes: PolicyGroupInsightsAccountAttachment |
| Add or remove policy packs | Yes: addPolicyPack and removePolicyPack | No |
| Rename the group | No | No |
| Change the group’s type, for example from audit to preventative | No: an update request has no field for it | No |
| Delete the group | No: DELETE rejects a default group | No |
With the REST API, a single PATCH request adds or removes stacks, accounts, and policy packs. Note that the stacks, policyPacks, and insightsAccounts fields replace the group’s entire list, so use the add* and remove* fields to change one membership at a time. To apply several changes at once, PATCH .../batch accepts an array of the same request bodies.
With Pulumi IaC, each attachment resource manages a single membership, so you can declare one against a default group without taking ownership of the group itself. The provider has no resource for attaching a policy pack to an existing policy group, so policy pack membership on a default group has to be managed from the console, the CLI, or the REST API. The provider also cannot rename a default group or change its type: both properties force a replacement on the PolicyGroup resource, and replacing a group means deleting it first, which Pulumi Cloud rejects for a default group.
Because default-policy-group cannot be deleted, renamed, or converted to an audit group, what you change to stop it from blocking deployments is its policy packs: remove them, disable them with pulumi policy disable, or set their policies to advisory.
PolicyGroup resource. That resource owns the group’s lifecycle, so pulumi destroy attempts to delete it, and its policyPacks property replaces the group’s entire list of policy packs. Use the attachment resources to manage membership instead.Enforcement levels
Policies within policy groups can have different enforcement levels:
- Advisory: Issues warnings but allows deployments to proceed. Useful for testing new policies or providing informational guidance.
- Mandatory: Blocks deployments when violations are detected. Use for critical security, compliance, or cost policies.
Managing policy groups at scale with ESC
Once you have more than a handful of policy groups, keeping their configuration in sync becomes the hard part. Policy packs in a policy group can reference Pulumi ESC environments, which lets you define that configuration once and share it across every group that needs it, instead of editing each group separately.
When you attach an ESC environment to a policy pack, values from the environment’s policyConfig and environmentVariables are available to the policy pack at runtime. Updating the environment updates every policy group that references it.
Environment references support versioning and tagging, so a configuration change does not have to reach every group at once. Pin a reference to a specific revision or tag, such as my-env@stable or my-env@v1, to control when the change takes effect. This pairs well with tiered policy groups: point production at a pinned tag and lower environments at the moving one, so changes are exercised before they reach the stacks that matter most.
Best practices
Choosing a policy group type
Prefer preventative policy groups wherever you can. Catching a problem before the resource is provisioned is the cheapest possible outcome: nothing is created, nothing has to be remediated, and no insecure resource ever exists, even briefly. The developer also sees the violation in the pulumi preview or pulumi up they were already running, rather than in a report someone reads days later.
Audit policy groups are the right choice in three situations:
Your infrastructure isn’t all managed by Pulumi. Preventative policies only see resources that Pulumi manages, so if people in your organization still make changes by hand in the cloud console with any regularity, or use other infrastructure tools, an audit group is the only way to evaluate those resources at all.
You are adopting policy for the first time. An audit group gives you a full catalog of what is already non-compliant before you decide what to enforce. That is a far better starting point than turning on preventative policies and discovering the same backlog one blocked deployment at a time.
The teams hitting the policy may not be able to act on it. A preventative policy is only useful if the person it blocks knows what to do next. Blocking a deployment on a violation a team lacks the context to resolve produces confusion and workarounds rather than compliance.
Choosing an enforcement level
Match the enforcement level to what the environment actually requires, rather than applying the same strictness everywhere.
In development, test, and other lower environments, advisory enforcement is usually the better default. The warnings still tell developers what the standards are, but nobody is blocked from trying something out. Strict controls in these environments are often unnecessary and sometimes counterproductive, since discouraging experimentation costs more than the risk it removes.
Reserve mandatory enforcement for environments that genuinely need strong controls: those holding sensitive data, serving production traffic, or falling within the scope of an audit. There, the cost of a violation reaching the environment is high enough to justify stopping the deployment.
Because enforcement levels are set per policy pack, and per policy within a pack, the usual way to express this is with a separate policy group for each environment tier: one group covering lower-environment stacks where the packs are advisory, and another covering production stacks where the critical packs are mandatory.
Adopting policy across an organization
Rolling policy out in stages gives teams time to absorb each change and gives you a chance to find noisy rules before they block anyone:
Start with an audit policy group. Add the packs you are considering to an audit group covering your cloud accounts and stacks. Nothing is blocked, and after the first scan you have a complete inventory of what would be flagged. Work through the highest-severity findings before enforcing anything.
Move to a preventative policy group with everything advisory. Once the backlog is manageable, add the packs to a preventative group with every policy set to advisory. Developers begin seeing violations at deployment time, and you learn which rules are noisy or produce false positives without anyone being stopped.
Make specific policies mandatory. Promote policies to mandatory selectively, starting with the ones where a violation is genuinely unacceptable and the fix is well understood. Expand from there as teams build familiarity.