The aws:cloudwatch/logAccountPolicy:LogAccountPolicy resource, part of the Pulumi AWS provider, defines account-wide CloudWatch Logs policies that apply data protection, subscription filters, or field indexing across multiple log groups. This guide focuses on three capabilities: data protection and redaction, subscription filter routing, and field indexing for queries.
Account policies operate across all log groups in a region by default. Subscription filter policies require existing CloudWatch Logs destinations like Kinesis streams or Lambda functions. The examples are intentionally small. Combine them with your own log group structure and destinations.
Detect and redact sensitive data across log groups
Organizations handling regulated data need to prevent sensitive information from appearing in CloudWatch Logs. Data protection policies scan incoming log events and either audit or mask detected patterns.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const dataProtection = new aws.cloudwatch.LogAccountPolicy("data_protection", {
policyName: "data-protection",
policyType: "DATA_PROTECTION_POLICY",
policyDocument: JSON.stringify({
Name: "DataProtection",
Version: "2021-06-01",
Statement: [
{
Sid: "Audit",
DataIdentifier: ["arn:aws:dataprotection::aws:data-identifier/EmailAddress"],
Operation: {
Audit: {
FindingsDestination: {},
},
},
},
{
Sid: "Redact",
DataIdentifier: ["arn:aws:dataprotection::aws:data-identifier/EmailAddress"],
Operation: {
Deidentify: {
MaskConfig: {},
},
},
},
],
}),
});
import pulumi
import json
import pulumi_aws as aws
data_protection = aws.cloudwatch.LogAccountPolicy("data_protection",
policy_name="data-protection",
policy_type="DATA_PROTECTION_POLICY",
policy_document=json.dumps({
"Name": "DataProtection",
"Version": "2021-06-01",
"Statement": [
{
"Sid": "Audit",
"DataIdentifier": ["arn:aws:dataprotection::aws:data-identifier/EmailAddress"],
"Operation": {
"Audit": {
"FindingsDestination": {},
},
},
},
{
"Sid": "Redact",
"DataIdentifier": ["arn:aws:dataprotection::aws:data-identifier/EmailAddress"],
"Operation": {
"Deidentify": {
"MaskConfig": {},
},
},
},
],
}))
package main
import (
"encoding/json"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cloudwatch"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
tmpJSON0, err := json.Marshal(map[string]interface{}{
"Name": "DataProtection",
"Version": "2021-06-01",
"Statement": []interface{}{
map[string]interface{}{
"Sid": "Audit",
"DataIdentifier": []string{
"arn:aws:dataprotection::aws:data-identifier/EmailAddress",
},
"Operation": map[string]interface{}{
"Audit": map[string]interface{}{
"FindingsDestination": map[string]interface{}{},
},
},
},
map[string]interface{}{
"Sid": "Redact",
"DataIdentifier": []string{
"arn:aws:dataprotection::aws:data-identifier/EmailAddress",
},
"Operation": map[string]interface{}{
"Deidentify": map[string]interface{}{
"MaskConfig": map[string]interface{}{},
},
},
},
},
})
if err != nil {
return err
}
json0 := string(tmpJSON0)
_, err = cloudwatch.NewLogAccountPolicy(ctx, "data_protection", &cloudwatch.LogAccountPolicyArgs{
PolicyName: pulumi.String("data-protection"),
PolicyType: pulumi.String("DATA_PROTECTION_POLICY"),
PolicyDocument: pulumi.String(json0),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var dataProtection = new Aws.CloudWatch.LogAccountPolicy("data_protection", new()
{
PolicyName = "data-protection",
PolicyType = "DATA_PROTECTION_POLICY",
PolicyDocument = JsonSerializer.Serialize(new Dictionary<string, object?>
{
["Name"] = "DataProtection",
["Version"] = "2021-06-01",
["Statement"] = new[]
{
new Dictionary<string, object?>
{
["Sid"] = "Audit",
["DataIdentifier"] = new[]
{
"arn:aws:dataprotection::aws:data-identifier/EmailAddress",
},
["Operation"] = new Dictionary<string, object?>
{
["Audit"] = new Dictionary<string, object?>
{
["FindingsDestination"] = new Dictionary<string, object?>
{
},
},
},
},
new Dictionary<string, object?>
{
["Sid"] = "Redact",
["DataIdentifier"] = new[]
{
"arn:aws:dataprotection::aws:data-identifier/EmailAddress",
},
["Operation"] = new Dictionary<string, object?>
{
["Deidentify"] = new Dictionary<string, object?>
{
["MaskConfig"] = new Dictionary<string, object?>
{
},
},
},
},
},
}),
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cloudwatch.LogAccountPolicy;
import com.pulumi.aws.cloudwatch.LogAccountPolicyArgs;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var dataProtection = new LogAccountPolicy("dataProtection", LogAccountPolicyArgs.builder()
.policyName("data-protection")
.policyType("DATA_PROTECTION_POLICY")
.policyDocument(serializeJson(
jsonObject(
jsonProperty("Name", "DataProtection"),
jsonProperty("Version", "2021-06-01"),
jsonProperty("Statement", jsonArray(
jsonObject(
jsonProperty("Sid", "Audit"),
jsonProperty("DataIdentifier", jsonArray("arn:aws:dataprotection::aws:data-identifier/EmailAddress")),
jsonProperty("Operation", jsonObject(
jsonProperty("Audit", jsonObject(
jsonProperty("FindingsDestination", jsonObject(
))
))
))
),
jsonObject(
jsonProperty("Sid", "Redact"),
jsonProperty("DataIdentifier", jsonArray("arn:aws:dataprotection::aws:data-identifier/EmailAddress")),
jsonProperty("Operation", jsonObject(
jsonProperty("Deidentify", jsonObject(
jsonProperty("MaskConfig", jsonObject(
))
))
))
)
))
)))
.build());
}
}
resources:
dataProtection:
type: aws:cloudwatch:LogAccountPolicy
name: data_protection
properties:
policyName: data-protection
policyType: DATA_PROTECTION_POLICY
policyDocument:
fn::toJSON:
Name: DataProtection
Version: 2021-06-01
Statement:
- Sid: Audit
DataIdentifier:
- arn:aws:dataprotection::aws:data-identifier/EmailAddress
Operation:
Audit:
FindingsDestination: {}
- Sid: Redact
DataIdentifier:
- arn:aws:dataprotection::aws:data-identifier/EmailAddress
Operation:
Deidentify:
MaskConfig: {}
When log events arrive, CloudWatch scans them against the DataIdentifier patterns. The Audit operation records findings without modifying logs; the Deidentify operation masks matching data with the MaskConfig. This policy applies to all log groups in the account, protecting email addresses automatically.
Route filtered logs to a destination across log groups
Teams often need to forward logs matching specific patterns to external systems. Subscription filter policies apply a single filter and destination to multiple log groups.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const subscriptionFilter = new aws.cloudwatch.LogAccountPolicy("subscription_filter", {
policyName: "subscription-filter",
policyType: "SUBSCRIPTION_FILTER_POLICY",
policyDocument: JSON.stringify({
DestinationArn: test.arn,
FilterPattern: "test",
}),
selectionCriteria: "LogGroupName NOT IN [\"excluded_log_group_name\"]",
});
import pulumi
import json
import pulumi_aws as aws
subscription_filter = aws.cloudwatch.LogAccountPolicy("subscription_filter",
policy_name="subscription-filter",
policy_type="SUBSCRIPTION_FILTER_POLICY",
policy_document=json.dumps({
"DestinationArn": test["arn"],
"FilterPattern": "test",
}),
selection_criteria="LogGroupName NOT IN [\"excluded_log_group_name\"]")
package main
import (
"encoding/json"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cloudwatch"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
tmpJSON0, err := json.Marshal(map[string]interface{}{
"DestinationArn": test.Arn,
"FilterPattern": "test",
})
if err != nil {
return err
}
json0 := string(tmpJSON0)
_, err = cloudwatch.NewLogAccountPolicy(ctx, "subscription_filter", &cloudwatch.LogAccountPolicyArgs{
PolicyName: pulumi.String("subscription-filter"),
PolicyType: pulumi.String("SUBSCRIPTION_FILTER_POLICY"),
PolicyDocument: pulumi.String(json0),
SelectionCriteria: pulumi.String("LogGroupName NOT IN [\"excluded_log_group_name\"]"),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var subscriptionFilter = new Aws.CloudWatch.LogAccountPolicy("subscription_filter", new()
{
PolicyName = "subscription-filter",
PolicyType = "SUBSCRIPTION_FILTER_POLICY",
PolicyDocument = JsonSerializer.Serialize(new Dictionary<string, object?>
{
["DestinationArn"] = test.Arn,
["FilterPattern"] = "test",
}),
SelectionCriteria = "LogGroupName NOT IN [\"excluded_log_group_name\"]",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cloudwatch.LogAccountPolicy;
import com.pulumi.aws.cloudwatch.LogAccountPolicyArgs;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var subscriptionFilter = new LogAccountPolicy("subscriptionFilter", LogAccountPolicyArgs.builder()
.policyName("subscription-filter")
.policyType("SUBSCRIPTION_FILTER_POLICY")
.policyDocument(serializeJson(
jsonObject(
jsonProperty("DestinationArn", test.arn()),
jsonProperty("FilterPattern", "test")
)))
.selectionCriteria("LogGroupName NOT IN [\"excluded_log_group_name\"]")
.build());
}
}
resources:
subscriptionFilter:
type: aws:cloudwatch:LogAccountPolicy
name: subscription_filter
properties:
policyName: subscription-filter
policyType: SUBSCRIPTION_FILTER_POLICY
policyDocument:
fn::toJSON:
DestinationArn: ${test.arn}
FilterPattern: test
selectionCriteria: LogGroupName NOT IN ["excluded_log_group_name"]
The policyDocument specifies the DestinationArn (Kinesis, Firehose, or Lambda) and FilterPattern for matching log events. The selectionCriteria property excludes specific log groups using the LogGroupName NOT IN syntax. This avoids creating individual subscription filters per log group.
Index custom fields for faster log queries
CloudWatch Logs Insights queries scan all log data by default. Field indexing accelerates queries by pre-indexing specific JSON fields.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const fieldIndex = new aws.cloudwatch.LogAccountPolicy("field_index", {
policyName: "field-index",
policyType: "FIELD_INDEX_POLICY",
policyDocument: JSON.stringify({
Fields: [
"field1",
"field2",
],
}),
});
import pulumi
import json
import pulumi_aws as aws
field_index = aws.cloudwatch.LogAccountPolicy("field_index",
policy_name="field-index",
policy_type="FIELD_INDEX_POLICY",
policy_document=json.dumps({
"Fields": [
"field1",
"field2",
],
}))
package main
import (
"encoding/json"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cloudwatch"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
tmpJSON0, err := json.Marshal(map[string]interface{}{
"Fields": []string{
"field1",
"field2",
},
})
if err != nil {
return err
}
json0 := string(tmpJSON0)
_, err = cloudwatch.NewLogAccountPolicy(ctx, "field_index", &cloudwatch.LogAccountPolicyArgs{
PolicyName: pulumi.String("field-index"),
PolicyType: pulumi.String("FIELD_INDEX_POLICY"),
PolicyDocument: pulumi.String(json0),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var fieldIndex = new Aws.CloudWatch.LogAccountPolicy("field_index", new()
{
PolicyName = "field-index",
PolicyType = "FIELD_INDEX_POLICY",
PolicyDocument = JsonSerializer.Serialize(new Dictionary<string, object?>
{
["Fields"] = new[]
{
"field1",
"field2",
},
}),
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cloudwatch.LogAccountPolicy;
import com.pulumi.aws.cloudwatch.LogAccountPolicyArgs;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var fieldIndex = new LogAccountPolicy("fieldIndex", LogAccountPolicyArgs.builder()
.policyName("field-index")
.policyType("FIELD_INDEX_POLICY")
.policyDocument(serializeJson(
jsonObject(
jsonProperty("Fields", jsonArray(
"field1",
"field2"
))
)))
.build());
}
}
resources:
fieldIndex:
type: aws:cloudwatch:LogAccountPolicy
name: field_index
properties:
policyName: field-index
policyType: FIELD_INDEX_POLICY
policyDocument:
fn::toJSON:
Fields:
- field1
- field2
The Fields array lists JSON field names to index across all log groups. CloudWatch pre-processes incoming logs to extract and index these fields, speeding up queries that filter or aggregate on them. This is most useful for high-volume log groups with frequent queries.
Beyond these examples
These snippets focus on specific account policy features: data protection and redaction, subscription filtering with selective application, and field indexing for query performance. They’re intentionally minimal rather than full logging architectures.
The examples may reference pre-existing infrastructure such as CloudWatch Logs destinations (Kinesis, Firehose, Lambda) for subscription filters. They focus on configuring the policy rather than provisioning destinations.
To keep things focused, common policy patterns are omitted, including:
- Transformer policies (TRANSFORMER_POLICY type)
- Scope configuration (currently only accepts ALL)
- Multiple policies per type (limited to one per type per account)
- Cross-region policy management
These omissions are intentional: the goal is to illustrate how each policy type is wired, not provide drop-in logging modules. See the CloudWatch Log Account Policy resource reference for all available configuration options.
Let's configure AWS CloudWatch Log Account 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 & Limits
DATA_PROTECTION_POLICY, SUBSCRIPTION_FILTER_POLICY, FIELD_INDEX_POLICY, and TRANSFORMER_POLICY.Configuration & Immutability
policyName, policyType, and selectionCriteria properties are immutable. Changing any of these forces resource replacement.selectionCriteria with the syntax LogGroupName NOT IN ["excluded_log_group_name"]. This is the only allowable criteria selector format.Policy Document Structure
Name, Version, and Statement array. Each statement includes Sid, DataIdentifier (ARNs), and Operation (either Audit with FindingsDestination or Deidentify with MaskConfig).DestinationArn (where logs are sent) and FilterPattern (log filtering criteria).Fields array containing the field names you want to index.Using a different cloud?
Explore monitoring guides for other cloud providers: