The gcp:compute/regionSecurityPolicy:RegionSecurityPolicy resource, part of the Pulumi GCP provider, defines a Cloud Armor security policy that filters traffic at the HTTP or network layer within a specific GCP region. This guide focuses on four capabilities: policy type selection, rule-based request filtering with reCAPTCHA, DDoS protection, and custom packet field extraction.
Security policies are created independently but must be attached to backend services or load balancers to filter traffic. The examples are intentionally small. Combine them with your own backend services and attach policies using separate resources.
Create a basic Cloud Armor security policy
Most deployments start with a minimal policy that establishes the foundation for request filtering.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const region_sec_policy_basic = new gcp.compute.RegionSecurityPolicy("region-sec-policy-basic", {
name: "my-sec-policy-basic",
description: "basic region security policy",
type: "CLOUD_ARMOR",
});
import pulumi
import pulumi_gcp as gcp
region_sec_policy_basic = gcp.compute.RegionSecurityPolicy("region-sec-policy-basic",
name="my-sec-policy-basic",
description="basic region security policy",
type="CLOUD_ARMOR")
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := compute.NewRegionSecurityPolicy(ctx, "region-sec-policy-basic", &compute.RegionSecurityPolicyArgs{
Name: pulumi.String("my-sec-policy-basic"),
Description: pulumi.String("basic region security policy"),
Type: pulumi.String("CLOUD_ARMOR"),
})
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 region_sec_policy_basic = new Gcp.Compute.RegionSecurityPolicy("region-sec-policy-basic", new()
{
Name = "my-sec-policy-basic",
Description = "basic region security policy",
Type = "CLOUD_ARMOR",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.RegionSecurityPolicy;
import com.pulumi.gcp.compute.RegionSecurityPolicyArgs;
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 region_sec_policy_basic = new RegionSecurityPolicy("region-sec-policy-basic", RegionSecurityPolicyArgs.builder()
.name("my-sec-policy-basic")
.description("basic region security policy")
.type("CLOUD_ARMOR")
.build());
}
}
resources:
region-sec-policy-basic:
type: gcp:compute:RegionSecurityPolicy
properties:
name: my-sec-policy-basic
description: basic region security policy
type: CLOUD_ARMOR
The type property determines where the policy operates. CLOUD_ARMOR policies filter HTTP requests before they reach backend services. The policy itself doesn’t include rules yet; you can add them later or let Cloud Armor create a default allow rule.
Filter requests with reCAPTCHA and IP-based rules
Security policies enforce access control through rules that evaluate request properties and block suspicious traffic.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const region_sec_policy_with_rules = new gcp.compute.RegionSecurityPolicy("region-sec-policy-with-rules", {
name: "my-sec-policy-with-rules",
description: "basic region security policy with multiple rules",
type: "CLOUD_ARMOR",
rules: [
{
action: "deny",
priority: 1000,
match: {
expr: {
expression: "request.path.matches(\"/login.html\") && token.recaptcha_session.score < 0.2",
},
},
},
{
action: "deny",
priority: 2147483647,
match: {
versionedExpr: "SRC_IPS_V1",
config: {
srcIpRanges: ["*"],
},
},
description: "default rule",
},
],
});
import pulumi
import pulumi_gcp as gcp
region_sec_policy_with_rules = gcp.compute.RegionSecurityPolicy("region-sec-policy-with-rules",
name="my-sec-policy-with-rules",
description="basic region security policy with multiple rules",
type="CLOUD_ARMOR",
rules=[
{
"action": "deny",
"priority": 1000,
"match": {
"expr": {
"expression": "request.path.matches(\"/login.html\") && token.recaptcha_session.score < 0.2",
},
},
},
{
"action": "deny",
"priority": 2147483647,
"match": {
"versioned_expr": "SRC_IPS_V1",
"config": {
"src_ip_ranges": ["*"],
},
},
"description": "default rule",
},
])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := compute.NewRegionSecurityPolicy(ctx, "region-sec-policy-with-rules", &compute.RegionSecurityPolicyArgs{
Name: pulumi.String("my-sec-policy-with-rules"),
Description: pulumi.String("basic region security policy with multiple rules"),
Type: pulumi.String("CLOUD_ARMOR"),
Rules: compute.RegionSecurityPolicyRuleTypeArray{
&compute.RegionSecurityPolicyRuleTypeArgs{
Action: pulumi.String("deny"),
Priority: pulumi.Int(1000),
Match: &compute.RegionSecurityPolicyRuleMatchArgs{
Expr: &compute.RegionSecurityPolicyRuleMatchExprArgs{
Expression: pulumi.String("request.path.matches(\"/login.html\") && token.recaptcha_session.score < 0.2"),
},
},
},
&compute.RegionSecurityPolicyRuleTypeArgs{
Action: pulumi.String("deny"),
Priority: pulumi.Int(2147483647),
Match: &compute.RegionSecurityPolicyRuleMatchArgs{
VersionedExpr: pulumi.String("SRC_IPS_V1"),
Config: &compute.RegionSecurityPolicyRuleMatchConfigArgs{
SrcIpRanges: pulumi.StringArray{
pulumi.String("*"),
},
},
},
Description: pulumi.String("default rule"),
},
},
})
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 region_sec_policy_with_rules = new Gcp.Compute.RegionSecurityPolicy("region-sec-policy-with-rules", new()
{
Name = "my-sec-policy-with-rules",
Description = "basic region security policy with multiple rules",
Type = "CLOUD_ARMOR",
Rules = new[]
{
new Gcp.Compute.Inputs.RegionSecurityPolicyRuleArgs
{
Action = "deny",
Priority = 1000,
Match = new Gcp.Compute.Inputs.RegionSecurityPolicyRuleMatchArgs
{
Expr = new Gcp.Compute.Inputs.RegionSecurityPolicyRuleMatchExprArgs
{
Expression = "request.path.matches(\"/login.html\") && token.recaptcha_session.score < 0.2",
},
},
},
new Gcp.Compute.Inputs.RegionSecurityPolicyRuleArgs
{
Action = "deny",
Priority = 2147483647,
Match = new Gcp.Compute.Inputs.RegionSecurityPolicyRuleMatchArgs
{
VersionedExpr = "SRC_IPS_V1",
Config = new Gcp.Compute.Inputs.RegionSecurityPolicyRuleMatchConfigArgs
{
SrcIpRanges = new[]
{
"*",
},
},
},
Description = "default rule",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.RegionSecurityPolicy;
import com.pulumi.gcp.compute.RegionSecurityPolicyArgs;
import com.pulumi.gcp.compute.inputs.RegionSecurityPolicyRuleArgs;
import com.pulumi.gcp.compute.inputs.RegionSecurityPolicyRuleMatchArgs;
import com.pulumi.gcp.compute.inputs.RegionSecurityPolicyRuleMatchExprArgs;
import com.pulumi.gcp.compute.inputs.RegionSecurityPolicyRuleMatchConfigArgs;
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 region_sec_policy_with_rules = new RegionSecurityPolicy("region-sec-policy-with-rules", RegionSecurityPolicyArgs.builder()
.name("my-sec-policy-with-rules")
.description("basic region security policy with multiple rules")
.type("CLOUD_ARMOR")
.rules(
RegionSecurityPolicyRuleArgs.builder()
.action("deny")
.priority(1000)
.match(RegionSecurityPolicyRuleMatchArgs.builder()
.expr(RegionSecurityPolicyRuleMatchExprArgs.builder()
.expression("request.path.matches(\"/login.html\") && token.recaptcha_session.score < 0.2")
.build())
.build())
.build(),
RegionSecurityPolicyRuleArgs.builder()
.action("deny")
.priority(2147483647)
.match(RegionSecurityPolicyRuleMatchArgs.builder()
.versionedExpr("SRC_IPS_V1")
.config(RegionSecurityPolicyRuleMatchConfigArgs.builder()
.srcIpRanges("*")
.build())
.build())
.description("default rule")
.build())
.build());
}
}
resources:
region-sec-policy-with-rules:
type: gcp:compute:RegionSecurityPolicy
properties:
name: my-sec-policy-with-rules
description: basic region security policy with multiple rules
type: CLOUD_ARMOR
rules:
- action: deny
priority: '1000'
match:
expr:
expression: request.path.matches("/login.html") && token.recaptcha_session.score < 0.2
- action: deny
priority: '2147483647'
match:
versionedExpr: SRC_IPS_V1
config:
srcIpRanges:
- '*'
description: default rule
Rules execute in priority order (lower numbers first). The first rule blocks requests to /login.html when reCAPTCHA scores fall below 0.2. The expression property uses Common Expression Language (CEL) to combine path matching with reCAPTCHA session scores. The second rule (priority 2147483647) acts as a default deny, blocking all traffic that doesn’t match earlier rules. The versionedExpr field uses predefined expressions; SRC_IPS_V1 matches source IP ranges.
Enable DDoS protection for network policies
Network-layer policies protect load balancing resources from volumetric attacks by analyzing traffic patterns.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const region_sec_policy_ddos_protection = new gcp.compute.RegionSecurityPolicy("region-sec-policy-ddos-protection", {
name: "my-sec-policy-ddos-protection",
description: "with ddos protection config",
type: "CLOUD_ARMOR_NETWORK",
ddosProtectionConfig: {
ddosProtection: "ADVANCED_PREVIEW",
},
});
import pulumi
import pulumi_gcp as gcp
region_sec_policy_ddos_protection = gcp.compute.RegionSecurityPolicy("region-sec-policy-ddos-protection",
name="my-sec-policy-ddos-protection",
description="with ddos protection config",
type="CLOUD_ARMOR_NETWORK",
ddos_protection_config={
"ddos_protection": "ADVANCED_PREVIEW",
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := compute.NewRegionSecurityPolicy(ctx, "region-sec-policy-ddos-protection", &compute.RegionSecurityPolicyArgs{
Name: pulumi.String("my-sec-policy-ddos-protection"),
Description: pulumi.String("with ddos protection config"),
Type: pulumi.String("CLOUD_ARMOR_NETWORK"),
DdosProtectionConfig: &compute.RegionSecurityPolicyDdosProtectionConfigArgs{
DdosProtection: pulumi.String("ADVANCED_PREVIEW"),
},
})
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 region_sec_policy_ddos_protection = new Gcp.Compute.RegionSecurityPolicy("region-sec-policy-ddos-protection", new()
{
Name = "my-sec-policy-ddos-protection",
Description = "with ddos protection config",
Type = "CLOUD_ARMOR_NETWORK",
DdosProtectionConfig = new Gcp.Compute.Inputs.RegionSecurityPolicyDdosProtectionConfigArgs
{
DdosProtection = "ADVANCED_PREVIEW",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.RegionSecurityPolicy;
import com.pulumi.gcp.compute.RegionSecurityPolicyArgs;
import com.pulumi.gcp.compute.inputs.RegionSecurityPolicyDdosProtectionConfigArgs;
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 region_sec_policy_ddos_protection = new RegionSecurityPolicy("region-sec-policy-ddos-protection", RegionSecurityPolicyArgs.builder()
.name("my-sec-policy-ddos-protection")
.description("with ddos protection config")
.type("CLOUD_ARMOR_NETWORK")
.ddosProtectionConfig(RegionSecurityPolicyDdosProtectionConfigArgs.builder()
.ddosProtection("ADVANCED_PREVIEW")
.build())
.build());
}
}
resources:
region-sec-policy-ddos-protection:
type: gcp:compute:RegionSecurityPolicy
properties:
name: my-sec-policy-ddos-protection
description: with ddos protection config
type: CLOUD_ARMOR_NETWORK
ddosProtectionConfig:
ddosProtection: ADVANCED_PREVIEW
The CLOUD_ARMOR_NETWORK type operates at the network layer, filtering packets before they reach backend services or instances. The ddosProtectionConfig enables advanced DDoS mitigation. ADVANCED_PREVIEW provides enhanced protection features during the preview period.
Extract custom packet fields for network filtering
Network policies can inspect arbitrary packet data beyond standard headers for specialized protocol filtering.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const region_sec_policy_user_defined_fields = new gcp.compute.RegionSecurityPolicy("region-sec-policy-user-defined-fields", {
name: "my-sec-policy-user-defined-fields",
description: "with user defined fields",
type: "CLOUD_ARMOR_NETWORK",
userDefinedFields: [
{
name: "SIG1_AT_0",
base: "UDP",
offset: 8,
size: 2,
mask: "0x8F00",
},
{
name: "SIG2_AT_8",
base: "UDP",
offset: 16,
size: 4,
mask: "0xFFFFFFFF",
},
],
});
import pulumi
import pulumi_gcp as gcp
region_sec_policy_user_defined_fields = gcp.compute.RegionSecurityPolicy("region-sec-policy-user-defined-fields",
name="my-sec-policy-user-defined-fields",
description="with user defined fields",
type="CLOUD_ARMOR_NETWORK",
user_defined_fields=[
{
"name": "SIG1_AT_0",
"base": "UDP",
"offset": 8,
"size": 2,
"mask": "0x8F00",
},
{
"name": "SIG2_AT_8",
"base": "UDP",
"offset": 16,
"size": 4,
"mask": "0xFFFFFFFF",
},
])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := compute.NewRegionSecurityPolicy(ctx, "region-sec-policy-user-defined-fields", &compute.RegionSecurityPolicyArgs{
Name: pulumi.String("my-sec-policy-user-defined-fields"),
Description: pulumi.String("with user defined fields"),
Type: pulumi.String("CLOUD_ARMOR_NETWORK"),
UserDefinedFields: compute.RegionSecurityPolicyUserDefinedFieldArray{
&compute.RegionSecurityPolicyUserDefinedFieldArgs{
Name: pulumi.String("SIG1_AT_0"),
Base: pulumi.String("UDP"),
Offset: pulumi.Int(8),
Size: pulumi.Int(2),
Mask: pulumi.String("0x8F00"),
},
&compute.RegionSecurityPolicyUserDefinedFieldArgs{
Name: pulumi.String("SIG2_AT_8"),
Base: pulumi.String("UDP"),
Offset: pulumi.Int(16),
Size: pulumi.Int(4),
Mask: pulumi.String("0xFFFFFFFF"),
},
},
})
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 region_sec_policy_user_defined_fields = new Gcp.Compute.RegionSecurityPolicy("region-sec-policy-user-defined-fields", new()
{
Name = "my-sec-policy-user-defined-fields",
Description = "with user defined fields",
Type = "CLOUD_ARMOR_NETWORK",
UserDefinedFields = new[]
{
new Gcp.Compute.Inputs.RegionSecurityPolicyUserDefinedFieldArgs
{
Name = "SIG1_AT_0",
Base = "UDP",
Offset = 8,
Size = 2,
Mask = "0x8F00",
},
new Gcp.Compute.Inputs.RegionSecurityPolicyUserDefinedFieldArgs
{
Name = "SIG2_AT_8",
Base = "UDP",
Offset = 16,
Size = 4,
Mask = "0xFFFFFFFF",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.RegionSecurityPolicy;
import com.pulumi.gcp.compute.RegionSecurityPolicyArgs;
import com.pulumi.gcp.compute.inputs.RegionSecurityPolicyUserDefinedFieldArgs;
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 region_sec_policy_user_defined_fields = new RegionSecurityPolicy("region-sec-policy-user-defined-fields", RegionSecurityPolicyArgs.builder()
.name("my-sec-policy-user-defined-fields")
.description("with user defined fields")
.type("CLOUD_ARMOR_NETWORK")
.userDefinedFields(
RegionSecurityPolicyUserDefinedFieldArgs.builder()
.name("SIG1_AT_0")
.base("UDP")
.offset(8)
.size(2)
.mask("0x8F00")
.build(),
RegionSecurityPolicyUserDefinedFieldArgs.builder()
.name("SIG2_AT_8")
.base("UDP")
.offset(16)
.size(4)
.mask("0xFFFFFFFF")
.build())
.build());
}
}
resources:
region-sec-policy-user-defined-fields:
type: gcp:compute:RegionSecurityPolicy
properties:
name: my-sec-policy-user-defined-fields
description: with user defined fields
type: CLOUD_ARMOR_NETWORK
userDefinedFields:
- name: SIG1_AT_0
base: UDP
offset: 8
size: 2
mask: 0x8F00
- name: SIG2_AT_8
base: UDP
offset: 16
size: 4
mask: 0xFFFFFFFF
User-defined fields extract specific byte ranges from packets. Each field specifies a base protocol (UDP or TCP), an offset in bytes from the protocol header, and a size. The mask property selects specific bits from the extracted bytes. SIG1_AT_0 extracts 2 bytes starting at offset 8 in the UDP header, applying mask 0x8F00. Rules can then match against these extracted values.
Beyond these examples
These snippets focus on specific security policy features: policy types, rule-based request filtering, and DDoS protection and custom packet inspection. They’re intentionally minimal rather than complete security configurations.
The examples assume pre-existing infrastructure such as GCP project and region configuration, backend services or load balancers to attach policies to, and reCAPTCHA Enterprise keys for reCAPTCHA-based rules. They focus on policy configuration without showing how policies attach to resources.
To keep things focused, common security policy patterns are omitted, including:
- Policy attachment to backend services or load balancers
- Advanced options (JSON parsing, log configuration)
- Rate limiting and adaptive protection
- Custom error responses and redirects
These omissions are intentional: the goal is to illustrate how each security policy feature is wired, not provide drop-in security modules. See the Region Security Policy resource reference for all available configuration options.
Let's configure GCP Cloud Armor Region Security Policies
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Policy Types & Use Cases
CLOUD_ARMOR filters HTTP requests to backend services before they reach origin servers. CLOUD_ARMOR_EDGE filters HTTP requests to backend services and Cloud Storage buckets before serving from Google’s cache. CLOUD_ARMOR_NETWORK filters packets targeting network load balancing resources like backend services, target pools, and instances with external IPs.CLOUD_ARMOR_NETWORK policies. They extract up to 4 bytes from packet headers (IPv4, IPv6, TCP, or UDP) with optional masks for custom matching rules.Rules & Default Behavior
match.expr.expression field with reCAPTCHA session tokens, like token.recaptcha_session.score < 0.2 to deny low-scoring requests.Immutability & Constraints
name, project, region, and type properties cannot be changed after resource creation. Modifying these requires recreating the resource.[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?, starting with a lowercase letter and ending with a letter or digit.Advanced Features
ddosProtectionConfig with the ddosProtection field set to a value like ADVANCED_PREVIEW. This is typically used with CLOUD_ARMOR_NETWORK policies.