The gcp:compute/regionSecurityPolicy:RegionSecurityPolicy resource, part of the Pulumi GCP provider, defines a regional Cloud Armor security policy that filters traffic to backend services, load balancers, or instances. This guide focuses on three capabilities: HTTP request filtering with rules, network-layer DDoS protection, and custom packet field extraction.
Security policies are created independently but must be attached to backend services, target pools, or instances to take effect. The examples are intentionally small. Combine them with your own backend infrastructure and attach policies using the appropriate resource properties.
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 applies. CLOUD_ARMOR policies filter HTTP requests before they reach backend services. Without explicit rules, Cloud Armor creates a default allow-all rule automatically.
Filter requests with reCAPTCHA and IP-based rules
Applications often block suspicious traffic based on reCAPTCHA scores or source IP addresses.
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
Cloud Armor evaluates rules in priority order (lowest number first). The first rule denies requests to /login.html when reCAPTCHA scores fall below 0.2. The match.expr.expression property accepts CEL (Common Expression Language) for flexible filtering. The second rule with priority 2147483647 serves as the default rule, required by Cloud Armor. Here it denies all traffic not matched by higher-priority rules.
Enable advanced DDoS protection for network traffic
Network-layer attacks require specialized protection below the HTTP layer.
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 shifts protection to the network layer, defending load balancers and instances with external IPs. The ddosProtectionConfig enables advanced DDoS mitigation that analyzes packet patterns and traffic volume. This configuration protects against volumetric attacks that HTTP-layer policies cannot detect.
Extract custom packet fields for network filtering
Some protocols require inspection of specific byte ranges in UDP or TCP packets.
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 bytes from packet headers for matching in rules. Each field specifies a base protocol (UDP, TCP, IPv4, IPv6), an offset in bytes from the header start, a size (1-4 bytes), and an optional mask to select specific bits. The name property creates an identifier you reference in rule match conditions. This enables protocol-specific filtering beyond standard IP and port matching.
Beyond these examples
These snippets focus on specific security policy features: HTTP and network-layer policy types, rule-based filtering with priorities, and DDoS protection and custom packet inspection. They’re intentionally minimal rather than full security configurations.
The examples may reference pre-existing infrastructure such as GCP project and region, and backend services or load balancers to attach policies to. They focus on configuring the policy rather than provisioning the protected infrastructure.
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
- Preconfigured WAF rules and threat intelligence
These omissions are intentional: the goal is to illustrate how each security policy feature is wired, not provide drop-in protection 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.Rules & Default Behavior
Immutability & Constraints
name, project, region, and type properties are all immutable and can only be set at resource creation time.[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?, meaning it starts with a lowercase letter, followed by lowercase letters, digits, or hyphens, and cannot end with a hyphen.Advanced Features
CLOUD_ARMOR_NETWORK policies.ddosProtectionConfig with the desired protection level. Use type: "CLOUD_ARMOR_NETWORK" and set ddosProtectionConfig.ddosProtection to your preferred level (e.g., “ADVANCED_PREVIEW”).token.recaptcha_session.score < 0.2 in the match.expr.expression field to filter requests based on reCAPTCHA scores.