The aws:cfg/recorder:Recorder resource, part of the Pulumi AWS provider, defines an AWS Config recorder that captures resource configuration changes across your account. This guide focuses on three capabilities: basic recorder setup, resource type filtering, and recording frequency control.
Config recorders require an IAM role with appropriate permissions and don’t start automatically. You must create a delivery channel and use the RecorderStatus resource to activate recording. The examples are intentionally small. Combine them with your own delivery channel and activation logic.
Create a recorder with minimal configuration
AWS Config tracks resource configuration changes across your account, capturing snapshots and sending them to a delivery channel.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const assumeRole = aws.iam.getPolicyDocument({
statements: [{
effect: "Allow",
principals: [{
type: "Service",
identifiers: ["config.amazonaws.com"],
}],
actions: ["sts:AssumeRole"],
}],
});
const r = new aws.iam.Role("r", {
name: "awsconfig-example",
assumeRolePolicy: assumeRole.then(assumeRole => assumeRole.json),
});
const foo = new aws.cfg.Recorder("foo", {
name: "example",
roleArn: r.arn,
});
import pulumi
import pulumi_aws as aws
assume_role = aws.iam.get_policy_document(statements=[{
"effect": "Allow",
"principals": [{
"type": "Service",
"identifiers": ["config.amazonaws.com"],
}],
"actions": ["sts:AssumeRole"],
}])
r = aws.iam.Role("r",
name="awsconfig-example",
assume_role_policy=assume_role.json)
foo = aws.cfg.Recorder("foo",
name="example",
role_arn=r.arn)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cfg"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iam"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
assumeRole, err := iam.GetPolicyDocument(ctx, &iam.GetPolicyDocumentArgs{
Statements: []iam.GetPolicyDocumentStatement{
{
Effect: pulumi.StringRef("Allow"),
Principals: []iam.GetPolicyDocumentStatementPrincipal{
{
Type: "Service",
Identifiers: []string{
"config.amazonaws.com",
},
},
},
Actions: []string{
"sts:AssumeRole",
},
},
},
}, nil)
if err != nil {
return err
}
r, err := iam.NewRole(ctx, "r", &iam.RoleArgs{
Name: pulumi.String("awsconfig-example"),
AssumeRolePolicy: pulumi.String(assumeRole.Json),
})
if err != nil {
return err
}
_, err = cfg.NewRecorder(ctx, "foo", &cfg.RecorderArgs{
Name: pulumi.String("example"),
RoleArn: r.Arn,
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var assumeRole = Aws.Iam.GetPolicyDocument.Invoke(new()
{
Statements = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementInputArgs
{
Effect = "Allow",
Principals = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementPrincipalInputArgs
{
Type = "Service",
Identifiers = new[]
{
"config.amazonaws.com",
},
},
},
Actions = new[]
{
"sts:AssumeRole",
},
},
},
});
var r = new Aws.Iam.Role("r", new()
{
Name = "awsconfig-example",
AssumeRolePolicy = assumeRole.Apply(getPolicyDocumentResult => getPolicyDocumentResult.Json),
});
var foo = new Aws.Cfg.Recorder("foo", new()
{
Name = "example",
RoleArn = r.Arn,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.iam.IamFunctions;
import com.pulumi.aws.iam.inputs.GetPolicyDocumentArgs;
import com.pulumi.aws.iam.Role;
import com.pulumi.aws.iam.RoleArgs;
import com.pulumi.aws.cfg.Recorder;
import com.pulumi.aws.cfg.RecorderArgs;
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) {
final var assumeRole = IamFunctions.getPolicyDocument(GetPolicyDocumentArgs.builder()
.statements(GetPolicyDocumentStatementArgs.builder()
.effect("Allow")
.principals(GetPolicyDocumentStatementPrincipalArgs.builder()
.type("Service")
.identifiers("config.amazonaws.com")
.build())
.actions("sts:AssumeRole")
.build())
.build());
var r = new Role("r", RoleArgs.builder()
.name("awsconfig-example")
.assumeRolePolicy(assumeRole.json())
.build());
var foo = new Recorder("foo", RecorderArgs.builder()
.name("example")
.roleArn(r.arn())
.build());
}
}
resources:
foo:
type: aws:cfg:Recorder
properties:
name: example
roleArn: ${r.arn}
r:
type: aws:iam:Role
properties:
name: awsconfig-example
assumeRolePolicy: ${assumeRole.json}
variables:
assumeRole:
fn::invoke:
function: aws:iam:getPolicyDocument
arguments:
statements:
- effect: Allow
principals:
- type: Service
identifiers:
- config.amazonaws.com
actions:
- sts:AssumeRole
The roleArn grants Config permissions to read resource configurations and write to the delivery channel. The name defaults to “default” if omitted. This example creates the IAM role inline with the basic assume-role policy Config requires.
Exclude specific resource types from recording
Large accounts reduce Config costs by excluding high-churn resources from continuous tracking.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const foo = new aws.cfg.Recorder("foo", {
name: "example",
roleArn: r.arn,
recordingGroup: {
allSupported: false,
exclusionByResourceTypes: [{
resourceTypes: ["AWS::EC2::Instance"],
}],
recordingStrategies: [{
useOnly: "EXCLUSION_BY_RESOURCE_TYPES",
}],
},
});
import pulumi
import pulumi_aws as aws
foo = aws.cfg.Recorder("foo",
name="example",
role_arn=r["arn"],
recording_group={
"all_supported": False,
"exclusion_by_resource_types": [{
"resource_types": ["AWS::EC2::Instance"],
}],
"recording_strategies": [{
"use_only": "EXCLUSION_BY_RESOURCE_TYPES",
}],
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cfg"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := cfg.NewRecorder(ctx, "foo", &cfg.RecorderArgs{
Name: pulumi.String("example"),
RoleArn: pulumi.Any(r.Arn),
RecordingGroup: &cfg.RecorderRecordingGroupArgs{
AllSupported: pulumi.Bool(false),
ExclusionByResourceTypes: cfg.RecorderRecordingGroupExclusionByResourceTypeArray{
&cfg.RecorderRecordingGroupExclusionByResourceTypeArgs{
ResourceTypes: pulumi.StringArray{
pulumi.String("AWS::EC2::Instance"),
},
},
},
RecordingStrategies: cfg.RecorderRecordingGroupRecordingStrategyArray{
&cfg.RecorderRecordingGroupRecordingStrategyArgs{
UseOnly: pulumi.String("EXCLUSION_BY_RESOURCE_TYPES"),
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var foo = new Aws.Cfg.Recorder("foo", new()
{
Name = "example",
RoleArn = r.Arn,
RecordingGroup = new Aws.Cfg.Inputs.RecorderRecordingGroupArgs
{
AllSupported = false,
ExclusionByResourceTypes = new[]
{
new Aws.Cfg.Inputs.RecorderRecordingGroupExclusionByResourceTypeArgs
{
ResourceTypes = new[]
{
"AWS::EC2::Instance",
},
},
},
RecordingStrategies = new[]
{
new Aws.Cfg.Inputs.RecorderRecordingGroupRecordingStrategyArgs
{
UseOnly = "EXCLUSION_BY_RESOURCE_TYPES",
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cfg.Recorder;
import com.pulumi.aws.cfg.RecorderArgs;
import com.pulumi.aws.cfg.inputs.RecorderRecordingGroupArgs;
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 foo = new Recorder("foo", RecorderArgs.builder()
.name("example")
.roleArn(r.arn())
.recordingGroup(RecorderRecordingGroupArgs.builder()
.allSupported(false)
.exclusionByResourceTypes(RecorderRecordingGroupExclusionByResourceTypeArgs.builder()
.resourceTypes("AWS::EC2::Instance")
.build())
.recordingStrategies(RecorderRecordingGroupRecordingStrategyArgs.builder()
.useOnly("EXCLUSION_BY_RESOURCE_TYPES")
.build())
.build())
.build());
}
}
resources:
foo:
type: aws:cfg:Recorder
properties:
name: example
roleArn: ${r.arn}
recordingGroup:
allSupported: false
exclusionByResourceTypes:
- resourceTypes:
- AWS::EC2::Instance
recordingStrategies:
- useOnly: EXCLUSION_BY_RESOURCE_TYPES
The recordingGroup controls which resources Config tracks. Setting allSupported to false lets you use exclusionByResourceTypes to filter out specific types like EC2 instances. The recordingStrategies property tells Config to use exclusion-based filtering rather than inclusion.
Mix continuous and periodic recording frequencies
Some resources need continuous monitoring while others can be checked daily to balance compliance with cost.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const foo = new aws.cfg.Recorder("foo", {
name: "example",
roleArn: r.arn,
recordingGroup: {
allSupported: false,
includeGlobalResourceTypes: false,
resourceTypes: [
"AWS::EC2::Instance",
"AWS::EC2::NetworkInterface",
],
},
recordingMode: {
recordingFrequency: "CONTINUOUS",
recordingModeOverride: {
description: "Only record EC2 network interfaces daily",
resourceTypes: ["AWS::EC2::NetworkInterface"],
recordingFrequency: "DAILY",
},
},
});
import pulumi
import pulumi_aws as aws
foo = aws.cfg.Recorder("foo",
name="example",
role_arn=r["arn"],
recording_group={
"all_supported": False,
"include_global_resource_types": False,
"resource_types": [
"AWS::EC2::Instance",
"AWS::EC2::NetworkInterface",
],
},
recording_mode={
"recording_frequency": "CONTINUOUS",
"recording_mode_override": {
"description": "Only record EC2 network interfaces daily",
"resource_types": ["AWS::EC2::NetworkInterface"],
"recording_frequency": "DAILY",
},
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cfg"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := cfg.NewRecorder(ctx, "foo", &cfg.RecorderArgs{
Name: pulumi.String("example"),
RoleArn: pulumi.Any(r.Arn),
RecordingGroup: &cfg.RecorderRecordingGroupArgs{
AllSupported: pulumi.Bool(false),
IncludeGlobalResourceTypes: pulumi.Bool(false),
ResourceTypes: pulumi.StringArray{
pulumi.String("AWS::EC2::Instance"),
pulumi.String("AWS::EC2::NetworkInterface"),
},
},
RecordingMode: &cfg.RecorderRecordingModeArgs{
RecordingFrequency: pulumi.String("CONTINUOUS"),
RecordingModeOverride: &cfg.RecorderRecordingModeRecordingModeOverrideArgs{
Description: pulumi.String("Only record EC2 network interfaces daily"),
ResourceTypes: pulumi.StringArray{
pulumi.String("AWS::EC2::NetworkInterface"),
},
RecordingFrequency: pulumi.String("DAILY"),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var foo = new Aws.Cfg.Recorder("foo", new()
{
Name = "example",
RoleArn = r.Arn,
RecordingGroup = new Aws.Cfg.Inputs.RecorderRecordingGroupArgs
{
AllSupported = false,
IncludeGlobalResourceTypes = false,
ResourceTypes = new[]
{
"AWS::EC2::Instance",
"AWS::EC2::NetworkInterface",
},
},
RecordingMode = new Aws.Cfg.Inputs.RecorderRecordingModeArgs
{
RecordingFrequency = "CONTINUOUS",
RecordingModeOverride = new Aws.Cfg.Inputs.RecorderRecordingModeRecordingModeOverrideArgs
{
Description = "Only record EC2 network interfaces daily",
ResourceTypes = new[]
{
"AWS::EC2::NetworkInterface",
},
RecordingFrequency = "DAILY",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cfg.Recorder;
import com.pulumi.aws.cfg.RecorderArgs;
import com.pulumi.aws.cfg.inputs.RecorderRecordingGroupArgs;
import com.pulumi.aws.cfg.inputs.RecorderRecordingModeArgs;
import com.pulumi.aws.cfg.inputs.RecorderRecordingModeRecordingModeOverrideArgs;
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 foo = new Recorder("foo", RecorderArgs.builder()
.name("example")
.roleArn(r.arn())
.recordingGroup(RecorderRecordingGroupArgs.builder()
.allSupported(false)
.includeGlobalResourceTypes(false)
.resourceTypes(
"AWS::EC2::Instance",
"AWS::EC2::NetworkInterface")
.build())
.recordingMode(RecorderRecordingModeArgs.builder()
.recordingFrequency("CONTINUOUS")
.recordingModeOverride(RecorderRecordingModeRecordingModeOverrideArgs.builder()
.description("Only record EC2 network interfaces daily")
.resourceTypes("AWS::EC2::NetworkInterface")
.recordingFrequency("DAILY")
.build())
.build())
.build());
}
}
resources:
foo:
type: aws:cfg:Recorder
properties:
name: example
roleArn: ${r.arn}
recordingGroup:
allSupported: false
includeGlobalResourceTypes: false
resourceTypes:
- AWS::EC2::Instance
- AWS::EC2::NetworkInterface
recordingMode:
recordingFrequency: CONTINUOUS
recordingModeOverride:
description: Only record EC2 network interfaces daily
resourceTypes:
- AWS::EC2::NetworkInterface
recordingFrequency: DAILY
The recordingMode sets the default frequency for all resources. The recordingModeOverride applies a different frequency to specific resource types. Here, EC2 instances are tracked continuously while network interfaces are recorded daily, reducing the volume of configuration snapshots.
Beyond these examples
These snippets focus on specific recorder-level features: resource type filtering and exclusion, and recording frequency control. They’re intentionally minimal rather than complete Config deployments.
The examples reference pre-existing infrastructure such as IAM roles with Config service permissions. They focus on configuring the recorder rather than provisioning the full Config pipeline.
To keep things focused, common recorder patterns are omitted, including:
- Delivery channel configuration (separate resource)
- Starting the recorder (requires RecorderStatus resource)
- Global resource recording (includeGlobalResourceTypes)
- Recording strategy combinations beyond exclusion
These omissions are intentional: the goal is to illustrate how each recorder feature is wired, not provide drop-in Config modules. See the Config Recorder resource reference for all available configuration options.
Let's configure AWS Config Recorders
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Setup & Activation
aws.cfg.RecorderStatus to start the recorder after creating both the recorder and its delivery channel.aws.cfg.RecorderStatus exists as a separate resource to start recording after both are created.aws.cfg.RecorderStatus to start the recorder. The recorder won’t begin recording until explicitly started.IAM & Permissions
config.amazonaws.com as the service principal in the assume role policy.Recording Configuration
exclusionByResourceTypes in recordingGroup with the resource types to exclude, and set useOnly to EXCLUSION_BY_RESOURCE_TYPES in recordingStrategies.recordingModeOverride within recordingMode to specify different frequencies (CONTINUOUS or DAILY) for specific resource types.Resource Management
name property is immutable. Changing it will destroy and recreate the recorder, so choose the name carefully during initial creation.Using a different cloud?
Explore monitoring guides for other cloud providers: