Containers

Securing Amazon Elastic Container Service applications using Application Load Balancer and Amazon Cognito

Introduction

Designing and maintaining secure user management, authentication and other related features for applications is not an easy task. Amazon Cognito takes care of this work, which allows developers to focus on building the core business logic of the application.

Amazon Cognito provides user management, authentication, and authorization for applications where users can log in in directly or through their pre-existing social or corporate credentials.

Amazon Elastic Containers Service (Amazon ECS) is a fully managed container orchestration service that makes it easy for customers to deploy, manage, and scale their container-based applications. When building using Amazon ECS, it is common to use Application Load Balancer (ALB) for application high availability and other features like SSL/TLS offloading, host based routing, and other application-aware traffic handling.

Another benefit of using the ALB with Amazon ECS is that the ALB has in-built support for Amazon Cognito.

When setting up the ALB, you can chose if you want incoming user traffic to be redirected to Amazon Cognito for authentication. By building secure containerized applications using Amazon ECS, and using ALB and its Amazon Cognito integration, you get the benefits of the ease of container orchestration and user authentication and authorization.

Flow of how Application Load Balancer authenticates users using Amazon Cognito

For an application fronted by ALB that integrates with Amazon Cognito and has been set up to authenticate users, the following stepwise flow describes what happens when a user attempts to access the application.

For more information, see the example built by the AWS Elastic Load Balancing Demos.

A visual representation of how an Application Load Balancer uses Cognito to authenticate users

You need to understand what the ALB is doing to secure user access with Amazon Cognito:

  1. A user sends a request to the application fronted by the ALB, which has a set of rules that it evaluates for all traffic to determine what action to carry out. The rule (such as the path-based rule saying all traffic for/login) when matched triggers the authentication action on the ALB. The ALB then inspects the user’s HTTP payload for an authentication cookie.
  2. Because this is the user’s first visit, this cookie isn’t present. The ALB doesn’t see any cookie and redirects the user to the configured Amazon Cognito’s authorization endpoint.
  3. The user is presented with an authentication page from Amazon Cognito, where the user inputs their credentials. Amazon Cognito redirects the user back to the ALB and passes an authorization code to the user in the redirect URL.
  4. The load balancer takes this authorization code and makes a request to Amazon Cognito’s token endpoint.
  5. Amazon Cognito validates the authorization code and presents the ALB with an ID and access token.
  6. The ALB forwards the access token to Amazon Cognito’s user info endpoint.
  7. Amazon Cognito’s user information endpoint presents the ALB with user claims.
  8. The ALB redirects the user who is trying to access the application (step 1) to the same URL while inserting the authentication cookie in the redirect response.
  9. The user makes the request to the ALB with the cookie and the ALB validates it and forwards the request to the ALB’s target. The ALB inserts information (such as user claims, access token, and the subject field) into a set of X-AMZN-OIDC-* HTTP headers to the target.
  10. The target generates a response and forwards to the ALB.
  11. The ALB sends the response to the authenticated user.

When the user makes subsequent requests for HTTP request and response, the flow will go through steps 9–11. If the user makes a new request without the authentication cookie, it goes through steps 1–11.

For more information, see the authentication flow between the ALB and Amazon Cognito.

Solution overview

You will use a PHP application built for demonstration purpose. The application is published and verified in the public docker hub. We use and configure Amazon Route 53 for Domain Name Service (DNS) handling and AWS Certificate Manager (ACM) to provision Transport Layer Security (TLS) Certificates for usage.

Amazon Cognito handles the Authentication flows and Amazon ECS handles the container scheduling and orchestration.

The following solution architecture diagram presents an overview of the solution.

A diagram showing the high-level architecture of the solution described in this post

Prerequisites

To complete this tutorial you need the following tools, which can be installed with the links:

Environment

In this post, I used the AWS Cloud9 as an Integrated Development Environment (IDE) to configure the settings in this tutorial. You can use AWS Cloud9 or your own IDE. The commands used were tested using Amazon Linux 2 running in the Amazon Cloud9 environment.

Follow the steps linked to install and configure Amazon Cloud9:

Create a workspace to deploy this solution, which includes creating an AWS Identity and Access Management (IAM) role that will be attached to the workspace instance.

Launch the base infrastructure platform that the resources reside in

The Amazon ECS needs to be launched into a Virtual Private Cloud (VPC) infrastructure. To create this infrastructure, you use an AWS CloudFormation template that automates the creation of the platform.

Download the zip file that contains an AWS CloudFormation yaml file: codebuild-vpc-cfn.yaml.

Once deployed, the following resources are created into your AWS account: a Virtual Private Cloud (VPC), an internet gateway, two public subnets, two private subnets, two Network Address Translation (NAT) Gateways, and one security group.

To launch the stack, follow these steps:

  • Sign in to the AWS Management Console.
  • In your Region of choice, you will see the Region list in the top right-hand corner.
  • Search for the AWS CloudFormation service in the Console search bar.
  • Choose Create Stack and select with new resources (standard).
  • To specify template, choose upload a template file.
  • Upload the previously downloaded: codebuild-vpc-cfn.yaml file.
  • To create the stack and configure stack options, choose Next.
  • Enter ecsplatform for stack name and ecsplatform for EnvironmentName. Choose Next.
  • Leave the rest of the default settings and choose Next.
  • Choose Create Stack.
  • When CloudFormation has completed its deployment its the resources, the status is CREATE_COMPLETE.

Next on your Amazon Cloud9 workspace terminal, set the below environment variables:

AUTH_ECS_REGION=eu-west-1 <-- Change to the region you used in your Cloudformation configuration
AUTH_ECS_CLUSTER=ecsauth
AUTH_ECS_VPC=$(aws cloudformation describe-stacks --stack-name ecsplatform --query "Stacks[0].Outputs[?OutputKey=='VPC'].OutputValue" --output text)
AUTH_ECS_PUBLICSUBNET_1=$(aws cloudformation describe-stacks --stack-name ecsplatform --query "Stacks[0].Outputs[?OutputKey=='PublicSubnet1'].OutputValue" --output text)
AUTH_ECS_PUBLICSUBNET_2=$(aws cloudformation describe-stacks --stack-name ecsplatform --query "Stacks[0].Outputs[?OutputKey=='PublicSubnet2'].OutputValue" --output text)
AUTH_ECS_PRIVATESUBNET_1=$(aws cloudformation describe-stacks --stack-name ecsplatform --query "Stacks[0].Outputs[?OutputKey=='PrivateSubnet1'].OutputValue" --output text)
AUTH_ECS_PRIVATESUBNET_2=$(aws cloudformation describe-stacks --stack-name ecsplatform --query "Stacks[0].Outputs[?OutputKey=='PrivateSubnet2'].OutputValue" --output text)
AUTH_ECS_SG=$(aws cloudformation describe-stacks --stack-name ecsplatform --query "Stacks[0].Outputs[?OutputKey=='NoIngressSecurityGroup'].OutputValue" --output text)
AUTH_ECS_DOMAIN=www.example.com <-- Change to a domain name you want to use for this solution for this solution

You will set additional variables later, but these are enough to begin building your solution.

Configure the security group rules needed for web traffic access

When users access the ALB, the security group attached to it needs to allow ingress port 443 (https) traffic. In addition, when the ALB forwards the web traffic to the Amazon ECS tasks there needs to be a ingress rules attached to the Amazon ECS container instances that allows ingress port 80 (http) traffic.

You can achieve this access with the following:

aws ec2 authorize-security-group-ingress \
  --group-id $AUTH_ECS_SG \
  --protocol tcp \
  --port 443 \
  --cidr 0.0.0.0/0
  
