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 routing multiple event sources to different destinations.

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 user notification logs to CloudWatch

Teams monitoring Cognito often start by routing notification events to CloudWatch Logs for centralized visibility into email and SMS delivery.

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 threshold (ERROR, INFO, etc.), and a destination. Here, cloudWatchLogsConfiguration sends logs to the specified Log Group ARN.

Archive notification logs directly to S3

For long-term retention or compliance, teams route 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 property sends logs directly to an S3 bucket. This is simpler than CloudWatch for archival use cases where you don’t need real-time querying or alerting.

Route different event sources to separate destinations

Production deployments often route different event types to different destinations based on retention requirements and downstream consumers.

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 logConfigurations entries let you route different event sources to different destinations. Here, userNotification events go to CloudWatch at INFO level, while userAuthEvents go to Firehose at ERROR level. The firehoseConfiguration property specifies the Kinesis Firehose stream ARN that will receive the logs.

Beyond these examples

These snippets focus on specific log delivery features: CloudWatch, S3, and Firehose destinations, event source filtering, and log level configuration. 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 S3 access. They focus on configuring log delivery rather than provisioning the surrounding infrastructure.

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

  • Log group encryption (KMS keys)
  • S3 bucket policies and lifecycle rules
  • Firehose buffering and compression settings
  • Multiple user pools with shared destinations

These omissions are intentional: the goal is to illustrate how log delivery 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 Basics
What's required to configure Cognito log delivery?
You need a userPoolId and at least one log configuration block in logConfigurations. Each configuration must specify an eventSource, logLevel, and a destination (CloudWatch, Firehose, or S3).
What event sources can I configure for logging?
The examples show userNotification and userAuthEvents as event sources. Each event source can be configured with its own log level and destination.
Log Levels & Destinations
What log levels are supported?
The examples demonstrate ERROR and INFO log levels. You can set different log levels for different event sources.
What log destinations can I use?
You can send logs to CloudWatch Logs (cloudWatchLogsConfiguration), Kinesis Firehose (firehoseConfiguration), or S3 (s3Configuration). Each destination requires its corresponding ARN.
Multiple Configurations
Can I send different event sources to different destinations?
Yes, you can configure multiple log configurations with different event sources and destinations. The example shows userNotification logs going to CloudWatch while userAuthEvents logs go to Firehose.
Permissions & IAM
What IAM permissions does Firehose need for Cognito log delivery?
The Firehose role requires S3 permissions on the destination bucket: s3:AbortMultipartUpload, s3:GetBucketLocation, s3:GetObject, s3:ListBucket, s3:ListBucketMultipartUploads, and s3:PutObject.

Using a different cloud?

Explore monitoring guides for other cloud providers: