Configure AWS Application Load Balancer Listeners

The aws:alb/listener:Listener resource, part of the Pulumi AWS provider, defines a load balancer listener that accepts incoming connections on a specific port and protocol, then routes traffic based on configured actions. This guide focuses on four capabilities: HTTPS termination and forwarding, HTTP-to-HTTPS redirection, weighted traffic splitting, and authentication integration.

Listeners attach to existing load balancers and reference target groups, TLS certificates, and authentication resources. The examples are intentionally small. Combine them with your own load balancers, target groups, and security configuration.

Route HTTPS traffic to a target group

Most deployments accept HTTPS traffic on port 443 and forward requests to backend instances.

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

const frontEnd = new aws.lb.LoadBalancer("front_end", {});
const frontEndTargetGroup = new aws.lb.TargetGroup("front_end", {});
const frontEndListener = new aws.lb.Listener("front_end", {
    loadBalancerArn: frontEnd.arn,
    port: 443,
    protocol: "HTTPS",
    sslPolicy: "ELBSecurityPolicy-2016-08",
    certificateArn: "arn:aws:iam::187416307283:server-certificate/test_cert_rab3wuqwgja25ct3n4jdj2tzu4",
    defaultActions: [{
        type: "forward",
        targetGroupArn: frontEndTargetGroup.arn,
    }],
});
import pulumi
import pulumi_aws as aws

