AWS CloudFront + TLS-ALPN/HTTP Challenges

After fumbling around with CloudFront for entirely too long, I came up with a solution that seems to work reliably.

AWS CloudFront

Verify you have the following enabled:

    - ViewerProtocolPolicy  = "allow-all"
    - OriginProtocolPolicy = "match-viewer"
    - DistributionHTTPProtocolVersions = "http2-and-http3"
    - DistributionSSLSupportMethod = "sni-only"
    - CachePolicyExclusionPath = "/.well-known/*"
    - OriginRequestPolicy
        - Include Headers
            - Origin
            - Accept-Charset
            - Accept
            - Access-Control-Request-Method
            - Access-Control-Request-Headers
            - Referer
            - Host
            - Accept-Language
            - Accept-Datetime
        - Include Query Strings: all
        - Include Cookies: all

Caddy

The config for Caddy is straightforward, this is my tls.automation.policy block (to support HTTP/3, make sure tcp+udp/443 are open to your Caddy instance):

          {
            "issuers": [
              {
                "ca": "https://acme-v02.api.letsencrypt.org/directory",
                "challenges": {
                  "http": {
                    "disabled": false
                  },
                  "tls-alpn": {
                    "disabled": false
                  }
                },
                "email": "somebody@example.org",
                "module": "acme"
              }
            ],
            "on_demand": true
          }

And, on my http listener, I added a route/match like this to redirect to https, if the URL does not contain /.well-known/...:

      "servers": {
        "http": {
          "listen": [
            "0.0.0.0:80"
          ],
          "routes": [
            {
              "group": "default",
              "handle": [
                {
                  "handler": "subroute",
                  "routes": [
                    {
                      "handle": [
                        {
                          "handler": "static_response",
                          "headers": {
                            "Location": [
                              "https://{http.request.host}{http.request.uri}"
                            ]
                          },
                          "status_code": 301
                        }
                      ],
                      "match": [
                        {
                          "not": [
                            {
                              "path": [
                                "/.well-known/*"
                              ]
                            }
                          ]
                        }
                      ]
                    }
                  ]
                },
                {
                  "body": "DEFAULT ROUTE",
                  "close": true,
                  "handler": "static_response",
                  "status_code": "200"
                }
              ]
            }
          ]
        },

Notes

  • In this setup, you will NOT have AWS CloudFront doing any httphttps redirection because you need at least some requests from ACME to get through to the origin via http.
  • Caveat: You may be able to add a CachePolicy that would allow http or https for /.well-known/* only, but I decided not to do that since my I need my Caddy instance to generally redirect httphttps for other use-cases anyways (but I have an exception in for /.well-known/*). If you did that in AWS CloudFront, that would allow you to only enable http + https access to the origin for a single URL /.well-known/*–YMMV, and I did not test that case since I did not need it.

Thank you for the help and pointers!!

1 Like