diff --git a/lib/constructs/slack-handler.ts b/lib/constructs/slack-handler.ts index 802faba..dfa8c2f 100644 --- a/lib/constructs/slack-handler.ts +++ b/lib/constructs/slack-handler.ts @@ -138,6 +138,33 @@ export class SlackHandlerConstruct extends Construct { }); } + // ── Access logging + throttling (audit M-18) ────────────────────────────── + const defaultStage = this.api.defaultStage!.node.defaultChild as apigatewayv2.CfnStage; + defaultStage.addPropertyOverride('DefaultRouteSettings', { + ThrottlingBurstLimit: 50, + ThrottlingRateLimit: 100, + }); + + const apiAccessLogGroup = new logs.LogGroup(this, 'ApiAccessLogGroup', { + logGroupName: '/aws/apigateway/seahaven-slack-webhook', + retention: logs.RetentionDays.THREE_MONTHS, + removalPolicy: cdk.RemovalPolicy.DESTROY, + }); + defaultStage.addPropertyOverride('AccessLogSettings', { + DestinationArn: apiAccessLogGroup.logGroupArn, + Format: JSON.stringify({ + requestId: '$context.requestId', + ip: '$context.identity.sourceIp', + requestTime: '$context.requestTime', + method: '$context.httpMethod', + routeKey: '$context.routeKey', + status: '$context.status', + protocol: '$context.protocol', + responseLength: '$context.responseLength', + integrationError: '$context.integrationErrorMessage', + }), + }); + // ── Custom domain: bot.seahaven.com ─────────────────────────────────────── const certificate = acm.Certificate.fromCertificateArn( this, 'WildcardCert', props.wildcardCertArn,