front_end = aws.lb.LoadBalancer("front_end")
front_end_target_group = aws.lb.TargetGroup("front_end")
front_end_listener = aws.lb.Listener("front_end",
    load_balancer_arn=front_end.arn,
    port=443,
    protocol="HTTPS",
    ssl_policy="ELBSecurityPolicy-2016-08",
    certificate_arn="arn:aws:iam::187416307283:server-certificate/test_cert_rab3wuqwgja25ct3n4jdj2tzu4",
    default_actions=[{
        "type": "forward",
        "target_group_arn": front_end_target_group.arn,
    }])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		frontEnd, err := lb.NewLoadBalancer(ctx, "front_end", nil)
		if err != nil {
			return err
		}
		frontEndTargetGroup, err := lb.NewTargetGroup(ctx, "front_end", nil)
		if err != nil {
			return err
		}
		_, err = lb.NewListener(ctx, "front_end", &lb.ListenerArgs{
			LoadBalancerArn: frontEnd.Arn,
			Port:            pulumi.Int(443),
			Protocol:        pulumi.String("HTTPS"),
			SslPolicy:       pulumi.String("ELBSecurityPolicy-2016-08"),
			CertificateArn:  pulumi.String("arn:aws:iam::187416307283:server-certificate/test_cert_rab3wuqwgja25ct3n4jdj2tzu4"),
			DefaultActions: lb.ListenerDefaultActionArray{
				&lb.ListenerDefaultActionArgs{
					Type:           pulumi.String("forward"),
					TargetGroupArn: frontEndTargetGroup.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 frontEnd = new Aws.LB.LoadBalancer("front_end");

    var frontEndTargetGroup = new Aws.LB.TargetGroup("front_end");

    var frontEndListener = new Aws.LB.Listener("front_end", new()
    {
        LoadBalancerArn = frontEnd.Arn,
        Port = 443,
        Protocol = "HTTPS",
        SslPolicy = "ELBSecurityPolicy-2016-08",
        CertificateArn = "arn:aws:iam::187416307283:server-certificate/test_cert_rab3wuqwgja25ct3n4jdj2tzu4",
        DefaultActions = new[]
        {
            new Aws.LB.Inputs.ListenerDefaultActionArgs
            {
                Type = "forward",
                TargetGroupArn = frontEndTargetGroup.Arn,
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lb.LoadBalancer;
import com.pulumi.aws.lb.TargetGroup;
import com.pulumi.aws.lb.Listener;
import com.pulumi.aws.lb.ListenerArgs;
import com.pulumi.aws.lb.inputs.ListenerDefaultActionArgs;
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 frontEnd = new LoadBalancer("frontEnd");

        var frontEndTargetGroup = new TargetGroup("frontEndTargetGroup");

        var frontEndListener = new Listener("frontEndListener", ListenerArgs.builder()
            .loadBalancerArn(frontEnd.arn())
            .port(443)
            .protocol("HTTPS")
            .sslPolicy("ELBSecurityPolicy-2016-08")
            .certificateArn("arn:aws:iam::187416307283:server-certificate/test_cert_rab3wuqwgja25ct3n4jdj2tzu4")
            .defaultActions(ListenerDefaultActionArgs.builder()
                .type("forward")
                .targetGroupArn(frontEndTargetGroup.arn())
                .build())
            .build());

    }
}
resources:
  frontEnd:
    type: aws:lb:LoadBalancer
    name: front_end
  frontEndTargetGroup:
    type: aws:lb:TargetGroup
    name: front_end
  frontEndListener:
    type: aws:lb:Listener
    name: front_end
    properties:
      loadBalancerArn: ${frontEnd.arn}
      port: '443'
      protocol: HTTPS
      sslPolicy: ELBSecurityPolicy-2016-08
      certificateArn: arn:aws:iam::187416307283:server-certificate/test_cert_rab3wuqwgja25ct3n4jdj2tzu4
      defaultActions:
        - type: forward
          targetGroupArn: ${frontEndTargetGroup.arn}

The listener terminates TLS using the certificateArn, then forwards decrypted requests to the target group. The protocol property sets HTTPS for client connections, while sslPolicy controls which cipher suites are allowed. The defaultActions array defines what happens to incoming requests; here, type “forward” sends traffic to the specified targetGroupArn.

Redirect HTTP to HTTPS automatically

Applications requiring encryption redirect HTTP traffic to HTTPS rather than serving unencrypted content.

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

const frontEnd = new aws.lb.LoadBalancer("front_end", {});
const frontEndListener = new aws.lb.Listener("front_end", {
    loadBalancerArn: frontEnd.arn,
    port: 80,
    protocol: "HTTP",
    defaultActions: [{
        type: "redirect",
        redirect: {
            port: "443",
            protocol: "HTTPS",
            statusCode: "HTTP_301",
        },
    }],
});
import pulumi
import pulumi_aws as aws

front_end = aws.lb.LoadBalancer("front_end")
front_end_listener = aws.lb.Listener("front_end",
    load_balancer_arn=front_end.arn,
    port=80,
    protocol="HTTP",
    default_actions=[{
        "type": "redirect",
        "redirect": {
            "port": "443",
            "protocol": "HTTPS",
            "status_code": "HTTP_301",
        },
    }])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		frontEnd, err := lb.NewLoadBalancer(ctx, "front_end", nil)
		if err != nil {
			return err
		}
		_, err = lb.NewListener(ctx, "front_end", &lb.ListenerArgs{
			LoadBalancerArn: frontEnd.Arn,
			Port:            pulumi.Int(80),
			Protocol:        pulumi.String("HTTP"),
			DefaultActions: lb.ListenerDefaultActionArray{
				&lb.ListenerDefaultActionArgs{
					Type: pulumi.String("redirect"),
					Redirect: &lb.ListenerDefaultActionRedirectArgs{
						Port:       pulumi.String("443"),
						Protocol:   pulumi.String("HTTPS"),
						StatusCode: pulumi.String("HTTP_301"),
					},
				},
			},
		})
		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 frontEnd = new Aws.LB.LoadBalancer("front_end");

    var frontEndListener = new Aws.LB.Listener("front_end", new()
    {
        LoadBalancerArn = frontEnd.Arn,
        Port = 80,
        Protocol = "HTTP",
        DefaultActions = new[]
        {
            new Aws.LB.Inputs.ListenerDefaultActionArgs
            {
                Type = "redirect",
                Redirect = new Aws.LB.Inputs.ListenerDefaultActionRedirectArgs
                {
                    Port = "443",
                    Protocol = "HTTPS",
                    StatusCode = "HTTP_301",
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lb.LoadBalancer;
import com.pulumi.aws.lb.Listener;
import com.pulumi.aws.lb.ListenerArgs;
import com.pulumi.aws.lb.inputs.ListenerDefaultActionArgs;
import com.pulumi.aws.lb.inputs.ListenerDefaultActionRedirectArgs;
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 frontEnd = new LoadBalancer("frontEnd");

        var frontEndListener = new Listener("frontEndListener", ListenerArgs.builder()
            .loadBalancerArn(frontEnd.arn())
            .port(80)
            .protocol("HTTP")
            .defaultActions(ListenerDefaultActionArgs.builder()
                .type("redirect")
                .redirect(ListenerDefaultActionRedirectArgs.builder()
                    .port("443")
                    .protocol("HTTPS")
                    .statusCode("HTTP_301")
                    .build())
                .build())
            .build());

    }
}
resources:
  frontEnd:
    type: aws:lb:LoadBalancer
    name: front_end
  frontEndListener:
    type: aws:lb:Listener
    name: front_end
    properties:
      loadBalancerArn: ${frontEnd.arn}
      port: '80'
      protocol: HTTP
      defaultActions:
        - type: redirect
          redirect:
            port: '443'
            protocol: HTTPS
            statusCode: HTTP_301

When a request arrives on port 80, the listener returns a 301 redirect pointing to port 443 with HTTPS protocol. The redirect action doesn’t forward to a target group; instead, it tells the client to retry with a different URL. The statusCode property controls whether browsers cache the redirect (HTTP_301) or treat it as temporary (HTTP_302).

Split traffic between target groups with weights

Blue-green deployments and canary releases split traffic between multiple target groups to gradually shift load.

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

const frontEnd = new aws.lb.LoadBalancer("front_end", {});
const frontEndBlue = new aws.lb.TargetGroup("front_end_blue", {});
const frontEndGreen = new aws.lb.TargetGroup("front_end_green", {});
const frontEndListener = new aws.lb.Listener("front_end", {
    loadBalancerArn: frontEnd.arn,
    port: 443,
    protocol: "HTTPS",
    sslPolicy: "ELBSecurityPolicy-2016-08",
    certificateArn: "arn:aws:iam::187416307283:server-certificate/test_cert_rab3wuqwgja25ct3n4jdj2tzu4",
    defaultActions: [{
        type: "forward",
        forward: {
            targetGroups: [
                {
                    arn: frontEndBlue.arn,
                    weight: 100,
                },
                {
                    arn: frontEndGreen.arn,
                    weight: 0,
                },
            ],
        },
    }],
});
import pulumi
import pulumi_aws as aws

front_end = aws.lb.LoadBalancer("front_end")
front_end_blue = aws.lb.TargetGroup("front_end_blue")
front_end_green = aws.lb.TargetGroup("front_end_green")
front_end_listener = aws.lb.Listener("front_end",
    load_balancer_arn=front_end.arn,
    port=443,
    protocol="HTTPS",
    ssl_policy="ELBSecurityPolicy-2016-08",
    certificate_arn="arn:aws:iam::187416307283:server-certificate/test_cert_rab3wuqwgja25ct3n4jdj2tzu4",
    default_actions=[{
        "type": "forward",
        "forward": {
            "target_groups": [
                {
                    "arn": front_end_blue.arn,
                    "weight": 100,
                },
                {
                    "arn": front_end_green.arn,
                    "weight": 0,
                },
            ],
        },
    }])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		frontEnd, err := lb.NewLoadBalancer(ctx, "front_end", nil)
		if err != nil {
			return err
		}
		frontEndBlue, err := lb.NewTargetGroup(ctx, "front_end_blue", nil)
		if err != nil {
			return err
		}
		frontEndGreen, err := lb.NewTargetGroup(ctx, "front_end_green", nil)
		if err != nil {
			return err
		}
		_, err = lb.NewListener(ctx, "front_end", &lb.ListenerArgs{
			LoadBalancerArn: frontEnd.Arn,
			Port:            pulumi.Int(443),
			Protocol:        pulumi.String("HTTPS"),
			SslPolicy:       pulumi.String("ELBSecurityPolicy-2016-08"),
			CertificateArn:  pulumi.String("arn:aws:iam::187416307283:server-certificate/test_cert_rab3wuqwgja25ct3n4jdj2tzu4"),
			DefaultActions: lb.ListenerDefaultActionArray{
				&lb.ListenerDefaultActionArgs{
					Type: pulumi.String("forward"),
					Forward: &lb.ListenerDefaultActionForwardArgs{
						TargetGroups: lb.ListenerDefaultActionForwardTargetGroupArray{
							&lb.ListenerDefaultActionForwardTargetGroupArgs{
								Arn:    frontEndBlue.Arn,
								Weight: pulumi.Int(100),
							},
							&lb.ListenerDefaultActionForwardTargetGroupArgs{
								Arn:    frontEndGreen.Arn,
								Weight: pulumi.Int(0),
							},
						},
					},
				},
			},
		})
		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 frontEnd = new Aws.LB.LoadBalancer("front_end");

    var frontEndBlue = new Aws.LB.TargetGroup("front_end_blue");

    var frontEndGreen = new Aws.LB.TargetGroup("front_end_green");

    var frontEndListener = new Aws.LB.Listener("front_end", new()
    {
        LoadBalancerArn = frontEnd.Arn,
        Port = 443,
        Protocol = "HTTPS",
        SslPolicy = "ELBSecurityPolicy-2016-08",
        CertificateArn = "arn:aws:iam::187416307283:server-certificate/test_cert_rab3wuqwgja25ct3n4jdj2tzu4",
        DefaultActions = new[]
        {
            new Aws.LB.Inputs.ListenerDefaultActionArgs
            {
                Type = "forward",
                Forward = new Aws.LB.Inputs.ListenerDefaultActionForwardArgs
                {
                    TargetGroups = new[]
                    {
                        new Aws.LB.Inputs.ListenerDefaultActionForwardTargetGroupArgs
                        {
                            Arn = frontEndBlue.Arn,
                            Weight = 100,
                        },
                        new Aws.LB.Inputs.ListenerDefaultActionForwardTargetGroupArgs
                        {
                            Arn = frontEndGreen.Arn,
                            Weight = 0,
                        },
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lb.LoadBalancer;
import com.pulumi.aws.lb.TargetGroup;
import com.pulumi.aws.lb.Listener;
import com.pulumi.aws.lb.ListenerArgs;
import com.pulumi.aws.lb.inputs.ListenerDefaultActionArgs;
import com.pulumi.aws.lb.inputs.ListenerDefaultActionForwardArgs;
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 frontEnd = new LoadBalancer("frontEnd");

        var frontEndBlue = new TargetGroup("frontEndBlue");

        var frontEndGreen = new TargetGroup("frontEndGreen");

        var frontEndListener = new Listener("frontEndListener", ListenerArgs.builder()
            .loadBalancerArn(frontEnd.arn())
            .port(443)
            .protocol("HTTPS")
            .sslPolicy("ELBSecurityPolicy-2016-08")
            .certificateArn("arn:aws:iam::187416307283:server-certificate/test_cert_rab3wuqwgja25ct3n4jdj2tzu4")
            .defaultActions(ListenerDefaultActionArgs.builder()
                .type("forward")
                .forward(ListenerDefaultActionForwardArgs.builder()
                    .targetGroups(                    
                        ListenerDefaultActionForwardTargetGroupArgs.builder()
                            .arn(frontEndBlue.arn())
                            .weight(100)
                            .build(),
                        ListenerDefaultActionForwardTargetGroupArgs.builder()
                            .arn(frontEndGreen.arn())
                            .weight(0)
                            .build())
                    .build())
                .build())
            .build());

    }
}
resources:
  frontEnd:
    type: aws:lb:LoadBalancer
    name: front_end
  frontEndBlue:
    type: aws:lb:TargetGroup
    name: front_end_blue
  frontEndGreen:
    type: aws:lb:TargetGroup
    name: front_end_green
  frontEndListener:
    type: aws:lb:Listener
    name: front_end
    properties:
      loadBalancerArn: ${frontEnd.arn}
      port: '443'
      protocol: HTTPS
      sslPolicy: ELBSecurityPolicy-2016-08
      certificateArn: arn:aws:iam::187416307283:server-certificate/test_cert_rab3wuqwgja25ct3n4jdj2tzu4
      defaultActions:
        - type: forward
          forward:
            targetGroups:
              - arn: ${frontEndBlue.arn}
                weight: 100
              - arn: ${frontEndGreen.arn}
                weight: 0

The forward block replaces the simple targetGroupArn with a targetGroups array, each entry specifying an ARN and weight. Weights determine the percentage of traffic each target group receives; here, 100% goes to the blue group while green receives 0%. Adjust weights to gradually shift traffic during deployments.

Authenticate users with Cognito before forwarding

Applications needing user authentication can delegate to Cognito User Pools, verifying identity before routing requests.

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

const frontEnd = new aws.lb.LoadBalancer("front_end", {});
const frontEndTargetGroup = new aws.lb.TargetGroup("front_end", {});
const pool = new aws.cognito.UserPool("pool", {});
const client = new aws.cognito.UserPoolClient("client", {});
const domain = new aws.cognito.UserPoolDomain("domain", {});
const frontEndListener = new aws.lb.Listener("front_end", {
    loadBalancerArn: frontEnd.arn,
    port: 80,
    protocol: "HTTP",
    defaultActions: [
        {
            type: "authenticate-cognito",
            authenticateCognito: {
                userPoolArn: pool.arn,
                userPoolClientId: client.id,
                userPoolDomain: domain.domain,
            },
        },
        {
            type: "forward",
            targetGroupArn: frontEndTargetGroup.arn,
        },
    ],
});
import pulumi
import pulumi_aws as aws

front_end = aws.lb.LoadBalancer("front_end")
front_end_target_group = aws.lb.TargetGroup("front_end")
pool = aws.cognito.UserPool("pool")
client = aws.cognito.UserPoolClient("client")
domain = aws.cognito.UserPoolDomain("domain")
front_end_listener = aws.lb.Listener("front_end",
    load_balancer_arn=front_end.arn,
    port=80,
    protocol="HTTP",
    default_actions=[
        {
            "type": "authenticate-cognito",
            "authenticate_cognito": {
                "user_pool_arn": pool.arn,
                "user_pool_client_id": client.id,
                "user_pool_domain": domain.domain,
            },
        },
        {
            "type": "forward",
            "target_group_arn": front_end_target_group.arn,
        },
    ])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		frontEnd, err := lb.NewLoadBalancer(ctx, "front_end", nil)
		if err != nil {
			return err
		}
		frontEndTargetGroup, err := lb.NewTargetGroup(ctx, "front_end", nil)
		if err != nil {
			return err
		}
		pool, err := cognito.NewUserPool(ctx, "pool", nil)
		if err != nil {
			return err
		}
		client, err := cognito.NewUserPoolClient(ctx, "client", nil)
		if err != nil {
			return err
		}
		domain, err := cognito.NewUserPoolDomain(ctx, "domain", nil)
		if err != nil {
			return err
		}
		_, err = lb.NewListener(ctx, "front_end", &lb.ListenerArgs{
			LoadBalancerArn: frontEnd.Arn,
			Port:            pulumi.Int(80),
			Protocol:        pulumi.String("HTTP"),
			DefaultActions: lb.ListenerDefaultActionArray{
				&lb.ListenerDefaultActionArgs{
					Type: pulumi.String("authenticate-cognito"),
					AuthenticateCognito: &lb.ListenerDefaultActionAuthenticateCognitoArgs{
						UserPoolArn:      pool.Arn,
						UserPoolClientId: client.ID(),
						UserPoolDomain:   domain.Domain,
					},
				},
				&lb.ListenerDefaultActionArgs{
					Type:           pulumi.String("forward"),
					TargetGroupArn: frontEndTargetGroup.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 frontEnd = new Aws.LB.LoadBalancer("front_end");

    var frontEndTargetGroup = new Aws.LB.TargetGroup("front_end");

    var pool = new Aws.Cognito.UserPool("pool");

    var client = new Aws.Cognito.UserPoolClient("client");

    var domain = new Aws.Cognito.UserPoolDomain("domain");

    var frontEndListener = new Aws.LB.Listener("front_end", new()
    {
        LoadBalancerArn = frontEnd.Arn,
        Port = 80,
        Protocol = "HTTP",
        DefaultActions = new[]
        {
            new Aws.LB.Inputs.ListenerDefaultActionArgs
            {
                Type = "authenticate-cognito",
                AuthenticateCognito = new Aws.LB.Inputs.ListenerDefaultActionAuthenticateCognitoArgs
                {
                    UserPoolArn = pool.Arn,
                    UserPoolClientId = client.Id,
                    UserPoolDomain = domain.Domain,
                },
            },
            new Aws.LB.Inputs.ListenerDefaultActionArgs
            {
                Type = "forward",
                TargetGroupArn = frontEndTargetGroup.Arn,
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lb.LoadBalancer;
import com.pulumi.aws.lb.TargetGroup;
import com.pulumi.aws.cognito.UserPool;
import com.pulumi.aws.cognito.UserPoolClient;
import com.pulumi.aws.cognito.UserPoolDomain;
import com.pulumi.aws.lb.Listener;
import com.pulumi.aws.lb.ListenerArgs;
import com.pulumi.aws.lb.inputs.ListenerDefaultActionArgs;
import com.pulumi.aws.lb.inputs.ListenerDefaultActionAuthenticateCognitoArgs;
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 frontEnd = new LoadBalancer("frontEnd");

        var frontEndTargetGroup = new TargetGroup("frontEndTargetGroup");

        var pool = new UserPool("pool");

        var client = new UserPoolClient("client");

        var domain = new UserPoolDomain("domain");

        var frontEndListener = new Listener("frontEndListener", ListenerArgs.builder()
            .loadBalancerArn(frontEnd.arn())
            .port(80)
            .protocol("HTTP")
            .defaultActions(            
                ListenerDefaultActionArgs.builder()
                    .type("authenticate-cognito")
                    .authenticateCognito(ListenerDefaultActionAuthenticateCognitoArgs.builder()
                        .userPoolArn(pool.arn())
                        .userPoolClientId(client.id())
                        .userPoolDomain(domain.domain())
                        .build())
                    .build(),
                ListenerDefaultActionArgs.builder()
                    .type("forward")
                    .targetGroupArn(frontEndTargetGroup.arn())
                    .build())
            .build());

    }
}
resources:
  frontEnd:
    type: aws:lb:LoadBalancer
    name: front_end
  frontEndTargetGroup:
    type: aws:lb:TargetGroup
    name: front_end
  pool:
    type: aws:cognito:UserPool
  client:
    type: aws:cognito:UserPoolClient
  domain:
    type: aws:cognito:UserPoolDomain
  frontEndListener:
    type: aws:lb:Listener
    name: front_end
    properties:
      loadBalancerArn: ${frontEnd.arn}
      port: '80'
      protocol: HTTP
      defaultActions:
        - type: authenticate-cognito
          authenticateCognito:
            userPoolArn: ${pool.arn}
            userPoolClientId: ${client.id}
            userPoolDomain: ${domain.domain}
        - type: forward
          targetGroupArn: ${frontEndTargetGroup.arn}

The defaultActions array chains multiple actions: first authenticateCognito verifies the user against the specified User Pool, then forward sends authenticated requests to the target group. The authenticateCognito block requires the User Pool ARN, Client ID, and Domain. Unauthenticated requests receive a redirect to the Cognito login page.

Require client certificates with mutual TLS

APIs needing strong client authentication can require client certificates, verifying both parties during the TLS handshake.

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

const example = new aws.lb.LoadBalancer("example", {loadBalancerType: "application"});
const exampleTargetGroup = new aws.lb.TargetGroup("example", {});
const exampleListener = new aws.lb.Listener("example", {
    loadBalancerArn: example.id,
    defaultActions: [{
        targetGroupArn: exampleTargetGroup.id,
        type: "forward",
    }],
    mutualAuthentication: {
        mode: "verify",
        trustStoreArn: "...",
    },
});
import pulumi
import pulumi_aws as aws

example = aws.lb.LoadBalancer("example", load_balancer_type="application")
example_target_group = aws.lb.TargetGroup("example")
example_listener = aws.lb.Listener("example",
    load_balancer_arn=example.id,
    default_actions=[{
        "target_group_arn": example_target_group.id,
        "type": "forward",
    }],
    mutual_authentication={
        "mode": "verify",
        "trust_store_arn": "...",
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := lb.NewLoadBalancer(ctx, "example", &lb.LoadBalancerArgs{
			LoadBalancerType: pulumi.String("application"),
		})
		if err != nil {
			return err
		}
		exampleTargetGroup, err := lb.NewTargetGroup(ctx, "example", nil)
		if err != nil {
			return err
		}
		_, err = lb.NewListener(ctx, "example", &lb.ListenerArgs{
			LoadBalancerArn: example.ID(),
			DefaultActions: lb.ListenerDefaultActionArray{
				&lb.ListenerDefaultActionArgs{
					TargetGroupArn: exampleTargetGroup.ID(),
					Type:           pulumi.String("forward"),
				},
			},
			MutualAuthentication: &lb.ListenerMutualAuthenticationArgs{
				Mode:          pulumi.String("verify"),
				TrustStoreArn: pulumi.String("..."),
			},
		})
		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.LB.LoadBalancer("example", new()
    {
        LoadBalancerType = "application",
    });

    var exampleTargetGroup = new Aws.LB.TargetGroup("example");

    var exampleListener = new Aws.LB.Listener("example", new()
    {
        LoadBalancerArn = example.Id,
        DefaultActions = new[]
        {
            new Aws.LB.Inputs.ListenerDefaultActionArgs
            {
                TargetGroupArn = exampleTargetGroup.Id,
                Type = "forward",
            },
        },
        MutualAuthentication = new Aws.LB.Inputs.ListenerMutualAuthenticationArgs
        {
            Mode = "verify",
            TrustStoreArn = "...",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lb.LoadBalancer;
import com.pulumi.aws.lb.LoadBalancerArgs;
import com.pulumi.aws.lb.TargetGroup;
import com.pulumi.aws.lb.Listener;
import com.pulumi.aws.lb.ListenerArgs;
import com.pulumi.aws.lb.inputs.ListenerDefaultActionArgs;
import com.pulumi.aws.lb.inputs.ListenerMutualAuthenticationArgs;
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 LoadBalancer("example", LoadBalancerArgs.builder()
            .loadBalancerType("application")
            .build());

        var exampleTargetGroup = new TargetGroup("exampleTargetGroup");

        var exampleListener = new Listener("exampleListener", ListenerArgs.builder()
            .loadBalancerArn(example.id())
            .defaultActions(ListenerDefaultActionArgs.builder()
                .targetGroupArn(exampleTargetGroup.id())
                .type("forward")
                .build())
            .mutualAuthentication(ListenerMutualAuthenticationArgs.builder()
                .mode("verify")
                .trustStoreArn("...")
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:lb:LoadBalancer
    properties:
      loadBalancerType: application
  exampleTargetGroup:
    type: aws:lb:TargetGroup
    name: example
  exampleListener:
    type: aws:lb:Listener
    name: example
    properties:
      loadBalancerArn: ${example.id}
      defaultActions:
        - targetGroupArn: ${exampleTargetGroup.id}
          type: forward
      mutualAuthentication:
        mode: verify
        trustStoreArn: '...'

The mutualAuthentication block enables certificate-based client authentication. The mode property controls enforcement: “verify” requires valid client certificates, while “passthrough” forwards certificate data to backends without validation. The trustStoreArn points to a trust store containing the CA certificates used to validate client certificates.

Beyond these examples

These snippets focus on specific listener-level features: traffic routing (forwarding, weighted splits, redirects), authentication (Cognito, OIDC, JWT, mutual TLS), and protocol handling (HTTP, HTTPS, TLS, GENEVE). They’re intentionally minimal rather than full load balancing solutions.

The examples reference pre-existing infrastructure such as load balancers (Application, Network, Gateway types), target groups with registered targets, TLS certificates (IAM or ACM), Cognito User Pools and clients (for authentication examples), and trust stores with CA certificates (for mutual TLS). They focus on configuring the listener rather than provisioning everything around it.

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

  • Listener rules for path-based or host-based routing
  • ALPN policy configuration for protocol negotiation
  • Custom HTTP header manipulation (routing* properties)
  • CORS and security headers (routingHttpResponse* properties)
  • TCP idle timeout tuning (tcpIdleTimeoutSeconds)
  • Fixed-response actions for maintenance pages

These omissions are intentional: the goal is to illustrate how each listener feature is wired, not provide drop-in load balancing modules. See the Load Balancer Listener resource reference for all available configuration options.

Let's configure AWS Application Load Balancer Listeners

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Protocols & Load Balancer Types
What's the difference between aws.alb.Listener and aws.lb.Listener?
They’re identical resources with different names. The functionality is the same.
What protocols are supported and what are their constraints?
For Application Load Balancers, use HTTP or HTTPS (default: HTTP). For Network Load Balancers, use TCP, TLS, UDP, or TCP_UDP. Gateway Load Balancers don’t use the protocol property. Note that UDP and TCP_UDP aren’t valid if dual-stack mode is enabled.
Can I use a port with Gateway Load Balancers?
No, the port property isn’t valid for Gateway Load Balancers.
SSL/TLS Configuration
Do I need a certificate for HTTPS listeners?
Yes, exactly one certificate is required if the protocol is HTTPS. Specify it using the certificateArn property.
How do I add multiple SSL certificates to a listener?
Use the certificateArn property for the default certificate, then use the aws.lb.ListenerCertificate resource to add additional certificates.
When do I need an SSL policy and what's the default?
An SSL policy is required if the protocol is HTTPS or TLS. The default is ELBSecurityPolicy-2016-08.
What's the ALPN policy used for?
ALPN (Application-Layer Protocol Negotiation) policy can be set when the protocol is TLS. Valid values are HTTP1Only, HTTP2Only, HTTP2Optional, HTTP2Preferred, and None.
Actions & Routing
What action types are available for listeners?
Six action types are supported: forward (to target groups), redirect (URL redirects), fixed-response (static responses), authenticate-cognito (AWS Cognito auth), authenticate-oidc (OpenID Connect auth), and jwt-validation (JWT token validation).
How do I configure weighted target groups for blue/green deployments?
Use a forward action with a forward block containing multiple targetGroups, each with an arn and weight property (0-100). For example, set blue to weight 100 and green to weight 0 for initial deployment.
Can I use routing configuration properties with all load balancer types?
No, all routing* properties (CORS headers, security headers, etc.) can only be set if the protocol is HTTP or HTTPS for Application Load Balancers. They’re not supported for Network Load Balancers or Gateway Load Balancers.
Configuration Constraints
What's the TCP idle timeout and when can I configure it?
The TCP idle timeout can only be set if the protocol is TCP on a Network Load Balancer or with a Gateway Load Balancer. Valid values are 60 to 6000 seconds, with a default of 350 seconds. It’s not supported for Application Load Balancers.
Can I change the load balancer after creating a listener?
No, the loadBalancerArn property is immutable. You’ll need to recreate the listener to associate it with a different load balancer.

Using a different cloud?

Explore networking guides for other cloud providers: