Reputation: 19257
I created a simple public Lambda function that returns a simple HTML page. I have a custom domain with SSL setup (via Cloudfront). Everything works except it can't create a cookie when using the custom domain.
The Lambda uses the (relatively new) URL capability, and provides the URL https://xxxxxxxx.lambda-url.us-east-1.on.aws. AUTH type is set to none (e.g. public).
In order to access the Lambda via a custom URL (map.mydomain.com), I setup a Cloudfront distribution with a SSL certificate for that subdomain (map.mydomain.com).
So I can access the Lambda via either the AWS-provided URL or via the custom domain map.mydomain.com.
The only thing NOT working is setting a cookie, when using the custom domain.
The Lambda returns (for example) the following:
{
:statusCode=>200,
:body=>"<!DOCTYPE html><html><head><meta charset='UTF-8'>
</head><body>Cookie set to FOO</body></html>",
:headers=>{
:"Content-Type"=>"text/html",
:"Set-Cookie"=>"my_cookie_name=FOO; Path=/; Max-Age=300; Secure; SameSite=None;"
}
}
What Works: When I access the Lambda via the AWS-provided URL, I can see the cookie and its contents in my browser's Developer tools.
What Doesn't: If I access the Lambda via map.mydomain.com, I see the HTML page, but the browser's Developer tools shows no cookies for the domain.
I had thought perhaps that adding "Secure; SameSite=None;" to the Set-Cookie header would solve the issue, but it didn't.
I also turned on CORS for the Lambda "Function URL" setting, with Allow Origin set to the wildcard (*), and "credentials" turn ON.
Using curl -v -X GET <url>
(or the Network tab in browser's Developer tools) I do see the "Set-Cookie" header when browsing the Lambda Function URL, and I do not see a "Set-Cookie" header when browsing the custom domain URL... so that "Set-Cookie" header is being removed somewhere between the browser and the lambda function.
Specifically, here is the response returned by the Lambda in response to a curl request. (Note the Lambda sends a "Set-Cookie" header. I tried both with and without "Domain=FOO.MYDOMAIN.NET;" in the header, same result the set-cookie header does not arrive with the html.)
{:statusCode=>200,
:body=>"<!DOCTYPE html><html><head><meta charset='UTF-8'></head><body>Cookie set to rand82_1652845019</body></html>",
:headers=>{
:"Content-Type"=>"text/html",
:"Set-Cookie"=>"cookie_ktree=rand82_1652845019; Path=/; Domain=FOO.MYDOMAIN.NET; Max-Age=300; Secure; SameSite=None;",
:"Access-Control-Allow-Origin"=>"*",
:"Access-Control-Allow-Credentials"=>true
}
}
And here is what the curl command received (note the absence of any Set-Cookie" header)
curl -v -X GET https://FOO.MYDOMAIN.NET/SOME-TESTURL
Note: Unnecessary use of -X or --request, GET is already inferred.
* Trying X.X.X.X...
* TCP_NODELAY set
* Connected to FOO.MYDOMAIN.NET (X.X.X.X) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/cert.pem
CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=FOO.MYDOMAIN.NET
* start date: May 13 00:00:00 2022 GMT
* expire date: Jun 11 23:59:59 2023 GMT
* subjectAltName: host "FOO.MYDOMAIN.NET" matched cert's "FOO.MYDOMAIN.NET"
* issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7fad78008200)
> GET /SOME-TESTURL HTTP/2
> Host: FOO.MYDOMAIN.NET
> User-Agent: curl/7.64.1
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200
< content-type: text/html
< content-length: 107
< date: Wed, 18 May 2022 03:36:59 GMT
< x-amzn-requestid: 7a013097-14d6-462e-9ca5-ae1a2fdd03fb
< access-control-allow-origin: *
< x-amzn-trace-id: root=1-628469db-680ee5ca7b9e5bf75b9e5b8c;sampled=0
< access-control-allow-credentials: true
< x-cache: Miss from cloudfront
< via: 1.1 fb4c985c6e0ddb6f82a2dffdde62d23e.cloudfront.net (CloudFront)
< x-amz-cf-pop: MIA3-P3
< x-amz-cf-id: YBVjC-na0PvGljCnr7fNUSu1q87L1e7V8gcZZL0YdDDeeyJnFS6UzQ==
<
* Connection #0 to host FOO.MYDOMAIN.NET left intact
<!DOCTYPE html><html><head><meta charset='UTF-8'></head><body>Cookie set to rand82_1652845019</body></html>* Closing connection 0
What else could I try to get the Lambda to set a cookie when using a custom domain?
Upvotes: 1
Views: 1841
Reputation: 1887
Your Lambda sounds correctly configured but CloudFront is omitting the header from the response.
To fix this, consider adding a cache policy that allows cookies to be sent to the origin, as this also controls whether or not CloudFront allows the Set-Cookie
header to be passed from the origin response (your Lambda) to the viewer response (what's currently missing the header).
You can start about allowing all cookies to verify your changes, and then later switch to a whitelist of only the cookies from your Lambda.
Reference from the AWS Documentation
[... When not adding cookies to the cache key] CloudFront removes cookies before forwarding requests to your origin, and removes Set-Cookie headers from responses before returning responses to your viewers.
Learn more about CloudFront cookie cache policies
Upvotes: 4
Reputation: 2914
Set the cookie Domain=mydomain.com
The Domain attribute specifies which hosts can receive a cookie. If unspecified, the attribute defaults to the same host that set the cookie, (on.aws).
Upvotes: 0