skip to Main Content

I have an AWS application load balancer set up to access a target group in an ECS Fargate. I have a custom domain example.com with an AWS-managed certificate with an alias targeting the load balancer. Thus if I enter https://example.com/, it hits the load balancer which forwards to my ECS Fargate container. It seems to work fine.

However if I go into the AWS console for the load balancer, I see a DNS name in the form foo-bar-1234567890.region.elb.amazonaws.com. It turns out that I can bypass the example.com and access the load balancer directly (ignoring the certificate warning) using https://foo-bar-1234567890.region.elb.amazonaws.com.

How can I easily prevent someone from directly accessing the load balancer by its AWS DNS name, bypassing the domain name in the hosted zone I’ve set up with the SSL certificate?

Surely this is a common scenario. I wouldn’t be surprised if many setups in the wild did not address this detail, and have their load balancers directly exposed via the AWS DNS name. However I don’t feel this configuration is ideal nor desirable. Note that how likely or easily someone could discover the load balancer DNS name is a separate issue and is not what I’m asking.

2

Answers


  1. Chosen as BEST ANSWER

    I went with Marc B's suggestion of adding an Application Load Balancer rule to restrict the Host header to match that of the expected domain (the one I have the SSL certificate for).

    Rather than redirecting, I indicate the request is forbidden. Redirecting from HTTP to HTTPS is a user convenience; the user might have intended HTTPS but inadvertently left off the https: in the URL; and redirecting is helping them out. But no user accidentally discovers the load balancer URL and inadvertently tries to connect to it. Thus I forbid direct access to the load balancer URL altogether.

    I could approach this two ways: I could deny access if the load balancer URL is used, or I could only allow access if the correct domain is used (denying all others). The latter seems safer. (Maybe there is some additional third URL I don't know about; this would prevent that as well.)

    Unfortunately AWS application load balancer listener rules don't seem to accept NOT Boolean logic, so I can't easily override the default forwarding to the target group if the domain is not correct. So I take the opposite approach: I forbid all connections by default, and add an override rule to only allow connections if the domain is correct. Here's an example in CloudFormation. (Note that the SSL certificate and domain name are defined elsewhere.)

      LoadBalancerListenerHttps:
        Type: AWS::ElasticLoadBalancingV2::Listener
        Properties:
          LoadBalancerArn: !Ref LoadBalancer
          Port: 443
          Protocol: HTTPS
          Certificates:
            - CertificateArn: !Ref DomainCertificateArn
          DefaultActions: 
            - Type: fixed-response
              FixedResponseConfig:
                StatusCode: 403
                ContentType: text/plain
                MessageBody: "Unsupported host domain name."
    
      LoadBalancerListenerHttpsRequireHostDomain:
        Type: AWS::ElasticLoadBalancingV2::ListenerRule
        Properties:
          ListenerArn: !Ref LoadBalancerListenerHttps
          Priority: 1
          Conditions:
            - Field: host-header
              HostHeaderConfig:
                Values: !Ref DomainName
          Actions:
            - Type: forward
              TargetGroupArn: !Ref TargetGroup
    
    

    (You'll see lots of encouragement to use Terraform instead of CloudFormation, and I don't doubt it is more powerful. But it is my understanding that the IaC framework is still limited by the capabilities of the cloud platform. In this case, for example, I highly doubt that Terraform would somehow add support for a NOT condition in load balancer rules, because AWS itself does not support that. In theory a complex rules engine might allow it and then transform it to a default forbid with an override as I have done here, but don't imagine Terraform does this. In other words, in Terraform I would guess that you would be stuck with the same sort of configuration I've shown here. If my assumption is incorrect please let me know.)

    I could allow the HTTP listener to continue indiscriminately redirecting to the HTTPS port, which eventually would provide the same HTTP Forbidden response if the domain were incorrect. But I prefer to take the same approach as above even with HTTP, to deny access to an incorrect domain even before redirection takes place.

      LoadBalancerListenerHttp:
        Type: AWS::ElasticLoadBalancingV2::Listener
        Properties: 
          LoadBalancerArn: !Ref LoadBalancer
          Port: 80
          Protocol: HTTP
          DefaultActions: 
            - Type: fixed-response
              FixedResponseConfig:
                StatusCode: 403
                ContentType: text/plain
                MessageBody: "Unsupported host domain name."
    
      LoadBalancerListenerHttpRequireHostDomain:
        Type: AWS::ElasticLoadBalancingV2::ListenerRule
        Properties:
          ListenerArn: !Ref LoadBalancerListenerHttp
          Priority: 1
          Conditions:
            - Field: host-header
              HostHeaderConfig:
                Values: !Ref DomainName
          Actions:
            - Type: redirect
              RedirectConfig:
                Protocol: HTTPS
                Port: 443
                Host: "#{host}"
                Path: "/#{path}"
                Query: "#{query}"
                StatusCode: HTTP_301
    

    Interestingly a rule based upon the Host header even matches if I include an explicit port in the URL. Supposedly the Host header can include a port as well, so I don't know if A) AWS is ignoring the port when it does the comparison for host-header, or B) if the browser is stripping out the port if the default port is used. If the latter, then this could prevent access even to the correct domain if a browser decided to send the port in the Host header value. Hopefully AWS is parsing out the host part and only comparing that.


  2. This is commonly handled on the backend, by returning a redirect if the host name doesn’t match whatever host name your server is configured to respond to.

    However with Application Load Balancers you can also configure a rule to handle this. The rule would specify that if the Host-header is foo-bar-1234567890.region.elb.amazonaws.com then 301 redirect to your preferred domain name.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search