AWSTemplateFormatVersion: "2010-09-09"
Parameters:
  CertificateArn:
    Type: String
    Description: ARN of an existing certificate which will be attached to the ALB created by the stack, to serve HTTPS traffic.
  ClusterName:
    Type: String
    Default: forwarded-header-filter-example-cluster
Description: Provision the required resources for example from blog post
  'Setup Spring Boot behind a load balancer using the X-Forwarded headers'.
  Wait for creation to complete before testing.
Resources:
  VPCStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: https://tomgregory-cloudformation-examples.s3-eu-west-1.amazonaws.com/default-vpc.yml
  LoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Subnets:
        - !GetAtt VPCStack.Outputs.PublicSubnet1
        - !GetAtt VPCStack.Outputs.PublicSubnet2
      SecurityGroups:
        - !Ref LoadBalancerSecurityGroup
  LoadBalancerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: LoadBalancerSecurityGroup
      GroupDescription: Security group for load balancer
      VpcId: !GetAtt VPCStack.Outputs.VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 0.0.0.0/0
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 8080
          ToPort: 8080
          DestinationSecurityGroupId: !Ref ContainerSecurityGroup
  LoadBalancerListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      Certificates:
        - CertificateArn: !Ref CertificateArn
      DefaultActions:
        - Type: forward
          ForwardConfig:
            TargetGroups:
              - TargetGroupArn: !Ref TargetGroup
      LoadBalancerArn: !Ref LoadBalancer
      Port: 443
      Protocol: HTTPS
  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckPath: /actuator/health
      Name: TargetGroup
      Port: 8080
      Protocol: HTTP
      TargetType: ip
      VpcId: !GetAtt VPCStack.Outputs.VPC
      TargetGroupAttributes:
        - Key: deregistration_delay.timeout_seconds
          Value: 10
  ContainerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: ContainerSecurityGroup
      GroupDescription: Security group for container
      VpcId: !GetAtt VPCStack.Outputs.VPC
  ContainerLoadBalancerSecurityGroupIngress:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      IpProtocol: tcp
      FromPort: 8080
      ToPort: 8080
      GroupId: !Ref ContainerSecurityGroup
      SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup
  ECSCluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: !Ref ClusterName
  ExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: forwarded-header-filter-example-task-execution-role
      Path: /
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: !Sub forwarded-header-filter-example-task
      Cpu: 512
      Memory: 1024
      NetworkMode: awsvpc
      ExecutionRoleArn: !Ref ExecutionRole
      RequiresCompatibilities:
        - FARGATE
        - EC2
      ContainerDefinitions:
        - Name: forwarded-header-filter-example
          Image: tkgregory/forwarded-header-filter-example:1.0-SNAPSHOT
          PortMappings:
            - ContainerPort: 8080
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group: !Ref CloudwatchLogsGroup
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: forwarded-header-filter-example
  CloudwatchLogsGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Join ['-', [ECSLogGroup, !Ref 'AWS::StackName']]
      RetentionInDays: 14
  Service:
    Type: AWS::ECS::Service
    DependsOn: LoadBalancerListener
    Properties:
      Cluster: !Ref ECSCluster
      TaskDefinition: !Ref TaskDefinition
      DesiredCount: 1
      LaunchType: FARGATE
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          Subnets:
            - !GetAtt VPCStack.Outputs.PrivateSubnet1
            - !GetAtt VPCStack.Outputs.PrivateSubnet2
          SecurityGroups:
            - !GetAtt ContainerSecurityGroup.GroupId
      LoadBalancers:
        - ContainerName: forwarded-header-filter-example
          ContainerPort: 8080
          TargetGroupArn: !Ref TargetGroup