Skip to content

Commit 3ce8e47

Browse files
authored
feat(apigateway): add accessLogField static method (aws#22322)
Closes aws#21650 Add missing context fields. ---- ### All Submissions: * [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) ### Adding new Unconventional Dependencies: * [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies) ### New Features * [x] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)? * [x] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)? *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 25ca80c commit 3ce8e47

File tree

8 files changed

+197
-9
lines changed

8 files changed

+197
-9
lines changed

packages/@aws-cdk/aws-apigateway/README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -1085,7 +1085,8 @@ new apigateway.RestApi(this, 'books', {
10851085
deployOptions: {
10861086
accessLogDestination: new apigateway.LogGroupLogDestination(logGroup),
10871087
accessLogFormat: apigateway.AccessLogFormat.custom(
1088-
`${apigateway.AccessLogField.contextRequestId()} ${apigateway.AccessLogField.contextErrorMessage()} ${apigateway.AccessLogField.contextErrorMessageString()}`
1088+
`${apigateway.AccessLogField.contextRequestId()} ${apigateway.AccessLogField.contextErrorMessage()} ${apigateway.AccessLogField.contextErrorMessageString()}
1089+
${apigateway.AccessLogField.contextAuthorizerError()} ${apigateway.AccessLogField.contextAuthorizerIntegrationStatus()}`
10891090
)
10901091
}
10911092
});

packages/@aws-cdk/aws-apigateway/lib/access-log.ts

+175
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,66 @@ export class AccessLogField {
243243
return '$context.identity.sourceIp';
244244
}
245245

246+
/**
247+
* The PEM-encoded client certificate that the client presented during mutual TLS authentication.
248+
* Present when a client accesses an API by using a custom domain name that has mutual TLS enabled.
249+
* Present only in access logs if mutual TLS authentication fails.
250+
*/
251+
252+
public static contextIdentityClientCertPem() {
253+
return '$context.identity.clientCert.clientCertPem';
254+
}
255+
256+
/**
257+
* The distinguished name of the subject of the certificate that a client presents.
258+
* Present when a client accesses an API by using a custom domain name that has mutual TLS enabled.
259+
* Present only in access logs if mutual TLS authentication fails.
260+
*/
261+
262+
public static contextIdentityClientCertSubjectDN() {
263+
return '$context.identity.clientCert.subjectDN';
264+
}
265+
266+
/**
267+
* The distinguished name of the issuer of the certificate that a client presents.
268+
* Present when a client accesses an API by using a custom domain name that has mutual TLS enabled.
269+
* Present only in access logs if mutual TLS authentication fails.
270+
*/
271+
272+
public static contextIdentityClientCertIssunerDN() {
273+
return '$context.identity.clientCert.issuerDN';
274+
}
275+
276+
/**
277+
* The serial number of the certificate.
278+
* Present when a client accesses an API by using a custom domain name that has mutual TLS enabled.
279+
* Present only in access logs if mutual TLS authentication fails.
280+
*/
281+
282+
public static contextIdentityClientCertSerialNumber() {
283+
return '$context.identity.clientCert.serialNumber';
284+
}
285+
286+
/**
287+
* The date before which the certificate is invalid.
288+
* Present when a client accesses an API by using a custom domain name that has mutual TLS enabled.
289+
* Present only in access logs if mutual TLS authentication fails.
290+
*/
291+
292+
public static contextIdentityClientCertValidityNotBefore() {
293+
return '$context.identity.clientCert.validity.notBefore';
294+
}
295+
296+
/**
297+
* The date after which the certificate is invalid.
298+
* Present when a client accesses an API by using a custom domain name that has mutual TLS enabled.
299+
* Present only in access logs if mutual TLS authentication fails.
300+
*/
301+
302+
public static contextIdentityClientCertValidityNotAfter() {
303+
return '$context.identity.clientCert.validity.notAfter';
304+
}
305+
246306
/**
247307
* The principal identifier of the user making the request. Used in Lambda authorizers.
248308
* @see https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-output.html
@@ -449,6 +509,121 @@ export class AccessLogField {
449509
public static contextStatus() {
450510
return '$context.status';
451511
}
512+
513+
/**
514+
* The authorization error message.
515+
*/
516+
public static contextAuthorizeError() {
517+
return '$context.authorize.error';
518+
}
519+
520+
/**
521+
* The authorization latency in ms.
522+
*/
523+
public static contextAuthorizeLatency() {
524+
return '$context.authorize.latency';
525+
}
526+
527+
/**
528+
* The status code returned from an authorization attempt.
529+
*/
530+
public static contextAuthorizeStatus() {
531+
return '$context.authorize.status';
532+
}
533+
534+
/**
535+
* The error message returned from an authorizer.
536+
*/
537+
public static contextAuthorizerError() {
538+
return '$context.authorizer.error';
539+
}
540+
541+
/**
542+
* The status code returned from a Lambda authorizer.
543+
*/
544+
public static contextAuthorizerIntegrationStatus() {
545+
return '$context.authorizer.integrationStatus';
546+
}
547+
548+
/**
549+
* The authorizer latency in ms.
550+
*/
551+
public static contextAuthorizerLatency() {
552+
return '$context.authorizer.latency';
553+
}
554+
555+
/**
556+
* The AWS endpoint's request ID.
557+
*/
558+
public static contextAuthorizerRequestId() {
559+
return '$context.authorizer.requestId';
560+
}
561+
562+
/**
563+
* The status code returned from an authorizer.
564+
*/
565+
public static contextAuthorizerStatus() {
566+
return '$context.authorizer.status';
567+
}
568+
569+
/**
570+
* The error message returned from an authentication attempt.
571+
*/
572+
public static contextAuthenticateError() {
573+
return '$context.authenticate.error';
574+
}
575+
576+
/**
577+
* The authentication latency in ms.
578+
*/
579+
public static contextAuthenticateLatency() {
580+
return '$context.authenticate.latency';
581+
}
582+
583+
/**
584+
* The status code returned from an authentication attempt.
585+
*/
586+
public static contextAuthenticateStatus() {
587+
return '$context.authenticate.status';
588+
}
589+
590+
/**
591+
* The path for an API mapping that an incoming request matched.
592+
* Applicable when a client uses a custom domain name to access an API. For example if a client sends a request to
593+
* https://api.example.com/v1/orders/1234, and the request matches the API mapping with the path v1/orders, the value is v1/orders.
594+
* @see https://docs.aws.amazon.com/en_jp/apigateway/latest/developerguide/rest-api-mappings.html
595+
*/
596+
public static contextCustomDomainBasePathMatched() {
597+
return '$context.customDomain.basePathMatched';
598+
}
599+
600+
/**
601+
* A string that contains an integration error message.
602+
*/
603+
public static contextIntegrationErrorMessage() {
604+
return '$context.integrationErrorMessage';
605+
}
606+
607+
/**
608+
* The error message returned from AWS WAF.
609+
*/
610+
public static contextWafError() {
611+
return '$context.waf.error';
612+
}
613+
614+
/**
615+
* The AWS WAF latency in ms.
616+
*/
617+
public static contextWafLatency() {
618+
return '$context.waf.latency';
619+
}
620+
621+
/**
622+
* The status code returned from AWS WAF.
623+
*/
624+
public static contextWafStatus() {
625+
return '$context.waf.status';
626+
}
452627
}
453628

454629
/**

packages/@aws-cdk/aws-apigateway/test/access-log.test.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,13 @@ describe('access log', () => {
3737
sub: apigateway.AccessLogField.contextAuthorizerClaims('sub'),
3838
email: apigateway.AccessLogField.contextAuthorizerClaims('email'),
3939
},
40+
clientCertPem: apigateway.AccessLogField.contextIdentityClientCertPem(),
41+
subjectDN: apigateway.AccessLogField.contextIdentityClientCertSubjectDN(),
42+
issunerDN: apigateway.AccessLogField.contextIdentityClientCertIssunerDN(),
43+
serialNumber: apigateway.AccessLogField.contextIdentityClientCertSerialNumber(),
44+
validityNotBefore: apigateway.AccessLogField.contextIdentityClientCertValidityNotBefore(),
45+
validityNotAfter: apigateway.AccessLogField.contextIdentityClientCertValidityNotAfter(),
4046
}));
41-
expect(testFormat.toString()).toEqual('{"requestId":"$context.requestId","sourceIp":"$context.identity.sourceIp","method":"$context.httpMethod","callerAccountId":"$context.identity.accountId","ownerAccountId":"$context.accountId","userContext":{"sub":"$context.authorizer.claims.sub","email":"$context.authorizer.claims.email"}}');
47+
expect(testFormat.toString()).toEqual('{"requestId":"$context.requestId","sourceIp":"$context.identity.sourceIp","method":"$context.httpMethod","callerAccountId":"$context.identity.accountId","ownerAccountId":"$context.accountId","userContext":{"sub":"$context.authorizer.claims.sub","email":"$context.authorizer.claims.email"},"clientCertPem":"$context.identity.clientCert.clientCertPem","subjectDN":"$context.identity.clientCert.subjectDN","issunerDN":"$context.identity.clientCert.issuerDN","serialNumber":"$context.identity.clientCert.serialNumber","validityNotBefore":"$context.identity.clientCert.validity.notBefore","validityNotAfter":"$context.identity.clientCert.validity.notAfter"}');
4248
});
4349
});

packages/@aws-cdk/aws-apigateway/test/integ.restapi.access-log.ts

+6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ class Test extends cdk.Stack {
1717
sub: apigateway.AccessLogField.contextAuthorizerClaims('sub'),
1818
email: apigateway.AccessLogField.contextAuthorizerClaims('email'),
1919
},
20+
clientCertPem: apigateway.AccessLogField.contextIdentityClientCertPem(),
21+
subjectDN: apigateway.AccessLogField.contextIdentityClientCertSubjectDN(),
22+
issunerDN: apigateway.AccessLogField.contextIdentityClientCertIssunerDN(),
23+
serialNumber: apigateway.AccessLogField.contextIdentityClientCertSerialNumber(),
24+
validityNotBefore: apigateway.AccessLogField.contextIdentityClientCertValidityNotBefore(),
25+
validityNotAfter: apigateway.AccessLogField.contextIdentityClientCertValidityNotAfter(),
2026
}));
2127

2228
const logGroup = new logs.LogGroup(this, 'MyLogGroup');

packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"validateOnSynth": false,
2424
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
2525
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
26-
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/bfcd014ed17d9d37eb988448edc7e87eb2ab77e6f7508bf3de2714a6322c99b3.json",
26+
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/0605fe9fb02ad31c3236b358b7605999f20ba079969b6fad8e9cd3878d869ee6.json",
2727
"requiresBootstrapStackVersion": 6,
2828
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
2929
"additionalDependencies": [

packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/test-apigateway-access-logs.assets.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
{
22
"version": "21.0.0",
33
"files": {
4-
"bfcd014ed17d9d37eb988448edc7e87eb2ab77e6f7508bf3de2714a6322c99b3": {
4+
"0605fe9fb02ad31c3236b358b7605999f20ba079969b6fad8e9cd3878d869ee6": {
55
"source": {
66
"path": "test-apigateway-access-logs.template.json",
77
"packaging": "file"
88
},
99
"destinations": {
1010
"current_account-current_region": {
1111
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
12-
"objectKey": "bfcd014ed17d9d37eb988448edc7e87eb2ab77e6f7508bf3de2714a6322c99b3.json",
12+
"objectKey": "0605fe9fb02ad31c3236b358b7605999f20ba079969b6fad8e9cd3878d869ee6.json",
1313
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
1414
}
1515
}

packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/test-apigateway-access-logs.template.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
"Arn"
8989
]
9090
},
91-
"Format": "{\"requestId\":\"$context.requestId\",\"sourceIp\":\"$context.identity.sourceIp\",\"method\":\"$context.httpMethod\",\"callerAccountId\":\"$context.identity.accountId\",\"ownerAccountId\":\"$context.accountId\",\"userContext\":{\"sub\":\"$context.authorizer.claims.sub\",\"email\":\"$context.authorizer.claims.email\"}}"
91+
"Format": "{\"requestId\":\"$context.requestId\",\"sourceIp\":\"$context.identity.sourceIp\",\"method\":\"$context.httpMethod\",\"callerAccountId\":\"$context.identity.accountId\",\"ownerAccountId\":\"$context.accountId\",\"userContext\":{\"sub\":\"$context.authorizer.claims.sub\",\"email\":\"$context.authorizer.claims.email\"},\"clientCertPem\":\"$context.identity.clientCert.clientCertPem\",\"subjectDN\":\"$context.identity.clientCert.subjectDN\",\"issunerDN\":\"$context.identity.clientCert.issuerDN\",\"serialNumber\":\"$context.identity.clientCert.serialNumber\",\"validityNotBefore\":\"$context.identity.clientCert.validity.notBefore\",\"validityNotAfter\":\"$context.identity.clientCert.validity.notAfter\"}"
9292
},
9393
"DeploymentId": {
9494
"Ref": "MyApiDeploymentECB0D05E81594d6748b4b291f993111a5070d710"

packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/tree.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"path": "Tree",
1010
"constructInfo": {
1111
"fqn": "constructs.Construct",
12-
"version": "10.1.95"
12+
"version": "10.1.108"
1313
}
1414
},
1515
"test-apigateway-access-logs": {
@@ -173,7 +173,7 @@
173173
"Arn"
174174
]
175175
},
176-
"format": "{\"requestId\":\"$context.requestId\",\"sourceIp\":\"$context.identity.sourceIp\",\"method\":\"$context.httpMethod\",\"callerAccountId\":\"$context.identity.accountId\",\"ownerAccountId\":\"$context.accountId\",\"userContext\":{\"sub\":\"$context.authorizer.claims.sub\",\"email\":\"$context.authorizer.claims.email\"}}"
176+
"format": "{\"requestId\":\"$context.requestId\",\"sourceIp\":\"$context.identity.sourceIp\",\"method\":\"$context.httpMethod\",\"callerAccountId\":\"$context.identity.accountId\",\"ownerAccountId\":\"$context.accountId\",\"userContext\":{\"sub\":\"$context.authorizer.claims.sub\",\"email\":\"$context.authorizer.claims.email\"},\"clientCertPem\":\"$context.identity.clientCert.clientCertPem\",\"subjectDN\":\"$context.identity.clientCert.subjectDN\",\"issunerDN\":\"$context.identity.clientCert.issuerDN\",\"serialNumber\":\"$context.identity.clientCert.serialNumber\",\"validityNotBefore\":\"$context.identity.clientCert.validity.notBefore\",\"validityNotAfter\":\"$context.identity.clientCert.validity.notAfter\"}"
177177
},
178178
"deploymentId": {
179179
"Ref": "MyApiDeploymentECB0D05E81594d6748b4b291f993111a5070d710"
@@ -272,7 +272,7 @@
272272
"path": "apigateway-access-logs/DefaultTest/Default",
273273
"constructInfo": {
274274
"fqn": "constructs.Construct",
275-
"version": "10.1.95"
275+
"version": "10.1.108"
276276
}
277277
},
278278
"DeployAssert": {

0 commit comments

Comments
 (0)