aws ec2 authorize-security-group-ingress \
--group-id $AUTH_ECS_SG \
--protocol tcp \
--port 80 \
--cidr 0.0.0.0/0

Create a public Application Load Balancer

As described earlier, the ALB will receive and terminate all client requests to validate for authentication using Amazon Cognito. The ALB also handles TLS offloading where the TLS certificates for the domain name will be deployed on it.

To create the ALB do the below:

AUTH_ECS_ALBARN=$(aws elbv2 create-load-balancer --name $AUTH_ECS_CLUSTER --subnets $AUTH_ECS_PUBLICSUBNET_1 $AUTH_ECS_PUBLICSUBNET_2 --security-groups $AUTH_ECS_SG --query 'LoadBalancers[0].LoadBalancerArn' --output text)

AUTH_ECS_ALB_DNS=$(aws elbv2 describe-load-balancers --load-balancer-arns $AUTH_ECS_ALBARN --query 'LoadBalancers[0].DNSName' --output text)

Configure a Domain Name System

Clients will need a domain name that points to the ALB to type into their browsers.

In this post, the Domain Name System (DNS) name is registered using the DNS Resolution service, Amazon Route 53.

You can configure your domain name (such as www.example.com) where it‘s known as the record and placed in a Route 53-hosted zone.

 Configure both the Route 53 hosted zone and record

If you already have a Route53 publicly hosted zone for the apex domain and this is the location where you plan to add the record, then you will set its host zone ID (AUTH_ECS_R53HZ). For more information, see the hosted zone ID documentation.

The first command line shown below demonstrates how to identify a hosted zone ID. You can substitute example.com for your apex domain name. The other commands create a record that points to the ALB.

AUTH_ECS_R53HZ=$(aws route53 list-hosted-zones-by-name --dns-name example.com --query 'HostedZones[0].Id'  --output text | grep -o '/hostedzone/.*' | cut -b 13-27) 

cat << EOF > dnsrecord.json
{
  "Comment": "CREATE a DNS record that points to the ALB",
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "$AUTH_ECS_DOMAIN",
        "Type": "CNAME",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "$AUTH_ECS_ALB_DNS"
          }
        ]
      }
    }
  ]
}
EOF 
aws route53 change-resource-record-sets --hosted-zone-id $AUTH_ECS_R53HZ --change-batch file://dnsrecord.json

Request a public certificate

To ensure that web traffic sent by clients to the ALB is encrypted, integrate an ACM (AWS Certificate Manager) Certificate into the ALB’s listener. This ensures that the ALB serves HTTPS traffic and communications from clients to ALB is encrypted.  Public SSL/TLS certificates provisioned through AWS Certificate Manager are free. You pay only for the AWS resources you create to run your application.

Provision an ACM certificate

AUTH_ECS_ACM_CERT_ARN=$(aws acm request-certificate \
  --domain-name $AUTH_ECS_DOMAIN \
  --validation-method DNS \
  --region $AUTH_ECS_REGION \
  --query 'CertificateArn' \
  --output text)

When you create an SSL/TLS Certificate using ACM, it will try to confirm that you’re the owner of the domain name before fully provisioning the certificate for you to use. One method of confirmation is through DNS validation.

Through this method ACM creates two CNAME records that you must add in your Route53 hosted zone.

To add the ACM CNAME records in your Route53 hosted zones:

cat << EOF > acm_validate_cert_dns.json
{
   "Changes":[
      {
         "Action": "UPSERT",
         "ResourceRecordSet":{
            "Name": "$(aws acm describe-certificate --certificate-arn $AUTH_ECS_ACM_CERT_ARN --query 'Certificate.DomainValidationOptions[].ResourceRecord[].Name' --output text)",
            "Type": "CNAME",
            "TTL": 300,
            "ResourceRecords": [
               {
                  "Value": "$(aws acm describe-certificate --certificate-arn $AUTH_ECS_ACM_CERT_ARN --query 'Certificate.DomainValidationOptions[].ResourceRecord[].Value' --output text)"
               }
            ]
         }
      }
   ]
 }
EOF
aws route53 change-resource-record-sets \
  --hosted-zone-id $AUTH_ECS_R53HZ \
  --change-batch file://acm_validate_cert_dns.json

It takes some time before the certificate will change from ‘Pending Validation’ to ‘Success’.

Once the status shows ‘Issued’ on the ACM console then you can use the certificate.

Create an HTTPS listener and listener rule on the ALB

Now that you’ve created the ALB. In addition, you’ve also created a certificate to configure the HTTPS listener to accept incoming HTTPS request from clients and to terminate them.

You integrate the certificate into the listener and add a default rule action on the ALB:

cat << EOF > listener-defaultaction.json
[
  {
    "Type": "redirect",
    "RedirectConfig": {
      "Protocol": "HTTPS",
      "Port": "443",
      "Host": "$AUTH_ECS_DOMAIN",
      "StatusCode": "HTTP_301"
    }
  }
]
EOF
AUTH_ECS_ALBLISTENER=$(aws elbv2 create-listener \
    --load-balancer-arn $AUTH_ECS_ALBARN \
    --protocol HTTPS \
    --port 443 \
    --certificates CertificateArn=$AUTH_ECS_ACM_CERT_ARN \
    --ssl-policy ELBSecurityPolicy-2016-08 \
    --default-actions file://listener-defaultaction.json \
    --query 'Listeners[0].ListenerArn' \
    --output text)

Create an Amazon Cognito user pool

As previously described, Amazon Cognito provides user management, authentication and authorization for applications where users can login in directly or through their pre-existing social/corporate credentials.

Create a user pool, which is a user directory in Amazon Cognito that helps clients to access the website. Clients sign in with their credentials before they get access to the site.

To fully configure Amazon Cognito for integration with the ALB, create a user pool, a user pool application client, and a user pool domain. The following steps show you how to accomplish these tasks.

Create an Amazon Cognito user pool

AUTH_COGNITO_USER_POOL_ID=$(aws cognito-idp create-user-pool \
  --pool-name ${AUTH_ECS_CLUSTER}_Pool \
  --username-attributes email \
  --username-configuration=CaseSensitive=false \
  --region $AUTH_ECS_REGION \
  --query 'UserPool.Id' \
  --auto-verified-attributes email \
  --output text)

Create an Amazon Cognito user pool application client

AUTH_COGNITO_USER_POOL_CLIENT_ID=$(aws cognito-idp create-user-pool-client \
  --client-name ${AUTH_ECS_CLUSTER}_AppClient \
  --user-pool-id $AUTH_COGNITO_USER_POOL_ID \
  --generate-secret \
  --allowed-o-auth-flows "code" \
  --allowed-o-auth-scopes "openid" \
  --callback-urls "https://${AUTH_ECS_DOMAIN}/oauth2/idpresponse" \
  --supported-identity-providers "COGNITO" \
  --allowed-o-auth-flows-user-pool-client \
  --region $AUTH_ECS_REGION \
  --query 'UserPoolClient.ClientId' \
  --output text)

Create an Amazon Cognito user pool domain

AUTH_COGNITO_USER_POOL_ARN=$(aws cognito-idp describe-user-pool --user-pool-id $AUTH_COGNITO_USER_POOL_ID --query 'UserPool'.Arn --output text)

AUTH_COGNITO_DOMAIN=(authecsblog$(whoami))

aws cognito-idp create-user-pool-domain \
  --user-pool-id $AUTH_COGNITO_USER_POOL_ID \
  --region $AUTH_ECS_REGION  \
  --domain $AUTH_COGNITO_DOMAIN

Create and configure a target group for the ALB

Create a target group for the ALB. The target group is used to route requests to the Amazon ECS tasks.

