import * as cdk from "aws-cdk-lib"; import * as iam from "aws-cdk-lib/aws-iam"; import { Construct } from "constructs"; import { HcptfPolicyAspect } from "./hcptf-policy-aspect"; import { SeahavenSiteRoles } from "./seahaven-site-hcptf-stack"; /** * HCP exec roles. One stack per account. Prod is 011934824531 and also * hosts the seahaven-site apply and plan roles. Dev is 710827005802 and * stays payments-dashboard only. * * payments-dashboard: workspace payments-dashboard-prod, project * seahaven-prod, or workspace payments-dashboard-dev, project seahaven-dev. * * hcptf-payments-dashboard, hcptf-payments-dashboard-plan, and * payments-dashboard-lambda-boundary already existed in both accounts and * were imported. A create fails with a name conflict. The stacks are on * the dev and prod deploy jobs. That deploy creates the three managed * policies and removes the inline policies. * * `cdk import -c hcptfPaymentsImport=true` synthesizes only those three * resources, with the roles' current inline policy names and no reference * to the policies that do not exist yet. The default template is the * managed-policy state. */ export interface SeahavenHcptfStackProps extends cdk.StackProps { /** HCP project name: seahaven-prod or seahaven-dev. */ hcpProject: string; /** HCP workspace name: payments-dashboard-prod or payments-dashboard-dev. */ hcpWorkspace: string; /** DynamoDB CMK in this account. */ dynamodbCmkArn: string; /** * Secret ARNs in this order: slack-bot-token, slack-signing-secret, * boa-check-mgmt, boa-reporting, expense-slack-token, * expense-slack-signing-secret. */ secretArns: readonly string[]; /** * Synthesize the import template. Set from `-c hcptfPaymentsImport=true`. * Default is the managed-policy template. */ importExisting?: boolean; /** Prod only. Fold seahaven-site exec roles into this stack. */ includeSeahavenSite?: boolean; /** * Synthesize the seahaven-site import template. Set from * `-c hcptfSiteImport=true`. Omits site role tags and site outputs. */ siteImportExisting?: boolean; } export class SeahavenHcptfStack extends cdk.Stack { constructor(scope: Construct, id: string, props: SeahavenHcptfStackProps) { super(scope, id, props); if (props.importExisting && props.siteImportExisting) { throw new Error("hcptfPaymentsImport and hcptfSiteImport cannot both be set"); } paymentsDashboard(this, props); if (props.includeSeahavenSite) { new SeahavenSiteRoles(this, "SeahavenSite", { importExisting: props.siteImportExisting === true, }); } cdk.Aspects.of(this).add(new HcptfPolicyAspect(props.importExisting === true)); } } const VIEW_ONLY = "arn:aws:iam::aws:policy/job-function/ViewOnlyAccess"; /** Account and CMK id baked into the policy literals. Retarget rewrites them. */ const TEMPLATE_ACCOUNT = "011934824531"; const TEMPLATE_CMK_ID = "be5fa4cb-c546-40fe-a13d-c7bec79f5d12"; const TEMPLATE_SECRET_ARNS = [ "arn:aws:secretsmanager:us-east-1:011934824531:secret:payments-dashboard/slack-bot-token-0pAM3S", "arn:aws:secretsmanager:us-east-1:011934824531:secret:payments-dashboard/slack-signing-secret-u0T6h8", "arn:aws:secretsmanager:us-east-1:011934824531:secret:payments-dashboard/boa-check-mgmt-LEbC65", "arn:aws:secretsmanager:us-east-1:011934824531:secret:payments-dashboard/boa-reporting-JoR9lq", "arn:aws:secretsmanager:us-east-1:011934824531:secret:payments-dashboard/expense-slack-token-SeMg3s", "arn:aws:secretsmanager:us-east-1:011934824531:secret:payments-dashboard/expense-slack-signing-secret-lbb78J", ] as const; function retarget( document: object, account: string, target: SeahavenHcptfStackProps, ): object { if (target.secretArns.length !== TEMPLATE_SECRET_ARNS.length) { throw new Error("payments-dashboard secretArns must list six secrets"); } const cmkId = target.dynamodbCmkArn.split("/").pop(); if (!cmkId || !target.dynamodbCmkArn.includes(":key/")) { throw new Error("dynamodbCmkArn must be a KMS key ARN"); } let json = JSON.stringify(document); const containedCmk = json.includes(TEMPLATE_CMK_ID); for (let i = 0; i < TEMPLATE_SECRET_ARNS.length; i++) { json = json.replaceAll(TEMPLATE_SECRET_ARNS[i], target.secretArns[i]); } json = json.replaceAll(TEMPLATE_CMK_ID, cmkId); json = json.replaceAll(TEMPLATE_ACCOUNT, account); if (containedCmk && !json.includes(target.dynamodbCmkArn)) { throw new Error("CMK retarget did not produce dynamodbCmkArn"); } return JSON.parse(json); } function paymentsDashboard( stack: cdk.Stack, target: SeahavenHcptfStackProps, ): void { const account = stack.account; const providerArn = `arn:aws:iam::${account}:oidc-provider/app.terraform.io`; const workspace = `organization:seahaven:project:${target.hcpProject}:workspace:${target.hcpWorkspace}`; // CloudFormation rejects Tags and any RoleArn output on an IAM role import. // The deploy after import adds both. if (!target.importExisting) { cdk.Tags.of(stack).add("Project", "payments-dashboard"); cdk.Tags.of(stack).add("Owner", "adam@seahavenind.com"); cdk.Tags.of(stack).add("ManagedBy", "cdk"); } const boundary = managedPolicy( stack, "PaymentsDashboardLambdaBoundary", "payments-dashboard-lambda-boundary", boundaryDocument(account, target), "Per-workload Lambda permissions boundary for payments-dashboard (PLAT-79).", ); const applyTrust = trust( providerArn, `${workspace}:run_phase:apply`, "HcpApply", ); const planTrust = trust(providerArn, `${workspace}:run_phase:plan`, "HcpPlan"); // Import template: the two roles and the boundary only. Inline policy names // match the live roles so the later deploy can delete them. No Ref to the // three managed policies that do not exist yet. const apply = new iam.CfnRole(stack, "PaymentsDashboardApplyRole", { roleName: "hcptf-payments-dashboard", maxSessionDuration: 3600, assumeRolePolicyDocument: applyTrust, ...(target.importExisting ? { policies: [ { policyName: "payments-dashboard-services", policyDocument: servicesDocument(account, target), }, { policyName: "scoped-iam-management", policyDocument: scopedIamDocument(account, target), }, ], } : { managedPolicyArns: [ managedPolicy( stack, "PaymentsDashboardIam", "payments-dashboard-hcptf-iam", scopedIamDocument(account, target), ).ref, managedPolicy( stack, "PaymentsDashboardServices", "payments-dashboard-hcptf-services", servicesDocument(account, target), ).ref, ], }), ...(target.importExisting ? {} : { tags: roleTags() }), }); retain(apply); const plan = new iam.CfnRole(stack, "PaymentsDashboardPlanRole", { roleName: "hcptf-payments-dashboard-plan", maxSessionDuration: 3600, assumeRolePolicyDocument: planTrust, ...(target.importExisting ? { managedPolicyArns: [VIEW_ONLY], policies: [ { policyName: "payments-dashboard-plan-refresh", policyDocument: planDocument(account, target), }, ], } : { managedPolicyArns: [ VIEW_ONLY, managedPolicy( stack, "PaymentsDashboardPlan", "payments-dashboard-hcptf-plan", planDocument(account, target), ).ref, ], }), ...(target.importExisting ? {} : { tags: roleTags() }), }); retain(plan); if (!target.importExisting) { new cdk.CfnOutput(stack, "ApplyRoleArn", { value: apply.attrArn }); new cdk.CfnOutput(stack, "PlanRoleArn", { value: plan.attrArn }); new cdk.CfnOutput(stack, "LambdaBoundaryArn", { value: boundary.ref }); } } function managedPolicy( scope: Construct, id: string, name: string, policyDocument: object, description?: string, ): iam.CfnManagedPolicy { const policy = new iam.CfnManagedPolicy(scope, id, { managedPolicyName: name, path: "/tf-managed/", policyDocument, ...(description === undefined ? {} : { description }), }); retain(policy); return policy; } function retain(resource: cdk.CfnResource): void { resource.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.RETAIN; resource.cfnOptions.updateReplacePolicy = cdk.CfnDeletionPolicy.RETAIN; } function roleTags(): cdk.CfnTag[] { return [ { key: "Project", value: "payments-dashboard" }, { key: "Owner", value: "adam@seahavenind.com" }, { key: "ManagedBy", value: "cdk" }, ]; } function trust(providerArn: string, sub: string, sid: string): object { return { Version: "2012-10-17", Statement: [ { Sid: sid, Effect: "Allow", Action: "sts:AssumeRoleWithWebIdentity", Principal: { Federated: providerArn }, Condition: { StringEquals: { "app.terraform.io:aud": "aws.workload.identity", "app.terraform.io:sub": sub, }, }, }, ], }; } function scopedIamDocument( account: string, target: SeahavenHcptfStackProps, ): object { return retarget({ "Version": "2012-10-17", "Statement": [ { "Sid": "DenyCreatePolicy", "Effect": "Deny", "Action": [ "iam:CreatePolicy", "iam:CreatePolicyVersion", "iam:DeletePolicy", "iam:DeletePolicyVersion", "iam:SetDefaultPolicyVersion" ], "Resource": [ "*" ] }, { "Sid": "CreateExecRoleWithBoundary", "Effect": "Allow", "Action": [ "iam:CreateRole" ], "Resource": [ "arn:aws:iam::011934824531:role/tf-managed/payments-dashboard-*" ], "Condition": { "StringLike": { "iam:PermissionsBoundary": [ "arn:aws:iam::011934824531:policy/tf-managed/payments-dashboard-*", "arn:aws:iam::011934824531:policy/seahaven-lambda-execution-boundary", "arn:aws:iam::011934824531:policy/seahaven-lambda-execution-boundary-payments-dashboard" ] } } }, { "Sid": "MutateExecRoleWithBoundary", "Effect": "Allow", "Action": [ "iam:AttachRolePolicy", "iam:PutRolePolicy", "iam:PutRolePermissionsBoundary" ], "Resource": [ "arn:aws:iam::011934824531:role/tf-managed/payments-dashboard-*" ], "Condition": { "StringLike": { "iam:PermissionsBoundary": [ "arn:aws:iam::011934824531:policy/tf-managed/payments-dashboard-*", "arn:aws:iam::011934824531:policy/seahaven-lambda-execution-boundary", "arn:aws:iam::011934824531:policy/seahaven-lambda-execution-boundary-payments-dashboard" ] } } }, { "Sid": "WriteExecRoles", "Effect": "Allow", "Action": [ "iam:DeleteRole", "iam:DeleteRolePolicy", "iam:DetachRolePolicy", "iam:TagRole", "iam:UntagRole", "iam:UpdateAssumeRolePolicy", "iam:UpdateRole", "iam:UpdateRoleDescription" ], "Resource": [ "arn:aws:iam::011934824531:role/tf-managed/payments-dashboard-*" ] }, { "Sid": "PassExecRolesToLambda", "Effect": "Allow", "Action": [ "iam:PassRole" ], "Resource": [ "arn:aws:iam::011934824531:role/tf-managed/payments-dashboard-*" ], "Condition": { "StringEquals": { "iam:PassedToService": [ "lambda.amazonaws.com" ] } } }, { "Sid": "CreateDeployRole", "Effect": "Allow", "Action": [ "iam:CreateRole" ], "Resource": [ "arn:aws:iam::011934824531:role/tf-managed/githubdeploy-payments-dashboard" ], "Condition": { "Null": { "iam:PermissionsBoundary": [ "true" ] } } }, { "Sid": "WriteDeployRoles", "Effect": "Allow", "Action": [ "iam:AttachRolePolicy", "iam:DeleteRole", "iam:DeleteRolePolicy", "iam:DetachRolePolicy", "iam:PutRolePolicy", "iam:TagRole", "iam:UntagRole", "iam:UpdateAssumeRolePolicy", "iam:UpdateRole", "iam:UpdateRoleDescription" ], "Resource": [ "arn:aws:iam::011934824531:role/tf-managed/githubdeploy-payments-dashboard" ] }, { "Sid": "IamReadOnly", "Effect": "Allow", "Action": [ "iam:GetPolicy", "iam:GetPolicyVersion", "iam:GetRole", "iam:GetRolePolicy", "iam:ListAttachedRolePolicies", "iam:ListInstanceProfilesForRole", "iam:ListPolicies", "iam:ListPolicyVersions", "iam:ListRolePolicies", "iam:ListRoleTags", "iam:ListRoles" ], "Resource": [ "*" ] }, { "Sid": "DenySelfMutation", "Effect": "Deny", "Action": [ "iam:AttachRolePolicy", "iam:DeleteRole", "iam:DeleteRolePolicy", "iam:DeleteRolePermissionsBoundary", "iam:DetachRolePolicy", "iam:PutRolePolicy", "iam:PutRolePermissionsBoundary", "iam:UpdateAssumeRolePolicy", "iam:UpdateRole", "iam:UpdateRoleDescription" ], "Resource": [ "arn:aws:iam::011934824531:role/hcptf-*", "arn:aws:iam::011934824531:role/github-cfn-execution-role", "arn:aws:iam::011934824531:role/githubdeploy-*", "arn:aws:iam::011934824531:role/cdk-hnb659fds-*", "arn:aws:iam::011934824531:role/OrganizationAccountAccessRole", "arn:aws:iam::011934824531:role/seahaven-*" ] }, { "Sid": "DenyBoundaryTampering", "Effect": "Deny", "Action": [ "iam:DeleteRolePermissionsBoundary", "iam:DeleteUserPermissionsBoundary" ], "Resource": [ "arn:aws:iam::011934824531:role/*", "arn:aws:iam::011934824531:user/*" ] }, { "Sid": "DenyBoundaryPolicyEdit", "Effect": "Deny", "Action": [ "iam:CreatePolicyVersion", "iam:DeletePolicy", "iam:DeletePolicyVersion", "iam:SetDefaultPolicyVersion" ], "Resource": [ "arn:aws:iam::011934824531:policy/seahaven-*" ] } ] }, account, target); } function servicesDocument( account: string, target: SeahavenHcptfStackProps, ): object { return retarget({ "Version": "2012-10-17", "Statement": [ { "Sid": "LambdaAll", "Effect": "Allow", "Action": [ "lambda:*" ], "Resource": [ "arn:aws:lambda:us-east-1:011934824531:function:payments-*" ] }, { "Sid": "LambdaList", "Effect": "Allow", "Action": [ "lambda:ListFunctions", "lambda:ListLayers", "lambda:GetAccountSettings" ], "Resource": [ "*" ] }, { "Sid": "EventBridgeRules", "Effect": "Allow", "Action": [ "events:*" ], "Resource": [ "arn:aws:events:us-east-1:011934824531:rule/payments-dashboard-*" ] }, { "Sid": "EventBridgeList", "Effect": "Allow", "Action": [ "events:ListRules", "events:ListRuleNamesByTarget" ], "Resource": [ "*" ] }, { "Sid": "CloudWatchLogs", "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:DeleteLogGroup", "logs:PutRetentionPolicy", "logs:DeleteRetentionPolicy", "logs:TagResource", "logs:UntagResource", "logs:ListTagsForResource", "logs:PutMetricFilter", "logs:DeleteMetricFilter", "logs:DescribeMetricFilters" ], "Resource": [ "arn:aws:logs:us-east-1:011934824531:log-group:/aws/lambda/payments-*", "arn:aws:logs:us-east-1:011934824531:log-group:/aws/apigateway/payments-dashboard", "arn:aws:logs:us-east-1:011934824531:log-group:/aws/apigateway/payments-dashboard:*" ] }, { "Sid": "CloudWatchLogsDescribe", "Effect": "Allow", "Action": [ "logs:DescribeLogGroups" ], "Resource": [ "*" ] }, { "Sid": "ApiGwAccessLogDelivery", "Effect": "Allow", "Action": [ "logs:CreateLogDelivery", "logs:GetLogDelivery", "logs:UpdateLogDelivery", "logs:DeleteLogDelivery", "logs:ListLogDeliveries", "logs:PutResourcePolicy", "logs:DescribeResourcePolicies" ], "Resource": [ "*" ] }, { "Sid": "StackBuckets", "Effect": "Allow", "Action": [ "s3:*" ], "Resource": [ "arn:aws:s3:::payments-dashboard-artifacts-011934824531", "arn:aws:s3:::payments-dashboard-artifacts-011934824531/*", "arn:aws:s3:::seahaven-payments-csv-011934824531", "arn:aws:s3:::seahaven-payments-csv-011934824531/*", "arn:aws:s3:::seahaven-payments-boa-raw-011934824531", "arn:aws:s3:::seahaven-payments-boa-raw-011934824531/*" ] }, { "Sid": "DynamoDBTable", "Effect": "Allow", "Action": [ "dynamodb:*" ], "Resource": [ "arn:aws:dynamodb:us-east-1:011934824531:table/PaymentsDashboard", "arn:aws:dynamodb:us-east-1:011934824531:table/PaymentsDashboard/*" ] }, { "Sid": "DynamoDBList", "Effect": "Allow", "Action": [ "dynamodb:ListTables" ], "Resource": [ "*" ] }, { "Sid": "SqsDlq", "Effect": "Allow", "Action": [ "sqs:*" ], "Resource": [ "arn:aws:sqs:us-east-1:011934824531:payments-processPaymentCsv-async-dlq" ] }, { "Sid": "SqsList", "Effect": "Allow", "Action": [ "sqs:ListQueues" ], "Resource": [ "*" ] }, { "Sid": "HttpApiManage", "Effect": "Allow", "Action": [ "apigateway:*" ], "Resource": [ "arn:aws:apigateway:us-east-1::/apis", "arn:aws:apigateway:us-east-1::/apis/*", "arn:aws:apigateway:us-east-1::/tags/*", "arn:aws:apigateway:us-east-1::/vpclinks", "arn:aws:apigateway:us-east-1::/vpclinks/*" ] }, { "Sid": "PaymentsSsm", "Effect": "Allow", "Action": [ "ssm:GetParameter", "ssm:GetParameters", "ssm:PutParameter", "ssm:DeleteParameter", "ssm:AddTagsToResource", "ssm:RemoveTagsFromResource", "ssm:ListTagsForResource" ], "Resource": [ "arn:aws:ssm:us-east-1:011934824531:parameter/payments-dashboard/*", "arn:aws:ssm:us-east-1:011934824531:parameter/seahaven/dynamodb/cmk-arn" ] }, { "Sid": "SsmDescribeParameters", "Effect": "Allow", "Action": [ "ssm:DescribeParameters" ], "Resource": [ "*" ] }, { "Sid": "SecretsManagerRead", "Effect": "Allow", "Action": [ "secretsmanager:DescribeSecret", "secretsmanager:GetResourcePolicy", "secretsmanager:ListSecretVersionIds", "secretsmanager:TagResource", "secretsmanager:UntagResource" ], "Resource": [ "arn:aws:secretsmanager:us-east-1:011934824531:secret:payments-dashboard/*" ] }, { "Sid": "SecretsManagerList", "Effect": "Allow", "Action": [ "secretsmanager:ListSecrets" ], "Resource": [ "*" ] }, { "Sid": "KmsTableCmk", "Effect": "Allow", "Action": [ "kms:DescribeKey", "kms:GetKeyPolicy", "kms:ListResourceTags", "kms:CreateGrant", "kms:ListGrants", "kms:RetireGrant", "kms:Encrypt", "kms:Decrypt", "kms:GenerateDataKey", "kms:GenerateDataKeyWithoutPlaintext" ], "Resource": [ "arn:aws:kms:us-east-1:011934824531:key/be5fa4cb-c546-40fe-a13d-c7bec79f5d12" ] }, { "Sid": "CloudWatchAlarms", "Effect": "Allow", "Action": [ "cloudwatch:PutMetricAlarm", "cloudwatch:DeleteAlarms", "cloudwatch:DescribeAlarms", "cloudwatch:TagResource", "cloudwatch:UntagResource", "cloudwatch:ListTagsForResource" ], "Resource": [ "arn:aws:cloudwatch:us-east-1:011934824531:alarm:payments-*" ] }, { "Sid": "CloudWatchDescribeAlarms", "Effect": "Allow", "Action": [ "cloudwatch:DescribeAlarms" ], "Resource": [ "*" ] }, { "Sid": "SnsPublishSiteAlerts", "Effect": "Allow", "Action": [ "sns:Publish", "sns:GetTopicAttributes", "sns:ListTagsForResource" ], "Resource": [ "arn:aws:sns:us-east-1:011934824531:site-alerts" ] }, { "Sid": "ManageTfManagedBoundary", "Effect": "Allow", "Action": [ "iam:GetPolicy", "iam:GetPolicyVersion", "iam:ListPolicyVersions", "iam:ListPolicyTags", "iam:TagPolicy", "iam:UntagPolicy" ], "Resource": [ "arn:aws:iam::011934824531:policy/tf-managed/payments-dashboard-*" ] }, { "Sid": "Ec2VpcManagement", "Effect": "Allow", "Action": [ "ec2:AllocateAddress", "ec2:AssociateRouteTable", "ec2:AttachInternetGateway", "ec2:AuthorizeSecurityGroupEgress", "ec2:AuthorizeSecurityGroupIngress", "ec2:CreateInternetGateway", "ec2:CreateNatGateway", "ec2:CreateRoute", "ec2:CreateRouteTable", "ec2:CreateSecurityGroup", "ec2:CreateSubnet", "ec2:CreateVpc", "ec2:CreateVpcEndpoint", "ec2:CreateTags", "ec2:DeleteInternetGateway", "ec2:DeleteNatGateway", "ec2:DeleteRoute", "ec2:DeleteRouteTable", "ec2:DeleteSecurityGroup", "ec2:DeleteSubnet", "ec2:DeleteVpc", "ec2:DeleteVpcEndpoints", "ec2:DescribeAccountAttributes", "ec2:DescribeAddresses", "ec2:DescribeAddressesAttribute", "ec2:DescribeAvailabilityZones", "ec2:DescribeInternetGateways", "ec2:DescribeNatGateways", "ec2:DescribeNetworkInterfaces", "ec2:DescribeRouteTables", "ec2:DescribeSecurityGroupRules", "ec2:DescribeSecurityGroups", "ec2:DescribeSubnets", "ec2:DescribeTags", "ec2:DescribeVpcAttribute", "ec2:DescribeVpcEndpoints", "ec2:DescribeVpcs", "ec2:DescribePrefixLists", "ec2:DetachInternetGateway", "ec2:DisassociateAddress", "ec2:DisassociateRouteTable", "ec2:ModifySubnetAttribute", "ec2:ModifyVpcAttribute", "ec2:ModifyVpcEndpoint", "ec2:ReleaseAddress", "ec2:RevokeSecurityGroupEgress", "ec2:RevokeSecurityGroupIngress", "ec2:UpdateSecurityGroupRuleDescriptionsEgress", "ec2:UpdateSecurityGroupRuleDescriptionsIngress" ], "Resource": [ "*" ] } ] }, account, target); } function planDocument( account: string, target: SeahavenHcptfStackProps, ): object { return retarget({ "Version": "2012-10-17", "Statement": [ { "Sid": "RefreshIamRoles", "Effect": "Allow", "Action": [ "iam:GetRole", "iam:GetRolePolicy", "iam:ListRolePolicies", "iam:ListAttachedRolePolicies", "iam:ListRoleTags" ], "Resource": [ "arn:aws:iam::011934824531:role/tf-managed/payments-dashboard-*", "arn:aws:iam::011934824531:role/tf-managed/githubdeploy-payments-dashboard", "arn:aws:iam::011934824531:role/hcptf-payments-dashboard", "arn:aws:iam::011934824531:role/hcptf-payments-dashboard-plan" ] }, { "Sid": "RefreshManagedPolicies", "Effect": "Allow", "Action": [ "iam:GetPolicy", "iam:GetPolicyVersion" ], "Resource": [ "*" ] }, { "Sid": "RefreshLambda", "Effect": "Allow", "Action": [ "lambda:GetFunction", "lambda:GetFunctionConfiguration", "lambda:GetPolicy", "lambda:GetFunctionCodeSigningConfig", "lambda:GetFunctionConcurrency", "lambda:GetFunctionEventInvokeConfig", "lambda:GetFunctionUrlConfig", "lambda:GetRuntimeManagementConfig", "lambda:GetFunctionRecursionConfig", "lambda:ListTags", "lambda:ListVersionsByFunction", "lambda:ListAliases" ], "Resource": [ "arn:aws:lambda:us-east-1:011934824531:function:payments-*" ] }, { "Sid": "RefreshLambdaList", "Effect": "Allow", "Action": [ "lambda:ListFunctions", "lambda:ListLayers", "lambda:GetAccountSettings" ], "Resource": [ "*" ] }, { "Sid": "RefreshBuckets", "Effect": "Allow", "Action": [ "s3:GetAccelerateConfiguration", "s3:GetAnalyticsConfiguration", "s3:GetBucketAcl", "s3:GetBucketCORS", "s3:GetBucketLifecycleConfiguration", "s3:GetBucketLocation", "s3:GetBucketLogging", "s3:GetBucketNotification", "s3:GetBucketObjectLockConfiguration", "s3:GetBucketOwnershipControls", "s3:GetBucketPolicy", "s3:GetBucketPolicyStatus", "s3:GetBucketPublicAccessBlock", "s3:GetBucketReplication", "s3:GetBucketRequestPayment", "s3:GetBucketTagging", "s3:GetBucketVersioning", "s3:GetBucketWebsite", "s3:GetEncryptionConfiguration", "s3:GetIntelligentTieringConfiguration", "s3:GetInventoryConfiguration", "s3:GetLifecycleConfiguration", "s3:GetMetricsConfiguration", "s3:GetObject", "s3:GetObjectTagging", "s3:GetObjectVersion", "s3:GetReplicationConfiguration", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::payments-dashboard-artifacts-011934824531", "arn:aws:s3:::payments-dashboard-artifacts-011934824531/*", "arn:aws:s3:::seahaven-payments-csv-011934824531", "arn:aws:s3:::seahaven-payments-csv-011934824531/*", "arn:aws:s3:::seahaven-payments-boa-raw-011934824531", "arn:aws:s3:::seahaven-payments-boa-raw-011934824531/*" ] }, { "Sid": "RefreshDynamoDB", "Effect": "Allow", "Action": [ "dynamodb:DescribeTable", "dynamodb:DescribeTimeToLive", "dynamodb:DescribeContinuousBackups", "dynamodb:DescribeKinesisStreamingDestination", "dynamodb:ListTagsOfResource" ], "Resource": [ "arn:aws:dynamodb:us-east-1:011934824531:table/PaymentsDashboard" ] }, { "Sid": "RefreshEventBridge", "Effect": "Allow", "Action": [ "events:DescribeRule", "events:ListTargetsByRule", "events:ListTagsForResource" ], "Resource": [ "arn:aws:events:us-east-1:011934824531:rule/payments-dashboard-*" ] }, { "Sid": "RefreshLogs", "Effect": "Allow", "Action": [ "logs:DescribeLogGroups", "logs:ListTagsForResource" ], "Resource": [ "*" ] }, { "Sid": "RefreshHttpApi", "Effect": "Allow", "Action": [ "apigateway:GET" ], "Resource": [ "arn:aws:apigateway:us-east-1::/apis", "arn:aws:apigateway:us-east-1::/apis/*", "arn:aws:apigateway:us-east-1::/tags/*" ] }, { "Sid": "RefreshSsm", "Effect": "Allow", "Action": [ "ssm:GetParameter", "ssm:GetParameters", "ssm:ListTagsForResource" ], "Resource": [ "arn:aws:ssm:us-east-1:011934824531:parameter/payments-dashboard/*", "arn:aws:ssm:us-east-1:011934824531:parameter/seahaven/dynamodb/cmk-arn" ] }, { "Sid": "RefreshSsmDescribeParameters", "Effect": "Allow", "Action": [ "ssm:DescribeParameters" ], "Resource": [ "*" ] }, { "Sid": "RefreshSecrets", "Effect": "Allow", "Action": [ "secretsmanager:DescribeSecret", "secretsmanager:GetResourcePolicy", "secretsmanager:ListSecretVersionIds" ], "Resource": [ "arn:aws:secretsmanager:us-east-1:011934824531:secret:payments-dashboard/*" ] }, { "Sid": "RefreshSecretsList", "Effect": "Allow", "Action": [ "secretsmanager:ListSecrets" ], "Resource": [ "*" ] }, { "Sid": "RefreshAlarms", "Effect": "Allow", "Action": [ "cloudwatch:DescribeAlarms", "cloudwatch:ListTagsForResource" ], "Resource": [ "*" ] }, { "Sid": "RefreshSns", "Effect": "Allow", "Action": [ "sns:GetTopicAttributes", "sns:ListTagsForResource" ], "Resource": [ "arn:aws:sns:us-east-1:011934824531:site-alerts" ] }, { "Sid": "RefreshSqs", "Effect": "Allow", "Action": [ "sqs:GetQueueAttributes", "sqs:GetQueueUrl", "sqs:ListQueueTags" ], "Resource": [ "arn:aws:sqs:us-east-1:011934824531:payments-processPaymentCsv-async-dlq" ] }, { "Sid": "RefreshKms", "Effect": "Allow", "Action": [ "kms:DescribeKey", "kms:GetKeyPolicy", "kms:ListResourceTags", "kms:CreateGrant", "kms:ListGrants" ], "Resource": [ "arn:aws:kms:us-east-1:011934824531:key/be5fa4cb-c546-40fe-a13d-c7bec79f5d12" ] }, { "Sid": "RefreshEc2", "Effect": "Allow", "Action": [ "ec2:DescribeAccountAttributes", "ec2:DescribeAddresses", "ec2:DescribeAddressesAttribute", "ec2:DescribeAvailabilityZones", "ec2:DescribeInternetGateways", "ec2:DescribeNatGateways", "ec2:DescribeNetworkInterfaces", "ec2:DescribeRouteTables", "ec2:DescribeSecurityGroupRules", "ec2:DescribeSecurityGroups", "ec2:DescribeSubnets", "ec2:DescribeTags", "ec2:DescribeVpcAttribute", "ec2:DescribeVpcEndpoints", "ec2:DescribeVpcs", "ec2:DescribePrefixLists" ], "Resource": [ "*" ] } ] }, account, target); } function boundaryDocument( account: string, target: SeahavenHcptfStackProps, ): object { return retarget({ "Version": "2012-10-17", "Statement": [ { "Sid": "CloudWatchLogsWrite", "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogStreams" ], "Resource": [ "arn:aws:logs:us-east-1:011934824531:log-group:/aws/lambda*" ] }, { "Sid": "CloudWatchLogsDescribe", "Effect": "Allow", "Action": [ "logs:DescribeLogGroups" ], "Resource": [ "*" ] }, { "Sid": "XRay", "Effect": "Allow", "Action": [ "xray:PutTraceSegments", "xray:PutTelemetryRecords" ], "Resource": [ "*" ] }, { "Sid": "Ec2Eni", "Effect": "Allow", "Action": [ "ec2:CreateNetworkInterface", "ec2:DescribeNetworkInterfaces", "ec2:DeleteNetworkInterface", "ec2:DescribeSubnets", "ec2:DescribeSecurityGroups", "ec2:DescribeVpcs" ], "Resource": [ "*" ] }, { "Sid": "PaymentsSecrets", "Effect": "Allow", "Action": [ "secretsmanager:GetSecretValue" ], "Resource": [ "arn:aws:secretsmanager:us-east-1:011934824531:secret:payments-dashboard/slack-bot-token-0pAM3S", "arn:aws:secretsmanager:us-east-1:011934824531:secret:payments-dashboard/slack-signing-secret-u0T6h8", "arn:aws:secretsmanager:us-east-1:011934824531:secret:payments-dashboard/boa-check-mgmt-LEbC65", "arn:aws:secretsmanager:us-east-1:011934824531:secret:payments-dashboard/boa-reporting-JoR9lq", "arn:aws:secretsmanager:us-east-1:011934824531:secret:payments-dashboard/expense-slack-token-SeMg3s", "arn:aws:secretsmanager:us-east-1:011934824531:secret:payments-dashboard/expense-slack-signing-secret-lbb78J" ] }, { "Sid": "PaymentsDynamoDB", "Effect": "Allow", "Action": [ "dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:UpdateItem", "dynamodb:DeleteItem", "dynamodb:Query", "dynamodb:Scan", "dynamodb:BatchGetItem", "dynamodb:BatchWriteItem", "dynamodb:DescribeTable", "dynamodb:ConditionCheckItem" ], "Resource": [ "arn:aws:dynamodb:us-east-1:011934824531:table/PaymentsDashboard", "arn:aws:dynamodb:us-east-1:011934824531:table/PaymentsDashboard/*" ] }, { "Sid": "PaymentsCmk", "Effect": "Allow", "Action": [ "kms:Decrypt", "kms:GenerateDataKey", "kms:DescribeKey" ], "Resource": [ "arn:aws:kms:us-east-1:011934824531:key/be5fa4cb-c546-40fe-a13d-c7bec79f5d12" ], "Condition": { "StringEquals": { "kms:ViaService": [ "dynamodb.us-east-1.amazonaws.com" ] } } }, { "Sid": "PaymentsCsvRead", "Effect": "Allow", "Action": [ "s3:GetObject", "s3:GetObjectVersion" ], "Resource": [ "arn:aws:s3:::seahaven-payments-csv-011934824531/*" ] }, { "Sid": "PaymentsBoaRawPut", "Effect": "Allow", "Action": [ "s3:PutObject" ], "Resource": [ "arn:aws:s3:::seahaven-payments-boa-raw-011934824531/*" ] }, { "Sid": "PaymentsDlqSend", "Effect": "Allow", "Action": [ "sqs:SendMessage" ], "Resource": [ "arn:aws:sqs:us-east-1:011934824531:payments-processPaymentCsv-async-dlq" ] }, { "Sid": "PaymentsInvokeExpenseProcessor", "Effect": "Allow", "Action": [ "lambda:InvokeFunction" ], "Resource": [ "arn:aws:lambda:us-east-1:011934824531:function:payments-expenseProcessor" ] } ] }, account, target); }