cfn.yaml (604 lines of code) (raw):

AWSTemplateFormatVersion: "2010-09-09" Description: Zuora invoice management such as refunds, downloading PDF invoices, invoice preview Parameters: Stage: Description: Stage name Type: String AllowedValues: - CODE - PROD Default: CODE Mappings: StageMap: PROD: ConfigVersion: 1 DomainName: invoicing-api.support.guardianapis.com CODE: ConfigVersion: 2 DomainName: invoicing-api-code.support.guardianapis.com Conditions: IsProd: !Equals [!Ref "Stage", "PROD"] Resources: # **************************************************************************** # Alarms # **************************************************************************** FailedInvoicesAlarm: Type: AWS::CloudWatch::Alarm Condition: IsProd Properties: AlarmName: "URGENT 9-5 - PROD: Failed to fetch Zuora invoice by account" AlarmDescription: | - manage-frontend user will not be able to see/download invoices - https://github.com/guardian/invoicing-api/blob/main/src/main/scala/com/gu/invoicing/invoice/README.md - export AWS_DEFAULT_REGION=eu-west-1 && awslogs get --profile membership /aws/lambda/invoicing-api-invoices-PROD --start='DD/mm/yyyy HH:MM' --end='DD/mm/yyyy HH:MM' AlarmActions: - !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:alarms-handler-topic-PROD ComparisonOperator: GreaterThanOrEqualToThreshold Dimensions: - Name: FunctionName Value: !Ref InvoicesLambda EvaluationPeriods: 1 MetricName: Errors Namespace: AWS/Lambda Period: 900 Statistic: Sum Threshold: 5 TreatMissingData: notBreaching Tags: - Key: App Value: invoicing-api DependsOn: - InvoicingLambdaRole FailedPdfAlarm: Type: AWS::CloudWatch::Alarm Condition: IsProd Properties: AlarmName: "URGENT 9-5 - PROD: Failed to download invoice PDF" AlarmDescription: | - manage-frontend user will not be able to download invoice PDF - https://github.com/guardian/invoicing-api/blob/main/src/main/scala/com/gu/invoicing/pdf/README.md - export AWS_DEFAULT_REGION=eu-west-1 && awslogs get --profile membership /aws/lambda/invoicing-api-pdf-PROD --start='DD/mm/yyyy HH:MM' --end='DD/mm/yyyy HH:MM' AlarmActions: - !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:alarms-handler-topic-PROD ComparisonOperator: GreaterThanOrEqualToThreshold Dimensions: - Name: FunctionName Value: !Ref PdfLambda EvaluationPeriods: 1 MetricName: Errors Namespace: AWS/Lambda Period: 900 Statistic: Sum Threshold: 5 TreatMissingData: notBreaching Tags: - Key: App Value: invoicing-api DependsOn: - InvoicingLambdaRole NextInvoiceDateAlarm: Type: AWS::CloudWatch::Alarm Condition: IsProd Properties: AlarmName: "URGENT 9-5 - PROD: Failed to determine next invoice date" AlarmDescription: | - At least holiday or delivery problem credit processor will not be able to determine when to apply the credit - https://github.com/guardian/invoicing-api/blob/main/src/main/scala/com/gu/invoicing/nextinvoicedate/README.md - export AWS_DEFAULT_REGION=eu-west-1 && awslogs get --profile membership /aws/lambda/invoicing-api-nextinvoicedate-PROD --start='DD/mm/yyyy HH:MM' --end='DD/mm/yyyy HH:MM' AlarmActions: - !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:alarms-handler-topic-PROD ComparisonOperator: GreaterThanOrEqualToThreshold Dimensions: - Name: FunctionName Value: !Ref NextInvoiceDateLambda EvaluationPeriods: 1 MetricName: Errors Namespace: AWS/Lambda Period: 300 Statistic: Sum Threshold: 1 TreatMissingData: notBreaching Tags: - Key: App Value: invoicing-api DependsOn: - InvoicingLambdaRole PreviewAlarm: Type: AWS::CloudWatch::Alarm Condition: IsProd Properties: AlarmName: "URGENT 9-5 - PROD: Failed to preview affected publications within date range" AlarmDescription: | - At least holiday-stop-api will not be able to predict which publications should be suspended - https://github.com/guardian/invoicing-api/blob/main/src/main/scala/com/gu/invoicing/preview/README.md - export AWS_DEFAULT_REGION=eu-west-1 && awslogs get --profile membership /aws/lambda/invoicing-api-preview-PROD --start='DD/mm/yyyy HH:MM' --end='DD/mm/yyyy HH:MM' AlarmActions: - !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:alarms-handler-topic-PROD ComparisonOperator: GreaterThanOrEqualToThreshold Dimensions: - Name: FunctionName Value: !Ref PreviewLambda EvaluationPeriods: 1 MetricName: Errors Namespace: AWS/Lambda Period: 300 Statistic: Sum Threshold: 1 TreatMissingData: notBreaching Tags: - Key: App Value: invoicing-api DependsOn: - InvoicingLambdaRole # **************************************************************************** # Lambdas # **************************************************************************** RefundLambda: Type: AWS::Lambda::Function Properties: Description: Apply refund to Zuora invoice by adjusting invoice items FunctionName: !Sub invoicing-api-refund-${Stage} Code: S3Bucket: membership-dist S3Key: !Sub support/${Stage}/invoicing-api/invoicing-api.jar Handler: com.gu.invoicing.refund.Lambda::handleRequest Environment: Variables: Stage: !Ref Stage Config: !Sub - '{{resolve:ssm:/invoicing-api/${Stage}/config:${Version}}}' - Version: !FindInMap [StageMap, !Ref Stage, ConfigVersion] Role: !GetAtt InvoicingLambdaRole.Arn MemorySize: 3008 Runtime: java11 Timeout: 900 DependsOn: - InvoicingLambdaRole InvoicesLambda: Type: AWS::Lambda::Function Properties: Description: Retrieve all invoices with payment methods by accountId FunctionName: !Sub invoicing-api-invoices-${Stage} Code: S3Bucket: membership-dist S3Key: !Sub support/${Stage}/invoicing-api/invoicing-api.jar Handler: com.gu.invoicing.invoice.Lambda::handleRequest Environment: Variables: Stage: !Ref Stage Config: !Sub - '{{resolve:ssm:/invoicing-api/${Stage}/config:${Version}}}' - Version: !FindInMap [StageMap, !Ref Stage, ConfigVersion] Role: !GetAtt InvoicingLambdaRole.Arn MemorySize: 3008 Runtime: java11 Timeout: 900 DependsOn: - InvoicingLambdaRole PdfLambda: Type: AWS::Lambda::Function Properties: Description: Download PDF invoice by invoiceId FunctionName: !Sub invoicing-api-pdf-${Stage} Code: S3Bucket: membership-dist S3Key: !Sub support/${Stage}/invoicing-api/invoicing-api.jar Handler: com.gu.invoicing.pdf.Lambda::handleRequest Environment: Variables: Stage: !Ref Stage Config: !Sub - '{{resolve:ssm:/invoicing-api/${Stage}/config:${Version}}}' - Version: !FindInMap [StageMap, !Ref Stage, ConfigVersion] Role: !GetAtt InvoicingLambdaRole.Arn MemorySize: 3008 Runtime: java11 Timeout: 900 DependsOn: - InvoicingLambdaRole NextInvoiceDateLambda: Type: AWS::Lambda::Function Properties: Description: Get next invoice date (day after last invoice period) FunctionName: !Sub invoicing-api-nextinvoicedate-${Stage} Code: S3Bucket: membership-dist S3Key: !Sub support/${Stage}/invoicing-api/invoicing-api.jar Handler: com.gu.invoicing.nextinvoicedate.Lambda::handleRequest Environment: Variables: Stage: !Ref Stage Config: !Sub - '{{resolve:ssm:/invoicing-api/${Stage}/config:${Version}}}' - Version: !FindInMap [StageMap, !Ref Stage, ConfigVersion] Role: !GetAtt InvoicingLambdaRole.Arn MemorySize: 3008 Runtime: java11 Timeout: 900 DependsOn: - InvoicingLambdaRole PreviewLambda: Type: AWS::Lambda::Function Properties: Description: Preview affected publications within date range FunctionName: !Sub invoicing-api-preview-${Stage} Code: S3Bucket: membership-dist S3Key: !Sub support/${Stage}/invoicing-api/invoicing-api.jar Handler: com.gu.invoicing.preview.Lambda::handleRequest Environment: Variables: Stage: !Ref Stage Config: !Sub - '{{resolve:ssm:/invoicing-api/${Stage}/config:${Version}}}' - Version: !FindInMap [StageMap, !Ref Stage, ConfigVersion] Role: !GetAtt InvoicingLambdaRole.Arn MemorySize: 3008 Runtime: java11 Timeout: 900 DependsOn: - InvoicingLambdaRole RefundErroneousPaymentLambda: Type: AWS::Lambda::Function Properties: Description: Apply refund to Zuora invoice by shuffling credit balances. FunctionName: !Sub invoicing-api-refund-erroneous-payment-${Stage} Code: S3Bucket: membership-dist S3Key: !Sub support/${Stage}/invoicing-api/invoicing-api.jar Handler: com.gu.invoicing.refundErroneousPayment.Lambda::handleRequest Environment: Variables: Stage: !Ref Stage Config: !Sub - '{{resolve:ssm:/invoicing-api/${Stage}/config:${Version}}}' - Version: !FindInMap [StageMap, !Ref Stage, ConfigVersion] Role: !GetAtt InvoicingLambdaRole.Arn MemorySize: 3008 Runtime: java11 Timeout: 900 DependsOn: - InvoicingLambdaRole # **************************************************************************** # API # **************************************************************************** InvoicingApi: Type: AWS::ApiGateway::RestApi Properties: Name: !Sub invoicing-api-${Stage} Description: Zuora invoice management (refunds, list invoices, download PDF, invoice preview) BinaryMediaTypes: - application/pdf InvoicingApiStage: Type: AWS::ApiGateway::Stage Properties: RestApiId: !Ref InvoicingApi DeploymentId: !Ref InvoicingApiDeployment StageName: !Sub ${Stage} DependsOn: - RefundMethod InvoicingApiDeployment: Type: AWS::ApiGateway::Deployment Properties: RestApiId: !Ref InvoicingApi DependsOn: - RefundMethod InvoicingApiUsagePlan: Type: AWS::ApiGateway::UsagePlan Properties: UsagePlanName: invoicing-api ApiStages: - ApiId: !Ref InvoicingApi Stage: !Ref Stage DependsOn: - InvoicingApi - InvoicingApiStage InvoicingApiKey: Type: AWS::ApiGateway::ApiKey Properties: Description: Used by https://github.com/guardian/invoicing-api Enabled: true Name: !Sub invoicing-api-key-${Stage} StageKeys: - RestApiId: !Ref InvoicingApi StageName: !Sub ${Stage} DependsOn: - InvoicingApi - InvoicingApiStage InvoicingApiUsagePlanKey: Type: AWS::ApiGateway::UsagePlanKey Properties: KeyId: !Ref InvoicingApiKey KeyType: API_KEY UsagePlanId: !Ref InvoicingApiUsagePlan DependsOn: - InvoicingApiKey - InvoicingApiUsagePlan # **************************************************************************** # POST /refund # **************************************************************************** RefundEndpoint: Type: AWS::ApiGateway::Resource Properties: RestApiId: !Ref InvoicingApi ParentId: !GetAtt InvoicingApi.RootResourceId PathPart: refund DependsOn: InvoicingApi RefundMethod: Type: AWS::ApiGateway::Method Properties: ApiKeyRequired: true AuthorizationType: NONE RestApiId: !Ref InvoicingApi ResourceId: !Ref RefundEndpoint HttpMethod: POST Integration: Type: AWS_PROXY IntegrationHttpMethod: POST # this for the interaction between API Gateway and Lambda and MUST be POST Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${RefundLambda.Arn}/invocations DependsOn: - InvoicingApi - RefundEndpoint - RefundLambda # **************************************************************************** # POST /refund-erroneous-payment # **************************************************************************** RefundErroneousPaymentEndpoint: Type: AWS::ApiGateway::Resource Properties: RestApiId: !Ref InvoicingApi ParentId: !GetAtt InvoicingApi.RootResourceId PathPart: refund-erroneous-payment DependsOn: InvoicingApi RefundErroneousPaymentMethod: Type: AWS::ApiGateway::Method Properties: ApiKeyRequired: true AuthorizationType: NONE RestApiId: !Ref InvoicingApi ResourceId: !Ref RefundErroneousPaymentEndpoint HttpMethod: POST Integration: Type: AWS_PROXY IntegrationHttpMethod: POST # this for the interaction between API Gateway and Lambda and MUST be POST Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${RefundErroneousPaymentLambda.Arn}/invocations DependsOn: - InvoicingApi - RefundErroneousPaymentEndpoint - RefundErroneousPaymentLambda # **************************************************************************** # GET /invoices # **************************************************************************** InvoicesEndpoint: Type: AWS::ApiGateway::Resource Properties: RestApiId: !Ref InvoicingApi ParentId: !GetAtt InvoicingApi.RootResourceId PathPart: invoices DependsOn: InvoicingApi InvoicesEndpointGetMethod: Type: AWS::ApiGateway::Method Properties: AuthorizationType: AWS_IAM ApiKeyRequired: true RestApiId: !Ref InvoicingApi ResourceId: !Ref InvoicesEndpoint HttpMethod: GET RequestParameters: method.request.path.accountId: true Integration: Type: AWS_PROXY IntegrationHttpMethod: POST # this for the interaction between API Gateway and Lambda and MUST be POST Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${InvoicesLambda.Arn}/invocations DependsOn: - InvoicingApi - InvoicesEndpoint - InvoicesLambda # **************************************************************************** # GET /invoices/{invoiceId} # **************************************************************************** PdfInvoiceIdPath: Type: AWS::ApiGateway::Resource Properties: RestApiId: !Ref InvoicingApi ParentId: !Ref InvoicesEndpoint PathPart: "{invoiceId}" DependsOn: - InvoicingApi - InvoicesEndpoint PdfInvoiceIdPathGetMethod: Type: AWS::ApiGateway::Method Properties: AuthorizationType: AWS_IAM ApiKeyRequired: true RestApiId: !Ref InvoicingApi ResourceId: !Ref PdfInvoiceIdPath HttpMethod: GET RequestParameters: method.request.path.invoiceId: true Integration: Type: AWS_PROXY IntegrationHttpMethod: POST # this for the interaction between API Gateway and Lambda and MUST be POST Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PdfLambda.Arn}/invocations DependsOn: - InvoicingApi - PdfLambda - PdfInvoiceIdPath # **************************************************************************** # GET /next-invoice-date/{subscriptionName} # **************************************************************************** NextInvoiceDateEndpoint: # /next-invoice-date path Type: AWS::ApiGateway::Resource Properties: RestApiId: !Ref InvoicingApi ParentId: !GetAtt InvoicingApi.RootResourceId PathPart: next-invoice-date DependsOn: - InvoicingApi NextInvoiceDatePath: # {subscriptionName} path parameter Type: AWS::ApiGateway::Resource Properties: RestApiId: !Ref InvoicingApi ParentId: !Ref NextInvoiceDateEndpoint PathPart: "{subscriptionName}" DependsOn: - InvoicingApi - NextInvoiceDateEndpoint NextInvoiceDatePathGetMethod: # GET verb Type: AWS::ApiGateway::Method Properties: AuthorizationType: NONE ApiKeyRequired: true RestApiId: !Ref InvoicingApi ResourceId: !Ref NextInvoiceDatePath HttpMethod: GET RequestParameters: method.request.path.subscriptionName: true Integration: Type: AWS_PROXY IntegrationHttpMethod: POST # this for the interaction between API Gateway and Lambda and MUST be POST Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${NextInvoiceDateLambda.Arn}/invocations DependsOn: - InvoicingApi - NextInvoiceDateLambda - NextInvoiceDateEndpoint - NextInvoiceDatePath # **************************************************************************** # GET /preview/{subscriptionName}?startDate=yyyy-mm-dd&endDate=yyyy-mm-dd # **************************************************************************** PreviewEndpoint: # /preview path Type: AWS::ApiGateway::Resource Properties: RestApiId: !Ref InvoicingApi ParentId: !GetAtt InvoicingApi.RootResourceId PathPart: preview DependsOn: - InvoicingApi PreviewEndpointPath: # {subscriptionName} path parameter Type: AWS::ApiGateway::Resource Properties: RestApiId: !Ref InvoicingApi ParentId: !Ref PreviewEndpoint PathPart: "{subscriptionName}" DependsOn: - InvoicingApi - PreviewEndpoint PreviewEndpointPathGetMethod: # GET verb Type: AWS::ApiGateway::Method Properties: AuthorizationType: NONE ApiKeyRequired: true RestApiId: !Ref InvoicingApi ResourceId: !Ref PreviewEndpointPath HttpMethod: GET RequestParameters: method.request.path.subscriptionName: true method.request.querystring.startDate: true method.request.querystring.endDate: true Integration: Type: AWS_PROXY IntegrationHttpMethod: POST # this for the interaction between API Gateway and Lambda and MUST be POST Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PreviewLambda.Arn}/invocations DependsOn: - PreviewLambda - InvoicingApi - PreviewEndpoint - PreviewEndpointPath # **************************************************************************** # Access control # **************************************************************************** RefundLambdaPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:invokeFunction FunctionName: !Sub invoicing-api-refund-${Stage} Principal: apigateway.amazonaws.com DependsOn: - RefundLambda - RefundMethod InvoicesLambdaPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:invokeFunction FunctionName: !Sub invoicing-api-invoices-${Stage} Principal: apigateway.amazonaws.com DependsOn: - InvoicesLambda PdfLambdaPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:invokeFunction FunctionName: !Sub invoicing-api-pdf-${Stage} Principal: apigateway.amazonaws.com DependsOn: - PdfLambda NextInvoiceDateLambdaPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:invokeFunction FunctionName: !Sub invoicing-api-nextinvoicedate-${Stage} Principal: apigateway.amazonaws.com DependsOn: - NextInvoiceDateLambda PreviewLambdaPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:invokeFunction FunctionName: !Sub invoicing-api-preview-${Stage} Principal: apigateway.amazonaws.com DependsOn: - PreviewLambda InvoicingLambdaRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: LambdaPolicy PolicyDocument: Statement: - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents - lambda:InvokeFunction Resource: - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/invoicing-api-refund-${Stage}:log-stream:* - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/invoicing-api-invoices-${Stage}:log-stream:* - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/invoicing-api-pdf-${Stage}:log-stream:* - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/invoicing-api-nextinvoicedate-${Stage}:log-stream:* - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/invoicing-api-preview-${Stage}:log-stream:* - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/invoicing-api-refund-erroneous-payment-${Stage}:log-stream:* - PolicyName: ReadPrivateCredentials PolicyDocument: Statement: - Effect: Allow Action: s3:GetObject Resource: !Sub arn:aws:s3:::gu-reader-revenue-private/membership/support-service-lambdas/${Stage}/zuoraRest-${Stage}*.json - PolicyName: ReadFromDeploymentBucket PolicyDocument: Statement: - Effect: Allow Action: s3:GetObject Resource: arn:aws:s3::*:membership-dist/* RefundErroneousPaymentLambdaPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:invokeFunction FunctionName: !Sub invoicing-api-refund-erroneous-payment-${Stage} Principal: apigateway.amazonaws.com DependsOn: - RefundErroneousPaymentLambda - RefundErroneousPaymentMethod InvoicingApiDomainName: Type: "AWS::ApiGateway::DomainName" Properties: RegionalCertificateArn: # only for *.support.guardianapis.com !Sub arn:aws:acm:${AWS::Region}:${AWS::AccountId}:certificate/b384a6a0-2f54-4874-b99b-96eeff96c009 DomainName: !FindInMap [ StageMap, !Ref Stage, DomainName ] EndpointConfiguration: Types: - REGIONAL InvoicingApiBasePathMapping: Type: "AWS::ApiGateway::BasePathMapping" Properties: RestApiId: !Ref InvoicingApi DomainName: !Ref InvoicingApiDomainName Stage: !Sub ${Stage} DependsOn: - InvoicingApi - InvoicingApiDomainName - InvoicingApiStage InvoicingApiDNSRecord: Type: AWS::Route53::RecordSet Properties: HostedZoneName: support.guardianapis.com. Name: !FindInMap [ StageMap, !Ref Stage, DomainName ] Type: CNAME TTL: '120' ResourceRecords: - !GetAtt InvoicingApiDomainName.RegionalDomainName