When an ALB receives the HTTPS traffic from the web clients, it routes the requests to the target group (after authentication of the client has occurred) for a web response. (Amazon ECS tasks are registered to the target group in a later section “Configuring the ECS Service”).

Create an empty target group:

AUTH_ECS_ALBTG=$(aws elbv2 create-target-group \
      --name ${AUTH_ECS_CLUSTER}-tg \
      --protocol HTTP \
      --port 80 \
      --target-type instance \
      --vpc-id $AUTH_ECS_VPC \
      --query 'TargetGroups[0].TargetGroupArn' \
      --output text)

Host-based routing and an authentication rule on the ALB

The ALB routes requests based on the host name in the HTTP host header.

It is possible to configure multiple domains that all point to a single ALB because the ALB can route requests based on the incoming host header and forward the requests to the right target group for handling.

You can configure an authentication rule which tells the ALB what to do to the incoming requests. In this post, we want the requests to first be authenticated and, if successful, the request should get forwarded to the target group we created earlier.

Configure host-based routing and an authentication rule on the ALB

cat << EOF > actions-authenticate.json
        [
            {
                "Type": "authenticate-cognito",
                "AuthenticateCognitoConfig": {
                    "UserPoolArn": "$AUTH_COGNITO_USER_POOL_ARN",
                    "UserPoolClientId":
"$AUTH_COGNITO_USER_POOL_CLIENT_ID",
                    "UserPoolDomain": "$AUTH_COGNITO_DOMAIN",
                    "SessionCookieName": "AWSELBAuthSessionCookie",
                    "Scope": "openid",
                    "OnUnauthenticatedRequest": "authenticate"
                },
                "Order": 1
            },
            {
                "Type": "forward",
                "TargetGroupArn": "$AUTH_ECS_ALBTG",
                "Order": 2
            }
        ]
EOF

cat << EOF > conditions-hostrouting.json
[
  {
      "Field": "host-header",
      "HostHeaderConfig": {
          "Values": ["$AUTH_ECS_DOMAIN"]
      }
  }
]
EOF

aws elbv2 create-rule \
    --listener-arn $AUTH_ECS_ALBLISTENER \
    --priority 20 \
    --conditions file://conditions-hostrouting.json \
    --actions file://actions-authenticate.json

Amazon ECS configuration

The ALB and Amazon Cognito are now configured for processing incoming requests and authentication.

Next you will configure Amazon ECS to orchestrate and deploy running tasks to generate response for the client’s web request.

An Amazon ECS cluster is a logical grouping of tasks or services. Amazon ECS instances are part of the Amazon ECS infrastructure registered to a cluster that the Amazon ECS tasks run on.

Two t3.small Amazon ECS instances will be configured to run the tasks. Amazon ECS will run and maintain two tasks, which are configured based on parameters and settings contained in the task definition (a JSON text file).

For more information on Amazon ECS basics, constructs, and orchestration read the Amazon ECS components documentation.

Configure the Amazon ECS CLI

Amazon ECS CLI is the tool that you’d use to configure and launch the Amazon ECS components.

To download Amazon ECS CLI, follow the following steps:

Amazon ECS CLI needs a CLI profile, to proceed generate an access key ID, and access key using the AWS credentials documentation.

Set the $AWS_ACCESS_KEY_ID and $AWS_SECRET_ACCESS_KEY variables to the copied values generated by AWS IAM.

 Configure the Amazon ECS CLI for a CLI profile

ecs-cli configure profile --profile-name profile_name --access-key $AWS_ACCESS_KEY_ID --secret-key $AWS_SECRET_ACCESS_KEY

Create the Amazon ECS cluster

Create the Amazon ECS cluster, which consists of two t3.small instance types deployed in the VPC and residing in the two private subnets from earlier. For the instance-role, use the AWS IAM role created when configuring the AWS Cloud9 environment workspace (ecsworkshop-admin).

The first command creates a keypair and the second command configures the Amazon ECS cluster. The keypair is useful if you need to SSH into the Amazon ECS instances for troubleshooting.

 Configure the Amazon EC2 key pair and bring up the ECS cluster

aws ec2 create-key-pair \
    --key-name $AUTH_ECS_CLUSTER \
    --key-type rsa \
    --query "KeyMaterial" \
    --output text > $AUTH_ECS_CLUSTER.pem
    
ecs-cli up --instance-role ecsworkshop-admin --cluster $AUTH_ECS_CLUSTER --vpc $AUTH_ECS_VPC --subnets $AUTH_ECS_PRIVATESUBNET_1,$AUTH_ECS_PRIVATESUBNET_2 --port 443 --region $AUTH_ECS_REGION --keypair $AUTH_ECS_CLUSTER --size 2 --instance-type t3.small --security-group $AUTH_ECS_SG --launch-type EC2

The cluster creation will take some time, when fully deployed the AWS CloudFormation stack status will output ‘Cluster creation succeeded’.

 Configure the AWS Region and ECS cluster name using the configure command:

ecs-cli configure --region $AUTH_ECS_REGION --cluster $AUTH_ECS_CLUSTER --default-launch-type EC2 --config-name $AUTH_ECS_CLUSTER

The EC2 launch type, with Amazon ECS instances, is created and launched in your VPC. If you prefer not to manage the underlying instances hosting the tasks, then Fargate launch type is the option to use. Fargate is the serverless way to host your Amazon ECS workloads.

 Create the ECS service

The ecs-cli compose service up command will create the Amazon ECS service and tasks from a Docker Compose file (ecsauth-compose.yaml) that you create. This service is configured to use the ALB that you created earlier. A task definition is created by the command.

The Docker Compose file contains the configuration settings that the Amazon ECS service is spun up with. This includes the Docker image to pull and use, the ports to expose on the Amazon ECS instance, and the Amazon ECS task for network forwarding. In this post, we configured it to use the AWS published sample demo PHP application verified and published to Docker Hub. Also, the Transmission Control Protocol (TCP) port 80 will be opened on the Amazon ECS instance and traffic received on this port will be forwarded to the task on TCP port 80).

 Configuring the ECS service

cat << EOF > ecsauth-compose.yml
version: '2'
services:
 web:
   image: amazon/amazon-ecs-sample
   ports:
     - "80:80"
EOF
ecs-cli compose --project-name ${AUTH_ECS_CLUSTER}service --file ecsauth-compose.yml service up --target-group-arn $AUTH_ECS_ALBTG  --container-name web --container-port 80 --role ecsServiceRole
ecs-cli compose --project-name ${AUTH_ECS_CLUSTER}service --file ecsauth-compose.yml service scale 2

Testing the solution end to end

We now the have working components of the solution. To test the solution end to end, you can navigate to the https site of the domain name used in your browser (such as https://www.example.com).

echo $AUTH_ECS_DOMAIN

The sequence of events that follows is as we described in the flow of how the ALB authenticates users using Amazon Cognito (section “Flow of how Application Load Balancer authenticates users using Amazon Cognito”).

After redirection by the ALB to the Amazon Cognito configured domain’s login page (a hosted UI by Amazon Cognito), enter input your credentials.

Since this is the first time the page is accessed we will sign up as a new user. Amazon Cognito stores this information in the user pool. If you navigate to the Amazon Cognito user pool console after, you’ll see this new user.

A screenshot showing a new user signing up with a new account to access the site

After signing in to the ALB, it redirects you to the landing page of the sample demonstration PHP application, which is shown in the diagram below.

A screenshot showing the landing page of the site after a successful user login

User claims encoding and security

In this post, we configured the target group to use HTTP, because the ALB has handled the TLS offloading. However, for enhanced security, you should restrict the traffic getting to the Amazon ECS instances to only the load balancer using the security group.

After the load balancer authenticates a user successfully, it passes the claims of the user to the target. If you inspect traffic forwarded to the sample demonstration application through custom HTTP header logging in your access logs, you can see three HTTP headers. These headers contain information about the user claims and is signed by the ALB with a signature and algorithm that you can verify.

The three HTTP headers include the following:

x-amzn-oidc-accesstoken

The access token from the token endpoint, in plain text.

x-amzn-oidc-identity

The subject field (sub) from the user info endpoint, in plain text.

x-amzn-oidc-data

The user claims, in JSON web tokens (JWT) format.

From information encoded in the x-amzn-oidc-data, it is possible to extract information about the user.

The following is an example Python 3.x application that can decode the payload portion of the x-amzn-oidc-data to reveal the user claims passed by Amazon Cognito.

import jwt
import requests
import base64
import json

# Step 1: Get the key id from JWT headers (the kid field)
;
encoded_jwt = headers.dict['x-amzn-oidc-data']
jwt_headers = encoded_jwt.split('.')[0]
decoded_jwt_headers = base64.b64decode(jwt_headers)
decoded_jwt_headers = decoded_jwt_headers.decode("utf-8")
decoded_json = json.loads(decoded_jwt_headers)
kid = decoded_json['kid']

# Step 2: Get the public key from regional endpoint
url = 'https://public-keys.auth.elb.' + region + '.amazonaws.com/' + kidreq = requests.get(url)
pub_key = req.text

# Step 3: Get the payload
payload = jwt.decode(encoded_jwt, pub_key, algorithms=['ES256'])

Cleanup

Now that you are done building the solution and testing it to clean up all the resources you can run the following commands:

aws elbv2 delete-load-balancer \
  --load-balancer-arn $AUTH_ECS_ALBARN

aws ecs delete-service --cluster $AUTH_ECS_CLUSTER --service ${AUTH_ECS_CLUSTER}service –force

containerinstance1=$(aws ecs list-container-instances --cluster $AUTH_ECS_CLUSTER --query 'containerInstanceArns[0]' --output text)
containerinstance2=$(aws ecs list-container-instances –cluster
$AUTH_ECS_CLUSTER --query 'containerInstanceArns[1]' --output text)

aws ecs deregister-container-instance \
    --cluster $AUTH_ECS_CLUSTER \
    --container-instance $containerinstance1 \
    --force

aws ecs deregister-container-instance \
    --cluster $AUTH_ECS_CLUSTER \
    --container-instance $containerinstance2 \
    --force

aws ecs delete-cluster --cluster $AUTH_ECS_CLUSTER

aws ecs deregister-task-definition --task-definition ${AUTH_ECS_CLUSTER}service:1
aws acm delete-certificate --certificate-arn $AUTH_ECS_ACM_CERT_ARN
aws route53 delete-hosted-zone --id $AUTH_ECS_R53HZ

aws cognito-idp delete-user-pool-domain \
  --user-pool-id $AUTH_COGNITO_USER_POOL_ID \
  --domain $AUTH_COGNITO_DOMAIN

aws cognito-idp delete-user-pool --user-pool-id $AUTH_COGNITO_USER_POOL_ID

aws elbv2 delete-target-group \
  --target-group-arn $AUTH_ECS_ALBTG
 
aws cloudformation delete-stack \
   --stack-name amazon-ecs-cli-setup-$AUTH_ECS_CLUSTER
 
aws cloudformation delete-stack \
   --stack-name ecsplatform
    
aws ec2 delete-key-pair --key-name $AUTH_ECS_CLUSTER

Conclusion

In this post, we showed you how to authenticate users accessing your containerized application without writing authentication code, using the ALB’s inbuilt integration with Amazon Cognito. Maintaining and securing user management and authentication is offloaded from the application, which allows you to focus on building core business logic into the application. You don’t need to worry about platform tasks for managing, scheduling, and scaling containers for the web traffic because Amazon ECS handles all of that.