Configure GCP Access Context Manager Service Perimeters

The gcp:accesscontextmanager/servicePerimeter:ServicePerimeter resource, part of the Pulumi GCP provider, defines VPC Service Controls perimeters that restrict which GCP services projects can access and control data movement between perimeters. This guide focuses on three capabilities: basic service restrictions, ingress and egress policies, and dry-run testing.

Service perimeters belong to an AccessPolicy and may reference AccessLevel resources for conditional access. The examples are intentionally small. Combine them with your own access policies, project lists, and access levels.

Restrict service access with a basic perimeter

Organizations implementing zero-trust security start by defining perimeters that control which services projects can access.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const access_policy = new gcp.accesscontextmanager.AccessPolicy("access-policy", {
    parent: "organizations/123456789",
    title: "my policy",
});
const service_perimeter = new gcp.accesscontextmanager.ServicePerimeter("service-perimeter", {
    parent: pulumi.interpolate`accessPolicies/${access_policy.name}`,
    name: pulumi.interpolate`accessPolicies/${access_policy.name}/servicePerimeters/restrict_storage`,
    title: "restrict_storage",
    status: {
        restrictedServices: ["storage.googleapis.com"],
    },
});
const access_level = new gcp.accesscontextmanager.AccessLevel("access-level", {
    parent: pulumi.interpolate`accessPolicies/${access_policy.name}`,
    name: pulumi.interpolate`accessPolicies/${access_policy.name}/accessLevels/chromeos_no_lock`,
    title: "chromeos_no_lock",
    basic: {
        conditions: [{
            devicePolicy: {
                requireScreenLock: false,
                osConstraints: [{
                    osType: "DESKTOP_CHROME_OS",
                }],
            },
            regions: [
                "CH",
                "IT",
                "US",
            ],
        }],
    },
});
import pulumi
import pulumi_gcp as gcp

access_policy = gcp.accesscontextmanager.AccessPolicy("access-policy",
    parent="organizations/123456789",
    title="my policy")
service_perimeter = gcp.accesscontextmanager.ServicePerimeter("service-perimeter",
    parent=access_policy.name.apply(lambda name: f"accessPolicies/{name}"),
    name=access_policy.name.apply(lambda name: f"accessPolicies/{name}/servicePerimeters/restrict_storage"),
    title="restrict_storage",
    status={
        "restricted_services": ["storage.googleapis.com"],
    })
