Configure AWS Config Rules

The aws:cfg/rule:Rule resource, part of the Pulumi AWS provider, defines AWS Config rules that evaluate resource configurations against compliance requirements. This guide focuses on three capabilities: AWS managed rules for common checks, custom Lambda functions for organization-specific logic, and Guard policy language for declarative evaluation.

Config rules require an existing Configuration Recorder and IAM roles for the Config service. Custom rules also need Lambda functions or Guard policies. The examples are intentionally small. Combine them with your own Recorder setup and compliance requirements.

Evaluate resources with AWS managed rules

Most Config deployments start with AWS managed rules that check common compliance requirements like S3 versioning or encryption, without requiring custom code.

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 rRole = new aws.iam.Role("r", {
    name: "my-awsconfig-role",
    assumeRolePolicy: assumeRole.then(assumeRole => assumeRole.json),
});
const foo = new aws.cfg.Recorder("foo", {
    name: "example",
    roleArn: rRole.arn,
});
const r = new aws.cfg.Rule("r", {
    name: "example",
    source: {
        owner: "AWS",
        sourceIdentifier: "S3_BUCKET_VERSIONING_ENABLED",
    },
}, {
    dependsOn: [foo],
});
const p = aws.iam.getPolicyDocument({
    statements: [{
        effect: "Allow",
        actions: ["config:Put*"],
        resources: ["*"],
    }],
});
const pRolePolicy = new aws.iam.RolePolicy("p", {
    name: "my-awsconfig-policy",
    role: rRole.id,
    policy: p.then(p => p.json),
});
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_role = aws.iam.Role("r",
    name="my-awsconfig-role",
    assume_role_policy=assume_role.json)
foo = aws.cfg.Recorder("foo",
    name="example",
    role_arn=r_role.arn)
r = aws.cfg.Rule("r",
    name="example",
    source={
        "owner": "AWS",
        "source_identifier": "S3_BUCKET_VERSIONING_ENABLED",
    },
    opts = pulumi.ResourceOptions(depends_on=[foo]))
p = aws.iam.get_policy_document(statements=[{
    "effect": "Allow",
    "actions": ["config:Put*"],
    "resources": ["*"],
}])
p_role_policy = aws.iam.RolePolicy("p",
    name="my-awsconfig-policy",
    role=r_role.id,
    policy=p.json)
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
		}
		rRole, err := iam.NewRole(ctx, "r", &iam.RoleArgs{
			Name:             pulumi.String("my-awsconfig-role"),
			AssumeRolePolicy: pulumi.String(assumeRole.Json),
		})
		if err != nil {
			return err
		}
		foo, err := cfg.NewRecorder(ctx, "foo", &cfg.RecorderArgs{
			Name:    pulumi.String("example"),
			RoleArn: rRole.Arn,
		})
		if err != nil {
			return err
		}
		_, err = cfg.NewRule(ctx, "r", &cfg.RuleArgs{
			Name: pulumi.String("example"),
			Source: &cfg.RuleSourceArgs{
				Owner:            pulumi.String("AWS"),
				SourceIdentifier: pulumi.String("S3_BUCKET_VERSIONING_ENABLED"),
			},
		}, pulumi.DependsOn([]pulumi.Resource{
			foo,
		}))
		if err != nil {
			return err
		}
		p, err := iam.GetPolicyDocument(ctx, &iam.GetPolicyDocumentArgs{
			Statements: []iam.GetPolicyDocumentStatement{
				{
					Effect: pulumi.StringRef("Allow"),
					Actions: []string{
						"config:Put*",
					},
					Resources: []string{
						"*",
					},
				},
			},
		}, nil)
		if err != nil {
			return err
		}
		_, err = iam.NewRolePolicy(ctx, "p", &iam.RolePolicyArgs{
			Name:   pulumi.String("my-awsconfig-policy"),
			Role:   rRole.ID(),
			Policy: pulumi.String(p.Json),
		})
		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 rRole = new Aws.Iam.Role("r", new()
    {
        Name = "my-awsconfig-role",
        AssumeRolePolicy = assumeRole.Apply(getPolicyDocumentResult => getPolicyDocumentResult.Json),
    });

    var foo = new Aws.Cfg.Recorder("foo", new()
    {
        Name = "example",
        RoleArn = rRole.Arn,
    });

    var r = new Aws.Cfg.Rule("r", new()
    {
        Name = "example",
        Source = new Aws.Cfg.Inputs.RuleSourceArgs
        {
            Owner = "AWS",
            SourceIdentifier = "S3_BUCKET_VERSIONING_ENABLED",
        },
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            foo,
        },
    });

    var p = Aws.Iam.GetPolicyDocument.Invoke(new()
    {
        Statements = new[]
        {
            new Aws.Iam.Inputs.GetPolicyDocumentStatementInputArgs
            {
                Effect = "Allow",
                Actions = new[]
                {
                    "config:Put*",
                },
                Resources = new[]
                {
                    "*",
                },
            },
        },
    });

    var pRolePolicy = new Aws.Iam.RolePolicy("p", new()
    {
        Name = "my-awsconfig-policy",
        Role = rRole.Id,
        Policy = p.Apply(getPolicyDocumentResult => getPolicyDocumentResult.Json),
    });

});
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 com.pulumi.aws.cfg.Rule;
import com.pulumi.aws.cfg.RuleArgs;
import com.pulumi.aws.cfg.inputs.RuleSourceArgs;
import com.pulumi.aws.iam.RolePolicy;
import com.pulumi.aws.iam.RolePolicyArgs;
import com.pulumi.resources.CustomResourceOptions;
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 rRole = new Role("rRole", RoleArgs.builder()
            .name("my-awsconfig-role")
            .assumeRolePolicy(assumeRole.json())
            .build());

        var foo = new Recorder("foo", RecorderArgs.builder()
            .name("example")
            .roleArn(rRole.arn())
            .build());

        var r = new Rule("r", RuleArgs.builder()
            .name("example")
            .source(RuleSourceArgs.builder()
                .owner("AWS")
                .sourceIdentifier("S3_BUCKET_VERSIONING_ENABLED")
                .build())
            .build(), CustomResourceOptions.builder()
                .dependsOn(foo)
                .build());

        final var p = IamFunctions.getPolicyDocument(GetPolicyDocumentArgs.builder()
            .statements(GetPolicyDocumentStatementArgs.builder()
                .effect("Allow")
                .actions("config:Put*")
                .resources("*")
                .build())
            .build());

        var pRolePolicy = new RolePolicy("pRolePolicy", RolePolicyArgs.builder()
            .name("my-awsconfig-policy")
            .role(rRole.id())
            .policy(p.json())
            .build());

    }
}
resources:
  r:
    type: aws:cfg:Rule
    properties:
      name: example
      source:
        owner: AWS
        sourceIdentifier: S3_BUCKET_VERSIONING_ENABLED
    options:
      dependsOn:
        - ${foo}
  foo:
    type: aws:cfg:Recorder
    properties:
      name: example
      roleArn: ${rRole.arn}
  rRole:
    type: aws:iam:Role
    name: r
    properties:
      name: my-awsconfig-role
      assumeRolePolicy: ${assumeRole.json}
  pRolePolicy:
    type: aws:iam:RolePolicy
    name: p
    properties:
      name: my-awsconfig-policy
      role: ${rRole.id}
      policy: ${p.json}
variables:
  assumeRole:
    fn::invoke:
      function: aws:iam:getPolicyDocument
      arguments:
        statements:
          - effect: Allow
            principals:
              - type: Service
                identifiers:
                  - config.amazonaws.com
            actions:
              - sts:AssumeRole
  p:
    fn::invoke:
      function: aws:iam:getPolicyDocument
      arguments:
        statements:
          - effect: Allow
            actions:
              - config:Put*
            resources:
              - '*'

The source property identifies the rule type. Setting owner to “AWS” and sourceIdentifier to a managed rule name (like “S3_BUCKET_VERSIONING_ENABLED”) tells Config to use AWS-provided evaluation logic. The dependsOn relationship ensures the Recorder exists before creating the rule, avoiding race conditions during deployment.

Evaluate resources with custom Lambda logic

When AWS managed rules don’t cover your requirements, custom Lambda functions can implement organization-specific compliance checks.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.cfg.Recorder("example", {});
const exampleFunction = new aws.lambda.Function("example", {});
const examplePermission = new aws.lambda.Permission("example", {
    action: "lambda:InvokeFunction",
    "function": exampleFunction.arn,
    principal: "config.amazonaws.com",
    statementId: "AllowExecutionFromConfig",
});
const exampleRule = new aws.cfg.Rule("example", {source: {
    owner: "CUSTOM_LAMBDA",
    sourceIdentifier: exampleFunction.arn,
}}, {
    dependsOn: [
        example,
        examplePermission,
    ],
});
import pulumi
import pulumi_aws as aws

example = aws.cfg.Recorder("example")
example_function = aws.lambda_.Function("example")
example_permission = aws.lambda_.Permission("example",
    action="lambda:InvokeFunction",
    function=example_function.arn,
    principal="config.amazonaws.com",
    statement_id="AllowExecutionFromConfig")
example_rule = aws.cfg.Rule("example", source={
    "owner": "CUSTOM_LAMBDA",
    "source_identifier": example_function.arn,
},
opts = pulumi.ResourceOptions(depends_on=[
        example,
        example_permission,
    ]))
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cfg"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lambda"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := cfg.NewRecorder(ctx, "example", nil)
		if err != nil {
			return err
		}
		exampleFunction, err := lambda.NewFunction(ctx, "example", nil)
		if err != nil {
			return err
		}
		examplePermission, err := lambda.NewPermission(ctx, "example", &lambda.PermissionArgs{
			Action:      pulumi.String("lambda:InvokeFunction"),
			Function:    exampleFunction.Arn,
			Principal:   pulumi.String("config.amazonaws.com"),
			StatementId: pulumi.String("AllowExecutionFromConfig"),
		})
		if err != nil {
			return err
		}
		_, err = cfg.NewRule(ctx, "example", &cfg.RuleArgs{
			Source: &cfg.RuleSourceArgs{
				Owner:            pulumi.String("CUSTOM_LAMBDA"),
				SourceIdentifier: exampleFunction.Arn,
			},
		}, pulumi.DependsOn([]pulumi.Resource{
			example,
			examplePermission,
		}))
		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 example = new Aws.Cfg.Recorder("example");

    var exampleFunction = new Aws.Lambda.Function("example");

    var examplePermission = new Aws.Lambda.Permission("example", new()
    {
        Action = "lambda:InvokeFunction",
        Function = exampleFunction.Arn,
        Principal = "config.amazonaws.com",
        StatementId = "AllowExecutionFromConfig",
    });

    var exampleRule = new Aws.Cfg.Rule("example", new()
    {
        Source = new Aws.Cfg.Inputs.RuleSourceArgs
        {
            Owner = "CUSTOM_LAMBDA",
            SourceIdentifier = exampleFunction.Arn,
        },
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            example,
            examplePermission,
        },
    });

});
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.lambda.Function;
import com.pulumi.aws.lambda.Permission;
import com.pulumi.aws.lambda.PermissionArgs;
import com.pulumi.aws.cfg.Rule;
import com.pulumi.aws.cfg.RuleArgs;
import com.pulumi.aws.cfg.inputs.RuleSourceArgs;
import com.pulumi.resources.CustomResourceOptions;
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 example = new Recorder("example");

        var exampleFunction = new Function("exampleFunction");

        var examplePermission = new Permission("examplePermission", PermissionArgs.builder()
            .action("lambda:InvokeFunction")
            .function(exampleFunction.arn())
            .principal("config.amazonaws.com")
            .statementId("AllowExecutionFromConfig")
            .build());

        var exampleRule = new Rule("exampleRule", RuleArgs.builder()
            .source(RuleSourceArgs.builder()
                .owner("CUSTOM_LAMBDA")
                .sourceIdentifier(exampleFunction.arn())
                .build())
            .build(), CustomResourceOptions.builder()
                .dependsOn(                
                    example,
                    examplePermission)
                .build());

    }
}
resources:
  example:
    type: aws:cfg:Recorder
  exampleFunction:
    type: aws:lambda:Function
    name: example
  examplePermission:
    type: aws:lambda:Permission
    name: example
    properties:
      action: lambda:InvokeFunction
      function: ${exampleFunction.arn}
      principal: config.amazonaws.com
      statementId: AllowExecutionFromConfig
  exampleRule:
    type: aws:cfg:Rule
    name: example
    properties:
      source:
        owner: CUSTOM_LAMBDA
        sourceIdentifier: ${exampleFunction.arn}
    options:
      dependsOn:
        - ${example}
        - ${examplePermission}

Setting owner to “CUSTOM_LAMBDA” and sourceIdentifier to your Lambda function ARN directs Config to invoke your function for evaluations. The lambda.Permission resource grants Config service permission to invoke the function. The dependsOn array ensures both the Recorder and Permission exist before rule creation.

Define compliance checks with Guard policy language

Guard policies provide a declarative way to express compliance rules without Lambda code, using a domain-specific language for resource evaluation.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.cfg.Rule("example", {
    name: "example",
    source: {
        owner: "CUSTOM_POLICY",
        sourceDetails: [{
            messageType: "ConfigurationItemChangeNotification",
        }],
        customPolicyDetails: {
            policyRuntime: "guard-2.x.x",
            policyText: `\\t  rule tableisactive when
\\t\\t  resourceType == \\"AWS::DynamoDB::Table\\" {
\\t\\t  configuration.tableStatus == ['ACTIVE']
\\t  }
\\t  
\\t  rule checkcompliance when
\\t\\t  resourceType == \\"AWS::DynamoDB::Table\\"
\\t\\t  tableisactive {
\\t\\t\\t  supplementaryConfiguration.ContinuousBackupsDescription.pointInTimeRecoveryDescription.pointInTimeRecoveryStatus == \\"ENABLED\\"
\\t  }
`,
        },
    },
});
import pulumi
import pulumi_aws as aws

example = aws.cfg.Rule("example",
    name="example",
    source={
        "owner": "CUSTOM_POLICY",
        "source_details": [{
            "message_type": "ConfigurationItemChangeNotification",
        }],
        "custom_policy_details": {
            "policy_runtime": "guard-2.x.x",
            "policy_text": """\t  rule tableisactive when
\t\t  resourceType == \"AWS::DynamoDB::Table\" {
\t\t  configuration.tableStatus == ['ACTIVE']
\t  }
\t  
\t  rule checkcompliance when
\t\t  resourceType == \"AWS::DynamoDB::Table\"
\t\t  tableisactive {
\t\t\t  supplementaryConfiguration.ContinuousBackupsDescription.pointInTimeRecoveryDescription.pointInTimeRecoveryStatus == \"ENABLED\"
\t  }
""",
        },
    })
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.NewRule(ctx, "example", &cfg.RuleArgs{
			Name: pulumi.String("example"),
			Source: &cfg.RuleSourceArgs{
				Owner: pulumi.String("CUSTOM_POLICY"),
				SourceDetails: cfg.RuleSourceSourceDetailArray{
					&cfg.RuleSourceSourceDetailArgs{
						MessageType: pulumi.String("ConfigurationItemChangeNotification"),
					},
				},
				CustomPolicyDetails: &cfg.RuleSourceCustomPolicyDetailsArgs{
					PolicyRuntime: pulumi.String("guard-2.x.x"),
					PolicyText: pulumi.String(`\t  rule tableisactive when
\t\t  resourceType == \"AWS::DynamoDB::Table\" {
\t\t  configuration.tableStatus == ['ACTIVE']
\t  }
\t  
\t  rule checkcompliance when
\t\t  resourceType == \"AWS::DynamoDB::Table\"
\t\t  tableisactive {
\t\t\t  supplementaryConfiguration.ContinuousBackupsDescription.pointInTimeRecoveryDescription.pointInTimeRecoveryStatus == \"ENABLED\"
\t  }
`),
				},
			},
		})
		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 example = new Aws.Cfg.Rule("example", new()
    {
        Name = "example",
        Source = new Aws.Cfg.Inputs.RuleSourceArgs
        {
            Owner = "CUSTOM_POLICY",
            SourceDetails = new[]
            {
                new Aws.Cfg.Inputs.RuleSourceSourceDetailArgs
                {
                    MessageType = "ConfigurationItemChangeNotification",
                },
            },
            CustomPolicyDetails = new Aws.Cfg.Inputs.RuleSourceCustomPolicyDetailsArgs
            {
                PolicyRuntime = "guard-2.x.x",
                PolicyText = @"\t  rule tableisactive when
\t\t  resourceType == \""AWS::DynamoDB::Table\"" {
\t\t  configuration.tableStatus == ['ACTIVE']
\t  }
\t  
\t  rule checkcompliance when
\t\t  resourceType == \""AWS::DynamoDB::Table\""
\t\t  tableisactive {
\t\t\t  supplementaryConfiguration.ContinuousBackupsDescription.pointInTimeRecoveryDescription.pointInTimeRecoveryStatus == \""ENABLED\""
\t  }
",
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cfg.Rule;
import com.pulumi.aws.cfg.RuleArgs;
import com.pulumi.aws.cfg.inputs.RuleSourceArgs;
import com.pulumi.aws.cfg.inputs.RuleSourceCustomPolicyDetailsArgs;
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 example = new Rule("example", RuleArgs.builder()
            .name("example")
            .source(RuleSourceArgs.builder()
                .owner("CUSTOM_POLICY")
                .sourceDetails(RuleSourceSourceDetailArgs.builder()
                    .messageType("ConfigurationItemChangeNotification")
                    .build())
                .customPolicyDetails(RuleSourceCustomPolicyDetailsArgs.builder()
                    .policyRuntime("guard-2.x.x")
                    .policyText("""
\t  rule tableisactive when
\t\t  resourceType == \"AWS::DynamoDB::Table\" {
\t\t  configuration.tableStatus == ['ACTIVE']
\t  }
\t  
\t  rule checkcompliance when
\t\t  resourceType == \"AWS::DynamoDB::Table\"
\t\t  tableisactive {
\t\t\t  supplementaryConfiguration.ContinuousBackupsDescription.pointInTimeRecoveryDescription.pointInTimeRecoveryStatus == \"ENABLED\"
\t  }
                    """)
                    .build())
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:cfg:Rule
    properties:
      name: example
      source:
        owner: CUSTOM_POLICY
        sourceDetails:
          - messageType: ConfigurationItemChangeNotification
        customPolicyDetails:
          policyRuntime: guard-2.x.x
          policyText: "\\t  rule tableisactive when\n\\t\\t  resourceType == \\\"AWS::DynamoDB::Table\\\" {\n\\t\\t  configuration.tableStatus == ['ACTIVE']\n\\t  }\n\\t  \n\\t  rule checkcompliance when\n\\t\\t  resourceType == \\\"AWS::DynamoDB::Table\\\"\n\\t\\t  tableisactive {\n\\t\\t\\t  supplementaryConfiguration.ContinuousBackupsDescription.pointInTimeRecoveryDescription.pointInTimeRecoveryStatus == \\\"ENABLED\\\"\n\\t  }\n"

Setting owner to “CUSTOM_POLICY” enables Guard-based evaluation. The customPolicyDetails property contains the Guard policy text and runtime version. The sourceDetails property specifies when Config triggers evaluation (here, on configuration changes). Guard policies check resource properties against declarative rules written in the Guard language.

Beyond these examples

These snippets focus on specific Config rule features: AWS managed rules and custom Lambda evaluation, and Guard policy language for declarative checks. They’re intentionally minimal rather than full compliance frameworks.

The examples rely on pre-existing infrastructure such as Configuration Recorder (required dependency), IAM roles for Config service, and Lambda functions for custom rules. They focus on rule configuration rather than provisioning the surrounding infrastructure.

To keep things focused, common rule patterns are omitted, including:

  • Resource scope filtering (scope property)
  • Input parameters for parameterized rules (inputParameters)
  • Evaluation frequency controls (maximumExecutionFrequency)
  • Evaluation modes for proactive vs detective checks

These omissions are intentional: the goal is to illustrate how each rule type is wired, not provide drop-in compliance modules. See the Config Rule resource reference for all available configuration options.

Let's configure AWS Config Rules

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Setup & Dependencies
Why do I need to use dependsOn with Config rules?
Config rules require an existing Configuration Recorder to be present. Without dependsOn, you’ll encounter race conditions where the rule tries to create before the recorder is ready. All examples show dependsOn: [recorder] to ensure proper ordering.
Why am I getting permission errors with custom Lambda rules?
AWS Config needs explicit permission to invoke your Lambda function. Create an aws.lambda.Permission resource with action: "lambda:InvokeFunction", principal: "config.amazonaws.com", and include it in the rule’s dependsOn array.
Rule Types & Configuration
What are the three types of Config rules and how do they differ?

You can create three types of rules:

  1. AWS managed rules - Set source.owner to "AWS" and source.sourceIdentifier to the managed rule name (e.g., "S3_BUCKET_VERSIONING_ENABLED")
  2. Custom Lambda rules - Set source.owner to "CUSTOM_LAMBDA" and source.sourceIdentifier to your Lambda function’s ARN
  3. Custom policy rules - Set source.owner to "CUSTOM_POLICY" and provide Guard policy text in source.customPolicyDetails
Immutability & Limitations
Can I rename a Config rule after creation?
No, the name property is immutable and cannot be changed after the rule is created. You’ll need to destroy and recreate the rule with a new name.

Using a different cloud?

Explore monitoring guides for other cloud providers: