diff --git a/cdk/lib/__snapshots__/stack.test.ts.snap b/cdk/lib/__snapshots__/stack.test.ts.snap index 2cfa16bc..7620e71e 100644 --- a/cdk/lib/__snapshots__/stack.test.ts.snap +++ b/cdk/lib/__snapshots__/stack.test.ts.snap @@ -25,6 +25,7 @@ Object { "GuCname", "GuScheduledLambda", "GuLambdaErrorPercentageAlarm", + "GuDnsRecordSet", ], "gu:cdk:version": "49.5.0", }, @@ -1237,6 +1238,22 @@ Object { }, "Type": "AWS::Lambda::Function", }, + "EmailLambdaAllowSesF4B56FCC": Object { + "Properties": Object { + "Action": "lambda:InvokeFunction", + "FunctionName": Object { + "Fn::GetAtt": Array [ + "EmailLambda93E95E21", + "Arn", + ], + }, + "Principal": "ses.amazonaws.com", + "SourceAccount": Object { + "Ref": "AWS::AccountId", + }, + }, + "Type": "AWS::Lambda::Permission", + }, "EmailLambdaEmailLambdarate5minutes0AllowEventRulePinBoardStackTESTEmailLambdaA8A9241C239D7601": Object { "Properties": Object { "Action": "lambda:InvokeFunction", @@ -1401,6 +1418,38 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, + "EmailLambdaInvokeXqnJuNMWpUFsRhRCXsWa4yOW19FP8xr0uTAd7aw4M1E01C4F3": Object { + "Properties": Object { + "Action": "lambda:InvokeFunction", + "FunctionName": Object { + "Fn::GetAtt": Array [ + "EmailLambda93E95E21", + "Arn", + ], + }, + "Principal": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:ses:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":receipt-rule-set/", + Object { + "Ref": "EmailReceiptRuleSet45DC1ECE", + }, + ":receipt-rule/pinboard.test.dev-gutools.co.uk", + ], + ], + }, + }, + "Type": "AWS::Lambda::Permission", + }, "EmailLambdaServiceRoleCBE95916": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { @@ -1660,6 +1709,40 @@ Object { }, "Type": "AWS::IAM::Policy", }, + "EmailReceiptRuleSet45DC1ECE": Object { + "Properties": Object { + "RuleSetName": "pinboard.test.dev-gutools.co.uk", + }, + "Type": "AWS::SES::ReceiptRuleSet", + }, + "EmailReceiptRuleSetRule06AE7F2A5": Object { + "DependsOn": Array [ + "EmailLambdaAllowSesF4B56FCC", + ], + "Properties": Object { + "Rule": Object { + "Actions": Array [ + Object { + "LambdaAction": Object { + "FunctionArn": Object { + "Fn::GetAtt": Array [ + "EmailLambda93E95E21", + "Arn", + ], + }, + "InvocationType": "RequestResponse", + }, + }, + ], + "Enabled": true, + "Name": "pinboard.test.dev-gutools.co.uk", + }, + "RuleSetName": Object { + "Ref": "EmailReceiptRuleSet45DC1ECE", + }, + }, + "Type": "AWS::SES::ReceiptRule", + }, "GetDistributablePolicyPinboard553D3662": Object { "Properties": Object { "PolicyDocument": Object { @@ -2010,6 +2093,18 @@ Object { "Type": "AWS::SecretsManager::Secret", "UpdateReplacePolicy": "Delete", }, + "ReceiveEmailMXRecord": Object { + "Properties": Object { + "Name": "pinboard.test.dev-gutools.co.uk", + "RecordType": "MX", + "ResourceRecords": Array [ + "inbound-smtp.eu-west-1.amazonaws.com", + ], + "Stage": "TEST", + "TTL": 3600, + }, + "Type": "Guardian::DNS::RecordSet", + }, "RoleToInvokeLambdaFromRDSBC4A09D0": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { diff --git a/cdk/lib/stack.ts b/cdk/lib/stack.ts index 61b8be8c..fd4fcad0 100644 --- a/cdk/lib/stack.ts +++ b/cdk/lib/stack.ts @@ -13,6 +13,7 @@ import { aws_s3 as S3, aws_ssm as ssm, aws_ses as ses, + aws_ses_actions as sesActions, CfnOutput, Duration, Fn, @@ -55,7 +56,8 @@ import { import { GuAlarm } from "@guardian/cdk/lib/constructs/cloudwatch"; import { GuScheduledLambda } from "@guardian/cdk"; import { EmailIdentity } from "aws-cdk-lib/aws-ses"; -import { GuCname } from "@guardian/cdk/lib/constructs/dns"; +import { GuCname, GuDnsRecordSet } from "@guardian/cdk/lib/constructs/dns"; +import { LambdaInvocationType } from "aws-cdk-lib/aws-ses-actions/lib/lambda"; // if changing should also change .nvmrc (at the root of repo) const LAMBDA_NODE_VERSION = lambda.Runtime.NODEJS_18_X; @@ -628,6 +630,36 @@ export class PinBoardStack extends GuStack { pinboardWorkflowBridgeLambda.grantInvoke(emailLambda); emailLambda.grantInvoke(roleToInvokeLambdaFromRDS); databaseProxy.grantConnect(emailLambda); + new GuDnsRecordSet(this, "ReceiveEmailMXRecord", { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- TODO add 'MX' RecordType enum in GuDnsRecordSet + // @ts-ignore + recordType: "MX", + name: domainName, + ttl: Duration.hours(1), + resourceRecords: ["inbound-smtp.eu-west-1.amazonaws.com"], + }); + const emailReceiptRuleOptions = { + receiptRuleName: domainName, + actions: [ + new sesActions.Lambda({ + function: emailLambda, + invocationType: LambdaInvocationType.REQUEST_RESPONSE, + }), + ], + }; + const emailReceiptRuleSet = new ses.ReceiptRuleSet( + this, + "EmailReceiptRuleSet", + { + receiptRuleSetName: domainName, + rules: [emailReceiptRuleOptions], + } + ); + emailLambda.grantInvoke( + new iam.ArnPrincipal( + `arn:aws:ses:${region}:${account}:receipt-rule-set/${emailReceiptRuleSet.receiptRuleSetName}:receipt-rule/${emailReceiptRuleOptions.receiptRuleName}` + ) + ); const bootstrappingLambdaBasename = "pinboard-bootstrapping-lambda"; const bootstrappingLambdaApiBaseName = `${bootstrappingLambdaBasename}-api`;