Secure your AWS ECS resources with Cognito
In this post, we will protect our ECS Fargate containers behind an AWS ALB with Cognito authentication.
The authentication flow and the infrastructure are represented in the following image:
- 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. - 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.
- 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.
- The load balancer takes this authorization code and makes a request to Amazon Cognito’s token endpoint.
- Amazon Cognito validates the authorization code and presents the ALB with an ID and access token.
- The ALB forwards the access token to Amazon Cognito’s user info endpoint.
- Amazon Cognito’s user information endpoint presents the ALB with user claims.
- 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.
- 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. - The target generates a response and forwards to the ALB.
- The ALB sends the response to the authenticated user.
You can find more details in the AWS documentation at this link.
Prerequisites
You must have an AWS account and aws-cli installed on your machine. Here you can find instructions to satisfy the prerequisites for this tutorial.
Download the repository from GitHub here.
You also need to have a Domain (I bought mine on AWS Route53 Registrar but you can buy it from any provider you want, the cost is about 10$ per year) and a Route53 hosted zone related to your domain.
At last, you must have an active Certificate created with AWS ACM, here’s a procedure to create and validate a new TLS Certificate using the DNS Validation,
Repository structure:
The infrastructure will be deployed using AWS Cloudformation composed of 4 YAML files connected with the Cloudformation import and outputs features.
vpc.yaml
this stack contains all the VPC resources, here you can find all the details about;cognito.yaml
this stack contains Cognito UserPool, ClientId, and, UserPool Domain and will be discussed later in this article;core-resources.yaml
this stack contains the ECS cluster, Application Load Balancer, and the Route53 record inside your Domain hosted zoneecs.yaml
this stack contains the ALB rule related to the listener declared incore-resources.yaml
, the ECS task definition and service related to the ECS cluster incore-resources.yaml
.
VPC stack
I’ve already talked about all the resources in a vpc stack. You can find everything you need in this post: https://medium.com/aws-infrastructure/create-aws-vpc-infrastructure-with-cloudformation-d8fe17068228.
Deploy
aws cloudformation create-stack --stack-name vpc --template-body file://./vpc.yaml
The command “aws cloudformation create-stack” is used to create a new CloudFormation stack. The “ — stack-name” option allows you to specify a name for the stack, in this case “vpc”. The “ — template-body” option allows you to specify the location of the CloudFormation template that defines the resources to be created in the stack, in this case a local file named “vpc.yaml”.
Cognito stack
Parameters
Parameters:
DomainName:
Type: String
SubDomainName:
Type: String
UserPoolDomainName:
Type: String
The “Parameters” section of an AWS CloudFormation template defines input values that are passed to the template when it is launched. In this example, the following parameters are defined:
- DomainName: This is a string type parameter which is used as the domain name in the CallbackURLs property of CognitoClientID resource.
- SubDomainName: This is a string type parameter which is used as the sub-domain name in the CallbackURLs property of CognitoClientID resource.
- UserPoolDomainName: This is a string type parameter which is used as the user pool domain name, this parameter is used to specify a custom domain name for the user pool, instead of using the default Amazon Cognito domain name.
These parameters allow the user to provide input values for the domain name, sub-domain name, and user pool domain name when launching the CloudFormation stack. These values are then used in various resources of the template, such as the CognitoClientID resource, to customize the configuration of the resources that are created.
The “DomainName” parameter must contain the FQDN you bought as explained in the prerequisite section of this post. You can choose any string you want for the “SubDomainName” parameter.
UserPool
CognitoUserPool:
Type: AWS::Cognito::UserPool
Properties:
UsernameAttributes:
- email
UsernameConfiguration:
CaseSensitive: false
UserPoolName: User_Pool
VerificationMessageTemplate:
DefaultEmailOption: CONFIRM_WITH_CODE
AutoVerifiedAttributes:
- email
The CognitoUserPool
resource is a user pool in Amazon Cognito. It is created using the AWS::Cognito::UserPool
type.
The Properties
field of this resource contains several key-value pairs that configure the user pool.
UsernameAttributes
is a list of attributes that are used as the username for the user pool. In this case, it is set toemail
, meaning the email address is used as the username.UsernameConfiguration
is an object that configures how usernames are handled for the user pool. In this case, theCaseSensitive
property is set tofalse
, meaning that usernames are case-insensitive.UserPoolName
is a name for the user pool. In this case, it is set toUser_Pool
.VerificationMessageTemplate
is an object that configures the verification messages sent by Amazon Cognito. In this case, theDefaultEmailOption
property is set toCONFIRM_WITH_CODE
, meaning that a verification code is sent to the user via email.AutoVerifiedAttributes
is a list of attributes that are automatically verified by Amazon Cognito. In this case, it is set toemail
, meaning that the email address is automatically verified.
In summary, this resource creates a user pool in Amazon Cognito with email as the username, case-insensitive usernames, with a name of User_Pool, users will get a verification code via email and email addresses will be auto-verified.
ClientID
CognitoClientID:
Type: AWS::Cognito::UserPoolClient
Properties:
AllowedOAuthFlows:
- code
AllowedOAuthFlowsUserPoolClient: true
AllowedOAuthScopes:
- openid
CallbackURLs:
- !Sub https://${SubDomainName}.${DomainName}/oauth2/idpresponse
ClientName: Client_Name
GenerateSecret: true
SupportedIdentityProviders:
- COGNITO
UserPoolId: !Ref CognitoUserPool
The AWS CloudFormation resource described is a CognitoClientID, which represents a user pool client in Amazon Cognito. It has several properties that determine its behavior and configuration.
- The AllowedOAuthFlows property specifies that the client is allowed to use the “code” flow for OAuth 2.0 authentication.
- The AllowedOAuthFlowsUserPoolClient property is set to “true”, indicating that the client is a user pool client.
- The AllowedOAuthScopes property specifies that the client is allowed to request the “openid” scope during authentication.
- The CallbackURLs property specifies the URLs that the client is allowed to redirect to after a successful authentication. The URL is a combination of SubDomainName and DomainName passed as input parameters.
- The ClientName property specifies the name of the client.
- The GenerateSecret property is set to “true”, indicating that a client secret will be generated for the client.
- The SupportedIdentityProviders property specifies that the client is able to authenticate with the “COGNITO” identity provider.
- The UserPoolId property specifies the ID of the Cognito user pool that the client belongs to, and it is passed as input parameter and is referenced by CognitoUserPool.
UserPool Domain
CognitoUserPoolDomain:
Type: AWS::Cognito::UserPoolDomain
Properties:
Domain: !Ref UserPoolDomainName
UserPoolId: !Ref CognitoUserPool
The AWS CloudFormation resource described is a CognitoUserPoolDomain, which represents a domain for a user pool in Amazon Cognito. It has two properties that determine its behavior and configuration:
- The Domain property specifies the domain string for the user pool. It’s passed as input parameter and referenced by UserPoolDomainName.
- The UserPoolId property specifies the ID of the Cognito user pool that the domain belongs to. It’s the Cognito UserPool created in the same file and described above referenced by CognitoUserPool.
This resource creates a domain for the specified user pool and allows for a custom URL for the user pool’s sign-up and sign-in pages. This means that users can sign in to the user pool using a URL based on this domain, rather than the default Amazon Cognito domain.
Outputs
Outputs:
CognitoUserPoolArn:
Description: Cognito User Pool Arn
Value: !GetAtt CognitoUserPool.Arn
Export:
Name: !Sub ${AWS::StackName}-CognitoUserPoolArn
CognitoClientID:
Description: Cognito User Pool Client Id
Value: !Ref CognitoClientID
Export:
Name: !Sub ${AWS::StackName}-CognitoClientID
CognitoUserPoolDomainName:
Description: Cognito User Pool Domain Name
Value: !Ref CognitoUserPoolDomain
Export:
Name: !Sub ${AWS::StackName}-CognitoUserPoolDomainName
The outputs section in this CloudFormation template defines three different outputs:
- CognitoUserPoolArn: This output exports the Amazon Resource Number (ARN) of the Cognito user pool. The ARN is obtained by using the
!GetAtt
intrinsic function to retrieve the ARN attribute of theCognitoUserPool
resource, and it's exported with a name that is constructed using the!Sub
intrinsic function and theAWS::StackName
predefined variable. - CognitoClientID: This output exports the client ID of the Cognito user pool client. The client ID is obtained by using the
!Ref
intrinsic function to reference theCognitoClientID
resource, and it's exported with a name that is constructed using the!Sub
intrinsic function and theAWS::StackName
predefined variable. - CognitoUserPoolDomainName: This output exports the domain name of the Cognito user pool. The domain name is obtained by using the
!Ref
intrinsic function to reference theCognitoUserPoolDomain
resource, and it's exported with a name that is constructed using the!Sub
intrinsic function and theAWS::StackName
predefined variable.
These outputs can be used to reference the ARN, client ID, and domain name of the Cognito user pool, client and domain in other CloudFormation stacks or in other parts of the same CloudFormation stack, by using the exported name.
Deploy
aws cloudformation create-stack --stack-name cognito --template-body file://./cognito.yaml --parameters \
ParameterKey=DomainName,ParameterValue=demo-apps.link \
ParameterKey=SubDomainName,ParameterValue=www \
ParameterKey=UserPoolDomainName,ParameterValue=[YOUR USER POOL CUSTOM DOMAIN NAME]
Core Resources stack
Parameters
Parameters:
VPCId:
Type: String
ALBSubnet1:
Type: String
ALBSubnet2:
Type: String
Route53HostedZone:
Type: String
DomainName:
Type: String
SubDomainName:
Type: String
SubDomainName:
Type: String
ACMCertARN:
Type: String
These are parameters for an AWS CloudFormation template. The VPCId parameter is a string that represents the ID of an existing Virtual Private Cloud (VPC) in AWS. The ALBSubnet1 and ALBSubnet2 parameters are strings that represent the IDs of two subnets in the VPC that will be used for an Application Load Balancer (ALB). The Route53HostedZone parameter is a string that represents the ID of an existing Amazon Route 53 hosted zone. The DomainName and SubDomainName parameters are strings that will be used to create a domain name for the ALB. The ACMCertARN parameter is a string that represents the Amazon Resource Name (ARN) of an existing AWS Certificate Manager (ACM) certificate, which will be used to secure the ALB’s domain name.
ECS Cluster
ECSCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: "Cluster"
The ECSCluster is an AWS CloudFormation resource of the AWS Elastic Container Service (ECS) Cluster type. The Properties field is used to specify additional attributes for this resource. In this case, the ClusterName property is being set to “Cluster”. This property specifies the name of the ECS cluster that will be created by the CloudFormation template. This cluster will be used to manage and orchestrate containerized applications.
Application Load Balancer
LoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: ecs-services
Subnets:
- Fn::ImportValue: !Sub "${ALBSubnet1}"
- Fn::ImportValue: !Sub "${ALBSubnet2}"
SecurityGroups:
- !Ref LoadBalancerSecurityGroup
LoadBalancerListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn: !Ref LoadBalancer
Protocol: HTTPS
Port: 443
Certificates:
- CertificateArn: !Ref ACMCertARN
DefaultActions:
- Type: redirect
RedirectConfig:
Host: !Sub ${SubDomainName}.${DomainName}
StatusCode: HTTP_301
Port: "443"
Protocol: HTTPS
LoadBalancerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security group for loadbalancer to services on ECS
VpcId:
Fn::ImportValue: !Ref "VPCId"
SecurityGroupIngress:
- IpProtocol: tcp
CidrIp: 0.0.0.0/0
FromPort: 443
ToPort: 443
- IpProtocol: tcp
CidrIp: 0.0.0.0/0
FromPort: 80
ToPort: 80
This CloudFormation template creates an Elastic Load Balancer (ELB) and related resources for an ECS cluster.
The LoadBalancer resource is of the AWS ElasticLoadBalancingV2::LoadBalancer type. It is given a Name property of “ecs-services” and it specifies the subnets and security group to be used. The subnets are specified as a list of the two subnets that are specified in the ALBSubnet1 and ALBSubnet2 parameters. The security group is specified as a reference to the LoadBalancerSecurityGroup resource.
The LoadBalancerListener resource is of the AWS ElasticLoadBalancingV2::Listener type. It is associated with the LoadBalancer resource by specifying its ARN as the LoadBalancerArn property. It listens on port 443, uses the HTTPS protocol and the specified ACM certificate. It also has a default action of redirecting to the specified domain and port.
The LoadBalancerSecurityGroup resource is of the AWS EC2::SecurityGroup type. It is associated with the VPC that is specified by the VPCId parameter and it allows traffic on ports 80 and 443.
This CloudFormation template creates an Elastic Load Balancer (ELB) that listens on HTTPS and redirects all traffic to the specified subdomain using HTTPS protocol using a certificate from ACM. ELB is also associated with the specified VPC and ECS cluster and created with a security group to allow traffic on ports 80 and 443.
Route53 HostedZone
Route53ALBRecord:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneId: !Ref Route53HostedZone
Name: !Sub ${SubDomainName}.${DomainName}
ResourceRecords:
- !GetAtt LoadBalancer.DNSName
TTL: 300
Type: CNAME
The Route53ALBRecord is an AWS CloudFormation resource of the AWS Route53::RecordSet type. This resource creates a DNS record in an Amazon Route 53 hosted zone.
The Properties field is used to specify additional attributes for this resource. The HostedZoneId property is a reference to the Route53HostedZone parameter, which specifies the ID of the hosted zone in which the DNS record will be created. The Name property is specified using a !Sub function and the SubDomainName and DomainName parameters, which creates the fully qualified domain name of the DNS record. The ResourceRecords property is an array and contains the DNS name of the LoadBalancer, which is obtained using the !GetAtt function. The TTL (time to live) property is set to 300 seconds and the Type property is set to CNAME, which means that the record is a canonical name record and points to the LoadBalancer DNSName. This Route53 Record Set will point the specified subdomain to the DNS name of the LoadBalancer, allowing the specified subdomain to resolve to the IP addresses of the LoadBalancer.
Outputs
Outputs:
LoadBalancerName:
Description: Loadbalancer Name
Value: !GetAtt LoadBalancer.LoadBalancerName
Export:
Name: !Sub ${AWS::StackName}-LoadBalancer
LoadBalancerDNS:
Description: Loadbalancer DNS Name
Value: !GetAtt LoadBalancer.DNSName
Export:
Name: !Sub ${AWS::StackName}-LoadBalancerDNS
LoadBalancerARN:
Description: Loadbalancer ARN
Value: !Ref LoadBalancer
Export:
Name: !Sub ${AWS::StackName}-LoadBalancerARN
LoadBalancerListener:
Description: Load Balancer Listener
Value: !Ref LoadBalancerListener
Export:
Name: !Sub ${AWS::StackName}-LoadBalancerListener
LoadBalancerSecurityGroup:
Description: Load Balancer Listener
Value: !Ref LoadBalancerSecurityGroup
Export:
Name: !Sub ${AWS::StackName}-LoadBalancerSecurityGroup
ECSClusterArn:
Description: ECS cluster arn
Value: !GetAtt ECSCluster.Arn
Export:
Name: !Sub ${AWS::StackName}-ECSClusterArn
These are output sections of an AWS CloudFormation template. The outputs define values that can be easily imported by other CloudFormation templates, or accessed after the stack has been created.
The LoadBalancerName, LoadBalancerDNS, LoadBalancerARN, LoadBalancerListener, LoadBalancerSecurityGroup, and ECSClusterArn are all outputs of the CloudFormation stack. Each output has a Description, Value, and Export properties.
The Description property provides a human-readable description of the output, the Value property specifies the value of the output, and the Export property specifies the export name of the output, which can be used to import the output into another CloudFormation stack.
The output values are obtained using the !GetAtt and !Ref functions. The LoadBalancerName, LoadBalancerDNS, and LoadBalancerARN are obtained using the !GetAtt function, the LoadBalancerListener, LoadBalancerSecurityGroup, and ECSClusterArn are obtained using the !Ref function.
The export name is specified using the !Sub function and the AWS::StackName variable, which is the name of the CloudFormation stack that is currently being created. This allows each output to be easily imported by another stack by referencing the export name, which is unique to the stack.
Deploy
aws cloudformation create-stack --stack-name core-resources --template-body file://./core-resources.yaml --parameters \
ParameterKey=VPCId,ParameterValue=vpc-Vpc-Id \
ParameterKey=ALBSubnet1,ParameterValue=vpc-SubnetPublic1-Id \
ParameterKey=ALBSubnet2,ParameterValue=vpc-SubnetPublic2-Id \
ParameterKey=Route53HostedZone,ParameterValue=[YOUR HOSTED ZONE ID] \
ParameterKey=DomainName,ParameterValue=[YOUR FQDN]\
ParameterKey=SubDomainName,ParameterValue=www \
ParameterKey=ACMCertARN,ParameterValue=[YOUR ACM GENERATED CERTIFICATE]
ECS
Parameters
Parameters:
VPCId:
Type: String
ECSSubnet1:
Type: String
ECSSubnet2:
Type: String
LoadBalancerSecurityGroup:
Type: String
LoadBalancerName:
Type: String
LoadBalancerListener:
Type: String
CognitoUserPoolArn:
Type: String
UserPoolClientId:
Type: String
UserPoolDomainName:
Type: String
DomainName:
Type: String
SubDomainName:
Type: String
ECSClusterArn:
Type: String
- VPCId: The ID of the Virtual Private Cloud (VPC) in which the ECS cluster will be created.
- ECSSubnet1 and ECSSubnet2: The IDs of the subnets in which the ECS cluster will be created.
- LoadBalancerSecurityGroup: The ID of the security group associated with the load balancer.
- LoadBalancerName: The name of the load balancer.
- LoadBalancerListener: The protocol and port used by the load balancer to route incoming traffic.
- CognitoUserPoolArn: The Amazon Resource Number (ARN) of the Cognito user pool.
- UserPoolClientId: The client ID of the user pool.
- UserPoolDomainName: The domain name of the user pool.
- DomainName: The domain name of the website.
- SubDomainName: The subdomain name of the website.
- ECSClusterArn: The Amazon Resource Number (ARN) of the ECS cluster.
ALB Rule and Target Group
DefaultTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: ECS-Cluster-TG
TargetType: ip
VpcId:
Fn::ImportValue:
!Sub "${VPCId}"
Protocol: 'HTTP'
Port: '80'
LoadBalancerCognitoRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Priority: 20
ListenerArn:
Fn::ImportValue:
!Sub "${LoadBalancerListener}"
Actions:
- Type: authenticate-cognito
Order: 1
AuthenticateCognitoConfig:
OnUnauthenticatedRequest: authenticate
Scope: openid
SessionCookieName: AWSELBAuthSessionCookie
UserPoolArn:
Fn::ImportValue:
!Sub "${CognitoUserPoolArn}"
UserPoolClientId:
Fn::ImportValue:
!Sub "${UserPoolClientId}"
UserPoolDomain:
Fn::ImportValue:
!Sub "${UserPoolDomainName}"
- Type: forward
TargetGroupArn: !Ref DefaultTargetGroup
Order: 2
Conditions:
- Field: host-header
HostHeaderConfig:
Values:
- !Sub ${SubDomainName}.${DomainName}
DefaultTargetGroup: This creates an Elastic Load Balancing (ELB) target group named “ECS-Cluster-TG”. It uses the “ip” target type, and the VpcId is imported from the VPCId parameter. The target group listens for HTTP traffic on port 80.
LoadBalancerCognitoRule: This creates an ELB listener rule that is associated with the listener specified in the LoadBalancerListener parameter. This rule has a priority of 20. The rule has two actions:
- The first action is to authenticate requests using a Cognito user pool. The user pool is specified by the CognitoUserPoolArn, UserPoolClientId, and UserPoolDomainName parameters. The session cookie name is “AWSELBAuthSessionCookie” and the scope is “openid”.
- The second action forwards the request to the DefaultTargetGroup after authentication. The rule is applied only when the host-header field of the request matches with the condition specified by the SubDomainName and DomainName parameters.
ECS Task Definition and Service
Task:
Type: AWS::ECS::TaskDefinition
Properties:
Family: task-definition
Cpu: 256
Memory: 512
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
ExecutionRoleArn: !Ref ECSTaskExecutionRole
ContainerDefinitions:
- Name: service
Image: stefanomonti02/simple-node-app:v1
Cpu: 256
Memory: 512
PortMappings:
- ContainerPort: 80
Protocol: tcp
Service:
Type: AWS::ECS::Service
Properties:
ServiceName: service
TaskDefinition: !Ref Task
Cluster:
Fn::ImportValue:
!Sub "${ECSClusterArn}"
LaunchType: FARGATE
DesiredCount: 1
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 70
NetworkConfiguration:
AwsvpcConfiguration:
Subnets:
- Fn::ImportValue:
!Sub "${ECSSubnet1}"
- Fn::ImportValue:
!Sub "${ECSSubnet2}"
SecurityGroups:
- !Ref ContainerSecurityGroup
LoadBalancers:
- ContainerName: service
ContainerPort: 80
TargetGroupArn: !Ref DefaultTargetGroup
The first resource we will create is an ECS Task Definition. This resource defines the properties of the container that we want to run. In this example, the task definition has a family name of “task-definition”, and it requires 256 CPU units and 512MB of memory. It also specifies that it should use the “awsvpc” network mode and be compatible with the “FARGATE” launch type. The execution role for the task is specified by the ECSTaskExecutionRole parameter, and the container definition specifies the image to use, “stefanomonti02/simple-node-app:v1”, and the port mapping for the container.
You can find the used image here; this is a simple express app that print all the received header in json format.
Once the task definition is created, we can use it to create an ECS service. The service resource creates a service named “service” and associates it with the task definition we just created. It specifies the ECSClusterArn parameter as the cluster for the service, and uses the “FARGATE” launch type. The desired count for the service is set to 1, and the deployment configuration is set to a maximum of 200% and a minimum of 70%.
The NetworkConfiguration property of the service specifies the subnets and security group to use for the service. The Subnets property is specified by the ECSSubnet1 and ECSSubnet2 parameters, and the security group is specified by the ContainerSecurityGroup parameter.
Finally, the service is associated with a load balancer, specified by the DefaultTargetGroup parameter, and it specifies the container name and container port to use for the load balancer.
Deploy
aws cloudformation create-stack --stack-name ecs --template-body file://./ecs.yaml --capabilities CAPABILITY_IAM --parameters \
ParameterKey=VPCId,ParameterValue=vpc-Vpc-Id \
ParameterKey=ECSSubnet1,ParameterValue=vpc-SubnetPrivate1-Id \
ParameterKey=ECSSubnet2,ParameterValue=vpc-SubnetPrivate2-Id \
ParameterKey=LoadBalancerSecurityGroup,ParameterValue=core-resources-LoadBalancerSecurityGroup \
ParameterKey=LoadBalancerName,ParameterValue=core-resources-LoadBalancerName \
ParameterKey=LoadBalancerListener,ParameterValue=core-resources-LoadBalancerListener \
ParameterKey=DomainName,ParameterValue=[YOUR FQDN] \
ParameterKey=SubDomainName,ParameterValue=www \
ParameterKey=CognitoUserPoolArn,ParameterValue=cognito-CognitoUserPoolArn \
ParameterKey=UserPoolClientId,ParameterValue=cognito-CognitoClientID \
ParameterKey=UserPoolDomainName,ParameterValue=cognito-CognitoUserPoolDomainName \
ParameterKey=ECSClusterArn,ParameterValue=core-resources-ECSClusterArn
At this point you should have the service with 1 task running:
Test the Application
Type in the search bar of your browser the SubDomainwith the FQDN you selected for this demo. Mine is the following.
You will be redirected to the cognito page:
You don’t have any user in the system so you need Sign up:
Insert a valid email and password.
Insert the code you received in your email and you’ll be redirected to the ecs service
The ECS Service responds with all the HTTP Headers received from the Load Balancer. You can use this service https://jwt.io/ to verify the signature and encode the tokens inside the ‘x-amzn-oidc-data’ and ‘x-amzn-oidc-accessToken’ fields.
Bye 😘