Pular para o conteúdo principal

ALB - Application Load Balancer

Intelligently distribute HTTP/HTTPS traffic across multiple targets with content-based routing.

Prerequisite: AWSProvider Configuration

Before creating any AWS resource, you need to configure an AWSProvider that manages credentials and authentication with AWS.

IRSA:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: AWSProvider
metadata:
name: production-aws
namespace: default
spec:
region: us-east-1
roleARN: arn:aws:iam::123456789012:role/infra-operator-role
defaultTags:
managed-by: infra-operator
environment: production

Static Credentials:

apiVersion: v1
kind: Secret
metadata:
name: aws-credentials
namespace: default
type: Opaque
stringData:
access-key-id: test
secret-access-key: test
---
apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: AWSProvider
metadata:
name: localstack
namespace: default
spec:
region: us-east-1
accessKeyIDRef:
name: aws-credentials
key: access-key-id
secretAccessKeyRef:
name: aws-credentials
key: secret-access-key
defaultTags:
managed-by: infra-operator
environment: test

Verify Status:

kubectl get awsprovider
kubectl describe awsprovider production-aws
aviso

For production, always use IRSA (IAM Roles for Service Accounts) instead of static credentials.

Create IAM Role for IRSA

To use IRSA in production, you need to create an IAM Role with the necessary permissions:

Trust Policy (trust-policy.json):

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": "system:serviceaccount:infra-operator-system:infra-operator-controller-manager",
"oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com"
}
}
}
]
}

IAM Policy - ALB (alb-policy.json):

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"elasticloadbalancing:CreateLoadBalancer",
"elasticloadbalancing:DeleteLoadBalancer",
"elasticloadbalancing:DescribeLoadBalancers",
"elasticloadbalancing:DescribeLoadBalancerAttributes",
"elasticloadbalancing:ModifyLoadBalancerAttributes",
"elasticloadbalancing:DescribeTags",
"elasticloadbalancing:AddTags",
"elasticloadbalancing:RemoveTags"
],
"Resource": "*"
}
]
}

Create Role:

# Create IAM Role
aws iam create-role \
--role-name infra-operator-alb-role \
--assume-role-policy-document file://trust-policy.json

# Attach policy
aws iam put-role-policy \
--role-name infra-operator-alb-role \
--policy-name alb-policy \
--policy-document file://alb-policy.json

# Annotate Service Account in K8s
kubectl annotate serviceaccount infra-operator-controller-manager \
-n infra-operator-system \
eks.amazonaws.com/role-arn=arn:aws:iam::123456789012:role/infra-operator-alb-role

Creating Application Load Balancer

Internet-Facing ALB:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: ALB
metadata:
name: public-alb
namespace: default
spec:
providerRef:
name: production-aws

loadBalancerName: my-public-alb
scheme: internet-facing # Accessible from internet

subnets:
- subnet-abc123 # Public subnet AZ 1
- subnet-def456 # Public subnet AZ 2

securityGroups:
- sg-web123 # Security group allowing 80/443

ipAddressType: ipv4
enableHttp2: true
idleTimeout: 60

enableDeletionProtection: false

tags:
Name: public-alb
Environment: production
Team: platform

Internal ALB:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: ALB
metadata:
name: internal-alb
namespace: default
spec:
providerRef:
name: production-aws

loadBalancerName: my-internal-alb
scheme: internal # Accessible only within VPC

subnets:
- subnet-private1 # Private subnet AZ 1
- subnet-private2 # Private subnet AZ 2

securityGroups:
- sg-internal123

ipAddressType: ipv4
enableHttp2: true
idleTimeout: 120

enableDeletionProtection: false

tags:
Name: internal-alb
Environment: production
Purpose: microservices

ALB with WAF Protection:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: ALB
metadata:
name: waf-protected-alb
namespace: default
spec:
providerRef:
name: production-aws

loadBalancerName: waf-alb
scheme: internet-facing

subnets:
- subnet-abc123
- subnet-def456

securityGroups:
- sg-waf123

enableHttp2: true
enableWafFailOpen: true # Allow traffic if WAF is unavailable

enableDeletionProtection: true # Protection against accidental deletion

deletionPolicy: Retain # Do not delete ALB when removing CR

tags:
Name: waf-protected-alb
Environment: production
Protected: "true"

Verify Status:

# List ALBs
kubectl get alb

# View details
kubectl describe alb public-alb

# View ALB DNS (use this DNS to access)
kubectl get alb public-alb -o jsonpath='{.status.dnsName}'

# View ALB ARN
kubectl get alb public-alb -o jsonpath='{.status.loadBalancerARN}'

Specification Fields

FieldTypeRequiredDescription
loadBalancerNamestringApplication Load Balancer name (1-32 alphanumeric characters)
schemestringALB scheme: internet-facing (default) or internal
subnets[]stringList of subnet IDs (minimum 2 in different AZs)
securityGroups[]stringList of security group IDs
ipAddressTypestringIP address type: ipv4 (default) or dualstack (IPv4 + IPv6)
enableDeletionProtectionboolProtection against accidental deletion (default: false)
enableHttp2boolEnable HTTP/2 (default: true)
enableWafFailOpenboolAllow traffic if WAF is unavailable (default: false)
idleTimeoutint32Idle connection timeout in seconds (1-4000, default: 60)
tagsmap[string]stringCustom tags for ALB
deletionPolicystringDeletion policy: Delete (default) or Retain

Status Fields

