client certificate as cacheKeyParameters
Closed this issue · 7 comments
Hi, I'm writing APIs that use MTLS (client certificates) as authentication, I would like to cache results based on that property (i.e. cache per client), I tried:
caching:
enabled: true
ttlInSeconds: 60
cacheKeyParameters:
- name: request.requestContext.identity.clientCert.serialNumber
but fails with Invalid mapping expression
For reference, this is the event my lambda receives:
{
"event": {
"resource": "/v1/...",
"path": "/v1/...",
"httpMethod": "GET",
"headers": {
"accept": "*/*",
"accept-encoding": "gzip, deflate, br",
"cache-control": "no-cache",
"User-Agent": "PostmanRuntime/7.28.2"
},
"multiValueHeaders": {
"accept": [
"*/*"
],
"accept-encoding": [
"gzip, deflate, br"
],
"cache-control": [
"no-cache"
],
"User-Agent": [
"PostmanRuntime/7.28.2"
]
},
"queryStringParameters": null,
"multiValueQueryStringParameters": null,
"pathParameters": null,
"stageVariables": null,
"requestContext": {
"resourceId": "yzpjp5",
"resourcePath": "/v1/...",
"httpMethod": "GET",
"extendedRequestId": "PCkYaG3ziYcFouQ=",
"requestTime": "15/Mar/2022:19:22:16 +0000",
"path": "/v1/...",
"accountId": "105843011380",
"protocol": "HTTP/1.1",
"stage": "dev",
"domainPrefix": "core",
"requestTimeEpoch": 1647372136811,
"requestId": "1cfff372-3db0-4ad0-a023-46c570c8adeb",
"identity": {
"cognitoIdentityPoolId": null,
"clientCert": {
"clientCertPem": "-----BEGIN CERTIFICATE-----...-----END CERTIFICATE-----",
"serialNumber": "620155093573104977087960001264040226218798030419",
"issuerDN": "CN=...",
"validity": {
"notAfter": "Mar 3 20:27:42 2023 GMT",
"notBefore": "Mar 3 20:27:43 2022 GMT"
},
"subjectDN": "CN=acme,O=acme"
},
"cognitoIdentityId": null,
"principalOrgId": null,
"cognitoAuthenticationType": null,
"userArn": null,
"userAgent": "PostmanRuntime/7.28.2",
"accountId": null,
"caller": null,
"accessKey": null,
"cognitoAuthenticationProvider": null,
"user": null
},
"apiId": "lz44gudovl"
},
"body": null,
"isBase64Encoded": false
}
}
Is this possible? Thanks
Hi @andres-ntropy,
I don't know whether it's possible to do this, I haven't done it myself.
However, could you please try the syntax that is used for cache key parameters in the request body, for example:
events:
- http:
path: / # replace with your path
method: get # replace with your method
integration: lambda # use lambda integration
caching:
enabled: true
ttlInSeconds: 60
cacheKeyParameters:
- name: integration.request.header.clientCertSerialNumber # the name of the cache key parameter
mappedFrom: method.request.requestContext.identity.clientCert.serialNumber # where it lives in the request
Please let me know if this works.
Hi @DianaIonita
Unfortunately that didn't work. I did some trial & error and managed to make it work by commenting out this if condition
I'm not sure what that if
is for, and what consequences it brings by removing it, but by talking to AWS support & reading the docs, the way to make it work is to have an integration that looks like this (output from my actual aws apigateway get-integration
command):
{
"type": "AWS_PROXY",
"httpMethod": "POST",
"uri": "arn:aws:apigateway:us-east-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-2:XXXXXXXX:function:get-active-queue-count/invocations",
"requestParameters": {
"integration.request.header.clientCertSerialNumber": "context.identity.clientCert.serialNumber"
},
"requestTemplates": {},
"passthroughBehavior": "WHEN_NO_MATCH",
"timeoutInMillis": 29000,
"cacheNamespace": "ApiGatewayMethodV1CertificateQueueDashcountGetCacheNS",
"cacheKeyParameters": [
"integration.request.header.clientCertSerialNumber"
]
}
As you can see, the integration type is AWS_PROXY
but that doesn't prevent it from working and caching properly
The serverless.yml
snippet I used to produce that result:
events:
- http:
path: v1/certificate/queue-count
method: get
caching:
enabled: true
ttlInSeconds: 60
cacheKeyParameters:
- name: integration.request.header.clientCertSerialNumber
mappedFrom: context.identity.clientCert.serialNumber
Thanks,
Hi @andres-ntropy
Thank you for the information provided.
You're right, the AWS_PROXY
integration type check doesn't seem required. If I recall correctly, it was added to support cache key parameters coming from the body of a request. However, I ran some tests and it doesn't make a difference whether it's AWS
or AWS_PROXY
, the cache key parameters are still properly configured.
I have therefore released v1.8.0 of the plugin which removes that check.
Feel free to reopen this issue if it doesn't solve your problem.
Hi @DianaIonita,
FYI unfortunately something must have changed in AWS, because I deployed today a stack with this setting turned on and it failed with InvalidSignatureException
from API Gateway to Lambda, seemingly unrelated but when I removed the plugin it worked again
Hi @andres-ntropy,
Are you seeing this error in the latest version of the plugin 1.8.1?
If so, could you please try version 1.8.0? I'm curious if this is because of something I added.
hello Diana, I tried this with 1.9.0
and it's working again. Unfortunately there's no support from AWS to cache by client certificate, so I'll have to live with that 🤷♂️
Hi @tulsidas,
That's unfortunate :(
Thank you for the update.