mirror of
https://github.com/Sea-Haven-Industries/seahaven-org-baseline.git
synced 2026-10-03 04:33:13 +00:00
Add seahaven-hcptf in prod and dev for the imported payments-dashboard HCP roles and Lambda boundary, and move seahaven-site-hcptf inline policies to managed policies.
1232 lines
34 KiB
TypeScript
1232 lines
34 KiB
TypeScript
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";
|
|
|
|
/**
|
|
* payments-dashboard HCP exec roles. One stack per account. Prod is
|
|
* 011934824531, workspace payments-dashboard-prod, project seahaven-prod.
|
|
* Dev is 710827005802, 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;
|
|
}
|
|
|
|
export class SeahavenHcptfStack extends cdk.Stack {
|
|
constructor(scope: Construct, id: string, props: SeahavenHcptfStackProps) {
|
|
super(scope, id, props);
|
|
paymentsDashboard(this, props);
|
|
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);
|
|
}
|