Restrict access to ALB to via CloudFront

Restrict access to ALB to via CloudFront. AWS_EN

Restrict access to ALB to via CloudFront

In the following page, we introduced a configuration that specifies ALB as the CloudFront origin.

As explained in the page above, direct access to the ALB is still possible even if the ALB is specified as the CloudFront origin.

In this page, we will check how to restrict direct access to the ALB by setting a custom header, referring to the following page.

Restricting access to Application Load Balancers - Amazon CloudFront
Use a custom origin header in Amazon CloudFront to prevent users (viewers) from accessing your Application Load Balancer directly.


Detail of restricting access to ALB to via CloudFront.

The structure is the same as the page introduced at the beginning of this document.

However, we will restrict direct access to the ALB and force it to go through CloudFront.
Configure custom headers for CloudFront and ALB.

Information about custom headers is stored in the Secrets Manager.

CloudFormation template files

The above configuration is built using CloudFormation.
The CloudFormation template is located at the following URL

awstut-fa/132 at main · awstut-an-r/awstut-fa
Contribute to awstut-an-r/awstut-fa development by creating an account on GitHub.

Explanation of key points of template files

This page focuses on how to restrict direct access to the ALB.

For basic information on CloudFront, please refer to the following pages.

For basic information on ALB, please refer to the following pages.

(Reference) Secrets Manager

    Type: AWS::SecretsManager::Secret
      Description: test secret
        ExcludeCharacters: ""
        ExcludeLowercase: false
        ExcludeNumbers: false
        ExcludePunctuation: false
        ExcludeUppercase: false
        GenerateStringKey: !Ref CustomHeaderValueJsonKey
        IncludeSpace: false
        PasswordLength: !Ref CustomHeaderValueLength
        RequireEachIncludedType: true
        SecretStringTemplate: !Sub '{"${CustomHeaderNameJsonKey}": "${CustomHeaderName}", "${CustomHeaderValueJsonKey}": ""}'
      KmsKeyId: alias/aws/secretsmanager
      Name: !Ref Prefix
Code language: YAML (yaml)

To restrict direct access to ALB, configure CloudFront and ALB regarding custom headers.
The handling of this custom header information is mentioned in the AWS official documentation as follows

If the header name and value are not secret, other HTTP clients could potentially include them in requests that they send directly to the Application Load Balancer. This can cause the Application Load Balancer to behave as though the requests came from CloudFront when they did not. To prevent this, keep the custom header name and value secret.

Restricting access to Application Load Balancers

Follow the above, this time storing custom header information in the Secrets Manager.

The custom header name is fixed as “X-Custom-Header”.
On the other hand, the custom header value is a random password that is automatically generated when the secret is created.

For more information on how to generate a random password using Secrets Maanger, please see the following page.

The secret information to be created this time, in JSON format, is as follows.

{“CustomHeaderName”: “X-Custom-Header”, “CustomHeaderValue”: “[random-string]”}


    Type: AWS::CloudFront::Distribution
            - GET
            - HEAD
            - GET
            - HEAD
          Compress: true
              Forward: none
            QueryString: false
          TargetOriginId: !Ref ALBDNSName
          ViewerProtocolPolicy: allow-all
          DefaultTTL: !Ref CacheTTL
          MaxTTL: !Ref CacheTTL
          MinTTL: !Ref CacheTTL
        Enabled: true
          - CustomOriginConfig:
              OriginProtocolPolicy: http-only
            DomainName: !Ref ALBDNSName
            Id: !Ref ALBDNSName
              - HeaderName: !Sub "{{resolve:secretsmanager:${Secret}:SecretString:${CustomHeaderNameJsonKey}}}"
                HeaderValue: !Sub "{{resolve:secretsmanager:${Secret}:SecretString:${CustomHeaderValueJsonKey}}}"
        PriceClass: PriceClass_All
Code language: YAML (yaml)

The key point is the OriginCustomHeaders property.
The header information set here is added to the traffic between CloudFront and ALB.

The custom headers are set by referencing the aforementioned Secrets Manager values.
Specifically, use the dynamic reference in CloudFormation.

Using dynamic references to specify template values - AWS CloudFormation
Dynamic references provide a concise, powerful way for you to specify external values stored and managed in other services in your stack templates.

The HeaderName property refers to the value of CustomHeaderName from the JSON data in the Secrets Manager.
The HeaderValue property refers to the value of CustomHeaderValue from the JSON data in Secrets Manager.


    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
      Name: !Sub "${Prefix}-ALB"
      Scheme: internet-facing
        - !Ref ALBSecurityGroup
        - !Ref PublicSubnet1
        - !Ref PublicSubnet2
      Type: application

    Type: AWS::ElasticLoadBalancingV2::TargetGroup
      VpcId: !Ref VPC
      Name: !Sub "${Prefix}-ALBTargetGroup"
      Protocol: HTTP
      Port: !Ref HTTPPort
      HealthCheckProtocol: HTTP
      HealthCheckPath: /
      HealthCheckPort: traffic-port
      HealthyThresholdCount: !Ref HealthyThresholdCount
      UnhealthyThresholdCount: !Ref UnhealthyThresholdCount
      HealthCheckTimeoutSeconds: !Ref HealthCheckTimeoutSeconds
      HealthCheckIntervalSeconds: !Ref HealthCheckIntervalSeconds
        HttpCode: !Ref HttpCode
        - Id: !Ref Instance1
        - Id: !Ref Instance2
    Type: AWS::ElasticLoadBalancingV2::Listener
        - FixedResponseConfig:
            ContentType: text/plain
            MessageBody: Access denied
            StatusCode: 403
          Type: fixed-response
      LoadBalancerArn: !Ref ALB
      Port: !Ref HTTPPort
      Protocol: HTTP
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
        - TargetGroupArn: !Ref ALBTargetGroup
          Type: forward
        - Field: http-header
            HttpHeaderName: !Sub "{{resolve:secretsmanager:${Secret}:SecretString:${CustomHeaderNameJsonKey}}}"
              - !Sub "{{resolve:secretsmanager:${Secret}:SecretString:${CustomHeaderValueJsonKey}}}"
      ListenerArn: !Ref ALBListener
      Priority: 1
Code language: YAML (yaml)

There are two points.

The first point is the default action of the ALB listener.
In the configuration of the page introduced in the introduction, the default action was set to route to the ALB target group.
The default action in this configuration will be changed to return HTTP status code 403.

The second point is to add a listener rule.
Add a rule to route to the ALB target group.
In the Condition property, set the condition under which this rule is applied.
This condition is based on header information.
Incoming HTTP requests will be routed to the target group only if they have custom headers configured in CloudFront.
As for the custom header information to be checked, it refers to the values in Secrets Manager as well as CloudFront.

To summarize the two points, HTTP requests with custom headers configured in CloudFront will be routed to the ALB target group, while all others will return 403.


Using CloudFormation, we will build this environment and check the actual behavior

Create CloudFormation stacks and check the resources in the stacks

Create CloudFormation stacks.
Please refer to the following pages for information on how to create stacks and check each stack

After reviewing the resources in each stack, information on the main resources created in this case is as follows

  • Secrets Manager: fa-132
  • Instance 1: i-09f7807d448e1b62e
  • Instance 2: i-0e734e5fa1b1da141
  • DNS name of ALB:
  • DNS name of CloudFront distribution:

The AWS Management Console also checks the creation status of each resource.

Check Secrets Manager.

Detail of Secrets Manager 1.

The secret is successfully created.
The stored values show that the header name and header value are stored.
In particular, the header value is automatically set to a random string.

Check the ALB.

Detail of ALB 1.
Detail of ALB 2.

The ALB is successfully created.
If you look at the target group of the ALB, you will see that two instances have been registered.

Check the listener rules for this ALB.

Detail of ALB 3.

Two rules are configured.
The first rule concerns routing to the target group.
Only if the value of the custom header matches will it be routed to the target group.
This setting is based on the values stored in the Secrets Manager described above.

The last rule is for traffic that did not meet the above rules.
For example, if you access the ALB directly, the ALB will return a 403 code because the traffic does not have a custom header setting.

Check CloudFront.

Detail of CloudFront 1.
Detail of CloudFront 2.

The CloudFront distribution has been successfully created.
The aforementioned ALB is specified as the origin of the distribution.

Check the settings for this origin.

Detail of CloudFront 3.

If you look at the section on custom headers, you will see a setting similar to the ALB listener rule.
This means that traffic going through this CloudFront distribution will be given this custom header.

Operation Check

Now that you are ready, access CloudFront.

$ curl
instance-id: i-09f7807d448e1b62e

$ curl
instance-id: i-0e734e5fa1b1da141
Code language: Bash (bash)

We were able to access the two instances under the ALB.
When accessing via CloudFront, I was able to successfully access the instances under the ALB because a custom header is set on the way.

Then access the ALB directly.

$ curl
Access denied
Code language: Shell Session (shell)

Access denied.
A direct access to the ALB returned a 403 in the ALB because the custom header was not set.


We have identified a way to limit direct access to the ALB by setting a custom header.