The aws:alb/listener:Listener resource, part of the Pulumi AWS provider, defines how a load balancer accepts and routes incoming connections: its protocol, port, TLS configuration, and default actions. This guide focuses on four capabilities: HTTPS termination and traffic forwarding, weighted target group distribution, authentication (Cognito, JWT, mutual TLS), and HTTP-to-HTTPS redirection.
Listeners attach to existing load balancers and reference target groups, TLS certificates, and authentication providers. The examples are intentionally small. Combine them with your own load balancers, target groups, and security infrastructure.
Route HTTPS traffic to a target group
Most deployments accept HTTPS traffic on port 443 and forward requests to backend instances, terminating TLS at the load balancer.
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 accepts connections on the specified port using the protocol (HTTPS here). The certificateArn provides the TLS certificate for encryption, and sslPolicy controls which cipher suites are allowed. The defaultActions array defines what happens to requests: here, they’re forwarded to the target group specified by targetGroupArn.
Split traffic across target groups with weights
Blue-green deployments and canary releases route traffic to multiple target groups with configurable weight distribution.
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 specifies an ARN and weight. Weights determine the percentage of traffic each target group receives. Setting one weight to 0 and another to 100 creates a blue-green deployment where you can gradually shift traffic by adjusting weights.
Redirect HTTP to HTTPS automatically
Security policies often require redirecting all HTTP traffic to HTTPS to ensure encrypted connections.
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
The redirect action sends clients to a different URL. Here, it changes the protocol to HTTPS and port to 443, using a 301 permanent redirect. This listener handles HTTP on port 80 and redirects to HTTPS without needing a certificate or target group.
Authenticate users with Cognito before forwarding
Applications that need user authentication can delegate to Cognito User Pools before allowing access to backend resources.
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 authenticate-cognito, then forward. The authenticateCognito block specifies the Cognito User Pool, client, and domain. When a request arrives, the listener checks for a valid session cookie. If missing, it redirects to Cognito for login, then forwards authenticated requests to the target group.
Validate JWT tokens before routing requests
API gateways and microservices often validate JWT tokens at the edge to verify caller identity and claims before forwarding to backends.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const test = new aws.lb.Listener("test", {
loadBalancerArn: testAwsLb.id,
protocol: "HTTPS",
port: 443,
sslPolicy: "ELBSecurityPolicy-2016-08",
certificateArn: testAwsIamServerCertificate.arn,
defaultActions: [
{
type: "jwt-validation",
jwtValidation: {
issuer: "https://example.com",
jwksEndpoint: "https://example.com/.well-known/jwks.json",
additionalClaims: [
{
format: "string-array",
name: "claim_name1",
values: [
"value1",
"value2",
],
},
{
format: "single-string",
name: "claim_name2",
values: ["value1"],
},
],
},
},
{
targetGroupArn: testAwsLbTargetGroup.id,
type: "forward",
},
],
});
import pulumi
import pulumi_aws as aws
test = aws.lb.Listener("test",
load_balancer_arn=test_aws_lb["id"],
protocol="HTTPS",
port=443,
ssl_policy="ELBSecurityPolicy-2016-08",
certificate_arn=test_aws_iam_server_certificate["arn"],
default_actions=[
{
"type": "jwt-validation",
"jwt_validation": {
"issuer": "https://example.com",
"jwks_endpoint": "https://example.com/.well-known/jwks.json",
"additional_claims": [
{
"format": "string-array",
"name": "claim_name1",
"values": [
"value1",
"value2",
],
},
{
"format": "single-string",
"name": "claim_name2",
"values": ["value1"],
},
],
},
},
{
"target_group_arn": test_aws_lb_target_group["id"],
"type": "forward",
},
])
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 {
_, err := lb.NewListener(ctx, "test", &lb.ListenerArgs{
LoadBalancerArn: pulumi.Any(testAwsLb.Id),
Protocol: pulumi.String("HTTPS"),
Port: pulumi.Int(443),
SslPolicy: pulumi.String("ELBSecurityPolicy-2016-08"),
CertificateArn: pulumi.Any(testAwsIamServerCertificate.Arn),
DefaultActions: lb.ListenerDefaultActionArray{
&lb.ListenerDefaultActionArgs{
Type: pulumi.String("jwt-validation"),
JwtValidation: &lb.ListenerDefaultActionJwtValidationArgs{
Issuer: pulumi.String("https://example.com"),
JwksEndpoint: pulumi.String("https://example.com/.well-known/jwks.json"),
AdditionalClaims: lb.ListenerDefaultActionJwtValidationAdditionalClaimArray{
&lb.ListenerDefaultActionJwtValidationAdditionalClaimArgs{
Format: pulumi.String("string-array"),
Name: pulumi.String("claim_name1"),
Values: pulumi.StringArray{
pulumi.String("value1"),
pulumi.String("value2"),
},
},
&lb.ListenerDefaultActionJwtValidationAdditionalClaimArgs{
Format: pulumi.String("single-string"),
Name: pulumi.String("claim_name2"),
Values: pulumi.StringArray{
pulumi.String("value1"),
},
},
},
},
},
&lb.ListenerDefaultActionArgs{
TargetGroupArn: pulumi.Any(testAwsLbTargetGroup.Id),
Type: pulumi.String("forward"),
},
},
})
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 test = new Aws.LB.Listener("test", new()
{
LoadBalancerArn = testAwsLb.Id,
Protocol = "HTTPS",
Port = 443,
SslPolicy = "ELBSecurityPolicy-2016-08",
CertificateArn = testAwsIamServerCertificate.Arn,
DefaultActions = new[]
{
new Aws.LB.Inputs.ListenerDefaultActionArgs
{
Type = "jwt-validation",
JwtValidation = new Aws.LB.Inputs.ListenerDefaultActionJwtValidationArgs
{
Issuer = "https://example.com",
JwksEndpoint = "https://example.com/.well-known/jwks.json",
AdditionalClaims = new[]
{
new Aws.LB.Inputs.ListenerDefaultActionJwtValidationAdditionalClaimArgs
{
Format = "string-array",
Name = "claim_name1",
Values = new[]
{
"value1",
"value2",
},
},
new Aws.LB.Inputs.ListenerDefaultActionJwtValidationAdditionalClaimArgs
{
Format = "single-string",
Name = "claim_name2",
Values = new[]
{
"value1",
},
},
},
},
},
new Aws.LB.Inputs.ListenerDefaultActionArgs
{
TargetGroupArn = testAwsLbTargetGroup.Id,
Type = "forward",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
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.ListenerDefaultActionJwtValidationArgs;
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 test = new Listener("test", ListenerArgs.builder()
.loadBalancerArn(testAwsLb.id())
.protocol("HTTPS")
.port(443)
.sslPolicy("ELBSecurityPolicy-2016-08")
.certificateArn(testAwsIamServerCertificate.arn())
.defaultActions(
ListenerDefaultActionArgs.builder()
.type("jwt-validation")
.jwtValidation(ListenerDefaultActionJwtValidationArgs.builder()
.issuer("https://example.com")
.jwksEndpoint("https://example.com/.well-known/jwks.json")
.additionalClaims(
ListenerDefaultActionJwtValidationAdditionalClaimArgs.builder()
.format("string-array")
.name("claim_name1")
.values(
"value1",
"value2")
.build(),
ListenerDefaultActionJwtValidationAdditionalClaimArgs.builder()
.format("single-string")
.name("claim_name2")
.values("value1")
.build())
.build())
.build(),
ListenerDefaultActionArgs.builder()
.targetGroupArn(testAwsLbTargetGroup.id())
.type("forward")
.build())
.build());
}
}
resources:
test:
type: aws:lb:Listener
properties:
loadBalancerArn: ${testAwsLb.id}
protocol: HTTPS
port: '443'
sslPolicy: ELBSecurityPolicy-2016-08
certificateArn: ${testAwsIamServerCertificate.arn}
defaultActions:
- type: jwt-validation
jwtValidation:
issuer: https://example.com
jwksEndpoint: https://example.com/.well-known/jwks.json
additionalClaims:
- format: string-array
name: claim_name1
values:
- value1
- value2
- format: single-string
name: claim_name2
values:
- value1
- targetGroupArn: ${testAwsLbTargetGroup.id}
type: forward
The jwt-validation action verifies tokens against the issuer’s JWKS endpoint. The additionalClaims array specifies required claims and their expected values. Tokens must contain matching claims to pass validation. Failed validation blocks the request before it reaches your application.
Require client certificates with mutual TLS
High-security environments require clients to present certificates for mutual authentication, verifying both server and client identity.
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 client certificate validation. Setting mode to “verify” requires clients to present valid certificates from the trust store. The trustStoreArn points to an S3-backed trust store containing allowed certificate authorities. Requests without valid certificates are rejected at the load balancer.
Beyond these examples
These snippets focus on specific listener-level features: traffic routing and weighted distribution, authentication (Cognito, OIDC, JWT), and HTTP-to-HTTPS redirection and mutual TLS. They’re intentionally minimal rather than full load balancing solutions.
The examples reference pre-existing infrastructure such as load balancers and target groups, TLS certificates and trust stores, and Cognito User Pools or OIDC providers. 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
- Fixed-response actions for maintenance pages
- ALPN policies for protocol negotiation
- CORS and security headers (routing* properties)
- TCP idle timeout tuning (tcpIdleTimeoutSeconds)
These omissions are intentional: the goal is to illustrate how each listener feature is wired, not provide drop-in load balancing modules. See the ALB 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 FREEFrequently Asked Questions
Protocol & Load Balancer Types
HTTP and HTTPS (default: HTTP). Network Load Balancers support TCP, TLS, UDP, TCP_UDP, QUIC, and TCP_QUIC. Gateway Load Balancers don’t use the protocol property for listeners.QUIC and TCP_QUIC protocols aren’t valid if security groups are configured or dual-stack mode is enabled. UDP and TCP_UDP aren’t valid if dual-stack mode is enabled on your Network Load Balancer.port property isn’t valid for Gateway Load Balancers. Only Application and Network Load Balancers require a port specification.SSL/TLS & Certificates
protocol is HTTPS. You must provide exactly one certificate via certificateArn. For additional certificates, use the aws.lb.ListenerCertificate resource.ELBSecurityPolicy-2016-08. You must specify an sslPolicy if your protocol is HTTPS or TLS, though the default will be used if you don’t provide one.alpnPolicy property when your protocol is TLS. Valid values are HTTP1Only, HTTP2Only, HTTP2Optional, HTTP2Preferred, and None.Actions & Routing
forward (route to target groups), redirect (redirect requests), fixed-response (return static content), authenticate-cognito (Cognito authentication), authenticate-oidc (OIDC authentication), and jwt-validation (JWT token validation).forward action with a forward block containing multiple targetGroups. Each target group has an arn and weight property (e.g., blue with weight 100, green with weight 0 for initial deployment).redirect action with port set to "443", protocol set to "HTTPS", and statusCode set to "HTTP_301" for permanent redirects.fixed-response action with contentType (e.g., "text/plain"), messageBody, and statusCode properties to return static content directly from the load balancer.Authentication & Security
authenticate-cognito (AWS Cognito user pools), authenticate-oidc (OpenID Connect providers), and jwt-validation (JWT token validation). Chain authentication actions with a forward action to protect your backend.mutualAuthentication block with mode set to "verify" and provide a trustStoreArn pointing to your trust store containing client CA certificates.Advanced Configuration
HTTP or HTTPS protocols. You can modify mTLS client certificate headers, TLS cipher suite headers, and CORS headers using the routingHttpRequest* and routingHttpResponse* properties. These aren’t supported for Network or Gateway Load Balancers.tcpIdleTimeoutSeconds (range: 60-6000) only when the protocol is TCP on Network Load Balancers or with Gateway Load Balancers. It’s not supported for Application Load Balancers.loadBalancerArn property is immutable. Changing the load balancer requires recreating the listener.Using a different cloud?
Explore networking guides for other cloud providers: