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 log groups. This guide focuses on three capabilities: data protection with sensitive data detection, subscription filters with pattern matching, and field indexing for query optimization.
Account policies operate across all log groups in a region by default. Subscription filter policies can reference destination ARNs that must exist separately. The examples are intentionally small. Combine them with your own log group structure and processing destinations.
Detect and redact sensitive data across log groups
Organizations handling customer data often need to prevent sensitive information from being stored in CloudWatch Logs by scanning and masking 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: {}
The policyDocument defines two operations: Audit tracks where sensitive data appears, and Deidentify masks it using MaskConfig. The DataIdentifier property specifies which patterns to detect (here, email addresses using AWS-managed identifiers). This policy applies to all log groups in the account automatically.
Route logs to destinations with pattern matching
Teams centralizing logs forward specific log groups to Kinesis, Lambda, or Firehose for processing, while excluding certain groups from the filter.
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 (where logs go) and FilterPattern (which events match). The selectionCriteria property uses a NOT IN clause to exclude specific log groups by name. Without selectionCriteria, the filter applies to all log groups.
Index custom fields for faster log queries
Applications logging structured JSON benefit from indexing specific fields to improve CloudWatch Logs Insights query performance.
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 policyDocument lists field names to index. CloudWatch Logs Insights queries against these fields run faster because the service pre-indexes them across all log groups. This is particularly useful for high-cardinality fields you query frequently.
Beyond these examples
These snippets focus on specific account policy features: data protection with audit and redaction, subscription filters with exclusion criteria, and field indexing for query performance. They’re intentionally minimal rather than full logging architectures.
The examples may reference pre-existing infrastructure such as destination ARNs for Kinesis streams, Lambda functions, or Firehose delivery streams. 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)
- Regional policy management (region property)
- Scope configuration (currently only accepts ALL)
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. You can have only one account policy per type in an account.scope property currently defaults to and only accepts the value ALL.Policy Document Structure
Name, Version, and Statement array. Each statement includes DataIdentifier (ARN of data type to detect) and Operation (either Audit with FindingsDestination or Deidentify with MaskConfig).DestinationArn (where logs are sent) and FilterPattern (pattern to match log events).Fields array containing the field names you want to index.Selection & Filtering
selectionCriteria with the format LogGroupName NOT IN ["excluded_log_group_name"]. This is the only allowable criteria selector syntax.Immutability & Updates
policyName, policyType, and selectionCriteria. Changing any of these will force resource replacement.Using a different cloud?
Explore monitoring guides for other cloud providers: