Configure AWS Cognito Log Delivery

The aws:cognito/logDeliveryConfiguration:LogDeliveryConfiguration resource, part of the Pulumi AWS provider, configures where Cognito User Pool logs are delivered: CloudWatch Logs, S3, or Kinesis Firehose. This guide focuses on three capabilities: CloudWatch Logs delivery, S3 archival, and multi-destination routing by event source.

Log delivery configurations reference existing User Pools and destination resources. The examples are intentionally small. Combine them with your own User Pools, Log Groups, S3 buckets, and Firehose streams.

Send error logs to CloudWatch Logs

Teams monitoring Cognito user pools often start by routing error-level logs to CloudWatch for centralized visibility into notification failures.

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

const example = new aws.cognito.UserPool("example", {name: "example"});
const exampleLogGroup = new aws.cloudwatch.LogGroup("example", {name: "example"});
const exampleLogDeliveryConfiguration = new aws.cognito.LogDeliveryConfiguration("example", {
    userPoolId: example.id,
    logConfigurations: [{
        eventSource: "userNotification",
        logLevel: "ERROR",
        cloudWatchLogsConfiguration: {
            logGroupArn: exampleLogGroup.arn,
        },
    }],
});
import pulumi
import pulumi_aws as aws

example = aws.cognito.UserPool("example", name="example")
example_log_group = aws.cloudwatch.LogGroup("example", name="example")
example_log_delivery_configuration = aws.cognito.LogDeliveryConfiguration("example",
    user_pool_id=example.id,
    log_configurations=[{
        "event_source": "userNotification",
        "log_level": "ERROR",
        "cloud_watch_logs_configuration": {
            "log_group_arn": example_log_group.arn,
        },
    }])
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cloudwatch"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cognito"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := cognito.NewUserPool(ctx, "example", &cognito.UserPoolArgs{
			Name: pulumi.String("example"),
		})
		if err != nil {
			return err
		}
		exampleLogGroup, err := cloudwatch.NewLogGroup(ctx, "example", &cloudwatch.LogGroupArgs{
			Name: pulumi.String("example"),
		})
		if err != nil {
			return err
		}
		_, err = cognito.NewLogDeliveryConfiguration(ctx, "example", &cognito.LogDeliveryConfigurationArgs{
			UserPoolId: example.ID(),
			LogConfigurations: cognito.LogDeliveryConfigurationLogConfigurationArray{
				&cognito.LogDeliveryConfigurationLogConfigurationArgs{
					EventSource: pulumi.String("userNotification"),
					LogLevel:    pulumi.String("ERROR"),
					CloudWatchLogsConfiguration: &cognito.LogDeliveryConfigurationLogConfigurationCloudWatchLogsConfigurationArgs{
						LogGroupArn: exampleLogGroup.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 example = new Aws.Cognito.UserPool("example", new()
    {
        Name = "example",
    });

    var exampleLogGroup = new Aws.CloudWatch.LogGroup("example", new()
    {
        Name = "example",
    });

    var exampleLogDeliveryConfiguration = new Aws.Cognito.LogDeliveryConfiguration("example", new()
    {
        UserPoolId = example.Id,
        LogConfigurations = new[]
        {
            new Aws.Cognito.Inputs.LogDeliveryConfigurationLogConfigurationArgs
            {
                EventSource = "userNotification",
                LogLevel = "ERROR",
                CloudWatchLogsConfiguration = new Aws.Cognito.Inputs.LogDeliveryConfigurationLogConfigurationCloudWatchLogsConfigurationArgs
                {
                    LogGroupArn = exampleLogGroup.Arn,
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cognito.UserPool;
import com.pulumi.aws.cognito.UserPoolArgs;
import com.pulumi.aws.cloudwatch.LogGroup;
import com.pulumi.aws.cloudwatch.LogGroupArgs;
import com.pulumi.aws.cognito.LogDeliveryConfiguration;
import com.pulumi.aws.cognito.LogDeliveryConfigurationArgs;
import com.pulumi.aws.cognito.inputs.LogDeliveryConfigurationLogConfigurationArgs;
import com.pulumi.aws.cognito.inputs.LogDeliveryConfigurationLogConfigurationCloudWatchLogsConfigurationArgs;
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 UserPool("example", UserPoolArgs.builder()
            .name("example")
            .build());

        var exampleLogGroup = new LogGroup("exampleLogGroup", LogGroupArgs.builder()
            .name("example")
            .build());

        var exampleLogDeliveryConfiguration = new LogDeliveryConfiguration("exampleLogDeliveryConfiguration", LogDeliveryConfigurationArgs.builder()
            .userPoolId(example.id())
            .logConfigurations(LogDeliveryConfigurationLogConfigurationArgs.builder()
                .eventSource("userNotification")
                .logLevel("ERROR")
                .cloudWatchLogsConfiguration(LogDeliveryConfigurationLogConfigurationCloudWatchLogsConfigurationArgs.builder()
                    .logGroupArn(exampleLogGroup.arn())
                    .build())
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:cognito:UserPool
    properties:
      name: example
  exampleLogGroup:
    type: aws:cloudwatch:LogGroup
    name: example
    properties:
      name: example
  exampleLogDeliveryConfiguration:
    type: aws:cognito:LogDeliveryConfiguration
    name: example
    properties:
      userPoolId: ${example.id}
      logConfigurations:
        - eventSource: userNotification
          logLevel: ERROR
          cloudWatchLogsConfiguration:
            logGroupArn: ${exampleLogGroup.arn}

The logConfigurations array defines one or more log routing rules. Each configuration specifies an eventSource (like userNotification), a logLevel (ERROR, INFO, or DEBUG), and a destination. The cloudWatchLogsConfiguration block points to a Log Group ARN where Cognito writes matching events.

Archive logs directly to S3

For long-term retention or compliance requirements, teams route Cognito logs directly to S3 without intermediate processing.

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

const example = new aws.cognito.UserPool("example", {name: "example"});
const exampleBucket = new aws.s3.Bucket("example", {
    bucket: "example-bucket",
    forceDestroy: true,
});
const exampleLogDeliveryConfiguration = new aws.cognito.LogDeliveryConfiguration("example", {
    userPoolId: example.id,
    logConfigurations: [{
        eventSource: "userNotification",
        logLevel: "ERROR",
        s3Configuration: {
            bucketArn: exampleBucket.arn,
        },
    }],
});
import pulumi
import pulumi_aws as aws

example = aws.cognito.UserPool("example", name="example")
example_bucket = aws.s3.Bucket("example",
    bucket="example-bucket",
    force_destroy=True)
example_log_delivery_configuration = aws.cognito.LogDeliveryConfiguration("example",
    user_pool_id=example.id,
    log_configurations=[{
        "event_source": "userNotification",
        "log_level": "ERROR",
        "s3_configuration": {
            "bucket_arn": example_bucket.arn,
        },
    }])
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cognito"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/s3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := cognito.NewUserPool(ctx, "example", &cognito.UserPoolArgs{
			Name: pulumi.String("example"),
		})
		if err != nil {
			return err
		}
		exampleBucket, err := s3.NewBucket(ctx, "example", &s3.BucketArgs{
			Bucket:       pulumi.String("example-bucket"),
			ForceDestroy: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		_, err = cognito.NewLogDeliveryConfiguration(ctx, "example", &cognito.LogDeliveryConfigurationArgs{
			UserPoolId: example.ID(),
			LogConfigurations: cognito.LogDeliveryConfigurationLogConfigurationArray{
				&cognito.LogDeliveryConfigurationLogConfigurationArgs{
					EventSource: pulumi.String("userNotification"),
					LogLevel:    pulumi.String("ERROR"),
					S3Configuration: &cognito.LogDeliveryConfigurationLogConfigurationS3ConfigurationArgs{
						BucketArn: exampleBucket.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 example = new Aws.Cognito.UserPool("example", new()
    {
        Name = "example",
    });

    var exampleBucket = new Aws.S3.Bucket("example", new()
    {
        BucketName = "example-bucket",
        ForceDestroy = true,
    });

    var exampleLogDeliveryConfiguration = new Aws.Cognito.LogDeliveryConfiguration("example", new()
    {
        UserPoolId = example.Id,
        LogConfigurations = new[]
        {
            new Aws.Cognito.Inputs.LogDeliveryConfigurationLogConfigurationArgs
            {
                EventSource = "userNotification",
                LogLevel = "ERROR",
                S3Configuration = new Aws.Cognito.Inputs.LogDeliveryConfigurationLogConfigurationS3ConfigurationArgs
                {
                    BucketArn = exampleBucket.Arn,
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cognito.UserPool;
import com.pulumi.aws.cognito.UserPoolArgs;
import com.pulumi.aws.s3.Bucket;
import com.pulumi.aws.s3.BucketArgs;
import com.pulumi.aws.cognito.LogDeliveryConfiguration;
import com.pulumi.aws.cognito.LogDeliveryConfigurationArgs;
import com.pulumi.aws.cognito.inputs.LogDeliveryConfigurationLogConfigurationArgs;
import com.pulumi.aws.cognito.inputs.LogDeliveryConfigurationLogConfigurationS3ConfigurationArgs;
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 UserPool("example", UserPoolArgs.builder()
            .name("example")
            .build());

        var exampleBucket = new Bucket("exampleBucket", BucketArgs.builder()
            .bucket("example-bucket")
            .forceDestroy(true)
            .build());

        var exampleLogDeliveryConfiguration = new LogDeliveryConfiguration("exampleLogDeliveryConfiguration", LogDeliveryConfigurationArgs.builder()
            .userPoolId(example.id())
            .logConfigurations(LogDeliveryConfigurationLogConfigurationArgs.builder()
                .eventSource("userNotification")
                .logLevel("ERROR")
                .s3Configuration(LogDeliveryConfigurationLogConfigurationS3ConfigurationArgs.builder()
                    .bucketArn(exampleBucket.arn())
                    .build())
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:cognito:UserPool
    properties:
      name: example
  exampleBucket:
    type: aws:s3:Bucket
    name: example
    properties:
      bucket: example-bucket
      forceDestroy: true
  exampleLogDeliveryConfiguration:
    type: aws:cognito:LogDeliveryConfiguration
    name: example
    properties:
      userPoolId: ${example.id}
      logConfigurations:
        - eventSource: userNotification
          logLevel: ERROR
          s3Configuration:
            bucketArn: ${exampleBucket.arn}

The s3Configuration block replaces cloudWatchLogsConfiguration, sending logs directly to an S3 bucket. This approach works well for archival scenarios where you don’t need real-time querying or alerting.

Route different event sources to separate destinations

Production environments often need to route different event types to different destinations, sending high-volume info logs to one system and critical errors to another.

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

const example = new aws.cognito.UserPool("example", {name: "example"});
const exampleLogGroup = new aws.cloudwatch.LogGroup("example", {name: "example"});
const exampleBucket = new aws.s3.Bucket("example", {
    bucket: "example-bucket",
    forceDestroy: true,
});
const firehose = new aws.iam.Role("firehose", {
    name: "firehose-role",
    assumeRolePolicy: JSON.stringify({
        Version: "2012-10-17",
        Statement: [{
            Action: "sts:AssumeRole",
            Effect: "Allow",
            Principal: {
                Service: "firehose.amazonaws.com",
            },
        }],
    }),
});
const firehoseRolePolicy = new aws.iam.RolePolicy("firehose", {
    name: "firehose-policy",
    role: firehose.id,
    policy: pulumi.jsonStringify({
        Version: "2012-10-17",
        Statement: [{
            Effect: "Allow",
            Action: [
                "s3:AbortMultipartUpload",
                "s3:GetBucketLocation",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:ListBucketMultipartUploads",
                "s3:PutObject",
            ],
            Resource: [
                exampleBucket.arn,
                pulumi.interpolate`${exampleBucket.arn}/*`,
            ],
        }],
    }),
});
const exampleFirehoseDeliveryStream = new aws.kinesis.FirehoseDeliveryStream("example", {
    name: "example-stream",
    destination: "extended_s3",
    extendedS3Configuration: {
        roleArn: firehose.arn,
        bucketArn: exampleBucket.arn,
    },
});
const exampleLogDeliveryConfiguration = new aws.cognito.LogDeliveryConfiguration("example", {
    userPoolId: example.id,
    logConfigurations: [
        {
            eventSource: "userNotification",
            logLevel: "INFO",
            cloudWatchLogsConfiguration: {
                logGroupArn: exampleLogGroup.arn,
            },
        },
        {
            eventSource: "userAuthEvents",
            logLevel: "ERROR",
            firehoseConfiguration: {
                streamArn: exampleFirehoseDeliveryStream.arn,
            },
        },
    ],
});
import pulumi
import json
import pulumi_aws as aws

example = aws.cognito.UserPool("example", name="example")
example_log_group = aws.cloudwatch.LogGroup("example", name="example")
example_bucket = aws.s3.Bucket("example",
    bucket="example-bucket",
    force_destroy=True)
firehose = aws.iam.Role("firehose",
    name="firehose-role",
    assume_role_policy=json.dumps({
        "Version": "2012-10-17",
        "Statement": [{
            "Action": "sts:AssumeRole",
            "Effect": "Allow",
            "Principal": {
                "Service": "firehose.amazonaws.com",
            },
        }],
    }))
firehose_role_policy = aws.iam.RolePolicy("firehose",
    name="firehose-policy",
    role=firehose.id,
    policy=pulumi.Output.json_dumps({
        "Version": "2012-10-17",
        "Statement": [{
            "Effect": "Allow",
            "Action": [
                "s3:AbortMultipartUpload",
                "s3:GetBucketLocation",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:ListBucketMultipartUploads",
                "s3:PutObject",
            ],
            "Resource": [
                example_bucket.arn,
                example_bucket.arn.apply(lambda arn: f"{arn}/*"),
            ],
        }],
    }))
example_firehose_delivery_stream = aws.kinesis.FirehoseDeliveryStream("example",
    name="example-stream",
    destination="extended_s3",
    extended_s3_configuration={
        "role_arn": firehose.arn,
        "bucket_arn": example_bucket.arn,
    })
example_log_delivery_configuration = aws.cognito.LogDeliveryConfiguration("example",
    user_pool_id=example.id,
    log_configurations=[
        {
            "event_source": "userNotification",
            "log_level": "INFO",
            "cloud_watch_logs_configuration": {
                "log_group_arn": example_log_group.arn,
            },
        },
        {
            "event_source": "userAuthEvents",
            "log_level": "ERROR",
            "firehose_configuration": {
                "stream_arn": example_firehose_delivery_stream.arn,
            },
        },
    ])
package main

import (
	"encoding/json"
	"fmt"

	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cloudwatch"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cognito"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iam"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/kinesis"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/s3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := cognito.NewUserPool(ctx, "example", &cognito.UserPoolArgs{
			Name: pulumi.String("example"),
		})
		if err != nil {
			return err
		}
		exampleLogGroup, err := cloudwatch.NewLogGroup(ctx, "example", &cloudwatch.LogGroupArgs{
			Name: pulumi.String("example"),
		})
		if err != nil {
			return err
		}
		exampleBucket, err := s3.NewBucket(ctx, "example", &s3.BucketArgs{
			Bucket:       pulumi.String("example-bucket"),
			ForceDestroy: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		tmpJSON0, err := json.Marshal(map[string]interface{}{
			"Version": "2012-10-17",
			"Statement": []map[string]interface{}{
				map[string]interface{}{
					"Action": "sts:AssumeRole",
					"Effect": "Allow",
					"Principal": map[string]interface{}{
						"Service": "firehose.amazonaws.com",
					},
				},
			},
		})
		if err != nil {
			return err
		}
		json0 := string(tmpJSON0)
		firehose, err := iam.NewRole(ctx, "firehose", &iam.RoleArgs{
			Name:             pulumi.String("firehose-role"),
			AssumeRolePolicy: pulumi.String(json0),
		})
		if err != nil {
			return err
		}
		_, err = iam.NewRolePolicy(ctx, "firehose", &iam.RolePolicyArgs{
			Name: pulumi.String("firehose-policy"),
			Role: firehose.ID(),
			Policy: pulumi.All(exampleBucket.Arn, exampleBucket.Arn).ApplyT(func(_args []interface{}) (string, error) {
				exampleBucketArn := _args[0].(string)
				exampleBucketArn1 := _args[1].(string)
				var _zero string
				tmpJSON1, err := json.Marshal(map[string]interface{}{
					"Version": "2012-10-17",
					"Statement": []map[string]interface{}{
						map[string]interface{}{
							"Effect": "Allow",
							"Action": []string{
								"s3:AbortMultipartUpload",
								"s3:GetBucketLocation",
								"s3:GetObject",
								"s3:ListBucket",
								"s3:ListBucketMultipartUploads",
								"s3:PutObject",
							},
							"Resource": []string{
								exampleBucketArn,
								fmt.Sprintf("%v/*", exampleBucketArn1),
							},
						},
					},
				})
				if err != nil {
					return _zero, err
				}
				json1 := string(tmpJSON1)
				return json1, nil
			}).(pulumi.StringOutput),
		})
		if err != nil {
			return err
		}
		exampleFirehoseDeliveryStream, err := kinesis.NewFirehoseDeliveryStream(ctx, "example", &kinesis.FirehoseDeliveryStreamArgs{
			Name:        pulumi.String("example-stream"),
			Destination: pulumi.String("extended_s3"),
			ExtendedS3Configuration: &kinesis.FirehoseDeliveryStreamExtendedS3ConfigurationArgs{
				RoleArn:   firehose.Arn,
				BucketArn: exampleBucket.Arn,
			},
		})
		if err != nil {
			return err
		}
		_, err = cognito.NewLogDeliveryConfiguration(ctx, "example", &cognito.LogDeliveryConfigurationArgs{
			UserPoolId: example.ID(),
			LogConfigurations: cognito.LogDeliveryConfigurationLogConfigurationArray{
				&cognito.LogDeliveryConfigurationLogConfigurationArgs{
					EventSource: pulumi.String("userNotification"),
					LogLevel:    pulumi.String("INFO"),
					CloudWatchLogsConfiguration: &cognito.LogDeliveryConfigurationLogConfigurationCloudWatchLogsConfigurationArgs{
						LogGroupArn: exampleLogGroup.Arn,
					},
				},
				&cognito.LogDeliveryConfigurationLogConfigurationArgs{
					EventSource: pulumi.String("userAuthEvents"),
					LogLevel:    pulumi.String("ERROR"),
					FirehoseConfiguration: &cognito.LogDeliveryConfigurationLogConfigurationFirehoseConfigurationArgs{
						StreamArn: exampleFirehoseDeliveryStream.Arn,
					},
				},
			},
		})
		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 example = new Aws.Cognito.UserPool("example", new()
    {
        Name = "example",
    });

    var exampleLogGroup = new Aws.CloudWatch.LogGroup("example", new()
    {
        Name = "example",
    });

    var exampleBucket = new Aws.S3.Bucket("example", new()
    {
        BucketName = "example-bucket",
        ForceDestroy = true,
    });

    var firehose = new Aws.Iam.Role("firehose", new()
    {
        Name = "firehose-role",
        AssumeRolePolicy = JsonSerializer.Serialize(new Dictionary<string, object?>
        {
            ["Version"] = "2012-10-17",
            ["Statement"] = new[]
            {
                new Dictionary<string, object?>
                {
                    ["Action"] = "sts:AssumeRole",
                    ["Effect"] = "Allow",
                    ["Principal"] = new Dictionary<string, object?>
                    {
                        ["Service"] = "firehose.amazonaws.com",
                    },
                },
            },
        }),
    });

    var firehoseRolePolicy = new Aws.Iam.RolePolicy("firehose", new()
    {
        Name = "firehose-policy",
        Role = firehose.Id,
        Policy = Output.JsonSerialize(Output.Create(new Dictionary<string, object?>
        {
            ["Version"] = "2012-10-17",
            ["Statement"] = new[]
            {
                new Dictionary<string, object?>
                {
                    ["Effect"] = "Allow",
                    ["Action"] = new[]
                    {
                        "s3:AbortMultipartUpload",
                        "s3:GetBucketLocation",
                        "s3:GetObject",
                        "s3:ListBucket",
                        "s3:ListBucketMultipartUploads",
                        "s3:PutObject",
                    },
                    ["Resource"] = new[]
                    {
                        exampleBucket.Arn,
                        exampleBucket.Arn.Apply(arn => $"{arn}/*"),
                    },
                },
            },
        })),
    });

    var exampleFirehoseDeliveryStream = new Aws.Kinesis.FirehoseDeliveryStream("example", new()
    {
        Name = "example-stream",
        Destination = "extended_s3",
        ExtendedS3Configuration = new Aws.Kinesis.Inputs.FirehoseDeliveryStreamExtendedS3ConfigurationArgs
        {
            RoleArn = firehose.Arn,
            BucketArn = exampleBucket.Arn,
        },
    });

    var exampleLogDeliveryConfiguration = new Aws.Cognito.LogDeliveryConfiguration("example", new()
    {
        UserPoolId = example.Id,
        LogConfigurations = new[]
        {
            new Aws.Cognito.Inputs.LogDeliveryConfigurationLogConfigurationArgs
            {
                EventSource = "userNotification",
                LogLevel = "INFO",
                CloudWatchLogsConfiguration = new Aws.Cognito.Inputs.LogDeliveryConfigurationLogConfigurationCloudWatchLogsConfigurationArgs
                {
                    LogGroupArn = exampleLogGroup.Arn,
                },
            },
            new Aws.Cognito.Inputs.LogDeliveryConfigurationLogConfigurationArgs
            {
                EventSource = "userAuthEvents",
                LogLevel = "ERROR",
                FirehoseConfiguration = new Aws.Cognito.Inputs.LogDeliveryConfigurationLogConfigurationFirehoseConfigurationArgs
                {
                    StreamArn = exampleFirehoseDeliveryStream.Arn,
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cognito.UserPool;
import com.pulumi.aws.cognito.UserPoolArgs;
import com.pulumi.aws.cloudwatch.LogGroup;
import com.pulumi.aws.cloudwatch.LogGroupArgs;
import com.pulumi.aws.s3.Bucket;
import com.pulumi.aws.s3.BucketArgs;
import com.pulumi.aws.iam.Role;
import com.pulumi.aws.iam.RoleArgs;
import com.pulumi.aws.iam.RolePolicy;
import com.pulumi.aws.iam.RolePolicyArgs;
import com.pulumi.aws.kinesis.FirehoseDeliveryStream;
import com.pulumi.aws.kinesis.FirehoseDeliveryStreamArgs;
import com.pulumi.aws.kinesis.inputs.FirehoseDeliveryStreamExtendedS3ConfigurationArgs;
import com.pulumi.aws.cognito.LogDeliveryConfiguration;
import com.pulumi.aws.cognito.LogDeliveryConfigurationArgs;
import com.pulumi.aws.cognito.inputs.LogDeliveryConfigurationLogConfigurationArgs;
import com.pulumi.aws.cognito.inputs.LogDeliveryConfigurationLogConfigurationCloudWatchLogsConfigurationArgs;
import com.pulumi.aws.cognito.inputs.LogDeliveryConfigurationLogConfigurationFirehoseConfigurationArgs;
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 example = new UserPool("example", UserPoolArgs.builder()
            .name("example")
            .build());

        var exampleLogGroup = new LogGroup("exampleLogGroup", LogGroupArgs.builder()
            .name("example")
            .build());

        var exampleBucket = new Bucket("exampleBucket", BucketArgs.builder()
            .bucket("example-bucket")
            .forceDestroy(true)
            .build());

        var firehose = new Role("firehose", RoleArgs.builder()
            .name("firehose-role")
            .assumeRolePolicy(serializeJson(
                jsonObject(
                    jsonProperty("Version", "2012-10-17"),
                    jsonProperty("Statement", jsonArray(jsonObject(
                        jsonProperty("Action", "sts:AssumeRole"),
                        jsonProperty("Effect", "Allow"),
                        jsonProperty("Principal", jsonObject(
                            jsonProperty("Service", "firehose.amazonaws.com")
                        ))
                    )))
                )))
            .build());

        var firehoseRolePolicy = new RolePolicy("firehoseRolePolicy", RolePolicyArgs.builder()
            .name("firehose-policy")
            .role(firehose.id())
            .policy(Output.tuple(exampleBucket.arn(), exampleBucket.arn()).applyValue(values -> {
                var exampleBucketArn = values.t1;
                var exampleBucketArn1 = values.t2;
                return serializeJson(
                    jsonObject(
                        jsonProperty("Version", "2012-10-17"),
                        jsonProperty("Statement", jsonArray(jsonObject(
                            jsonProperty("Effect", "Allow"),
                            jsonProperty("Action", jsonArray(
                                "s3:AbortMultipartUpload", 
                                "s3:GetBucketLocation", 
                                "s3:GetObject", 
                                "s3:ListBucket", 
                                "s3:ListBucketMultipartUploads", 
                                "s3:PutObject"
                            )),
                            jsonProperty("Resource", jsonArray(
                                exampleBucketArn, 
                                String.format("%s/*", exampleBucketArn1)
                            ))
                        )))
                    ));
            }))
            .build());

        var exampleFirehoseDeliveryStream = new FirehoseDeliveryStream("exampleFirehoseDeliveryStream", FirehoseDeliveryStreamArgs.builder()
            .name("example-stream")
            .destination("extended_s3")
            .extendedS3Configuration(FirehoseDeliveryStreamExtendedS3ConfigurationArgs.builder()
                .roleArn(firehose.arn())
                .bucketArn(exampleBucket.arn())
                .build())
            .build());

        var exampleLogDeliveryConfiguration = new LogDeliveryConfiguration("exampleLogDeliveryConfiguration", LogDeliveryConfigurationArgs.builder()
            .userPoolId(example.id())
            .logConfigurations(            
                LogDeliveryConfigurationLogConfigurationArgs.builder()
                    .eventSource("userNotification")
                    .logLevel("INFO")
                    .cloudWatchLogsConfiguration(LogDeliveryConfigurationLogConfigurationCloudWatchLogsConfigurationArgs.builder()
                        .logGroupArn(exampleLogGroup.arn())
                        .build())
                    .build(),
                LogDeliveryConfigurationLogConfigurationArgs.builder()
                    .eventSource("userAuthEvents")
                    .logLevel("ERROR")
                    .firehoseConfiguration(LogDeliveryConfigurationLogConfigurationFirehoseConfigurationArgs.builder()
                        .streamArn(exampleFirehoseDeliveryStream.arn())
                        .build())
                    .build())
            .build());

    }
}
resources:
  example:
    type: aws:cognito:UserPool
    properties:
      name: example
  exampleLogGroup:
    type: aws:cloudwatch:LogGroup
    name: example
    properties:
      name: example
  exampleBucket:
    type: aws:s3:Bucket
    name: example
    properties:
      bucket: example-bucket
      forceDestroy: true
  firehose:
    type: aws:iam:Role
    properties:
      name: firehose-role
      assumeRolePolicy:
        fn::toJSON:
          Version: 2012-10-17
          Statement:
            - Action: sts:AssumeRole
              Effect: Allow
              Principal:
                Service: firehose.amazonaws.com
  firehoseRolePolicy:
    type: aws:iam:RolePolicy
    name: firehose
    properties:
      name: firehose-policy
      role: ${firehose.id}
      policy:
        fn::toJSON:
          Version: 2012-10-17
          Statement:
            - Effect: Allow
              Action:
                - s3:AbortMultipartUpload
                - s3:GetBucketLocation
                - s3:GetObject
                - s3:ListBucket
                - s3:ListBucketMultipartUploads
                - s3:PutObject
              Resource:
                - ${exampleBucket.arn}
                - ${exampleBucket.arn}/*
  exampleFirehoseDeliveryStream:
    type: aws:kinesis:FirehoseDeliveryStream
    name: example
    properties:
      name: example-stream
      destination: extended_s3
      extendedS3Configuration:
        roleArn: ${firehose.arn}
        bucketArn: ${exampleBucket.arn}
  exampleLogDeliveryConfiguration:
    type: aws:cognito:LogDeliveryConfiguration
    name: example
    properties:
      userPoolId: ${example.id}
      logConfigurations:
        - eventSource: userNotification
          logLevel: INFO
          cloudWatchLogsConfiguration:
            logGroupArn: ${exampleLogGroup.arn}
        - eventSource: userAuthEvents
          logLevel: ERROR
          firehoseConfiguration:
            streamArn: ${exampleFirehoseDeliveryStream.arn}

Multiple entries in logConfigurations let you split logs by eventSource and logLevel. Here, userNotification events at INFO level go to CloudWatch, while userAuthEvents errors stream through Firehose to S3. The firehoseConfiguration block requires a Kinesis Firehose Delivery Stream ARN and an IAM role that grants Firehose permission to write to the destination bucket.

Beyond these examples

These snippets focus on specific log delivery features: CloudWatch Logs and S3 destinations, Firehose streaming for downstream processing, and event source and log level filtering. They’re intentionally minimal rather than full logging solutions.

The examples reference pre-existing infrastructure such as Cognito User Pools, CloudWatch Log Groups, S3 buckets, Kinesis Firehose streams, and IAM roles for Firehose delivery. They focus on configuring log routing rather than provisioning the underlying infrastructure.

To keep things focused, common log delivery patterns are omitted, including:

  • Log retention policies and lifecycle rules
  • Encryption configuration (KMS keys)
  • Cross-account log delivery
  • Monitoring and alerting on log delivery failures

These omissions are intentional: the goal is to illustrate how each log delivery feature is wired, not provide drop-in logging modules. See the Cognito Log Delivery Configuration resource reference for all available configuration options.

Let's configure AWS Cognito Log Delivery

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Configuration & Event Sources
What log destinations are available for Cognito User Pool logs?
You can send logs to three destinations: CloudWatch Logs (cloudWatchLogsConfiguration), Kinesis Firehose (firehoseConfiguration), or S3 (s3Configuration).
Can I send different event types to different destinations?
Yes, you can configure multiple logConfigurations with different eventSource and destination settings. For example, send userNotification events to CloudWatch and userAuthEvents to Firehose.
What event sources can I configure for logging?
The examples show userNotification and userAuthEvents as available event sources.
What log levels are supported?
The examples demonstrate ERROR and INFO log levels.
IAM & Permissions
What IAM permissions does Firehose need for S3 delivery?
The Firehose role requires these S3 permissions: s3:AbortMultipartUpload, s3:GetBucketLocation, s3:GetObject, s3:ListBucket, s3:ListBucketMultipartUploads, and s3:PutObject on both the bucket and its objects.

Using a different cloud?

Explore monitoring guides for other cloud providers: