The gcp:orgpolicy/policy:Policy resource, part of the Pulumi GCP provider, defines organization policies that enforce constraints on Google Cloud resource configurations across projects, folders, and organizations. This guide focuses on four capabilities: enforcement at different hierarchy levels, conditional rules with allowed/denied values, dry-run testing, and parameter passing to custom constraints.
Policies reference existing projects, folders, or organizations and may depend on custom constraints or resource tags. The examples are intentionally small. Combine them with your own resource hierarchy and constraint definitions.
Enforce a constraint at the project level
Teams often disable specific security features for development projects while keeping them enforced in production.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const basic = new gcp.organizations.Project("basic", {
projectId: "id",
name: "id",
orgId: "123456789",
deletionPolicy: "DELETE",
});
const primary = new gcp.orgpolicy.Policy("primary", {
name: pulumi.interpolate`projects/${basic.projectId}/policies/iam.disableServiceAccountKeyUpload`,
parent: pulumi.interpolate`projects/${basic.projectId}`,
spec: {
rules: [{
enforce: "FALSE",
}],
},
});
import pulumi
import pulumi_gcp as gcp
basic = gcp.organizations.Project("basic",
project_id="id",
name="id",
org_id="123456789",
deletion_policy="DELETE")
primary = gcp.orgpolicy.Policy("primary",
name=basic.project_id.apply(lambda project_id: f"projects/{project_id}/policies/iam.disableServiceAccountKeyUpload"),
parent=basic.project_id.apply(lambda project_id: f"projects/{project_id}"),
spec={
"rules": [{
"enforce": "FALSE",
}],
})
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/orgpolicy"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
basic, err := organizations.NewProject(ctx, "basic", &organizations.ProjectArgs{
ProjectId: pulumi.String("id"),
Name: pulumi.String("id"),
OrgId: pulumi.String("123456789"),
DeletionPolicy: pulumi.String("DELETE"),
})
if err != nil {
return err
}
_, err = orgpolicy.NewPolicy(ctx, "primary", &orgpolicy.PolicyArgs{
Name: basic.ProjectId.ApplyT(func(projectId string) (string, error) {
return fmt.Sprintf("projects/%v/policies/iam.disableServiceAccountKeyUpload", projectId), nil
}).(pulumi.StringOutput),
Parent: basic.ProjectId.ApplyT(func(projectId string) (string, error) {
return fmt.Sprintf("projects/%v", projectId), nil
}).(pulumi.StringOutput),
Spec: &orgpolicy.PolicySpecArgs{
Rules: orgpolicy.PolicySpecRuleArray{
&orgpolicy.PolicySpecRuleArgs{
Enforce: pulumi.String("FALSE"),
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var basic = new Gcp.Organizations.Project("basic", new()
{
ProjectId = "id",
Name = "id",
OrgId = "123456789",
DeletionPolicy = "DELETE",
});
var primary = new Gcp.OrgPolicy.Policy("primary", new()
{
Name = basic.ProjectId.Apply(projectId => $"projects/{projectId}/policies/iam.disableServiceAccountKeyUpload"),
Parent = basic.ProjectId.Apply(projectId => $"projects/{projectId}"),
Spec = new Gcp.OrgPolicy.Inputs.PolicySpecArgs
{
Rules = new[]
{
new Gcp.OrgPolicy.Inputs.PolicySpecRuleArgs
{
Enforce = "FALSE",
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.Project;
import com.pulumi.gcp.organizations.ProjectArgs;
import com.pulumi.gcp.orgpolicy.Policy;
import com.pulumi.gcp.orgpolicy.PolicyArgs;
import com.pulumi.gcp.orgpolicy.inputs.PolicySpecArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var basic = new Project("basic", ProjectArgs.builder()
.projectId("id")
.name("id")
.orgId("123456789")
.deletionPolicy("DELETE")
.build());
var primary = new Policy("primary", PolicyArgs.builder()
.name(basic.projectId().applyValue(_projectId -> String.format("projects/%s/policies/iam.disableServiceAccountKeyUpload", _projectId)))
.parent(basic.projectId().applyValue(_projectId -> String.format("projects/%s", _projectId)))
.spec(PolicySpecArgs.builder()
.rules(PolicySpecRuleArgs.builder()
.enforce("FALSE")
.build())
.build())
.build());
}
}
resources:
primary:
type: gcp:orgpolicy:Policy
properties:
name: projects/${basic.projectId}/policies/iam.disableServiceAccountKeyUpload
parent: projects/${basic.projectId}
spec:
rules:
- enforce: FALSE
basic:
type: gcp:organizations:Project
properties:
projectId: id
name: id
orgId: '123456789'
deletionPolicy: DELETE
The name property identifies both the parent resource and the constraint being configured. The spec.rules array contains enforcement directives; setting enforce to “FALSE” disables the constraint for this project. The parent property establishes where the policy applies in your resource hierarchy.
Apply policies to folder hierarchies with inheritance
Organizations with multiple teams group projects into folders and apply policies that cascade down the hierarchy.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const basic = new gcp.organizations.Folder("basic", {
parent: "organizations/123456789",
displayName: "folder",
deletionProtection: false,
});
const primary = new gcp.orgpolicy.Policy("primary", {
name: pulumi.interpolate`${basic.name}/policies/gcp.resourceLocations`,
parent: basic.name,
spec: {
inheritFromParent: true,
rules: [{
denyAll: "TRUE",
}],
},
});
import pulumi
import pulumi_gcp as gcp
basic = gcp.organizations.Folder("basic",
parent="organizations/123456789",
display_name="folder",
deletion_protection=False)
primary = gcp.orgpolicy.Policy("primary",
name=basic.name.apply(lambda name: f"{name}/policies/gcp.resourceLocations"),
parent=basic.name,
spec={
"inherit_from_parent": True,
"rules": [{
"deny_all": "TRUE",
}],
})
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/orgpolicy"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
basic, err := organizations.NewFolder(ctx, "basic", &organizations.FolderArgs{
Parent: pulumi.String("organizations/123456789"),
DisplayName: pulumi.String("folder"),
DeletionProtection: pulumi.Bool(false),
})
if err != nil {
return err
}
_, err = orgpolicy.NewPolicy(ctx, "primary", &orgpolicy.PolicyArgs{
Name: basic.Name.ApplyT(func(name string) (string, error) {
return fmt.Sprintf("%v/policies/gcp.resourceLocations", name), nil
}).(pulumi.StringOutput),
Parent: basic.Name,
Spec: &orgpolicy.PolicySpecArgs{
InheritFromParent: pulumi.Bool(true),
Rules: orgpolicy.PolicySpecRuleArray{
&orgpolicy.PolicySpecRuleArgs{
DenyAll: pulumi.String("TRUE"),
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var basic = new Gcp.Organizations.Folder("basic", new()
{
Parent = "organizations/123456789",
DisplayName = "folder",
DeletionProtection = false,
});
var primary = new Gcp.OrgPolicy.Policy("primary", new()
{
Name = basic.Name.Apply(name => $"{name}/policies/gcp.resourceLocations"),
Parent = basic.Name,
Spec = new Gcp.OrgPolicy.Inputs.PolicySpecArgs
{
InheritFromParent = true,
Rules = new[]
{
new Gcp.OrgPolicy.Inputs.PolicySpecRuleArgs
{
DenyAll = "TRUE",
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.Folder;
import com.pulumi.gcp.organizations.FolderArgs;
import com.pulumi.gcp.orgpolicy.Policy;
import com.pulumi.gcp.orgpolicy.PolicyArgs;
import com.pulumi.gcp.orgpolicy.inputs.PolicySpecArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var basic = new Folder("basic", FolderArgs.builder()
.parent("organizations/123456789")
.displayName("folder")
.deletionProtection(false)
.build());
var primary = new Policy("primary", PolicyArgs.builder()
.name(basic.name().applyValue(_name -> String.format("%s/policies/gcp.resourceLocations", _name)))
.parent(basic.name())
.spec(PolicySpecArgs.builder()
.inheritFromParent(true)
.rules(PolicySpecRuleArgs.builder()
.denyAll("TRUE")
.build())
.build())
.build());
}
}
resources:
primary:
type: gcp:orgpolicy:Policy
properties:
name: ${basic.name}/policies/gcp.resourceLocations
parent: ${basic.name}
spec:
inheritFromParent: true
rules:
- denyAll: TRUE
basic:
type: gcp:organizations:Folder
properties:
parent: organizations/123456789
displayName: folder
deletionProtection: false
The inheritFromParent property allows this policy to merge with parent policies rather than replacing them. The denyAll rule blocks all values for the gcp.resourceLocations constraint, restricting where resources can be created. Folder-level policies affect all projects within the folder unless overridden.
Reset a policy to organization defaults
When policies have been customized at lower levels, you may need to restore the organization’s baseline configuration.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const primary = new gcp.orgpolicy.Policy("primary", {
name: "organizations/123456789/policies/gcp.detailedAuditLoggingMode",
parent: "organizations/123456789",
spec: {
reset: true,
},
});
import pulumi
import pulumi_gcp as gcp
primary = gcp.orgpolicy.Policy("primary",
name="organizations/123456789/policies/gcp.detailedAuditLoggingMode",
parent="organizations/123456789",
spec={
"reset": True,
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/orgpolicy"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := orgpolicy.NewPolicy(ctx, "primary", &orgpolicy.PolicyArgs{
Name: pulumi.String("organizations/123456789/policies/gcp.detailedAuditLoggingMode"),
Parent: pulumi.String("organizations/123456789"),
Spec: &orgpolicy.PolicySpecArgs{
Reset: pulumi.Bool(true),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var primary = new Gcp.OrgPolicy.Policy("primary", new()
{
Name = "organizations/123456789/policies/gcp.detailedAuditLoggingMode",
Parent = "organizations/123456789",
Spec = new Gcp.OrgPolicy.Inputs.PolicySpecArgs
{
Reset = true,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.orgpolicy.Policy;
import com.pulumi.gcp.orgpolicy.PolicyArgs;
import com.pulumi.gcp.orgpolicy.inputs.PolicySpecArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var primary = new Policy("primary", PolicyArgs.builder()
.name("organizations/123456789/policies/gcp.detailedAuditLoggingMode")
.parent("organizations/123456789")
.spec(PolicySpecArgs.builder()
.reset(true)
.build())
.build());
}
}
resources:
primary:
type: gcp:orgpolicy:Policy
properties:
name: organizations/123456789/policies/gcp.detailedAuditLoggingMode
parent: organizations/123456789
spec:
reset: true
The reset property clears all custom rules and restores the policy to its organization-level defaults. This is useful when removing project-specific overrides or simplifying policy management.
Define conditional rules with allowed and denied values
Complex policies need different rules for different resources, using conditions to match tags or other attributes.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const basic = new gcp.organizations.Project("basic", {
projectId: "id",
name: "id",
orgId: "123456789",
deletionPolicy: "DELETE",
});
const primary = new gcp.orgpolicy.Policy("primary", {
name: pulumi.interpolate`projects/${basic.projectId}/policies/gcp.resourceLocations`,
parent: pulumi.interpolate`projects/${basic.projectId}`,
spec: {
rules: [
{
condition: {
description: "A sample condition for the policy",
expression: "resource.matchTagId('tagKeys/123', 'tagValues/345')",
location: "sample-location.log",
title: "sample-condition",
},
values: {
allowedValues: ["projects/allowed-project"],
deniedValues: ["projects/denied-project"],
},
},
{
allowAll: "TRUE",
},
],
},
});
import pulumi
import pulumi_gcp as gcp
basic = gcp.organizations.Project("basic",
project_id="id",
name="id",
org_id="123456789",
deletion_policy="DELETE")
primary = gcp.orgpolicy.Policy("primary",
name=basic.project_id.apply(lambda project_id: f"projects/{project_id}/policies/gcp.resourceLocations"),
parent=basic.project_id.apply(lambda project_id: f"projects/{project_id}"),
spec={
"rules": [
{
"condition": {
"description": "A sample condition for the policy",
"expression": "resource.matchTagId('tagKeys/123', 'tagValues/345')",
"location": "sample-location.log",
"title": "sample-condition",
},
"values": {
"allowed_values": ["projects/allowed-project"],
"denied_values": ["projects/denied-project"],
},
},
{
"allow_all": "TRUE",
},
],
})
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/orgpolicy"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
basic, err := organizations.NewProject(ctx, "basic", &organizations.ProjectArgs{
ProjectId: pulumi.String("id"),
Name: pulumi.String("id"),
OrgId: pulumi.String("123456789"),
DeletionPolicy: pulumi.String("DELETE"),
})
if err != nil {
return err
}
_, err = orgpolicy.NewPolicy(ctx, "primary", &orgpolicy.PolicyArgs{
Name: basic.ProjectId.ApplyT(func(projectId string) (string, error) {
return fmt.Sprintf("projects/%v/policies/gcp.resourceLocations", projectId), nil
}).(pulumi.StringOutput),
Parent: basic.ProjectId.ApplyT(func(projectId string) (string, error) {
return fmt.Sprintf("projects/%v", projectId), nil
}).(pulumi.StringOutput),
Spec: &orgpolicy.PolicySpecArgs{
Rules: orgpolicy.PolicySpecRuleArray{
&orgpolicy.PolicySpecRuleArgs{
Condition: &orgpolicy.PolicySpecRuleConditionArgs{
Description: pulumi.String("A sample condition for the policy"),
Expression: pulumi.String("resource.matchTagId('tagKeys/123', 'tagValues/345')"),
Location: pulumi.String("sample-location.log"),
Title: pulumi.String("sample-condition"),
},
Values: &orgpolicy.PolicySpecRuleValuesArgs{
AllowedValues: pulumi.StringArray{
pulumi.String("projects/allowed-project"),
},
DeniedValues: pulumi.StringArray{
pulumi.String("projects/denied-project"),
},
},
},
&orgpolicy.PolicySpecRuleArgs{
AllowAll: pulumi.String("TRUE"),
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var basic = new Gcp.Organizations.Project("basic", new()
{
ProjectId = "id",
Name = "id",
OrgId = "123456789",
DeletionPolicy = "DELETE",
});
var primary = new Gcp.OrgPolicy.Policy("primary", new()
{
Name = basic.ProjectId.Apply(projectId => $"projects/{projectId}/policies/gcp.resourceLocations"),
Parent = basic.ProjectId.Apply(projectId => $"projects/{projectId}"),
Spec = new Gcp.OrgPolicy.Inputs.PolicySpecArgs
{
Rules = new[]
{
new Gcp.OrgPolicy.Inputs.PolicySpecRuleArgs
{
Condition = new Gcp.OrgPolicy.Inputs.PolicySpecRuleConditionArgs
{
Description = "A sample condition for the policy",
Expression = "resource.matchTagId('tagKeys/123', 'tagValues/345')",
Location = "sample-location.log",
Title = "sample-condition",
},
Values = new Gcp.OrgPolicy.Inputs.PolicySpecRuleValuesArgs
{
AllowedValues = new[]
{
"projects/allowed-project",
},
DeniedValues = new[]
{
"projects/denied-project",
},
},
},
new Gcp.OrgPolicy.Inputs.PolicySpecRuleArgs
{
AllowAll = "TRUE",
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.Project;
import com.pulumi.gcp.organizations.ProjectArgs;
import com.pulumi.gcp.orgpolicy.Policy;
import com.pulumi.gcp.orgpolicy.PolicyArgs;
import com.pulumi.gcp.orgpolicy.inputs.PolicySpecArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var basic = new Project("basic", ProjectArgs.builder()
.projectId("id")
.name("id")
.orgId("123456789")
.deletionPolicy("DELETE")
.build());
var primary = new Policy("primary", PolicyArgs.builder()
.name(basic.projectId().applyValue(_projectId -> String.format("projects/%s/policies/gcp.resourceLocations", _projectId)))
.parent(basic.projectId().applyValue(_projectId -> String.format("projects/%s", _projectId)))
.spec(PolicySpecArgs.builder()
.rules(
PolicySpecRuleArgs.builder()
.condition(PolicySpecRuleConditionArgs.builder()
.description("A sample condition for the policy")
.expression("resource.matchTagId('tagKeys/123', 'tagValues/345')")
.location("sample-location.log")
.title("sample-condition")
.build())
.values(PolicySpecRuleValuesArgs.builder()
.allowedValues("projects/allowed-project")
.deniedValues("projects/denied-project")
.build())
.build(),
PolicySpecRuleArgs.builder()
.allowAll("TRUE")
.build())
.build())
.build());
}
}
resources:
primary:
type: gcp:orgpolicy:Policy
properties:
name: projects/${basic.projectId}/policies/gcp.resourceLocations
parent: projects/${basic.projectId}
spec:
rules:
- condition:
description: A sample condition for the policy
expression: resource.matchTagId('tagKeys/123', 'tagValues/345')
location: sample-location.log
title: sample-condition
values:
allowedValues:
- projects/allowed-project
deniedValues:
- projects/denied-project
- allowAll: TRUE
basic:
type: gcp:organizations:Project
properties:
projectId: id
name: id
orgId: '123456789'
deletionPolicy: DELETE
The condition property uses CEL expressions to match resources by tags or other attributes. The values block specifies allowedValues and deniedValues lists that apply when the condition matches. The second rule with allowAll provides a fallback for resources that don’t match the condition.
Test policy impact with dry-run mode
Before enforcing a new policy, teams use dry-run mode to audit how it would affect existing and future resources.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const constraint = new gcp.orgpolicy.CustomConstraint("constraint", {
name: "custom.disableGkeAutoUpgrade_2234",
parent: "organizations/123456789",
displayName: "Disable GKE auto upgrade",
description: "Only allow GKE NodePool resource to be created or updated if AutoUpgrade is not enabled where this custom constraint is enforced.",
actionType: "ALLOW",
condition: "resource.management.autoUpgrade == false",
methodTypes: ["CREATE"],
resourceTypes: ["container.googleapis.com/NodePool"],
});
const primary = new gcp.orgpolicy.Policy("primary", {
name: pulumi.interpolate`organizations/123456789/policies/${constraint.name}`,
parent: "organizations/123456789",
spec: {
rules: [{
enforce: "FALSE",
}],
},
dryRunSpec: {
inheritFromParent: false,
reset: false,
rules: [{
enforce: "FALSE",
}],
},
});
import pulumi
import pulumi_gcp as gcp
constraint = gcp.orgpolicy.CustomConstraint("constraint",
name="custom.disableGkeAutoUpgrade_2234",
parent="organizations/123456789",
display_name="Disable GKE auto upgrade",
description="Only allow GKE NodePool resource to be created or updated if AutoUpgrade is not enabled where this custom constraint is enforced.",
action_type="ALLOW",
condition="resource.management.autoUpgrade == false",
method_types=["CREATE"],
resource_types=["container.googleapis.com/NodePool"])
primary = gcp.orgpolicy.Policy("primary",
name=constraint.name.apply(lambda name: f"organizations/123456789/policies/{name}"),
parent="organizations/123456789",
spec={
"rules": [{
"enforce": "FALSE",
}],
},
dry_run_spec={
"inherit_from_parent": False,
"reset": False,
"rules": [{
"enforce": "FALSE",
}],
})
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/orgpolicy"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
constraint, err := orgpolicy.NewCustomConstraint(ctx, "constraint", &orgpolicy.CustomConstraintArgs{
Name: pulumi.String("custom.disableGkeAutoUpgrade_2234"),
Parent: pulumi.String("organizations/123456789"),
DisplayName: pulumi.String("Disable GKE auto upgrade"),
Description: pulumi.String("Only allow GKE NodePool resource to be created or updated if AutoUpgrade is not enabled where this custom constraint is enforced."),
ActionType: pulumi.String("ALLOW"),
Condition: pulumi.String("resource.management.autoUpgrade == false"),
MethodTypes: pulumi.StringArray{
pulumi.String("CREATE"),
},
ResourceTypes: pulumi.StringArray{
pulumi.String("container.googleapis.com/NodePool"),
},
})
if err != nil {
return err
}
_, err = orgpolicy.NewPolicy(ctx, "primary", &orgpolicy.PolicyArgs{
Name: constraint.Name.ApplyT(func(name string) (string, error) {
return fmt.Sprintf("organizations/123456789/policies/%v", name), nil
}).(pulumi.StringOutput),
Parent: pulumi.String("organizations/123456789"),
Spec: &orgpolicy.PolicySpecArgs{
Rules: orgpolicy.PolicySpecRuleArray{
&orgpolicy.PolicySpecRuleArgs{
Enforce: pulumi.String("FALSE"),
},
},
},
DryRunSpec: &orgpolicy.PolicyDryRunSpecArgs{
InheritFromParent: pulumi.Bool(false),
Reset: pulumi.Bool(false),
Rules: orgpolicy.PolicyDryRunSpecRuleArray{
&orgpolicy.PolicyDryRunSpecRuleArgs{
Enforce: pulumi.String("FALSE"),
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var constraint = new Gcp.OrgPolicy.CustomConstraint("constraint", new()
{
Name = "custom.disableGkeAutoUpgrade_2234",
Parent = "organizations/123456789",
DisplayName = "Disable GKE auto upgrade",
Description = "Only allow GKE NodePool resource to be created or updated if AutoUpgrade is not enabled where this custom constraint is enforced.",
ActionType = "ALLOW",
Condition = "resource.management.autoUpgrade == false",
MethodTypes = new[]
{
"CREATE",
},
ResourceTypes = new[]
{
"container.googleapis.com/NodePool",
},
});
var primary = new Gcp.OrgPolicy.Policy("primary", new()
{
Name = constraint.Name.Apply(name => $"organizations/123456789/policies/{name}"),
Parent = "organizations/123456789",
Spec = new Gcp.OrgPolicy.Inputs.PolicySpecArgs
{
Rules = new[]
{
new Gcp.OrgPolicy.Inputs.PolicySpecRuleArgs
{
Enforce = "FALSE",
},
},
},
DryRunSpec = new Gcp.OrgPolicy.Inputs.PolicyDryRunSpecArgs
{
InheritFromParent = false,
Reset = false,
Rules = new[]
{
new Gcp.OrgPolicy.Inputs.PolicyDryRunSpecRuleArgs
{
Enforce = "FALSE",
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.orgpolicy.CustomConstraint;
import com.pulumi.gcp.orgpolicy.CustomConstraintArgs;
import com.pulumi.gcp.orgpolicy.Policy;
import com.pulumi.gcp.orgpolicy.PolicyArgs;
import com.pulumi.gcp.orgpolicy.inputs.PolicySpecArgs;
import com.pulumi.gcp.orgpolicy.inputs.PolicyDryRunSpecArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var constraint = new CustomConstraint("constraint", CustomConstraintArgs.builder()
.name("custom.disableGkeAutoUpgrade_2234")
.parent("organizations/123456789")
.displayName("Disable GKE auto upgrade")
.description("Only allow GKE NodePool resource to be created or updated if AutoUpgrade is not enabled where this custom constraint is enforced.")
.actionType("ALLOW")
.condition("resource.management.autoUpgrade == false")
.methodTypes("CREATE")
.resourceTypes("container.googleapis.com/NodePool")
.build());
var primary = new Policy("primary", PolicyArgs.builder()
.name(constraint.name().applyValue(_name -> String.format("organizations/123456789/policies/%s", _name)))
.parent("organizations/123456789")
.spec(PolicySpecArgs.builder()
.rules(PolicySpecRuleArgs.builder()
.enforce("FALSE")
.build())
.build())
.dryRunSpec(PolicyDryRunSpecArgs.builder()
.inheritFromParent(false)
.reset(false)
.rules(PolicyDryRunSpecRuleArgs.builder()
.enforce("FALSE")
.build())
.build())
.build());
}
}
resources:
constraint:
type: gcp:orgpolicy:CustomConstraint
properties:
name: custom.disableGkeAutoUpgrade_2234
parent: organizations/123456789
displayName: Disable GKE auto upgrade
description: Only allow GKE NodePool resource to be created or updated if AutoUpgrade is not enabled where this custom constraint is enforced.
actionType: ALLOW
condition: resource.management.autoUpgrade == false
methodTypes:
- CREATE
resourceTypes:
- container.googleapis.com/NodePool
primary:
type: gcp:orgpolicy:Policy
properties:
name: organizations/123456789/policies/${constraint.name}
parent: organizations/123456789
spec:
rules:
- enforce: FALSE
dryRunSpec:
inheritFromParent: false
reset: false
rules:
- enforce: FALSE
The dryRunSpec property defines an audit-only version of the policy that logs violations without blocking operations. This lets you test policy impact before enforcement. The spec property contains the actual enforced rules, while dryRunSpec runs in parallel for monitoring.
Pass structured parameters to custom constraints
Custom constraints can accept parameters to make policies more flexible, such as size limits or allowed resource types.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const basic = new gcp.organizations.Project("basic", {
projectId: "id",
name: "id",
orgId: "123456789",
deletionPolicy: "DELETE",
});
const primary = new gcp.orgpolicy.Policy("primary", {
name: pulumi.interpolate`projects/${basic.name}/policies/compute.managed.restrictDiskCreation`,
parent: pulumi.interpolate`projects/${basic.name}`,
spec: {
rules: [{
enforce: "TRUE",
parameters: JSON.stringify({
isSizeLimitCheck: true,
allowedDiskTypes: [
"pd-ssd",
"pd-standard",
],
}),
}],
},
});
import pulumi
import json
import pulumi_gcp as gcp
basic = gcp.organizations.Project("basic",
project_id="id",
name="id",
org_id="123456789",
deletion_policy="DELETE")
primary = gcp.orgpolicy.Policy("primary",
name=basic.name.apply(lambda name: f"projects/{name}/policies/compute.managed.restrictDiskCreation"),
parent=basic.name.apply(lambda name: f"projects/{name}"),
spec={
"rules": [{
"enforce": "TRUE",
"parameters": json.dumps({
"isSizeLimitCheck": True,
"allowedDiskTypes": [
"pd-ssd",
"pd-standard",
],
}),
}],
})
package main
import (
"encoding/json"
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/orgpolicy"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
basic, err := organizations.NewProject(ctx, "basic", &organizations.ProjectArgs{
ProjectId: pulumi.String("id"),
Name: pulumi.String("id"),
OrgId: pulumi.String("123456789"),
DeletionPolicy: pulumi.String("DELETE"),
})
if err != nil {
return err
}
tmpJSON0, err := json.Marshal(map[string]interface{}{
"isSizeLimitCheck": true,
"allowedDiskTypes": []string{
"pd-ssd",
"pd-standard",
},
})
if err != nil {
return err
}
json0 := string(tmpJSON0)
_, err = orgpolicy.NewPolicy(ctx, "primary", &orgpolicy.PolicyArgs{
Name: basic.Name.ApplyT(func(name string) (string, error) {
return fmt.Sprintf("projects/%v/policies/compute.managed.restrictDiskCreation", name), nil
}).(pulumi.StringOutput),
Parent: basic.Name.ApplyT(func(name string) (string, error) {
return fmt.Sprintf("projects/%v", name), nil
}).(pulumi.StringOutput),
Spec: &orgpolicy.PolicySpecArgs{
Rules: orgpolicy.PolicySpecRuleArray{
&orgpolicy.PolicySpecRuleArgs{
Enforce: pulumi.String("TRUE"),
Parameters: pulumi.String(json0),
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var basic = new Gcp.Organizations.Project("basic", new()
{
ProjectId = "id",
Name = "id",
OrgId = "123456789",
DeletionPolicy = "DELETE",
});
var primary = new Gcp.OrgPolicy.Policy("primary", new()
{
Name = basic.Name.Apply(name => $"projects/{name}/policies/compute.managed.restrictDiskCreation"),
Parent = basic.Name.Apply(name => $"projects/{name}"),
Spec = new Gcp.OrgPolicy.Inputs.PolicySpecArgs
{
Rules = new[]
{
new Gcp.OrgPolicy.Inputs.PolicySpecRuleArgs
{
Enforce = "TRUE",
Parameters = JsonSerializer.Serialize(new Dictionary<string, object?>
{
["isSizeLimitCheck"] = true,
["allowedDiskTypes"] = new[]
{
"pd-ssd",
"pd-standard",
},
}),
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.Project;
import com.pulumi.gcp.organizations.ProjectArgs;
import com.pulumi.gcp.orgpolicy.Policy;
import com.pulumi.gcp.orgpolicy.PolicyArgs;
import com.pulumi.gcp.orgpolicy.inputs.PolicySpecArgs;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var basic = new Project("basic", ProjectArgs.builder()
.projectId("id")
.name("id")
.orgId("123456789")
.deletionPolicy("DELETE")
.build());
var primary = new Policy("primary", PolicyArgs.builder()
.name(basic.name().applyValue(_name -> String.format("projects/%s/policies/compute.managed.restrictDiskCreation", _name)))
.parent(basic.name().applyValue(_name -> String.format("projects/%s", _name)))
.spec(PolicySpecArgs.builder()
.rules(PolicySpecRuleArgs.builder()
.enforce("TRUE")
.parameters(serializeJson(
jsonObject(
jsonProperty("isSizeLimitCheck", true),
jsonProperty("allowedDiskTypes", jsonArray(
"pd-ssd",
"pd-standard"
))
)))
.build())
.build())
.build());
}
}
resources:
primary:
type: gcp:orgpolicy:Policy
properties:
name: projects/${basic.name}/policies/compute.managed.restrictDiskCreation
parent: projects/${basic.name}
spec:
rules:
- enforce: TRUE
parameters:
fn::toJSON:
isSizeLimitCheck: true
allowedDiskTypes:
- pd-ssd
- pd-standard
basic:
type: gcp:organizations:Project
properties:
projectId: id
name: id
orgId: '123456789'
deletionPolicy: DELETE
The parameters property passes JSON-encoded configuration to custom constraints. This example sends isSizeLimitCheck and allowedDiskTypes to the compute.managed.restrictDiskCreation constraint. Parameters let you reuse constraints across environments with different settings.
Beyond these examples
These snippets focus on specific policy-level features: enforcement at project, folder, and organization levels, conditional rules and value constraints, and dry-run testing and parameter passing. They’re intentionally minimal rather than full governance frameworks.
The examples may reference pre-existing infrastructure such as GCP projects, folders, or organizations, custom constraints for parameter-based policies, and resource tags for conditional matching. They focus on configuring the policy rather than provisioning the entire resource hierarchy.
To keep things focused, common policy patterns are omitted, including:
- Policy versioning and etag-based concurrency control
- Multiple rule combinations within a single policy
- Cross-service constraint coordination
- Policy deletion and cleanup workflows
These omissions are intentional: the goal is to illustrate how each policy feature is wired, not provide drop-in governance modules. See the Organization Policy resource reference for all available configuration options.
Let's configure GCP Organization Policies
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Policy Configuration & Structure
projects/{project_number}/policies/{constraint_name}, folders/{folder_id}/policies/{constraint_name}, or organizations/{organization_id}/policies/{constraint_name}. For example, projects/123/policies/compute.disableSerialPortAccess.name and parent are immutable and cannot be changed after the policy is created.projects/{project_id}/policies/{constraint_name} in requests, but responses always return the name using the equivalent project number.Rules & Enforcement
enforce (TRUE/FALSE), denyAll (TRUE), allowAll (TRUE), and values with allowedValues or deniedValues lists. You can also add condition expressions to rules.parameters field with a JSON string containing your custom parameters. For example, parameters: JSON.stringify({isSizeLimitCheck: true, allowedDiskTypes: ["pd-ssd"]}).Testing & Dry Runs
spec defines the enforced policy that actively restricts resources, while dryRunSpec is audit-only and monitors how the policy would impact resources without actually enforcing it.dryRunSpec with your desired rules. This creates an audit-only policy that monitors impact without enforcement.Advanced Features
inheritFromParent: true in the spec to inherit policy rules from the parent resource.reset: true in the spec to reset the policy to default.etag is computed by the server based on the policy state and used for concurrency control. Send it on update and delete requests to ensure you have an up-to-date value before proceeding.