access_level = gcp.accesscontextmanager.AccessLevel("access-level",
    parent=access_policy.name.apply(lambda name: f"accessPolicies/{name}"),
    name=access_policy.name.apply(lambda name: f"accessPolicies/{name}/accessLevels/chromeos_no_lock"),
    title="chromeos_no_lock",
    basic={
        "conditions": [{
            "device_policy": {
                "require_screen_lock": False,
                "os_constraints": [{
                    "os_type": "DESKTOP_CHROME_OS",
                }],
            },
            "regions": [
                "CH",
                "IT",
                "US",
            ],
        }],
    })
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/accesscontextmanager"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		access_policy, err := accesscontextmanager.NewAccessPolicy(ctx, "access-policy", &accesscontextmanager.AccessPolicyArgs{
			Parent: pulumi.String("organizations/123456789"),
			Title:  pulumi.String("my policy"),
		})
		if err != nil {
			return err
		}
		_, err = accesscontextmanager.NewServicePerimeter(ctx, "service-perimeter", &accesscontextmanager.ServicePerimeterArgs{
			Parent: access_policy.Name.ApplyT(func(name string) (string, error) {
				return fmt.Sprintf("accessPolicies/%v", name), nil
			}).(pulumi.StringOutput),
			Name: access_policy.Name.ApplyT(func(name string) (string, error) {
				return fmt.Sprintf("accessPolicies/%v/servicePerimeters/restrict_storage", name), nil
			}).(pulumi.StringOutput),
			Title: pulumi.String("restrict_storage"),
			Status: &accesscontextmanager.ServicePerimeterStatusArgs{
				RestrictedServices: pulumi.StringArray{
					pulumi.String("storage.googleapis.com"),
				},
			},
		})
		if err != nil {
			return err
		}
		_, err = accesscontextmanager.NewAccessLevel(ctx, "access-level", &accesscontextmanager.AccessLevelArgs{
			Parent: access_policy.Name.ApplyT(func(name string) (string, error) {
				return fmt.Sprintf("accessPolicies/%v", name), nil
			}).(pulumi.StringOutput),
			Name: access_policy.Name.ApplyT(func(name string) (string, error) {
				return fmt.Sprintf("accessPolicies/%v/accessLevels/chromeos_no_lock", name), nil
			}).(pulumi.StringOutput),
			Title: pulumi.String("chromeos_no_lock"),
			Basic: &accesscontextmanager.AccessLevelBasicArgs{
				Conditions: accesscontextmanager.AccessLevelBasicConditionArray{
					&accesscontextmanager.AccessLevelBasicConditionArgs{
						DevicePolicy: &accesscontextmanager.AccessLevelBasicConditionDevicePolicyArgs{
							RequireScreenLock: pulumi.Bool(false),
							OsConstraints: accesscontextmanager.AccessLevelBasicConditionDevicePolicyOsConstraintArray{
								&accesscontextmanager.AccessLevelBasicConditionDevicePolicyOsConstraintArgs{
									OsType: pulumi.String("DESKTOP_CHROME_OS"),
								},
							},
						},
						Regions: pulumi.StringArray{
							pulumi.String("CH"),
							pulumi.String("IT"),
							pulumi.String("US"),
						},
					},
				},
			},
		})
		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 access_policy = new Gcp.AccessContextManager.AccessPolicy("access-policy", new()
    {
        Parent = "organizations/123456789",
        Title = "my policy",
    });

    var service_perimeter = new Gcp.AccessContextManager.ServicePerimeter("service-perimeter", new()
    {
        Parent = access_policy.Name.Apply(name => $"accessPolicies/{name}"),
        Name = access_policy.Name.Apply(name => $"accessPolicies/{name}/servicePerimeters/restrict_storage"),
        Title = "restrict_storage",
        Status = new Gcp.AccessContextManager.Inputs.ServicePerimeterStatusArgs
        {
            RestrictedServices = new[]
            {
                "storage.googleapis.com",
            },
        },
    });

    var access_level = new Gcp.AccessContextManager.AccessLevel("access-level", new()
    {
        Parent = access_policy.Name.Apply(name => $"accessPolicies/{name}"),
        Name = access_policy.Name.Apply(name => $"accessPolicies/{name}/accessLevels/chromeos_no_lock"),
        Title = "chromeos_no_lock",
        Basic = new Gcp.AccessContextManager.Inputs.AccessLevelBasicArgs
        {
            Conditions = new[]
            {
                new Gcp.AccessContextManager.Inputs.AccessLevelBasicConditionArgs
                {
                    DevicePolicy = new Gcp.AccessContextManager.Inputs.AccessLevelBasicConditionDevicePolicyArgs
                    {
                        RequireScreenLock = false,
                        OsConstraints = new[]
                        {
                            new Gcp.AccessContextManager.Inputs.AccessLevelBasicConditionDevicePolicyOsConstraintArgs
                            {
                                OsType = "DESKTOP_CHROME_OS",
                            },
                        },
                    },
                    Regions = new[]
                    {
                        "CH",
                        "IT",
                        "US",
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.accesscontextmanager.AccessPolicy;
import com.pulumi.gcp.accesscontextmanager.AccessPolicyArgs;
import com.pulumi.gcp.accesscontextmanager.ServicePerimeter;
import com.pulumi.gcp.accesscontextmanager.ServicePerimeterArgs;
import com.pulumi.gcp.accesscontextmanager.inputs.ServicePerimeterStatusArgs;
import com.pulumi.gcp.accesscontextmanager.AccessLevel;
import com.pulumi.gcp.accesscontextmanager.AccessLevelArgs;
import com.pulumi.gcp.accesscontextmanager.inputs.AccessLevelBasicArgs;
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 access_policy = new AccessPolicy("access-policy", AccessPolicyArgs.builder()
            .parent("organizations/123456789")
            .title("my policy")
            .build());

        var service_perimeter = new ServicePerimeter("service-perimeter", ServicePerimeterArgs.builder()
            .parent(access_policy.name().applyValue(_name -> String.format("accessPolicies/%s", _name)))
            .name(access_policy.name().applyValue(_name -> String.format("accessPolicies/%s/servicePerimeters/restrict_storage", _name)))
            .title("restrict_storage")
            .status(ServicePerimeterStatusArgs.builder()
                .restrictedServices("storage.googleapis.com")
                .build())
            .build());

        var access_level = new AccessLevel("access-level", AccessLevelArgs.builder()
            .parent(access_policy.name().applyValue(_name -> String.format("accessPolicies/%s", _name)))
            .name(access_policy.name().applyValue(_name -> String.format("accessPolicies/%s/accessLevels/chromeos_no_lock", _name)))
            .title("chromeos_no_lock")
            .basic(AccessLevelBasicArgs.builder()
                .conditions(AccessLevelBasicConditionArgs.builder()
                    .devicePolicy(AccessLevelBasicConditionDevicePolicyArgs.builder()
                        .requireScreenLock(false)
                        .osConstraints(AccessLevelBasicConditionDevicePolicyOsConstraintArgs.builder()
                            .osType("DESKTOP_CHROME_OS")
                            .build())
                        .build())
                    .regions(                    
                        "CH",
                        "IT",
                        "US")
                    .build())
                .build())
            .build());

    }
}
resources:
  service-perimeter:
    type: gcp:accesscontextmanager:ServicePerimeter
    properties:
      parent: accessPolicies/${["access-policy"].name}
      name: accessPolicies/${["access-policy"].name}/servicePerimeters/restrict_storage
      title: restrict_storage
      status:
        restrictedServices:
          - storage.googleapis.com
  access-level:
    type: gcp:accesscontextmanager:AccessLevel
    properties:
      parent: accessPolicies/${["access-policy"].name}
      name: accessPolicies/${["access-policy"].name}/accessLevels/chromeos_no_lock
      title: chromeos_no_lock
      basic:
        conditions:
          - devicePolicy:
              requireScreenLock: false
              osConstraints:
                - osType: DESKTOP_CHROME_OS
            regions:
              - CH
              - IT
              - US
  access-policy:
    type: gcp:accesscontextmanager:AccessPolicy
    properties:
      parent: organizations/123456789
      title: my policy

The status block defines the enforced configuration. The restrictedServices array lists GCP APIs that cannot be accessed from outside the perimeter; here, Cloud Storage is blocked. Projects within the perimeter can still communicate freely with each other.

Control ingress and egress with fine-grained policies

Data exchange between projects often requires precise control over which operations are permitted and from which sources.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const access_policy = new gcp.accesscontextmanager.AccessPolicy("access-policy", {
    parent: "organizations/123456789",
    title: "my policy",
});
const secure_data_exchange = new gcp.accesscontextmanager.ServicePerimeters("secure-data-exchange", {
    parent: pulumi.interpolate`accessPolicies/${access_policy.name}`,
    servicePerimeters: [
        {
            name: pulumi.interpolate`accessPolicies/${access_policy.name}/servicePerimeters/`,
            title: "",
            status: {
                restrictedServices: ["storage.googleapis.com"],
            },
        },
        {
            name: pulumi.interpolate`accessPolicies/${access_policy.name}/servicePerimeters/`,
            title: "",
            status: {
                restrictedServices: ["bigtable.googleapis.com"],
                vpcAccessibleServices: {
                    enableRestriction: true,
                    allowedServices: ["bigquery.googleapis.com"],
                },
            },
        },
    ],
});
const access_level = new gcp.accesscontextmanager.AccessLevel("access-level", {
    parent: pulumi.interpolate`accessPolicies/${access_policy.name}`,
    name: pulumi.interpolate`accessPolicies/${access_policy.name}/accessLevels/secure_data_exchange`,
    title: "secure_data_exchange",
    basic: {
        conditions: [{
            devicePolicy: {
                requireScreenLock: false,
                osConstraints: [{
                    osType: "DESKTOP_CHROME_OS",
                }],
            },
            regions: [
                "CH",
                "IT",
                "US",
            ],
        }],
    },
});
const test_access = new gcp.accesscontextmanager.ServicePerimeter("test-access", {
    parent: `accessPolicies/${test_accessGoogleAccessContextManagerAccessPolicy.name}`,
    name: `accessPolicies/${test_accessGoogleAccessContextManagerAccessPolicy.name}/servicePerimeters/%s`,
    title: "%s",
    perimeterType: "PERIMETER_TYPE_REGULAR",
    status: {
        restrictedServices: [
            "bigquery.googleapis.com",
            "storage.googleapis.com",
        ],
        accessLevels: [access_level.name],
        vpcAccessibleServices: {
            enableRestriction: true,
            allowedServices: [
                "bigquery.googleapis.com",
                "storage.googleapis.com",
            ],
        },
        ingressPolicies: [{
            ingressFrom: {
                sources: [{
                    accessLevel: test_accessGoogleAccessContextManagerAccessLevel.name,
                }],
                identityType: "ANY_IDENTITY",
            },
            ingressTo: {
                resources: ["*"],
                operations: [
                    {
                        serviceName: "bigquery.googleapis.com",
                        methodSelectors: [
                            {
                                method: "BigQueryStorage.ReadRows",
                            },
                            {
                                method: "TableService.ListTables",
                            },
                            {
                                permission: "bigquery.jobs.get",
                            },
                        ],
                    },
                    {
                        serviceName: "storage.googleapis.com",
                        methodSelectors: [{
                            method: "google.storage.objects.create",
                        }],
                    },
                ],
            },
        }],
        egressPolicies: [{
            egressFrom: {
                identityType: "ANY_USER_ACCOUNT",
            },
        }],
    },
});
import pulumi
import pulumi_gcp as gcp

access_policy = gcp.accesscontextmanager.AccessPolicy("access-policy",
    parent="organizations/123456789",
    title="my policy")
secure_data_exchange = gcp.accesscontextmanager.ServicePerimeters("secure-data-exchange",
    parent=access_policy.name.apply(lambda name: f"accessPolicies/{name}"),
    service_perimeters=[
        {
            "name": access_policy.name.apply(lambda name: f"accessPolicies/{name}/servicePerimeters/"),
            "title": "",
            "status": {
                "restricted_services": ["storage.googleapis.com"],
            },
        },
        {
            "name": access_policy.name.apply(lambda name: f"accessPolicies/{name}/servicePerimeters/"),
            "title": "",
            "status": {
                "restricted_services": ["bigtable.googleapis.com"],
                "vpc_accessible_services": {
                    "enable_restriction": True,
                    "allowed_services": ["bigquery.googleapis.com"],
                },
            },
        },
    ])
access_level = gcp.accesscontextmanager.AccessLevel("access-level",
    parent=access_policy.name.apply(lambda name: f"accessPolicies/{name}"),
    name=access_policy.name.apply(lambda name: f"accessPolicies/{name}/accessLevels/secure_data_exchange"),
    title="secure_data_exchange",
    basic={
        "conditions": [{
            "device_policy": {
                "require_screen_lock": False,
                "os_constraints": [{
                    "os_type": "DESKTOP_CHROME_OS",
                }],
            },
            "regions": [
                "CH",
                "IT",
                "US",
            ],
        }],
    })
test_access = gcp.accesscontextmanager.ServicePerimeter("test-access",
    parent=f"accessPolicies/{test_access_google_access_context_manager_access_policy['name']}",
    name=f"accessPolicies/{test_access_google_access_context_manager_access_policy['name']}/servicePerimeters/%s",
    title="%s",
    perimeter_type="PERIMETER_TYPE_REGULAR",
    status={
        "restricted_services": [
            "bigquery.googleapis.com",
            "storage.googleapis.com",
        ],
        "access_levels": [access_level.name],
        "vpc_accessible_services": {
            "enable_restriction": True,
            "allowed_services": [
                "bigquery.googleapis.com",
                "storage.googleapis.com",
            ],
        },
        "ingress_policies": [{
            "ingress_from": {
                "sources": [{
                    "access_level": test_access_google_access_context_manager_access_level["name"],
                }],
                "identity_type": "ANY_IDENTITY",
            },
            "ingress_to": {
                "resources": ["*"],
                "operations": [
                    {
                        "service_name": "bigquery.googleapis.com",
                        "method_selectors": [
                            {
                                "method": "BigQueryStorage.ReadRows",
                            },
                            {
                                "method": "TableService.ListTables",
                            },
                            {
                                "permission": "bigquery.jobs.get",
                            },
                        ],
                    },
                    {
                        "service_name": "storage.googleapis.com",
                        "method_selectors": [{
                            "method": "google.storage.objects.create",
                        }],
                    },
                ],
            },
        }],
        "egress_policies": [{
            "egress_from": {
                "identity_type": "ANY_USER_ACCOUNT",
            },
        }],
    })
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/accesscontextmanager"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		access_policy, err := accesscontextmanager.NewAccessPolicy(ctx, "access-policy", &accesscontextmanager.AccessPolicyArgs{
			Parent: pulumi.String("organizations/123456789"),
			Title:  pulumi.String("my policy"),
		})
		if err != nil {
			return err
		}
		_, err = accesscontextmanager.NewServicePerimeters(ctx, "secure-data-exchange", &accesscontextmanager.ServicePerimetersArgs{
			Parent: access_policy.Name.ApplyT(func(name string) (string, error) {
				return fmt.Sprintf("accessPolicies/%v", name), nil
			}).(pulumi.StringOutput),
			ServicePerimeters: accesscontextmanager.ServicePerimetersServicePerimeterArray{
				&accesscontextmanager.ServicePerimetersServicePerimeterArgs{
					Name: access_policy.Name.ApplyT(func(name string) (string, error) {
						return fmt.Sprintf("accessPolicies/%v/servicePerimeters/", name), nil
					}).(pulumi.StringOutput),
					Title: pulumi.String(""),
					Status: &accesscontextmanager.ServicePerimetersServicePerimeterStatusArgs{
						RestrictedServices: pulumi.StringArray{
							pulumi.String("storage.googleapis.com"),
						},
					},
				},
				&accesscontextmanager.ServicePerimetersServicePerimeterArgs{
					Name: access_policy.Name.ApplyT(func(name string) (string, error) {
						return fmt.Sprintf("accessPolicies/%v/servicePerimeters/", name), nil
					}).(pulumi.StringOutput),
					Title: pulumi.String(""),
					Status: &accesscontextmanager.ServicePerimetersServicePerimeterStatusArgs{
						RestrictedServices: pulumi.StringArray{
							pulumi.String("bigtable.googleapis.com"),
						},
						VpcAccessibleServices: &accesscontextmanager.ServicePerimetersServicePerimeterStatusVpcAccessibleServicesArgs{
							EnableRestriction: pulumi.Bool(true),
							AllowedServices: pulumi.StringArray{
								pulumi.String("bigquery.googleapis.com"),
							},
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		access_level, err := accesscontextmanager.NewAccessLevel(ctx, "access-level", &accesscontextmanager.AccessLevelArgs{
			Parent: access_policy.Name.ApplyT(func(name string) (string, error) {
				return fmt.Sprintf("accessPolicies/%v", name), nil
			}).(pulumi.StringOutput),
			Name: access_policy.Name.ApplyT(func(name string) (string, error) {
				return fmt.Sprintf("accessPolicies/%v/accessLevels/secure_data_exchange", name), nil
			}).(pulumi.StringOutput),
			Title: pulumi.String("secure_data_exchange"),
			Basic: &accesscontextmanager.AccessLevelBasicArgs{
				Conditions: accesscontextmanager.AccessLevelBasicConditionArray{
					&accesscontextmanager.AccessLevelBasicConditionArgs{
						DevicePolicy: &accesscontextmanager.AccessLevelBasicConditionDevicePolicyArgs{
							RequireScreenLock: pulumi.Bool(false),
							OsConstraints: accesscontextmanager.AccessLevelBasicConditionDevicePolicyOsConstraintArray{
								&accesscontextmanager.AccessLevelBasicConditionDevicePolicyOsConstraintArgs{
									OsType: pulumi.String("DESKTOP_CHROME_OS"),
								},
							},
						},
						Regions: pulumi.StringArray{
							pulumi.String("CH"),
							pulumi.String("IT"),
							pulumi.String("US"),
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		_, err = accesscontextmanager.NewServicePerimeter(ctx, "test-access", &accesscontextmanager.ServicePerimeterArgs{
			Parent:        pulumi.Sprintf("accessPolicies/%v", test_accessGoogleAccessContextManagerAccessPolicy.Name),
			Name:          pulumi.Sprintf("accessPolicies/%v%v", test_accessGoogleAccessContextManagerAccessPolicy.Name, "/servicePerimeters/%s"),
			Title:         pulumi.String("%s"),
			PerimeterType: pulumi.String("PERIMETER_TYPE_REGULAR"),
			Status: &accesscontextmanager.ServicePerimeterStatusArgs{
				RestrictedServices: pulumi.StringArray{
					pulumi.String("bigquery.googleapis.com"),
					pulumi.String("storage.googleapis.com"),
				},
				AccessLevels: pulumi.StringArray{
					access_level.Name,
				},
				VpcAccessibleServices: &accesscontextmanager.ServicePerimeterStatusVpcAccessibleServicesArgs{
					EnableRestriction: pulumi.Bool(true),
					AllowedServices: pulumi.StringArray{
						pulumi.String("bigquery.googleapis.com"),
						pulumi.String("storage.googleapis.com"),
					},
				},
				IngressPolicies: accesscontextmanager.ServicePerimeterStatusIngressPolicyArray{
					&accesscontextmanager.ServicePerimeterStatusIngressPolicyArgs{
						IngressFrom: &accesscontextmanager.ServicePerimeterStatusIngressPolicyIngressFromArgs{
							Sources: accesscontextmanager.ServicePerimeterStatusIngressPolicyIngressFromSourceArray{
								&accesscontextmanager.ServicePerimeterStatusIngressPolicyIngressFromSourceArgs{
									AccessLevel: pulumi.Any(test_accessGoogleAccessContextManagerAccessLevel.Name),
								},
							},
							IdentityType: pulumi.String("ANY_IDENTITY"),
						},
						IngressTo: &accesscontextmanager.ServicePerimeterStatusIngressPolicyIngressToArgs{
							Resources: pulumi.StringArray{
								pulumi.String("*"),
							},
							Operations: accesscontextmanager.ServicePerimeterStatusIngressPolicyIngressToOperationArray{
								&accesscontextmanager.ServicePerimeterStatusIngressPolicyIngressToOperationArgs{
									ServiceName: pulumi.String("bigquery.googleapis.com"),
									MethodSelectors: accesscontextmanager.ServicePerimeterStatusIngressPolicyIngressToOperationMethodSelectorArray{
										&accesscontextmanager.ServicePerimeterStatusIngressPolicyIngressToOperationMethodSelectorArgs{
											Method: pulumi.String("BigQueryStorage.ReadRows"),
										},
										&accesscontextmanager.ServicePerimeterStatusIngressPolicyIngressToOperationMethodSelectorArgs{
											Method: pulumi.String("TableService.ListTables"),
										},
										&accesscontextmanager.ServicePerimeterStatusIngressPolicyIngressToOperationMethodSelectorArgs{
											Permission: pulumi.String("bigquery.jobs.get"),
										},
									},
								},
								&accesscontextmanager.ServicePerimeterStatusIngressPolicyIngressToOperationArgs{
									ServiceName: pulumi.String("storage.googleapis.com"),
									MethodSelectors: accesscontextmanager.ServicePerimeterStatusIngressPolicyIngressToOperationMethodSelectorArray{
										&accesscontextmanager.ServicePerimeterStatusIngressPolicyIngressToOperationMethodSelectorArgs{
											Method: pulumi.String("google.storage.objects.create"),
										},
									},
								},
							},
						},
					},
				},
				EgressPolicies: accesscontextmanager.ServicePerimeterStatusEgressPolicyArray{
					&accesscontextmanager.ServicePerimeterStatusEgressPolicyArgs{
						EgressFrom: &accesscontextmanager.ServicePerimeterStatusEgressPolicyEgressFromArgs{
							IdentityType: pulumi.String("ANY_USER_ACCOUNT"),
						},
					},
				},
			},
		})
		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 access_policy = new Gcp.AccessContextManager.AccessPolicy("access-policy", new()
    {
        Parent = "organizations/123456789",
        Title = "my policy",
    });

    var secure_data_exchange = new Gcp.AccessContextManager.ServicePerimeters("secure-data-exchange", new()
    {
        Parent = access_policy.Name.Apply(name => $"accessPolicies/{name}"),
        ServicePerimeterDetails = new[]
        {
            new Gcp.AccessContextManager.Inputs.ServicePerimetersServicePerimeterArgs
            {
                Name = access_policy.Name.Apply(name => $"accessPolicies/{name}/servicePerimeters/"),
                Title = "",
                Status = new Gcp.AccessContextManager.Inputs.ServicePerimetersServicePerimeterStatusArgs
                {
                    RestrictedServices = new[]
                    {
                        "storage.googleapis.com",
                    },
                },
            },
            new Gcp.AccessContextManager.Inputs.ServicePerimetersServicePerimeterArgs
            {
                Name = access_policy.Name.Apply(name => $"accessPolicies/{name}/servicePerimeters/"),
                Title = "",
                Status = new Gcp.AccessContextManager.Inputs.ServicePerimetersServicePerimeterStatusArgs
                {
                    RestrictedServices = new[]
                    {
                        "bigtable.googleapis.com",
                    },
                    VpcAccessibleServices = new Gcp.AccessContextManager.Inputs.ServicePerimetersServicePerimeterStatusVpcAccessibleServicesArgs
                    {
                        EnableRestriction = true,
                        AllowedServices = new[]
                        {
                            "bigquery.googleapis.com",
                        },
                    },
                },
            },
        },
    });

    var access_level = new Gcp.AccessContextManager.AccessLevel("access-level", new()
    {
        Parent = access_policy.Name.Apply(name => $"accessPolicies/{name}"),
        Name = access_policy.Name.Apply(name => $"accessPolicies/{name}/accessLevels/secure_data_exchange"),
        Title = "secure_data_exchange",
        Basic = new Gcp.AccessContextManager.Inputs.AccessLevelBasicArgs
        {
            Conditions = new[]
            {
                new Gcp.AccessContextManager.Inputs.AccessLevelBasicConditionArgs
                {
                    DevicePolicy = new Gcp.AccessContextManager.Inputs.AccessLevelBasicConditionDevicePolicyArgs
                    {
                        RequireScreenLock = false,
                        OsConstraints = new[]
                        {
                            new Gcp.AccessContextManager.Inputs.AccessLevelBasicConditionDevicePolicyOsConstraintArgs
                            {
                                OsType = "DESKTOP_CHROME_OS",
                            },
                        },
                    },
                    Regions = new[]
                    {
                        "CH",
                        "IT",
                        "US",
                    },
                },
            },
        },
    });

    var test_access = new Gcp.AccessContextManager.ServicePerimeter("test-access", new()
    {
        Parent = $"accessPolicies/{test_accessGoogleAccessContextManagerAccessPolicy.Name}",
        Name = $"accessPolicies/{test_accessGoogleAccessContextManagerAccessPolicy.Name}/servicePerimeters/%s",
        Title = "%s",
        PerimeterType = "PERIMETER_TYPE_REGULAR",
        Status = new Gcp.AccessContextManager.Inputs.ServicePerimeterStatusArgs
        {
            RestrictedServices = new[]
            {
                "bigquery.googleapis.com",
                "storage.googleapis.com",
            },
            AccessLevels = new[]
            {
                access_level.Name,
            },
            VpcAccessibleServices = new Gcp.AccessContextManager.Inputs.ServicePerimeterStatusVpcAccessibleServicesArgs
            {
                EnableRestriction = true,
                AllowedServices = new[]
                {
                    "bigquery.googleapis.com",
                    "storage.googleapis.com",
                },
            },
            IngressPolicies = new[]
            {
                new Gcp.AccessContextManager.Inputs.ServicePerimeterStatusIngressPolicyArgs
                {
                    IngressFrom = new Gcp.AccessContextManager.Inputs.ServicePerimeterStatusIngressPolicyIngressFromArgs
                    {
                        Sources = new[]
                        {
                            new Gcp.AccessContextManager.Inputs.ServicePerimeterStatusIngressPolicyIngressFromSourceArgs
                            {
                                AccessLevel = test_accessGoogleAccessContextManagerAccessLevel.Name,
                            },
                        },
                        IdentityType = "ANY_IDENTITY",
                    },
                    IngressTo = new Gcp.AccessContextManager.Inputs.ServicePerimeterStatusIngressPolicyIngressToArgs
                    {
                        Resources = new[]
                        {
                            "*",
                        },
                        Operations = new[]
                        {
                            new Gcp.AccessContextManager.Inputs.ServicePerimeterStatusIngressPolicyIngressToOperationArgs
                            {
                                ServiceName = "bigquery.googleapis.com",
                                MethodSelectors = new[]
                                {
                                    new Gcp.AccessContextManager.Inputs.ServicePerimeterStatusIngressPolicyIngressToOperationMethodSelectorArgs
                                    {
                                        Method = "BigQueryStorage.ReadRows",
                                    },
                                    new Gcp.AccessContextManager.Inputs.ServicePerimeterStatusIngressPolicyIngressToOperationMethodSelectorArgs
                                    {
                                        Method = "TableService.ListTables",
                                    },
                                    new Gcp.AccessContextManager.Inputs.ServicePerimeterStatusIngressPolicyIngressToOperationMethodSelectorArgs
                                    {
                                        Permission = "bigquery.jobs.get",
                                    },
                                },
                            },
                            new Gcp.AccessContextManager.Inputs.ServicePerimeterStatusIngressPolicyIngressToOperationArgs
                            {
                                ServiceName = "storage.googleapis.com",
                                MethodSelectors = new[]
                                {
                                    new Gcp.AccessContextManager.Inputs.ServicePerimeterStatusIngressPolicyIngressToOperationMethodSelectorArgs
                                    {
                                        Method = "google.storage.objects.create",
                                    },
                                },
                            },
                        },
                    },
                },
            },
            EgressPolicies = new[]
            {
                new Gcp.AccessContextManager.Inputs.ServicePerimeterStatusEgressPolicyArgs
                {
                    EgressFrom = new Gcp.AccessContextManager.Inputs.ServicePerimeterStatusEgressPolicyEgressFromArgs
                    {
                        IdentityType = "ANY_USER_ACCOUNT",
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.accesscontextmanager.AccessPolicy;
import com.pulumi.gcp.accesscontextmanager.AccessPolicyArgs;
import com.pulumi.gcp.accesscontextmanager.ServicePerimeters;
import com.pulumi.gcp.accesscontextmanager.ServicePerimetersArgs;
import com.pulumi.gcp.accesscontextmanager.inputs.ServicePerimetersServicePerimeterArgs;
import com.pulumi.gcp.accesscontextmanager.inputs.ServicePerimetersServicePerimeterStatusArgs;
import com.pulumi.gcp.accesscontextmanager.inputs.ServicePerimetersServicePerimeterStatusVpcAccessibleServicesArgs;
import com.pulumi.gcp.accesscontextmanager.AccessLevel;
import com.pulumi.gcp.accesscontextmanager.AccessLevelArgs;
import com.pulumi.gcp.accesscontextmanager.inputs.AccessLevelBasicArgs;
import com.pulumi.gcp.accesscontextmanager.ServicePerimeter;
import com.pulumi.gcp.accesscontextmanager.ServicePerimeterArgs;
import com.pulumi.gcp.accesscontextmanager.inputs.ServicePerimeterStatusArgs;
import com.pulumi.gcp.accesscontextmanager.inputs.ServicePerimeterStatusVpcAccessibleServicesArgs;
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 access_policy = new AccessPolicy("access-policy", AccessPolicyArgs.builder()
            .parent("organizations/123456789")
            .title("my policy")
            .build());

        var secure_data_exchange = new ServicePerimeters("secure-data-exchange", ServicePerimetersArgs.builder()
            .parent(access_policy.name().applyValue(_name -> String.format("accessPolicies/%s", _name)))
            .servicePerimeters(            
                ServicePerimetersServicePerimeterArgs.builder()
                    .name(access_policy.name().applyValue(_name -> String.format("accessPolicies/%s/servicePerimeters/", _name)))
                    .title("")
                    .status(ServicePerimetersServicePerimeterStatusArgs.builder()
                        .restrictedServices("storage.googleapis.com")
                        .build())
                    .build(),
                ServicePerimetersServicePerimeterArgs.builder()
                    .name(access_policy.name().applyValue(_name -> String.format("accessPolicies/%s/servicePerimeters/", _name)))
                    .title("")
                    .status(ServicePerimetersServicePerimeterStatusArgs.builder()
                        .restrictedServices("bigtable.googleapis.com")
                        .vpcAccessibleServices(ServicePerimetersServicePerimeterStatusVpcAccessibleServicesArgs.builder()
                            .enableRestriction(true)
                            .allowedServices("bigquery.googleapis.com")
                            .build())
                        .build())
                    .build())
            .build());

        var access_level = new AccessLevel("access-level", AccessLevelArgs.builder()
            .parent(access_policy.name().applyValue(_name -> String.format("accessPolicies/%s", _name)))
            .name(access_policy.name().applyValue(_name -> String.format("accessPolicies/%s/accessLevels/secure_data_exchange", _name)))
            .title("secure_data_exchange")
            .basic(AccessLevelBasicArgs.builder()
                .conditions(AccessLevelBasicConditionArgs.builder()
                    .devicePolicy(AccessLevelBasicConditionDevicePolicyArgs.builder()
                        .requireScreenLock(false)
                        .osConstraints(AccessLevelBasicConditionDevicePolicyOsConstraintArgs.builder()
                            .osType("DESKTOP_CHROME_OS")
                            .build())
                        .build())
                    .regions(                    
                        "CH",
                        "IT",
                        "US")
                    .build())
                .build())
            .build());

        var test_access = new ServicePerimeter("test-access", ServicePerimeterArgs.builder()
            .parent(String.format("accessPolicies/%s", test_accessGoogleAccessContextManagerAccessPolicy.name()))
            .name(String.format("accessPolicies/%s/servicePerimeters/%s", test_accessGoogleAccessContextManagerAccessPolicy.name()))
            .title("%s")
            .perimeterType("PERIMETER_TYPE_REGULAR")
            .status(ServicePerimeterStatusArgs.builder()
                .restrictedServices(                
                    "bigquery.googleapis.com",
                    "storage.googleapis.com")
                .accessLevels(access_level.name())
                .vpcAccessibleServices(ServicePerimeterStatusVpcAccessibleServicesArgs.builder()
                    .enableRestriction(true)
                    .allowedServices(                    
                        "bigquery.googleapis.com",
                        "storage.googleapis.com")
                    .build())
                .ingressPolicies(ServicePerimeterStatusIngressPolicyArgs.builder()
                    .ingressFrom(ServicePerimeterStatusIngressPolicyIngressFromArgs.builder()
                        .sources(ServicePerimeterStatusIngressPolicyIngressFromSourceArgs.builder()
                            .accessLevel(test_accessGoogleAccessContextManagerAccessLevel.name())
                            .build())
                        .identityType("ANY_IDENTITY")
                        .build())
                    .ingressTo(ServicePerimeterStatusIngressPolicyIngressToArgs.builder()
                        .resources("*")
                        .operations(                        
                            ServicePerimeterStatusIngressPolicyIngressToOperationArgs.builder()
                                .serviceName("bigquery.googleapis.com")
                                .methodSelectors(                                
                                    ServicePerimeterStatusIngressPolicyIngressToOperationMethodSelectorArgs.builder()
                                        .method("BigQueryStorage.ReadRows")
                                        .build(),
                                    ServicePerimeterStatusIngressPolicyIngressToOperationMethodSelectorArgs.builder()
                                        .method("TableService.ListTables")
                                        .build(),
                                    ServicePerimeterStatusIngressPolicyIngressToOperationMethodSelectorArgs.builder()
                                        .permission("bigquery.jobs.get")
                                        .build())
                                .build(),
                            ServicePerimeterStatusIngressPolicyIngressToOperationArgs.builder()
                                .serviceName("storage.googleapis.com")
                                .methodSelectors(ServicePerimeterStatusIngressPolicyIngressToOperationMethodSelectorArgs.builder()
                                    .method("google.storage.objects.create")
                                    .build())
                                .build())
                        .build())
                    .build())
                .egressPolicies(ServicePerimeterStatusEgressPolicyArgs.builder()
                    .egressFrom(ServicePerimeterStatusEgressPolicyEgressFromArgs.builder()
                        .identityType("ANY_USER_ACCOUNT")
                        .build())
                    .build())
                .build())
            .build());

    }
}
resources:
  secure-data-exchange:
    type: gcp:accesscontextmanager:ServicePerimeters
    properties:
      parent: accessPolicies/${["access-policy"].name}
      servicePerimeters:
        - name: accessPolicies/${["access-policy"].name}/servicePerimeters/
          title: ""
          status:
            restrictedServices:
              - storage.googleapis.com
        - name: accessPolicies/${["access-policy"].name}/servicePerimeters/
          title: ""
          status:
            restrictedServices:
              - bigtable.googleapis.com
            vpcAccessibleServices:
              enableRestriction: true
              allowedServices:
                - bigquery.googleapis.com
  access-level:
    type: gcp:accesscontextmanager:AccessLevel
    properties:
      parent: accessPolicies/${["access-policy"].name}
      name: accessPolicies/${["access-policy"].name}/accessLevels/secure_data_exchange
      title: secure_data_exchange
      basic:
        conditions:
          - devicePolicy:
              requireScreenLock: false
              osConstraints:
                - osType: DESKTOP_CHROME_OS
            regions:
              - CH
              - IT
              - US
  access-policy:
    type: gcp:accesscontextmanager:AccessPolicy
    properties:
      parent: organizations/123456789
      title: my policy
  test-access:
    type: gcp:accesscontextmanager:ServicePerimeter
    properties:
      parent: accessPolicies/${["test-accessGoogleAccessContextManagerAccessPolicy"].name}
      name: accessPolicies/${["test-accessGoogleAccessContextManagerAccessPolicy"].name}/servicePerimeters/%s
      title: '%s'
      perimeterType: PERIMETER_TYPE_REGULAR
      status:
        restrictedServices:
          - bigquery.googleapis.com
          - storage.googleapis.com
        accessLevels:
          - ${["access-level"].name}
        vpcAccessibleServices:
          enableRestriction: true
          allowedServices:
            - bigquery.googleapis.com
            - storage.googleapis.com
        ingressPolicies:
          - ingressFrom:
              sources:
                - accessLevel: ${["test-accessGoogleAccessContextManagerAccessLevel"].name}
              identityType: ANY_IDENTITY
            ingressTo:
              resources:
                - '*'
              operations:
                - serviceName: bigquery.googleapis.com
                  methodSelectors:
                    - method: BigQueryStorage.ReadRows
                    - method: TableService.ListTables
                    - permission: bigquery.jobs.get
                - serviceName: storage.googleapis.com
                  methodSelectors:
                    - method: google.storage.objects.create
        egressPolicies:
          - egressFrom:
              identityType: ANY_USER_ACCOUNT

Ingress policies define allowed inbound traffic. The ingressFrom block specifies source access levels and identity types; ingressTo lists target resources and allowed operations. The operations array uses methodSelectors to permit specific API methods (like BigQuery.ReadRows) or IAM permissions. Egress policies control outbound traffic using similar structures.

Test perimeter changes without enforcement

Before enforcing new restrictions, teams validate that policies won’t break existing workflows.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const access_policy = new gcp.accesscontextmanager.AccessPolicy("access-policy", {
    parent: "organizations/123456789",
    title: "my policy",
});
const service_perimeter = new gcp.accesscontextmanager.ServicePerimeter("service-perimeter", {
    parent: pulumi.interpolate`accessPolicies/${access_policy.name}`,
    name: pulumi.interpolate`accessPolicies/${access_policy.name}/servicePerimeters/restrict_bigquery_dryrun_storage`,
    title: "restrict_bigquery_dryrun_storage",
    status: {
        restrictedServices: ["bigquery.googleapis.com"],
    },
    spec: {
        restrictedServices: ["storage.googleapis.com"],
    },
    useExplicitDryRunSpec: true,
});
import pulumi
import pulumi_gcp as gcp

access_policy = gcp.accesscontextmanager.AccessPolicy("access-policy",
    parent="organizations/123456789",
    title="my policy")
service_perimeter = gcp.accesscontextmanager.ServicePerimeter("service-perimeter",
    parent=access_policy.name.apply(lambda name: f"accessPolicies/{name}"),
    name=access_policy.name.apply(lambda name: f"accessPolicies/{name}/servicePerimeters/restrict_bigquery_dryrun_storage"),
    title="restrict_bigquery_dryrun_storage",
    status={
        "restricted_services": ["bigquery.googleapis.com"],
    },
    spec={
        "restricted_services": ["storage.googleapis.com"],
    },
    use_explicit_dry_run_spec=True)
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/accesscontextmanager"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		access_policy, err := accesscontextmanager.NewAccessPolicy(ctx, "access-policy", &accesscontextmanager.AccessPolicyArgs{
			Parent: pulumi.String("organizations/123456789"),
			Title:  pulumi.String("my policy"),
		})
		if err != nil {
			return err
		}
		_, err = accesscontextmanager.NewServicePerimeter(ctx, "service-perimeter", &accesscontextmanager.ServicePerimeterArgs{
			Parent: access_policy.Name.ApplyT(func(name string) (string, error) {
				return fmt.Sprintf("accessPolicies/%v", name), nil
			}).(pulumi.StringOutput),
			Name: access_policy.Name.ApplyT(func(name string) (string, error) {
				return fmt.Sprintf("accessPolicies/%v/servicePerimeters/restrict_bigquery_dryrun_storage", name), nil
			}).(pulumi.StringOutput),
			Title: pulumi.String("restrict_bigquery_dryrun_storage"),
			Status: &accesscontextmanager.ServicePerimeterStatusArgs{
				RestrictedServices: pulumi.StringArray{
					pulumi.String("bigquery.googleapis.com"),
				},
			},
			Spec: &accesscontextmanager.ServicePerimeterSpecArgs{
				RestrictedServices: pulumi.StringArray{
					pulumi.String("storage.googleapis.com"),
				},
			},
			UseExplicitDryRunSpec: 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 access_policy = new Gcp.AccessContextManager.AccessPolicy("access-policy", new()
    {
        Parent = "organizations/123456789",
        Title = "my policy",
    });

    var service_perimeter = new Gcp.AccessContextManager.ServicePerimeter("service-perimeter", new()
    {
        Parent = access_policy.Name.Apply(name => $"accessPolicies/{name}"),
        Name = access_policy.Name.Apply(name => $"accessPolicies/{name}/servicePerimeters/restrict_bigquery_dryrun_storage"),
        Title = "restrict_bigquery_dryrun_storage",
        Status = new Gcp.AccessContextManager.Inputs.ServicePerimeterStatusArgs
        {
            RestrictedServices = new[]
            {
                "bigquery.googleapis.com",
            },
        },
        Spec = new Gcp.AccessContextManager.Inputs.ServicePerimeterSpecArgs
        {
            RestrictedServices = new[]
            {
                "storage.googleapis.com",
            },
        },
        UseExplicitDryRunSpec = true,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.accesscontextmanager.AccessPolicy;
import com.pulumi.gcp.accesscontextmanager.AccessPolicyArgs;
import com.pulumi.gcp.accesscontextmanager.ServicePerimeter;
import com.pulumi.gcp.accesscontextmanager.ServicePerimeterArgs;
import com.pulumi.gcp.accesscontextmanager.inputs.ServicePerimeterStatusArgs;
import com.pulumi.gcp.accesscontextmanager.inputs.ServicePerimeterSpecArgs;
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 access_policy = new AccessPolicy("access-policy", AccessPolicyArgs.builder()
            .parent("organizations/123456789")
            .title("my policy")
            .build());

        var service_perimeter = new ServicePerimeter("service-perimeter", ServicePerimeterArgs.builder()
            .parent(access_policy.name().applyValue(_name -> String.format("accessPolicies/%s", _name)))
            .name(access_policy.name().applyValue(_name -> String.format("accessPolicies/%s/servicePerimeters/restrict_bigquery_dryrun_storage", _name)))
            .title("restrict_bigquery_dryrun_storage")
            .status(ServicePerimeterStatusArgs.builder()
                .restrictedServices("bigquery.googleapis.com")
                .build())
            .spec(ServicePerimeterSpecArgs.builder()
                .restrictedServices("storage.googleapis.com")
                .build())
            .useExplicitDryRunSpec(true)
            .build());

    }
}
resources:
  service-perimeter:
    type: gcp:accesscontextmanager:ServicePerimeter
    properties:
      parent: accessPolicies/${["access-policy"].name}
      name: accessPolicies/${["access-policy"].name}/servicePerimeters/restrict_bigquery_dryrun_storage
      title: restrict_bigquery_dryrun_storage
      status:
        restrictedServices:
          - bigquery.googleapis.com
      spec:
        restrictedServices:
          - storage.googleapis.com
      useExplicitDryRunSpec: true
  access-policy:
    type: gcp:accesscontextmanager:AccessPolicy
    properties:
      parent: organizations/123456789
      title: my policy

The status block holds the currently enforced configuration, while spec defines the proposed changes. Setting useExplicitDryRunSpec to true activates dry-run mode, letting you analyze the impact of adding Storage restrictions without actually blocking traffic. This example tests adding storage.googleapis.com to an existing BigQuery perimeter.

Beyond these examples

These snippets focus on specific perimeter-level features: service restriction and perimeter boundaries, ingress and egress policy configuration, and dry-run testing for policy changes. They’re intentionally minimal rather than full VPC Service Controls deployments.

The examples rely on pre-existing infrastructure such as AccessPolicy (parent resource), AccessLevel resources for ingress/egress rules, and GCP projects to protect. They focus on configuring the perimeter rather than provisioning the surrounding access control hierarchy.

To keep things focused, common perimeter patterns are omitted, including:

  • VPC accessible services (vpcAccessibleServices)
  • Bridge perimeters (PERIMETER_TYPE_BRIDGE)
  • Resource lists (projects, resources arrays)
  • Access level conditions and device policies

These omissions are intentional: the goal is to illustrate how each perimeter feature is wired, not provide drop-in security modules. See the Service Perimeter resource reference for all available configuration options.

Let's configure GCP Access Context Manager Service Perimeters

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Authentication & Permissions
Why am I getting a 403 error when using User ADCs?
When using User Application Default Credentials, you must configure billingProject and set userProjectOverride to true in your provider configuration. Your account also needs the serviceusage.services.use permission on the billing project.
Perimeter Types & Topology
What's the difference between regular and bridge service perimeters?
Regular perimeters (PERIMETER_TYPE_REGULAR) contain resources, access levels, and restricted services. Bridge perimeters (PERIMETER_TYPE_BRIDGE) only contain resources and are used for sharing data between independent perimeters. Regular is the default type.
Can a project belong to multiple service perimeters?
It depends on the perimeter type. A project can belong to only ONE regular perimeter but can belong to multiple bridge perimeters simultaneously.
When should I use bridge perimeters?
Use bridge perimeters when building complex topologies where independent perimeters need to share data with a common perimeter but shouldn’t share data among themselves. Bridges enable cross-project operations when resources share a perimeter.
Configuration & Testing
What's the difference between status and spec?
status is the enforced configuration that actively restricts access. spec is a dry-run configuration for testing changes without enforcement. Use spec to analyze differences between current and proposed restrictions.
How do I test perimeter changes without enforcing them?
Configure the spec property with your proposed changes and set useExplicitDryRunSpec to true. This creates a dry-run version that you can test against the enforced status configuration.
Why do I need to set useExplicitDryRunSpec to true?
You must set useExplicitDryRunSpec to true when configuring any spec fields with non-default values. This flag inhibits the implicit spec generation and allows explicit dry-run configuration.
What properties can't be changed after creation?
The name, parent, and perimeterType properties are immutable and cannot be changed after the service perimeter is created.

Using a different cloud?

Explore security guides for other cloud providers: