The gcp:orgpolicy/policy:Policy resource, part of the Pulumi GCP provider, defines organization policies that enforce constraints on Google Cloud resource configurations. This guide focuses on three capabilities: enforcement at project, folder, and organization levels; conditional rules with value restrictions; and dry-run testing with parameterized constraints.
Policies attach to existing projects, folders, or organizations and reference predefined or custom constraints. The examples are intentionally small. Combine them with your own resource hierarchy and constraint definitions.
Enforce a policy at the project level
Teams often disable specific security features at the project level to accommodate development workflows.
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 defines enforcement behavior; setting enforce to “FALSE” disables the constraint. This policy prevents service account key upload restrictions for the specified project.
Apply folder-level policies with inheritance
Organizations structure resources into folders to apply governance at scale, with policies inheriting from parent levels.
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 pulls rules from higher levels in the hierarchy before applying folder-specific rules. Setting denyAll to “TRUE” blocks all values for the gcp.resourceLocations constraint, restricting where resources can be created across all projects in the folder.
Reset organization-wide policy to defaults
When policies need to return to their default state, the reset option clears custom rules without deleting the resource.
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
Setting spec.reset to true removes all custom rules and restores the constraint’s default behavior. This is useful when unwinding temporary policy changes or returning to baseline governance.
Define conditional rules with allowed and denied values
Complex policies need different rules for different resources based on 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 property 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, dry-run mode audits how the policy would affect resources without blocking operations.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const constraint = new gcp.orgpolicy.CustomConstraint("constraint", {
name: "custom.disableGkeAutoUpgrade_32270",
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_32270",
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_32270"),
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_32270",
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_32270")
.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_32270
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 enforcement. This lets you preview impact on existing resources and future operations. The spec property defines the actual enforcement rules that will apply once testing is complete.
Pass structured parameters to custom constraints
Custom constraints can accept parameters to make policies more flexible without modifying constraint definitions.
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 a JSON object to the custom constraint. Here, it configures disk creation limits with isSizeLimitCheck and allowedDiskTypes. The constraint evaluates these parameters when checking resource compliance.
Beyond these examples
These snippets focus on specific policy-level features: enforcement at project, folder, and organization levels; conditional rules and value restrictions; and dry-run testing and parameterized constraints. They’re intentionally minimal rather than full governance frameworks.
The examples reference pre-existing infrastructure such as projects, folders, or organizations to attach policies to; custom constraints for parameterized policies; and resource tags for conditional rules. They focus on policy configuration rather than provisioning the resource hierarchy.
To keep things focused, common policy patterns are omitted, including:
- Policy deletion and lifecycle management
- Etag-based concurrency control
- Multiple rule combinations and precedence
- Integration with custom constraint creation 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
Resource Naming & Hierarchy
{parent_type}/{parent_id}/policies/{constraint_name}, where parent_type is projects, folders, or organizations. For example: projects/123/policies/compute.disableSerialPortAccess. Note that while the API accepts project_id, responses return the equivalent project_number.name and parent are immutable. Changing either property will force resource recreation, so plan these values carefully during initial setup.parent specifies the resource hierarchy level (project, folder, or organization) where the policy applies. It must match the parent specified in the name property.Policy Rules & Enforcement
You can use several rule types:
- enforce - Set to
"TRUE"or"FALSE"to enable/disable enforcement - denyAll - Set to
"TRUE"to deny all values - allowAll - Set to
"TRUE"to allow all values - values - Specify
allowedValuesanddeniedValueslists - reset - Set to
trueto reset policy to default state
condition field within a rule to specify an expression, description, location, and title. For example: resource.matchTagId('tagKeys/123', 'tagValues/345').parameters field with a JSON string (not an object). For example: JSON.stringify({isSizeLimitCheck: true, allowedDiskTypes: ["pd-ssd"]}).Policy Inheritance & Reset
inheritFromParent to true in the spec. This allows the policy to inherit rules from higher levels in the resource hierarchy.reset to true in the spec. This removes all custom rules and restores the policy to its default configuration.Dry Run & Testing
dryRunSpec to create an audit-only policy that monitors how the policy would impact existing and future resources without actually enforcing it. The dryRunSpec has the same structure as spec but operates in monitoring mode.Advanced Configuration
etag is computed by the server based on the policy’s current state and is used for concurrency control. Send it on update and delete requests to ensure you have an up-to-date value before making changes.