From f4149b964755af4ad83674754af129eb3902027a Mon Sep 17 00:00:00 2001 From: sonizuka-b Date: Sun, 2 Oct 2022 22:40:08 +0900 Subject: [PATCH] feat(apigateway): add accessLogField static method --- .../@aws-cdk/aws-apigateway/lib/access-log.ts | 175 ++++++++++++++++++ .../aws-apigateway/test/access-log.test.ts | 8 +- .../manifest.json | 2 +- .../test-apigateway-access-logs.assets.json | 4 +- .../test-apigateway-access-logs.template.json | 2 +- .../tree.json | 6 +- 6 files changed, 189 insertions(+), 8 deletions(-) diff --git a/packages/@aws-cdk/aws-apigateway/lib/access-log.ts b/packages/@aws-cdk/aws-apigateway/lib/access-log.ts index 77b13ec342fbb..7c5b13d3a6204 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/access-log.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/access-log.ts @@ -243,6 +243,66 @@ export class AccessLogField { return '$context.identity.sourceIp'; } + /** + * The PEM-encoded client certificate that the client presented during mutual TLS authentication. + * Present when a client accesses an API by using a custom domain name that has mutual TLS enabled. + * Present only in access logs if mutual TLS authentication fails. + */ + + public static contextIdentityClientCertPem() { + return '$context.identity.clientCert.clientCertPem'; + } + + /** + * The distinguished name of the subject of the certificate that a client presents. + * Present when a client accesses an API by using a custom domain name that has mutual TLS enabled. + * Present only in access logs if mutual TLS authentication fails. + */ + + public static contextIdentityClientCertSubjectDN() { + return '$context.identity.clientCert.subjectDN'; + } + + /** + * The distinguished name of the issuer of the certificate that a client presents. + * Present when a client accesses an API by using a custom domain name that has mutual TLS enabled. + * Present only in access logs if mutual TLS authentication fails. + */ + + public static contextIdentityClientCertIssunerDN() { + return '$context.identity.clientCert.issuerDN'; + } + + /** + * The serial number of the certificate. + * Present when a client accesses an API by using a custom domain name that has mutual TLS enabled. + * Present only in access logs if mutual TLS authentication fails. + */ + + public static contextIdentityClientCertSerialNumber() { + return '$context.identity.clientCert.serialNumber'; + } + + /** + * The date before which the certificate is invalid. + * Present when a client accesses an API by using a custom domain name that has mutual TLS enabled. + * Present only in access logs if mutual TLS authentication fails. + */ + + public static contextIdentityClientCertValidityNotBefore() { + return '$context.identity.clientCert.validity.notBefore'; + } + + /** + * The date after which the certificate is invalid. + * Present when a client accesses an API by using a custom domain name that has mutual TLS enabled. + * Present only in access logs if mutual TLS authentication fails. + */ + + public static contextIdentityClientCertValidityNotAfter() { + return '$context.identity.clientCert.validity.notAfter'; + } + /** * The principal identifier of the user making the request. Used in Lambda authorizers. * @see https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-output.html @@ -449,6 +509,121 @@ export class AccessLogField { public static contextStatus() { return '$context.status'; } + + /** + * The authorization error message. + */ + public static contextAuthorizeError() { + return '$context.authorize.error'; + } + + /** + * The authorization latency in ms. + */ + public static contextAuthorizeLatency() { + return '$context.authorize.latency'; + } + + /** + * The status code returned from an authorization attempt. + */ + public static contextAuthorizeStatus() { + return '$context.authorize.status'; + } + + /** + * The error message returned from an authorizer. + */ + public static contextAuthorizerError() { + return '$context.authorizer.error'; + } + + /** + * The status code returned from a Lambda authorizer. + */ + public static contextAuthorizerIntegrationStatus() { + return '$context.authorizer.integrationStatus'; + } + + /** + * The authorizer latency in ms. + */ + public static contextAuthorizerLatency() { + return '$context.authorizer.latency'; + } + + /** + * The AWS endpoint's request ID. + */ + public static contextAuthorizerRequestId() { + return '$context.authorizer.requestId'; + } + + /** + * The status code returned from an authorizer. + */ + public static contextAuthorizerStatus() { + return '$context.authorizer.status'; + } + + /** + * The error message returned from an authentication attempt. + */ + public static contextAuthenticateError() { + return '$context.authenticate.error'; + } + + /** + * The authentication latency in ms. + */ + public static contextAuthenticateLatency() { + return '$context.authenticate.latency'; + } + + /** + * The status code returned from an authentication attempt. + */ + public static contextAuthenticateStatus() { + return '$context.authenticate.status'; + } + + /** + * The path for an API mapping that an incoming request matched. + * Applicable when a client uses a custom domain name to access an API. For example if a client sends a request to + * https://api.example.com/v1/orders/1234, and the request matches the API mapping with the path v1/orders, the value is v1/orders. + * @see https://docs.aws.amazon.com/en_jp/apigateway/latest/developerguide/rest-api-mappings.html + */ + public static contextCustomDomainBasePathMatched() { + return '$context.customDomain.basePathMatched'; + } + + /** + * A string that contains an integration error message. + */ + public static contextIntegrationErrorMessage() { + return '$context.integrationErrorMessage'; + } + + /** + * The error message returned from AWS WAF. + */ + public static contextWafError() { + return '$context.waf.error'; + } + + /** + * The AWS WAF latency in ms. + */ + public static contextWafLatency() { + return '$context.waf.latency'; + } + + /** + * The status code returned from AWS WAF. + */ + public static contextWafStatus() { + return '$context.waf.status'; + } } /** diff --git a/packages/@aws-cdk/aws-apigateway/test/access-log.test.ts b/packages/@aws-cdk/aws-apigateway/test/access-log.test.ts index dcd89fcdc69f2..b6c4675fd89ed 100644 --- a/packages/@aws-cdk/aws-apigateway/test/access-log.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/access-log.test.ts @@ -37,7 +37,13 @@ describe('access log', () => { sub: apigateway.AccessLogField.contextAuthorizerClaims('sub'), email: apigateway.AccessLogField.contextAuthorizerClaims('email'), }, + clientCertPem: apigateway.AccessLogField.contextIdentityClientCertPem(), + subjectDN: apigateway.AccessLogField.contextIdentityClientCertSubjectDN(), + issunerDN: apigateway.AccessLogField.contextIdentityClientCertIssunerDN(), + serialNumber: apigateway.AccessLogField.contextIdentityClientCertSerialNumber(), + validityNotBefore: apigateway.AccessLogField.contextIdentityClientCertValidityNotBefore(), + validityNotAfter: apigateway.AccessLogField.contextIdentityClientCertValidityNotAfter(), })); - 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"}}'); + 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"}'); }); }); diff --git a/packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/manifest.json b/packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/manifest.json index e9a6bd1d33e07..4ca3a2ad14567 100644 --- a/packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/manifest.json +++ b/packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/manifest.json @@ -23,7 +23,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/bfcd014ed17d9d37eb988448edc7e87eb2ab77e6f7508bf3de2714a6322c99b3.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/0605fe9fb02ad31c3236b358b7605999f20ba079969b6fad8e9cd3878d869ee6.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ diff --git a/packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/test-apigateway-access-logs.assets.json b/packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/test-apigateway-access-logs.assets.json index c13870f1eec0b..a00497689b941 100644 --- a/packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/test-apigateway-access-logs.assets.json +++ b/packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/test-apigateway-access-logs.assets.json @@ -1,7 +1,7 @@ { "version": "21.0.0", "files": { - "bfcd014ed17d9d37eb988448edc7e87eb2ab77e6f7508bf3de2714a6322c99b3": { + "0605fe9fb02ad31c3236b358b7605999f20ba079969b6fad8e9cd3878d869ee6": { "source": { "path": "test-apigateway-access-logs.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "bfcd014ed17d9d37eb988448edc7e87eb2ab77e6f7508bf3de2714a6322c99b3.json", + "objectKey": "0605fe9fb02ad31c3236b358b7605999f20ba079969b6fad8e9cd3878d869ee6.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/test-apigateway-access-logs.template.json b/packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/test-apigateway-access-logs.template.json index f20a96de67427..f2f64ce616180 100644 --- a/packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/test-apigateway-access-logs.template.json +++ b/packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/test-apigateway-access-logs.template.json @@ -88,7 +88,7 @@ "Arn" ] }, - "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\"}}" + "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\"}" }, "DeploymentId": { "Ref": "MyApiDeploymentECB0D05E81594d6748b4b291f993111a5070d710" diff --git a/packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/tree.json b/packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/tree.json index 4520e2a77abb1..3232b7bf7191c 100644 --- a/packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/tree.json +++ b/packages/@aws-cdk/aws-apigateway/test/restapi.access-log.integ.snapshot/tree.json @@ -9,7 +9,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.95" + "version": "10.1.108" } }, "test-apigateway-access-logs": { @@ -173,7 +173,7 @@ "Arn" ] }, - "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\"}}" + "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\"}" }, "deploymentId": { "Ref": "MyApiDeploymentECB0D05E81594d6748b4b291f993111a5070d710" @@ -272,7 +272,7 @@ "path": "apigateway-access-logs/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.95" + "version": "10.1.108" } }, "DeployAssert": {