The gcp:compute/securityPolicyRule:SecurityPolicyRule resource, part of the Pulumi GCP provider, defines individual rules within a Cloud Armor security policy: their match conditions, actions, and evaluation priority. This guide focuses on three capabilities: IP-based traffic filtering, priority-based rule ordering, and default deny configurations.
Security policy rules belong to a SecurityPolicy resource and are evaluated in priority order, where 0 is the highest priority and 2147483647 is the lowest. The examples are intentionally small. Combine them with your own security policies and application-specific match conditions.
Allow traffic from a specific IP range
Most Cloud Armor deployments start with simple IP-based rules that permit traffic from trusted network ranges.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.compute.SecurityPolicy("default", {
name: "policyruletest",
description: "basic global security policy",
type: "CLOUD_ARMOR",
});
const policyRule = new gcp.compute.SecurityPolicyRule("policy_rule", {
securityPolicy: _default.name,
description: "new rule",
priority: 100,
match: {
versionedExpr: "SRC_IPS_V1",
config: {
srcIpRanges: ["10.10.0.0/16"],
},
},
action: "allow",
preview: true,
});
import pulumi
import pulumi_gcp as gcp
default = gcp.compute.SecurityPolicy("default",
name="policyruletest",
description="basic global security policy",
type="CLOUD_ARMOR")
policy_rule = gcp.compute.SecurityPolicyRule("policy_rule",
security_policy=default.name,
description="new rule",
priority=100,
match={
"versioned_expr": "SRC_IPS_V1",
"config": {
"src_ip_ranges": ["10.10.0.0/16"],
},
},
action="allow",
preview=True)
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 {
_default, err := compute.NewSecurityPolicy(ctx, "default", &compute.SecurityPolicyArgs{
Name: pulumi.String("policyruletest"),
Description: pulumi.String("basic global security policy"),
Type: pulumi.String("CLOUD_ARMOR"),
})
if err != nil {
return err
}
_, err = compute.NewSecurityPolicyRule(ctx, "policy_rule", &compute.SecurityPolicyRuleArgs{
SecurityPolicy: _default.Name,
Description: pulumi.String("new rule"),
Priority: pulumi.Int(100),
Match: &compute.SecurityPolicyRuleMatchArgs{
VersionedExpr: pulumi.String("SRC_IPS_V1"),
Config: &compute.SecurityPolicyRuleMatchConfigArgs{
SrcIpRanges: pulumi.StringArray{
pulumi.String("10.10.0.0/16"),
},
},
},
Action: pulumi.String("allow"),
Preview: 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 @default = new Gcp.Compute.SecurityPolicy("default", new()
{
Name = "policyruletest",
Description = "basic global security policy",
Type = "CLOUD_ARMOR",
});
var policyRule = new Gcp.Compute.SecurityPolicyRule("policy_rule", new()
{
SecurityPolicy = @default.Name,
Description = "new rule",
Priority = 100,
Match = new Gcp.Compute.Inputs.SecurityPolicyRuleMatchArgs
{
VersionedExpr = "SRC_IPS_V1",
Config = new Gcp.Compute.Inputs.SecurityPolicyRuleMatchConfigArgs
{
SrcIpRanges = new[]
{
"10.10.0.0/16",
},
},
},
Action = "allow",
Preview = true,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.SecurityPolicy;
import com.pulumi.gcp.compute.SecurityPolicyArgs;
import com.pulumi.gcp.compute.SecurityPolicyRule;
import com.pulumi.gcp.compute.SecurityPolicyRuleArgs;
import com.pulumi.gcp.compute.inputs.SecurityPolicyRuleMatchArgs;
import com.pulumi.gcp.compute.inputs.SecurityPolicyRuleMatchConfigArgs;
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 default_ = new SecurityPolicy("default", SecurityPolicyArgs.builder()
.name("policyruletest")
.description("basic global security policy")
.type("CLOUD_ARMOR")
.build());
var policyRule = new SecurityPolicyRule("policyRule", SecurityPolicyRuleArgs.builder()
.securityPolicy(default_.name())
.description("new rule")
.priority(100)
.match(SecurityPolicyRuleMatchArgs.builder()
.versionedExpr("SRC_IPS_V1")
.config(SecurityPolicyRuleMatchConfigArgs.builder()
.srcIpRanges("10.10.0.0/16")
.build())
.build())
.action("allow")
.preview(true)
.build());
}
}
resources:
default:
type: gcp:compute:SecurityPolicy
properties:
name: policyruletest
description: basic global security policy
type: CLOUD_ARMOR
policyRule:
type: gcp:compute:SecurityPolicyRule
name: policy_rule
properties:
securityPolicy: ${default.name}
description: new rule
priority: 100
match:
versionedExpr: SRC_IPS_V1
config:
srcIpRanges:
- 10.10.0.0/16
action: allow
preview: true
When a request arrives, Cloud Armor evaluates it against the match condition. The versionedExpr property specifies the match type (SRC_IPS_V1 for IP-based matching), and srcIpRanges lists the CIDR blocks to match. If the source IP falls within 10.10.0.0/16, the action property determines the outcome (allow in this case). The preview property, when set to true, logs matches without enforcing the action, useful for testing rules before activation.
Configure a default deny rule with exceptions
Security policies often follow a deny-by-default approach where all traffic is blocked unless explicitly allowed by higher-priority rules.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.compute.SecurityPolicy("default", {
name: "policyruletest",
description: "basic global security policy",
type: "CLOUD_ARMOR",
});
const defaultRule = new gcp.compute.SecurityPolicyRule("default_rule", {
securityPolicy: _default.name,
description: "default rule",
action: "deny",
priority: 2147483647,
match: {
versionedExpr: "SRC_IPS_V1",
config: {
srcIpRanges: ["*"],
},
},
});
const policyRule = new gcp.compute.SecurityPolicyRule("policy_rule", {
securityPolicy: _default.name,
description: "new rule",
priority: 100,
match: {
versionedExpr: "SRC_IPS_V1",
config: {
srcIpRanges: ["10.10.0.0/16"],
},
},
action: "allow",
preview: true,
});
import pulumi
import pulumi_gcp as gcp
default = gcp.compute.SecurityPolicy("default",
name="policyruletest",
description="basic global security policy",
type="CLOUD_ARMOR")
default_rule = gcp.compute.SecurityPolicyRule("default_rule",
security_policy=default.name,
description="default rule",
action="deny",
priority=2147483647,
match={
"versioned_expr": "SRC_IPS_V1",
"config": {
"src_ip_ranges": ["*"],
},
})
policy_rule = gcp.compute.SecurityPolicyRule("policy_rule",
security_policy=default.name,
description="new rule",
priority=100,
match={
"versioned_expr": "SRC_IPS_V1",
"config": {
"src_ip_ranges": ["10.10.0.0/16"],
},
},
action="allow",
preview=True)
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 {
_default, err := compute.NewSecurityPolicy(ctx, "default", &compute.SecurityPolicyArgs{
Name: pulumi.String("policyruletest"),
Description: pulumi.String("basic global security policy"),
Type: pulumi.String("CLOUD_ARMOR"),
})
if err != nil {
return err
}
_, err = compute.NewSecurityPolicyRule(ctx, "default_rule", &compute.SecurityPolicyRuleArgs{
SecurityPolicy: _default.Name,
Description: pulumi.String("default rule"),
Action: pulumi.String("deny"),
Priority: pulumi.Int(2147483647),
Match: &compute.SecurityPolicyRuleMatchArgs{
VersionedExpr: pulumi.String("SRC_IPS_V1"),
Config: &compute.SecurityPolicyRuleMatchConfigArgs{
SrcIpRanges: pulumi.StringArray{
pulumi.String("*"),
},
},
},
})
if err != nil {
return err
}
_, err = compute.NewSecurityPolicyRule(ctx, "policy_rule", &compute.SecurityPolicyRuleArgs{
SecurityPolicy: _default.Name,
Description: pulumi.String("new rule"),
Priority: pulumi.Int(100),
Match: &compute.SecurityPolicyRuleMatchArgs{
VersionedExpr: pulumi.String("SRC_IPS_V1"),
Config: &compute.SecurityPolicyRuleMatchConfigArgs{
SrcIpRanges: pulumi.StringArray{
pulumi.String("10.10.0.0/16"),
},
},
},
Action: pulumi.String("allow"),
Preview: 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 @default = new Gcp.Compute.SecurityPolicy("default", new()
{
Name = "policyruletest",
Description = "basic global security policy",
Type = "CLOUD_ARMOR",
});
var defaultRule = new Gcp.Compute.SecurityPolicyRule("default_rule", new()
{
SecurityPolicy = @default.Name,
Description = "default rule",
Action = "deny",
Priority = 2147483647,
Match = new Gcp.Compute.Inputs.SecurityPolicyRuleMatchArgs
{
VersionedExpr = "SRC_IPS_V1",
Config = new Gcp.Compute.Inputs.SecurityPolicyRuleMatchConfigArgs
{
SrcIpRanges = new[]
{
"*",
},
},
},
});
var policyRule = new Gcp.Compute.SecurityPolicyRule("policy_rule", new()
{
SecurityPolicy = @default.Name,
Description = "new rule",
Priority = 100,
Match = new Gcp.Compute.Inputs.SecurityPolicyRuleMatchArgs
{
VersionedExpr = "SRC_IPS_V1",
Config = new Gcp.Compute.Inputs.SecurityPolicyRuleMatchConfigArgs
{
SrcIpRanges = new[]
{
"10.10.0.0/16",
},
},
},
Action = "allow",
Preview = true,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.SecurityPolicy;
import com.pulumi.gcp.compute.SecurityPolicyArgs;
import com.pulumi.gcp.compute.SecurityPolicyRule;
import com.pulumi.gcp.compute.SecurityPolicyRuleArgs;
import com.pulumi.gcp.compute.inputs.SecurityPolicyRuleMatchArgs;
import com.pulumi.gcp.compute.inputs.SecurityPolicyRuleMatchConfigArgs;
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 default_ = new SecurityPolicy("default", SecurityPolicyArgs.builder()
.name("policyruletest")
.description("basic global security policy")
.type("CLOUD_ARMOR")
.build());
var defaultRule = new SecurityPolicyRule("defaultRule", SecurityPolicyRuleArgs.builder()
.securityPolicy(default_.name())
.description("default rule")
.action("deny")
.priority(2147483647)
.match(SecurityPolicyRuleMatchArgs.builder()
.versionedExpr("SRC_IPS_V1")
.config(SecurityPolicyRuleMatchConfigArgs.builder()
.srcIpRanges("*")
.build())
.build())
.build());
var policyRule = new SecurityPolicyRule("policyRule", SecurityPolicyRuleArgs.builder()
.securityPolicy(default_.name())
.description("new rule")
.priority(100)
.match(SecurityPolicyRuleMatchArgs.builder()
.versionedExpr("SRC_IPS_V1")
.config(SecurityPolicyRuleMatchConfigArgs.builder()
.srcIpRanges("10.10.0.0/16")
.build())
.build())
.action("allow")
.preview(true)
.build());
}
}
resources:
default:
type: gcp:compute:SecurityPolicy
properties:
name: policyruletest
description: basic global security policy
type: CLOUD_ARMOR
defaultRule:
type: gcp:compute:SecurityPolicyRule
name: default_rule
properties:
securityPolicy: ${default.name}
description: default rule
action: deny
priority: '2147483647'
match:
versionedExpr: SRC_IPS_V1
config:
srcIpRanges:
- '*'
policyRule:
type: gcp:compute:SecurityPolicyRule
name: policy_rule
properties:
securityPolicy: ${default.name}
description: new rule
priority: 100
match:
versionedExpr: SRC_IPS_V1
config:
srcIpRanges:
- 10.10.0.0/16
action: allow
preview: true
The default rule uses priority 2147483647, the lowest possible value, ensuring it’s evaluated last. The srcIpRanges value of “*” matches all traffic. Combined with action set to “deny”, this blocks any request not matched by higher-priority allow rules. In this configuration, traffic from 10.10.0.0/16 is allowed (priority 100), while everything else is denied.
Layer multiple allow rules by priority
Complex policies require multiple rules evaluated in priority order, allowing you to create fine-grained access controls.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.compute.SecurityPolicy("default", {
name: "policywithmultiplerules",
description: "basic global security policy",
type: "CLOUD_ARMOR",
});
const policyRuleOne = new gcp.compute.SecurityPolicyRule("policy_rule_one", {
securityPolicy: _default.name,
description: "new rule one",
priority: 100,
match: {
versionedExpr: "SRC_IPS_V1",
config: {
srcIpRanges: ["10.10.0.0/16"],
},
},
action: "allow",
preview: true,
});
const policyRuleTwo = new gcp.compute.SecurityPolicyRule("policy_rule_two", {
securityPolicy: _default.name,
description: "new rule two",
priority: 101,
match: {
versionedExpr: "SRC_IPS_V1",
config: {
srcIpRanges: [
"192.168.0.0/16",
"10.0.0.0/8",
],
},
},
action: "allow",
preview: true,
});
import pulumi
import pulumi_gcp as gcp
default = gcp.compute.SecurityPolicy("default",
name="policywithmultiplerules",
description="basic global security policy",
type="CLOUD_ARMOR")
policy_rule_one = gcp.compute.SecurityPolicyRule("policy_rule_one",
security_policy=default.name,
description="new rule one",
priority=100,
match={
"versioned_expr": "SRC_IPS_V1",
"config": {
"src_ip_ranges": ["10.10.0.0/16"],
},
},
action="allow",
preview=True)
policy_rule_two = gcp.compute.SecurityPolicyRule("policy_rule_two",
security_policy=default.name,
description="new rule two",
priority=101,
match={
"versioned_expr": "SRC_IPS_V1",
"config": {
"src_ip_ranges": [
"192.168.0.0/16",
"10.0.0.0/8",
],
},
},
action="allow",
preview=True)
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 {
_default, err := compute.NewSecurityPolicy(ctx, "default", &compute.SecurityPolicyArgs{
Name: pulumi.String("policywithmultiplerules"),
Description: pulumi.String("basic global security policy"),
Type: pulumi.String("CLOUD_ARMOR"),
})
if err != nil {
return err
}
_, err = compute.NewSecurityPolicyRule(ctx, "policy_rule_one", &compute.SecurityPolicyRuleArgs{
SecurityPolicy: _default.Name,
Description: pulumi.String("new rule one"),
Priority: pulumi.Int(100),
Match: &compute.SecurityPolicyRuleMatchArgs{
VersionedExpr: pulumi.String("SRC_IPS_V1"),
Config: &compute.SecurityPolicyRuleMatchConfigArgs{
SrcIpRanges: pulumi.StringArray{
pulumi.String("10.10.0.0/16"),
},
},
},
Action: pulumi.String("allow"),
Preview: pulumi.Bool(true),
})
if err != nil {
return err
}
_, err = compute.NewSecurityPolicyRule(ctx, "policy_rule_two", &compute.SecurityPolicyRuleArgs{
SecurityPolicy: _default.Name,
Description: pulumi.String("new rule two"),
Priority: pulumi.Int(101),
Match: &compute.SecurityPolicyRuleMatchArgs{
VersionedExpr: pulumi.String("SRC_IPS_V1"),
Config: &compute.SecurityPolicyRuleMatchConfigArgs{
SrcIpRanges: pulumi.StringArray{
pulumi.String("192.168.0.0/16"),
pulumi.String("10.0.0.0/8"),
},
},
},
Action: pulumi.String("allow"),
Preview: 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 @default = new Gcp.Compute.SecurityPolicy("default", new()
{
Name = "policywithmultiplerules",
Description = "basic global security policy",
Type = "CLOUD_ARMOR",
});
var policyRuleOne = new Gcp.Compute.SecurityPolicyRule("policy_rule_one", new()
{
SecurityPolicy = @default.Name,
Description = "new rule one",
Priority = 100,
Match = new Gcp.Compute.Inputs.SecurityPolicyRuleMatchArgs
{
VersionedExpr = "SRC_IPS_V1",
Config = new Gcp.Compute.Inputs.SecurityPolicyRuleMatchConfigArgs
{
SrcIpRanges = new[]
{
"10.10.0.0/16",
},
},
},
Action = "allow",
Preview = true,
});
var policyRuleTwo = new Gcp.Compute.SecurityPolicyRule("policy_rule_two", new()
{
SecurityPolicy = @default.Name,
Description = "new rule two",
Priority = 101,
Match = new Gcp.Compute.Inputs.SecurityPolicyRuleMatchArgs
{
VersionedExpr = "SRC_IPS_V1",
Config = new Gcp.Compute.Inputs.SecurityPolicyRuleMatchConfigArgs
{
SrcIpRanges = new[]
{
"192.168.0.0/16",
"10.0.0.0/8",
},
},
},
Action = "allow",
Preview = true,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.SecurityPolicy;
import com.pulumi.gcp.compute.SecurityPolicyArgs;
import com.pulumi.gcp.compute.SecurityPolicyRule;
import com.pulumi.gcp.compute.SecurityPolicyRuleArgs;
import com.pulumi.gcp.compute.inputs.SecurityPolicyRuleMatchArgs;
import com.pulumi.gcp.compute.inputs.SecurityPolicyRuleMatchConfigArgs;
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 default_ = new SecurityPolicy("default", SecurityPolicyArgs.builder()
.name("policywithmultiplerules")
.description("basic global security policy")
.type("CLOUD_ARMOR")
.build());
var policyRuleOne = new SecurityPolicyRule("policyRuleOne", SecurityPolicyRuleArgs.builder()
.securityPolicy(default_.name())
.description("new rule one")
.priority(100)
.match(SecurityPolicyRuleMatchArgs.builder()
.versionedExpr("SRC_IPS_V1")
.config(SecurityPolicyRuleMatchConfigArgs.builder()
.srcIpRanges("10.10.0.0/16")
.build())
.build())
.action("allow")
.preview(true)
.build());
var policyRuleTwo = new SecurityPolicyRule("policyRuleTwo", SecurityPolicyRuleArgs.builder()
.securityPolicy(default_.name())
.description("new rule two")
.priority(101)
.match(SecurityPolicyRuleMatchArgs.builder()
.versionedExpr("SRC_IPS_V1")
.config(SecurityPolicyRuleMatchConfigArgs.builder()
.srcIpRanges(
"192.168.0.0/16",
"10.0.0.0/8")
.build())
.build())
.action("allow")
.preview(true)
.build());
}
}
resources:
default:
type: gcp:compute:SecurityPolicy
properties:
name: policywithmultiplerules
description: basic global security policy
type: CLOUD_ARMOR
policyRuleOne:
type: gcp:compute:SecurityPolicyRule
name: policy_rule_one
properties:
securityPolicy: ${default.name}
description: new rule one
priority: 100
match:
versionedExpr: SRC_IPS_V1
config:
srcIpRanges:
- 10.10.0.0/16
action: allow
preview: true
policyRuleTwo:
type: gcp:compute:SecurityPolicyRule
name: policy_rule_two
properties:
securityPolicy: ${default.name}
description: new rule two
priority: 101
match:
versionedExpr: SRC_IPS_V1
config:
srcIpRanges:
- 192.168.0.0/16
- 10.0.0.0/8
action: allow
preview: true
Rules are evaluated from lowest to highest priority number. Here, priority 100 allows 10.10.0.0/16, and priority 101 allows both 192.168.0.0/16 and 10.0.0.0/8. If a request matches multiple rules, the lowest priority number wins. This lets you create exceptions (low priority numbers) before broader rules (higher priority numbers).
Beyond these examples
These snippets focus on specific security policy rule features: IP-based traffic filtering, priority-based rule evaluation, and default deny policies. They’re intentionally minimal rather than full security configurations.
The examples reference pre-existing infrastructure such as Cloud Armor SecurityPolicy resources. They focus on configuring individual rules rather than provisioning the entire security policy.
To keep things focused, common rule patterns are omitted, including:
- Rate limiting and banning (rateLimitOptions)
- reCAPTCHA and redirect actions (redirectOptions)
- Header manipulation (headerAction)
- Preconfigured WAF rules (preconfiguredWafConfig)
These omissions are intentional: the goal is to illustrate how each rule feature is wired, not provide drop-in security modules. See the SecurityPolicyRule resource reference for all available configuration options.
Let's configure GCP Cloud Armor Security Policy Rules
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Rule Configuration & Actions
allow, deny(STATUS) (where STATUS is 403, 404, or 502), rate_based_ban, redirect, and throttle.rate_based_ban and throttle actions require rateLimitOptions to be set, or the rule will fail.redirect action, redirectOptions, and headerAction are only supported in Global Security Policies with type: CLOUD_ARMOR.Priority & Evaluation Order
2147483647 (the lowest priority) with srcIpRanges: ["*"] to create a catch-all rule that matches all traffic.Testing & Preview Mode
preview: true to evaluate the rule without enforcing the action. This lets you test rule behavior before enabling enforcement.Immutability & Updates
priority, securityPolicy, and project properties are immutable and require resource replacement if changed.Traffic Matching
srcIpRanges: ["*"] in the match config to match all traffic.srcIpRanges, such as ["192.168.0.0/16", "10.0.0.0/8"].