FieldTypeDescription
readyboolWhether the ALB is active (state = "active")
loadBalancerARNstringARN of the created ALB
dnsNamestringPublic DNS of the ALB (use to access)
statestringState: provisioning, active, failed
vpcIDstringVPC where the ALB was created
canonicalHostedZoneIDstringHosted Zone ID for Route53
lastSyncTimetimeLast synchronization with AWS

Use Cases

Public ALB for Web Application

Example:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: ALB
metadata:
name: web-app-alb
namespace: production
spec:
providerRef:
name: production-aws

loadBalancerName: webapp-alb
scheme: internet-facing

subnets:
- subnet-public-1a
- subnet-public-1b
- subnet-public-1c

securityGroups:
- sg-web-https

enableHttp2: true
idleTimeout: 60

tags:
Application: web-app
Environment: production
CostCenter: engineering

Internal ALB for Microservices

Example:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: ALB
metadata:
name: microservices-alb
namespace: backend
spec:
providerRef:
name: production-aws

loadBalancerName: internal-services
scheme: internal

subnets:
- subnet-private-1a
- subnet-private-1b

securityGroups:
- sg-internal-services

enableHttp2: true
idleTimeout: 300 # 5 minutes for long-polling

tags:
Purpose: microservices-mesh
Environment: production

Troubleshooting

ALB Not Getting Ready

Check ALB state

Command:

kubectl describe alb my-alb

Look for:

  • State: provisioning - ALB is still being provisioned (can take 2-3 minutes)
  • State: failed - Provisioning failed (check operator logs)

Check subnets

Command:

# Check if subnets exist and are in different AZs
aws ec2 describe-subnets --subnet-ids subnet-abc123 subnet-def456

# ALB requires at least 2 subnets in different AZs

Common error: Subnets in the same AZ Solution: Use subnets in different AZs

Check security groups

Command:

# Check if security groups exist
aws ec2 describe-security-groups --group-ids sg-web123

# Check ingress rules
aws ec2 describe-security-groups --group-ids sg-web123 \
--query 'SecurityGroups[0].IpPermissions'

Common error: Security group without ingress rules Solution: Add rules allowing ports 80/443

Check IAM permissions

Command:

# View operator logs
kubectl logs -n infra-operator-system -l control-plane=controller-manager

# Look for "AccessDenied" errors

Common error: IAM role without ELBv2 permissions Solution: Add elasticloadbalancing:* policy to IRSA role

ALB Stuck in "provisioning"

Normal provisioning time

ALB typically takes 2-5 minutes to become active.

Command:

# Check state in AWS
aws elbv2 describe-load-balancers \
--names my-public-alb \
--query 'LoadBalancers[0].State'

If stuck for more than 10 minutes, check:

  • Subnets have connectivity to AWS API
  • No ALB limit reached on AWS account

Check account limits

Command:

# Check ALB quota
aws service-quotas get-service-quota \
--service-code elasticloadbalancing \
--quota-code L-53DA6B97

# List existing ALBs
aws elbv2 describe-load-balancers --query 'length(LoadBalancers)'

If limit reached (default: 50 ALBs per region):

  • Request quota increase via AWS Console
  • Delete unused ALBs

Error Deleting ALB

Deletion protection enabled

Command:

kubectl get alb my-alb -o yaml | grep deletionProtection

If enableDeletionProtection: true:

  1. Disable protection:
kubectl patch alb my-alb --type=merge -p '{"spec":{"enableDeletionProtection":false}}'
  1. Wait for reconciliation (1-2 minutes)

  2. Delete again:

kubectl delete alb my-alb

ALB with listeners/target groups

ALB cannot be deleted if it has associated listeners or target groups.

Command:

# List listeners
aws elbv2 describe-listeners --load-balancer-arn <ALB-ARN>

# List target groups
aws elbv2 describe-target-groups --load-balancer-arn <ALB-ARN>

Solution: Delete listeners and target groups manually first:

# Delete listeners
aws elbv2 delete-listener --listener-arn <LISTENER-ARN>

# Delete target groups
aws elbv2 delete-target-group --target-group-arn <TG-ARN>

# Now delete the ALB
kubectl delete alb my-alb

Deletion Policies

Delete (Default)

When the CR is deleted, the ALB in AWS is automatically deleted:

spec:
deletionPolicy: Delete # Default

Retain

The ALB in AWS is retained even after deleting the CR:

spec:
deletionPolicy: Retain

Use case: ALBs with complex configurations (listeners, rules, certificates) that you want to keep.

aviso

With deletionPolicy: Retain, the ALB continues to be charged even after deleting the CR.

Advanced Examples

ALB with IPv6 (Dual Stack)

Example:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: ALB
metadata:
name: ipv6-alb
spec:
providerRef:
name: production-aws

loadBalancerName: dual-stack-alb
scheme: internet-facing

subnets:
- subnet-abc123
- subnet-def456

ipAddressType: dualstack # IPv4 + IPv6

enableHttp2: true

ALB with Custom Timeout

Example:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: ALB
metadata:
name: long-polling-alb
spec:
providerRef:
name: production-aws

loadBalancerName: websocket-alb

subnets:
- subnet-abc123
- subnet-def456

idleTimeout: 3600 # 1 hour for WebSockets

tags:
Purpose: websocket-connections

Next Steps

After creating the ALB:

  1. Configure Listeners (HTTP/HTTPS) via AWS Console or Terraform
  2. Create Target Groups pointing to your Kubernetes pods
  3. Configure Rules for path/host-based routing
  4. Add SSL Certificates via ACM
  5. Configure WAF for protection against attacks
informação

The operator only manages the ALB. Listeners, target groups, and rules must be configured separately.

References