From f19c9ab17022b6b52a04f9e20d6b542d4386eef6 Mon Sep 17 00:00:00 2001 From: Chris Wilton-Magras Date: Wed, 11 Sep 2024 16:20:27 +0100 Subject: [PATCH] Assign least-privilege IAM policies to pipeline --- cloud/bin/pipeline.ts | 27 ++- cloud/lib/app-stage.ts | 20 +- cloud/lib/pipeline-stack.ts | 57 +++-- cloud/lib/ui-stack.ts | 42 ++-- cloud/package.json | 4 + cloud/permissions/README.md | 78 +++++++ .../permissions/execution_policy_basics.json | 69 ++++++ cloud/permissions/execution_policy_basics.ts | 66 ++++++ .../execution_policy_cloudfront.json | 42 ++++ .../execution_policy_cloudfront.ts | 52 +++++ .../permissions/execution_policy_cognito.json | 37 +++ cloud/permissions/execution_policy_cognito.ts | 36 +++ .../execution_policy_edgelambda.json | 17 ++ .../execution_policy_pipeline.json | 73 ++++++ .../permissions/execution_policy_route53.json | 57 +++++ cloud/permissions/execution_policy_route53.ts | 60 +++++ cloud/permissions/execution_policy_vpc.json | 206 +++++++++++++++++ cloud/permissions/execution_policy_vpc.ts | 211 ++++++++++++++++++ cloud/permissions/index.ts | 5 + 19 files changed, 1102 insertions(+), 57 deletions(-) create mode 100644 cloud/permissions/README.md create mode 100644 cloud/permissions/execution_policy_basics.json create mode 100644 cloud/permissions/execution_policy_basics.ts create mode 100644 cloud/permissions/execution_policy_cloudfront.json create mode 100644 cloud/permissions/execution_policy_cloudfront.ts create mode 100644 cloud/permissions/execution_policy_cognito.json create mode 100644 cloud/permissions/execution_policy_cognito.ts create mode 100644 cloud/permissions/execution_policy_edgelambda.json create mode 100644 cloud/permissions/execution_policy_pipeline.json create mode 100644 cloud/permissions/execution_policy_route53.json create mode 100644 cloud/permissions/execution_policy_route53.ts create mode 100644 cloud/permissions/execution_policy_vpc.json create mode 100644 cloud/permissions/execution_policy_vpc.ts create mode 100644 cloud/permissions/index.ts diff --git a/cloud/bin/pipeline.ts b/cloud/bin/pipeline.ts index 47780b25..f4566e3a 100644 --- a/cloud/bin/pipeline.ts +++ b/cloud/bin/pipeline.ts @@ -25,20 +25,23 @@ const tags = { stage: stageName(app), }; +const generateStackName = stackName(app); +const generateDescription = resourceDescription(app); + /* Pipeline is now responsible for deploying all other Stacks */ -const pipelineUsEast1Stack = new PipelineAssistUsEast1Stack( - app, - stackName(app)('pipeline-useast1'), - { - description: resourceDescription(app)('Code Pipeline Cross-Region resources stack (us-east-1)'), - env, - tags, - } -); - -new PipelineStack(app, stackName(app)('pipeline'), { - description: resourceDescription(app)('Code Pipeline stack'), +const pipelineUsEast1StackName = generateStackName('pipeline-useast1'); +const pipelineUsEast1Stack = new PipelineAssistUsEast1Stack(app, pipelineUsEast1StackName, { + stackName: pipelineUsEast1StackName, + description: generateDescription('Code Pipeline Cross-Region resources stack (us-east-1)'), + env, + tags, +}); + +const pipelineStackName = generateStackName('pipeline'); +new PipelineStack(app, pipelineStackName, { + stackName: pipelineStackName, + description: generateDescription('Code Pipeline stack'), env, tags, usEast1Bucket: pipelineUsEast1Stack.resourceBucket, diff --git a/cloud/lib/app-stage.ts b/cloud/lib/app-stage.ts index c0373396..55c8e828 100644 --- a/cloud/lib/app-stage.ts +++ b/cloud/lib/app-stage.ts @@ -30,13 +30,17 @@ export class AppStage extends Stage { const generateDescription = resourceDescription(scope); const generateStackName = stackName(scope); - const hostedZoneStack = new HostedZoneStack(this, generateStackName('hostedzone'), { + const hostedZoneStackName = generateStackName('hostedzone'); + const hostedZoneStack = new HostedZoneStack(this, hostedZoneStackName, { + stackName: hostedZoneStackName, description: generateDescription('Hosted Zone stack'), env, tags, }); - const certificateStack = new CertificateStack(this, generateStackName('certificate'), { + const certificateStackName = generateStackName('certificate'); + const certificateStack = new CertificateStack(this, certificateStackName, { + stackName: certificateStackName, description: generateDescription('Certificate stack'), env, tags, @@ -44,14 +48,18 @@ export class AppStage extends Stage { hostedZone: hostedZoneStack.hostedZone, }); - const authStack = new AuthStack(this, generateStackName('auth'), { + const authStackName = generateStackName('auth'); + const authStack = new AuthStack(this, authStackName, { + stackName: authStackName, description: generateDescription('Auth stack'), env, tags, domainName: hostedZoneStack.topLevelDomain.value as string, }); - new ApiStack(this, generateStackName('api'), { + const apiStackName = generateStackName('api'); + new ApiStack(this, apiStackName, { + stackName: apiStackName, description: generateDescription('API stack'), env, tags, @@ -63,7 +71,9 @@ export class AppStage extends Stage { hostedZone: hostedZoneStack.hostedZone, }); - const uiStack = new UiStack(this, generateStackName('ui'), { + const uiStackName = generateStackName('ui'); + const uiStack = new UiStack(this, uiStackName, { + stackName: uiStackName, description: generateDescription('UI stack'), env, tags, diff --git a/cloud/lib/pipeline-stack.ts b/cloud/lib/pipeline-stack.ts index 237163d5..8d54fd3e 100644 --- a/cloud/lib/pipeline-stack.ts +++ b/cloud/lib/pipeline-stack.ts @@ -1,4 +1,8 @@ -import { BuildEnvironmentVariableType, BuildSpec } from 'aws-cdk-lib/aws-codebuild'; +import { + BuildEnvironmentVariable, + BuildEnvironmentVariableType, + BuildSpec, +} from 'aws-cdk-lib/aws-codebuild'; import { PolicyStatement } from 'aws-cdk-lib/aws-iam'; import { IBucket } from 'aws-cdk-lib/aws-s3'; import { Stack, StackProps } from 'aws-cdk-lib/core'; @@ -25,18 +29,44 @@ export class PipelineStack extends Stack { const generateResourceId = resourceId(scope); const stage = stageName(scope); - const sourceCode = CodePipelineSource.connection('ScottLogic/prompt-injection', 'main', { - connectionArn: `arn:aws:codestar-connections:${env.region}:${env.account}:connection/05c0f0a4-2233-4269-a697-33a339f8a6bc`, - }); + // FIXME Reset branch to 'main' !!! + const sourceCode = CodePipelineSource.connection( + 'ScottLogic/prompt-injection', + 'feature/aws-cloud-infrastructure', + { + //connectionArn: `arn:aws:codestar-connections:${env.region}:${env.account}:connection/05c0f0a4-2233-4269-a697-33a339f8a6bc`, + connectionArn: `arn:aws:codestar-connections:eu-north-1:${env.account}:connection/05c0f0a4-2233-4269-a697-33a339f8a6bc`, + } + ); const hostBucketName = generateResourceId('host-bucket'); + const identityProviderEnv: Record = + process.env.IDP_NAME?.toUpperCase() === 'AZURE' + ? { + IDP_NAME: { + type: BuildEnvironmentVariableType.PLAINTEXT, + value: 'AZURE', + }, + AZURE_APPLICATION_ID: { + type: BuildEnvironmentVariableType.PARAMETER_STORE, + value: 'AZURE_APPLICATION_ID', + }, + AZURE_TENANT_ID: { + type: BuildEnvironmentVariableType.PARAMETER_STORE, + value: 'AZURE_TENANT_ID', + }, + } + : {}; + const pipeline = new CodePipeline(this, generateResourceId('pipeline'), { synth: new ShellStep('Synth', { input: sourceCode, installCommands: ['npm ci'], - commands: ['cd cloud', `npm run cdk:synth -- --context STAGE=${stage}`], - primaryOutputDirectory: 'cloud/cdk.out', + // FIXME Revert this to `npm run cdk:synth -- --context STAGE=${stage}` + commands: ['cd cloud', 'npm run cdk:dev:synth'], + // FIXME Revert this to 'cloud/cdk.out' + primaryOutputDirectory: 'cloud/cdk.dev.out', }), synthCodeBuildDefaults: { buildEnvironment: { @@ -49,18 +79,7 @@ export class PipelineStack extends Stack { type: BuildEnvironmentVariableType.PARAMETER_STORE, value: 'HOSTED_ZONE_ID', }, - IDP_NAME: { - type: BuildEnvironmentVariableType.PLAINTEXT, - value: 'AZURE', - }, - AZURE_APPLICATION_ID: { - type: BuildEnvironmentVariableType.PARAMETER_STORE, - value: 'AZURE_APPLICATION_ID', - }, - AZURE_TENANT_ID: { - type: BuildEnvironmentVariableType.PARAMETER_STORE, - value: 'AZURE_TENANT_ID', - }, + ...identityProviderEnv, }, }, }, @@ -74,6 +93,8 @@ export class PipelineStack extends Stack { // Pre-deployment quality checks deployment.addPre( + // TODO Add a ConfirmPermissionsBroadening step: + // new ConfirmPermissionsBroadening('Check Permissions', { stage: appStage }), new CodeBuildStep('API-CodeChecks', { input: sourceCode, commands: [ diff --git a/cloud/lib/ui-stack.ts b/cloud/lib/ui-stack.ts index 0e6fc37c..516e5edf 100644 --- a/cloud/lib/ui-stack.ts +++ b/cloud/lib/ui-stack.ts @@ -96,29 +96,27 @@ export class UiStack extends Stack { If so, we might be able to switch to a CloudFront Function instead of Edge, and use CloudFront KeyValueStore to hold our jwks value as JSON. */ - const verifierEdgeFunction = new experimental.EdgeFunction( - this, - generateResourceId('api-gatekeeper'), - { - stackId: stackName(scope)('edge-lambda'), - handler: 'index.handler', - runtime: Runtime.NODEJS_18_X, - code: new TypeScriptCode(join(__dirname, 'lambdas/verifyAuth/index.ts'), { - buildOptions: { - bundle: true, - external: ['@aws-sdk/client-ssm'], - minify: false, - platform: 'node', - target: 'node18', - define: { - 'process.env.DOMAIN_NAME': `"${domainName}"`, - 'process.env.PARAM_USERPOOL_ID': `"${parameterNameUserPoolId}"`, - 'process.env.PARAM_USERPOOL_CLIENT': `"${parameterNameUserPoolClient}"`, - }, + const edgeFunctionName = generateResourceId('api-gatekeeper'); + const verifierEdgeFunction = new experimental.EdgeFunction(this, edgeFunctionName, { + stackId: stackName(scope)('edge-lambda'), + functionName: edgeFunctionName, + handler: 'index.handler', + runtime: Runtime.NODEJS_18_X, + code: new TypeScriptCode(join(__dirname, 'lambdas/verifyAuth/index.ts'), { + buildOptions: { + bundle: true, + external: ['@aws-sdk/client-ssm'], + minify: false, + platform: 'node', + target: 'node18', + define: { + 'process.env.DOMAIN_NAME': `"${domainName}"`, + 'process.env.PARAM_USERPOOL_ID': `"${parameterNameUserPoolId}"`, + 'process.env.PARAM_USERPOOL_CLIENT': `"${parameterNameUserPoolClient}"`, }, - }), - } - ); + }, + }), + }); verifierEdgeFunction.addToRolePolicy( new PolicyStatement({ effect: Effect.ALLOW, diff --git a/cloud/package.json b/cloud/package.json index 5332dffa..6269bef9 100644 --- a/cloud/package.json +++ b/cloud/package.json @@ -19,6 +19,10 @@ "cdk:test:destroy": "cdk destroy --app cdk.test.out", "cdk:test:destroy:all": "cdk destroy --app cdk.test.out --all", "cdk:test:clean": "rimraf cdk.test.out", + "cdk:dev:synth": "cdk synth -o cdk.dev.out --context STAGE=dev", + "cdk:dev:deploy": "cdk deploy --app cdk.dev.out --all", + "cdk:dev:destroy": "cdk destroy --app cdk.dev.out --all", + "cdk:dev:clean": "rimraf cdk.dev.out", "codecheck": "concurrently \"npm run lint:check\" \"npm run format:check\"", "format": "prettier . --write", "format:check": "prettier . --check", diff --git a/cloud/permissions/README.md b/cloud/permissions/README.md new file mode 100644 index 00000000..65e894d2 --- /dev/null +++ b/cloud/permissions/README.md @@ -0,0 +1,78 @@ +# IAM Execution Policies + +It's a bad idea to give AdministratorAccess to the CDK execution role, even with a permissions boundary in place. +Instead, we have custom policies authorizing all actions needed to deploy the stacks: + +- `execution_policy_basics.json` Basic permissions for CDK deployments, including Lambda creation and execution +- `execution_policy_cloudfront.json` Permissions for creating a site Distribution with associated behaviors, cache + policies and origin forwarding policies +- `execution_policy_cognito.json` Permissions required for Cognito userpools, clients and domains +- `execution_policy_edgelambda.json` Permissions to create a Cloudfront Lambda@Edge function (in us-east-1) +- `execution_policy_route53.json` Permissions required for Route53 records and ACM certificates +- `execution_policy_vpc.json` Permissions for deploying, updating and destroying a load-balanced, Fargate-managed + container +- `execution_policy_pipeline.json` Permissions for deploying the pipelines, which then orchestrate all other stacks + +## Commands: + +### Upload IAM policies to your AWS environment + +```shell +aws iam create-policy \ + --policy-name cdk-execution-policy-basics \ + --policy-document file://permissions/execution_policy_basics.json + --description "Baseline permissions for cloudformation deployments" + +aws iam create-policy \ + --policy-name cdk-execution-policy-pipeline \ + --policy-document file://permissions/execution_policy_pipeline.json + --description "Permissions to deploy a codepipeline and codebuild projects" + +aws iam create-policy \ + --policy-name cdk-execution-policy-cloudfront \ + --policy-document file://permissions/execution_policy_cloudfront.json + --description "Permissions to deploy cloudfront resources, except for lambda@edge functions" + +aws iam create-policy \ + --policy-name cdk-execution-policy-cognito \ + --policy-document file://permissions/execution_policy_cognito.json + --description "Permissions to deploy cognito userpools and related resources" + +aws iam create-policy \ + --policy-name cdk-execution-policy-edgelambda \ + --policy-document file://permissions/execution_policy_edgelambda.json + --description "Permissions to deploy lambda@edge functions for a cloudfront distribution" + +aws iam create-policy \ + --policy-name cdk-execution-policy-route53 \ + --policy-document file://permissions/execution_policy_route53.json + --description "Permissions to deploy domain records and ACM certificates" + +aws iam create-policy \ + --policy-name cdk-execution-policy-vpc \ + --policy-document file://permissions/execution_policy_vpc.json + --description "Permissions to deploy VPC, EC2 and ECS resources for a Fargate-managed container app" +``` + +### Bootstrap CDK using the uploaded execution policies + +If your primary region is NOT `us-east-1`, then you need to bootstrap that region as well, because +CloudFront mandates some resources are deployed to `us-east-1`. + +```shell +# Bootstrap primary region +npx cdk bootstrap aws://{account}/{region} \ + --cloudformation-execution-policies "arn:aws:iam::{account}:policy/cdk-execution-policy-basics,arn:aws:iam::{account}:policy/cdk-execution-policy-cloudfront,arn:aws:iam::{account}:policy/cdk-execution-policy-cognito,arn:aws:iam::{account}:policy/cdk-execution-policy-pipeline,arn:aws:iam::{account}:policy/cdk-execution-policy-route53,arn:aws:iam::{account}:policy/cdk-execution-policy-vpc" + +# Bootstrap us-east-1 for cloudfront +npx cdk bootstrap aws://{account}/us-east-1 \ + --cloudformation-execution-policies "arn:aws:iam::{account}:policy/cdk-execution-policy-basics,arn:aws:iam::{account}:policy/cdk-execution-policy-edgelambda" +``` + +If you ARE deploying your stage to us-east-1, then you only need one bootstrap command: + +```shell +# Bootstrap us-east-1 +npx cdk bootstrap aws://{account}/us-east-1 \ + --cloudformation-execution-policies "arn:aws:iam::{account}:policy/cdk-execution-policy-basics,arn:aws:iam::{account}:policy/cdk-execution-policy-cloudfront,arn:aws:iam::{account}:policy/cdk-execution-policy-cognito,arn:aws:iam::{account}:policy/cdk-execution-policy-edgelambda,arn:aws:iam::{account}:policy/cdk-execution-policy-pipeline,arn:aws:iam::{account}:policy/cdk-execution-policy-route53,arn:aws:iam::{account}:policy/cdk-execution-policy-vpc" +``` diff --git a/cloud/permissions/execution_policy_basics.json b/cloud/permissions/execution_policy_basics.json new file mode 100644 index 00000000..e557a0f8 --- /dev/null +++ b/cloud/permissions/execution_policy_basics.json @@ -0,0 +1,69 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "IAMRole", + "Effect": "Allow", + "Action": [ + "iam:Get*", + "iam:List*", + "iam:CreateRole", + "iam:DeleteRole", + "iam:TagRole", + "iam:AttachRolePolicy", + "iam:DeleteRolePolicy", + "iam:DetachRolePolicy", + "iam:PutRolePolicy" + ], + "Resource": "arn:aws:iam::*:role/*spylogic*" + }, + { + "Sid": "IAMPassRole", + "Effect": "Allow", + "Action": "iam:PassRole", + "Resource": ["arn:aws:iam::*:role/*spylogic*"] + }, + { + "Sid": "S3Read", + "Effect": "Allow", + "Action": "s3:GetObject", + "Resource": "*" + }, + { + "Sid": "S3Write", + "Effect": "Allow", + "Action": [ + "s3:CreateBucket", + "s3:DeleteBucket", + "s3:PutObject", + "s3:DeleteObject", + "s3:PutBucketPolicy", + "s3:DeleteBucketPolicy", + "s3:PutBucketTagging" + ], + "Resource": "arn:aws:s3:::*spylogic*" + }, + { + "Sid": "SSMRead", + "Effect": "Allow", + "Action": "ssm:GetParameters", + "Resource": "arn:aws:ssm:*:*:parameter/cdk-bootstrap/*/version" + }, + { + "Sid": "Lambdas", + "Effect": "Allow", + "Action": [ + "lambda:Get*", + "lambda:List*", + "lambda:CreateFunction", + "lambda:UpdateFunctionCode", + "lambda:UpdateFunctionConfiguration", + "lambda:DeleteFunction", + "lambda:InvokeFunction", + "lambda:TagResource", + "lambda:UntagResource" + ], + "Resource": "arn:aws:lambda:*:*:function:*spylogic*" + } + ] +} diff --git a/cloud/permissions/execution_policy_basics.ts b/cloud/permissions/execution_policy_basics.ts new file mode 100644 index 00000000..fe883af9 --- /dev/null +++ b/cloud/permissions/execution_policy_basics.ts @@ -0,0 +1,66 @@ +import { Effect, PolicyStatement } from 'aws-cdk-lib/aws-iam'; + +export const cdkBaselineStatements: PolicyStatement[] = [ + new PolicyStatement({ + sid: 'IAMRole', + effect: Effect.ALLOW, + actions: [ + 'iam:Get*', + 'iam:List*', + 'iam:CreateRole', + 'iam:DeleteRole', + 'iam:TagRole', + 'iam:AttachRolePolicy', + 'iam:DeleteRolePolicy', + 'iam:DetachRolePolicy', + 'iam:PutRolePolicy', + ], + resources: ['arn:aws:iam::*:role/*spylogic*'], + }), + new PolicyStatement({ + sid: 'IAMPassRole', + effect: Effect.ALLOW, + actions: ['iam:PassRole'], + resources: ['arn:aws:iam::*:role/*spylogic*'], + }), + new PolicyStatement({ + sid: 'S3Read', + effect: Effect.ALLOW, + actions: ['s3:GetObject'], + resources: ['*'], + }), + new PolicyStatement({ + sid: 'S3Write', + effect: Effect.ALLOW, + actions: [ + 's3:CreateBucket', + 's3:DeleteBucket', + 's3:PutObject', + 's3:DeleteObject', + 's3:PutBucketTagging', + ], + resources: ['arn:aws:s3:::*spylogic*'], + }), + new PolicyStatement({ + sid: 'SSMRead', // TODO Do we actually need this? + effect: Effect.ALLOW, + actions: ['ssm:GetParameters'], + resources: ['arn:aws:ssm:*:*:parameter/cdk-bootstrap/*/version'], + }), + new PolicyStatement({ + sid: 'Lambdas', + effect: Effect.ALLOW, + actions: [ + 'lambda:Get*', + 'lambda:List*', + 'lambda:CreateFunction', + 'lambda:UpdateFunctionCode', + 'lambda:UpdateFunctionConfiguration', + 'lambda:DeleteFunction', + 'lambda:InvokeFunction', + 'lambda:TagResource', + 'lambda:UntagResource', + ], + resources: ['arn:aws:lambda:*:*:function:*spylogic*'], + }), +]; diff --git a/cloud/permissions/execution_policy_cloudfront.json b/cloud/permissions/execution_policy_cloudfront.json new file mode 100644 index 00000000..bf63ebfe --- /dev/null +++ b/cloud/permissions/execution_policy_cloudfront.json @@ -0,0 +1,42 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "S3", + "Effect": "Allow", + "Action": [ + "s3:GetBucketAcl", + "s3:PutBucketAcl", + "s3:PutBucketOwnershipControls", + "s3:PutBucketPublicAccessBlock", + "s3:PutEncryptionConfiguration" + ], + "Resource": "arn:aws:s3:::*spylogic*" + }, + { + "Sid": "Cloudfront", + "Effect": "Allow", + "Action": [ + "cloudfront:Get*", + "cloudfront:AssociateAlias", + "cloudfront:CreateCachePolicy", + "cloudfront:UpdateCachePolicy", + "cloudfront:DeleteCachePolicy", + "cloudfront:CreateCloudFrontOriginAccessIdentity", + "cloudfront:UpdateCloudFrontOriginAccessIdentity", + "cloudfront:DeleteCloudFrontOriginAccessIdentity", + "cloudfront:CreateDistribution", + "cloudfront:UpdateDistribution", + "cloudfront:DeleteDistribution", + "cloudfront:CreateInvalidation", + "cloudfront:TagResource", + "cloudfront:UntagResource" + ], + "Resource": [ + "arn:aws:cloudfront::*:distribution/*", + "arn:aws:cloudfront::*:cache-policy/*", + "arn:aws:cloudfront::*:origin-access-identity/*" + ] + } + ] +} diff --git a/cloud/permissions/execution_policy_cloudfront.ts b/cloud/permissions/execution_policy_cloudfront.ts new file mode 100644 index 00000000..e4486211 --- /dev/null +++ b/cloud/permissions/execution_policy_cloudfront.ts @@ -0,0 +1,52 @@ +import { Effect, PolicyStatement } from 'aws-cdk-lib/aws-iam'; + +export const cloudfrontStatements: PolicyStatement[] = [ + new PolicyStatement({ + sid: 'S3HostBucket', + effect: Effect.ALLOW, + actions: [ + 's3:CreateBucket', + 's3:DeleteBucket', + 's3:PutObject', + 's3:DeleteObject', + 's3:GetBucketAcl', + 's3:PutBucketAcl', + 's3:PutBucketOwnershipControls', + 's3:PutBucketPublicAccessBlock', + 's3:PutBucketTagging', + 's3:PutEncryptionConfiguration', + ], + resources: ['arn:aws:s3:::*spylogic*'], + }), + new PolicyStatement({ + sid: 'Cloudfront', + effect: Effect.ALLOW, + actions: [ + 'cloudfront:Get*', + 'cloudfront:AssociateAlias', + 'cloudfront:CreateCachePolicy', + 'cloudfront:UpdateCachePolicy', + 'cloudfront:DeleteCachePolicy', + 'cloudfront:CreateCloudFrontOriginAccessIdentity', + 'cloudfront:UpdateCloudFrontOriginAccessIdentity', + 'cloudfront:DeleteCloudFrontOriginAccessIdentity', + 'cloudfront:CreateDistribution', + 'cloudfront:UpdateDistribution', + 'cloudfront:DeleteDistribution', + 'cloudfront:CreateInvalidation', + 'cloudfront:TagResource', + 'cloudfront:UntagResource', + ], + resources: [ + 'arn:aws:cloudfront::*:distribution/*', + 'arn:aws:cloudfront::*:cache-policy/*', + 'arn:aws:cloudfront::*:origin-access-identity/*', + ], + }), + new PolicyStatement({ + sid: 'EdgeLambda', + effect: Effect.ALLOW, + actions: ['lambda:EnableReplication', 'lambda:DisableReplication'], + resources: ['arn:aws:lambda:us-east-1:*:function:*spylogic*'], + }), +]; diff --git a/cloud/permissions/execution_policy_cognito.json b/cloud/permissions/execution_policy_cognito.json new file mode 100644 index 00000000..48aa842d --- /dev/null +++ b/cloud/permissions/execution_policy_cognito.json @@ -0,0 +1,37 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "Cognito", + "Effect": "Allow", + "Action": [ + "cognito-idp:CreateUserPool*", + "cognito-idp:CreateIdentityProvider", + "cognito-idp:DeleteUserPool*", + "cognito-idp:DeleteIdentityProvider", + "cognito-idp:Describe*", + "cognito-idp:List*", + "cognito-idp:TagResource", + "cognito-idp:UntagResource", + "cognito-idp:UpdateUserPool*", + "cognito-idp:UpdateIdentityProvider" + ], + "Resource": "*" + }, + { + "Sid": "SSMWrite", + "Effect": "Allow", + "Action": [ + "ssm:PutParameter", + "ssm:GetParameter", + "ssm:DeleteParameter", + "ssm:AddTagsToResource", + "ssm:RemoveTagsFromResource" + ], + "Resource": [ + "arn:aws:ssm:*:*:parameter/*/userpool-id", + "arn:aws:ssm:*:*:parameter/*/userpool-client" + ] + } + ] +} diff --git a/cloud/permissions/execution_policy_cognito.ts b/cloud/permissions/execution_policy_cognito.ts new file mode 100644 index 00000000..449759a0 --- /dev/null +++ b/cloud/permissions/execution_policy_cognito.ts @@ -0,0 +1,36 @@ +import { Effect, PolicyStatement } from 'aws-cdk-lib/aws-iam'; + +export const cognitoStatements: PolicyStatement[] = [ + new PolicyStatement({ + sid: 'Cognito', + effect: Effect.ALLOW, + actions: [ + 'cognito-idp:CreateUserPool*', + 'cognito-idp:CreateIdentityProvider', + 'cognito-idp:DeleteUserPool*', + 'cognito-idp:DeleteIdentityProvider', + 'cognito-idp:Describe*', + 'cognito-idp:List*', + 'cognito-idp:TagResource', + 'cognito-idp:UntagResource', + 'cognito-idp:UpdateUserPool*', + 'cognito-idp:UpdateIdentityProvider', + ], + resources: ['*'], + }), + new PolicyStatement({ + sid: 'SSMWrite', + effect: Effect.ALLOW, + actions: [ + 'ssm:PutParameter', + 'ssm:GetParameter', + 'ssm:DeleteParameter', + 'ssm:AddTagsToResource', + 'ssm:RemoveTagsFromResource', + ], + resources: [ + 'arn:aws:ssm:*:*:parameter/*/userpool-id', + 'arn:aws:ssm:*:*:parameter/*/userpool-client', + ], + }), +]; diff --git a/cloud/permissions/execution_policy_edgelambda.json b/cloud/permissions/execution_policy_edgelambda.json new file mode 100644 index 00000000..134df6fd --- /dev/null +++ b/cloud/permissions/execution_policy_edgelambda.json @@ -0,0 +1,17 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "EdgeLambda", + "Effect": "Allow", + "Action": ["lambda:EnableReplication", "lambda:DisableReplication", "lambda:PublishVersion"], + "Resource": "arn:aws:lambda:us-east-1:*:function:*spylogic*" + }, + { + "Sid": "SSMParameters", + "Effect": "Allow", + "Action": ["ssm:PutParameter", "ssm:DeleteParameter"], + "Resource": "arn:aws:ssm:us-east-1:*:parameter/cdk/EdgeFunctionArn/*" + } + ] +} diff --git a/cloud/permissions/execution_policy_pipeline.json b/cloud/permissions/execution_policy_pipeline.json new file mode 100644 index 00000000..df590386 --- /dev/null +++ b/cloud/permissions/execution_policy_pipeline.json @@ -0,0 +1,73 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "IAMPolicy", + "Effect": "Allow", + "Action": [ + "iam:CreatePolicy", + "iam:TagPolicy", + "iam:UntagPolicy", + "iam:DeletePolicy", + "iam:CreatePolicyVersion", + "iam:SetDefaultPolicyVersion", + "iam:DeletePolicyVersion", + "iam:UpdateAssumeRolePolicy" + ], + "Resource": ["arn:aws:iam::*:role/*spylogic*", "arn:aws:iam::*:policy/*spylogic*"] + }, + { + "Sid": "IAMPassRole", + "Effect": "Allow", + "Action": "iam:PassRole", + "Resource": [ + "arn:aws:iam::*:role/cdk-hnb659fds-deploy-role-*", + "arn:aws:iam::*:role/cdk-hnb659fds-cfn-exec-role-*" + ] + }, + { + "Sid": "S3Write", + "Effect": "Allow", + "Action": ["s3:PutBucketPublicAccessBlock", "s3:PutEncryptionConfiguration"], + "Resource": "arn:aws:s3:::*spylogic*" + }, + { + "Sid": "CodePipelineRead", + "Effect": "Allow", + "Action": ["codepipeline:Get*", "codepipeline:List*"], + "Resource": "*" + }, + { + "Sid": "CodePipelineWrite", + "Effect": "Allow", + "Action": [ + "codepipeline:CreatePipeline", + "codepipeline:UpdatePipeline", + "codepipeline:DeletePipeline", + "codepipeline:PutActionRevision", + "codepipeline:StartPipelineExecution", + "codepipeline:StopPipelineExecution", + "codepipeline:TagResource", + "codepipeline:UntagResource" + ], + "Resource": "arn:aws:codepipeline:*:*:*spylogic*" + }, + { + "Sid": "CodeBuild", + "Effect": "Allow", + "Action": [ + "codebuild:BatchGetProjects", + "codebuild:CreateProject", + "codebuild:UpdateProject", + "codebuild:DeleteProject" + ], + "Resource": "arn:aws:codebuild:*:*:project/*spylogic*" + }, + { + "Sid": "CodeStar", + "Effect": "Allow", + "Action": ["codestar-connections:PassConnection", "codestar-connections:UseConnection"], + "Resource": "arn:aws:codestar-connections:*:*:connection/*" + } + ] +} diff --git a/cloud/permissions/execution_policy_route53.json b/cloud/permissions/execution_policy_route53.json new file mode 100644 index 00000000..a9aa54d4 --- /dev/null +++ b/cloud/permissions/execution_policy_route53.json @@ -0,0 +1,57 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ACMAllowAll", + "Effect": "Allow", + "Action": "acm:*", + "Resource": "*" + }, + { + "Sid": "ACMThenDenyThese", + "Effect": "Deny", + "Action": [ + "acm:ExportCertificate", + "acm:ImportCertificate", + "acm:PutAccountConfiguration", + "acm:ResendValidationEmail" + ], + "Resource": "*" + }, + { + "Sid": "ACMAddServiceLinkedRole", + "Effect": "Allow", + "Action": "iam:CreateServiceLinkedRole", + "Resource": "arn:aws:iam::*:role/aws-service-role/acm.amazonaws.com/AWSServiceRoleForCertificateManager*", + "Condition": { + "StringEquals": { + "iam:AWSServiceName": "acm.amazonaws.com" + } + } + }, + { + "Sid": "ACMRemoveServiceLinkedRole", + "Effect": "Allow", + "Action": [ + "iam:DeleteServiceLinkedRole", + "iam:GetServiceLinkedRoleDeletionStatus", + "iam:GetRole" + ], + "Resource": "arn:aws:iam::*:role/aws-service-role/acm.amazonaws.com/AWSServiceRoleForCertificateManager*" + }, + { + "Sid": "Route53RecordSets", + "Effect": "Allow", + "Action": [ + "route53:Get*", + "route53:List*", + "route53:TestDNSAnswer", + "route53:ChangeResourceRecordSets", + "route53:ChangeTagsForResource", + "cloudfront:ListDistributions", + "elasticloadbalancing:DescribeLoadBalancers" + ], + "Resource": ["arn:aws:route53:::change/*", "arn:aws:route53:::hostedzone/*"] + } + ] +} diff --git a/cloud/permissions/execution_policy_route53.ts b/cloud/permissions/execution_policy_route53.ts new file mode 100644 index 00000000..9c243aa9 --- /dev/null +++ b/cloud/permissions/execution_policy_route53.ts @@ -0,0 +1,60 @@ +import { Effect, PolicyStatement } from 'aws-cdk-lib/aws-iam'; + +export const route53AndCertStatements: PolicyStatement[] = [ + new PolicyStatement({ + sid: 'ACMAllowAll', + effect: Effect.ALLOW, + actions: ['acm:*'], + resources: ['*'], + }), + new PolicyStatement({ + sid: 'ACMThenDenyThese', + effect: Effect.DENY, + actions: [ + 'acm:ExportCertificate', + 'acm:ImportCertificate', + 'acm:PutAccountConfiguration', + 'acm:ResendValidationEmail', + ], + resources: ['*'], + }), + new PolicyStatement({ + sid: 'ACMAddServiceLinkedRole', + effect: Effect.ALLOW, + actions: ['iam:CreateServiceLinkedRole'], + resources: [ + 'arn:aws:iam::*:role/aws-service-role/acm.amazonaws.com/AWSServiceRoleForCertificateManager*', + ], + conditions: { + StringEquals: { + 'iam:AWSServiceName': 'acm.amazonaws.com', + }, + }, + }), + new PolicyStatement({ + sid: 'ACMRemoveServiceLinkedRole', + effect: Effect.ALLOW, + actions: [ + 'iam:DeleteServiceLinkedRole', + 'iam:GetServiceLinkedRoleDeletionStatus', + 'iam:GetRole', + ], + resources: [ + 'arn:aws:iam::*:role/aws-service-role/acm.amazonaws.com/AWSServiceRoleForCertificateManager*', + ], + }), + new PolicyStatement({ + sid: 'Route53RecordSets', + effect: Effect.ALLOW, + actions: [ + 'route53:Get*', + 'route53:List*', + 'route53:TestDNSAnswer', + 'route53:ChangeResourceRecordSets', + 'route53:ChangeTagsForResource', + 'cloudfront:ListDistributions', + 'elasticloadbalancing:DescribeLoadBalancers', + ], + resources: ['arn:aws:route53:::change/*', 'arn:aws:route53:::hostedzone/*'], + }), +]; diff --git a/cloud/permissions/execution_policy_vpc.json b/cloud/permissions/execution_policy_vpc.json new file mode 100644 index 00000000..c8e8916e --- /dev/null +++ b/cloud/permissions/execution_policy_vpc.json @@ -0,0 +1,206 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "IAMInstance", + "Effect": "Allow", + "Action": [ + "iam:CreateInstanceProfile", + "iam:DeleteInstanceProfile", + "iam:AddRoleToInstanceProfile", + "iam:RemoveRoleFromInstanceProfile" + ], + "Resource": [ + "arn:aws:iam::*:instance-profile/*spylogicvpc*", + "arn:aws:iam::*:role/*spylogicvpc*" + ] + }, + { + "Sid": "IAMPassRole", + "Effect": "Allow", + "Action": "iam:PassRole", + "Resource": "arn:aws:iam::*:instance-profile/*spylogicvpc*" + }, + { + "Sid": "SecretsRead", + "Effect": "Allow", + "Action": ["secretsmanager:DescribeSecret", "secretsmanager:GetSecretValue"], + "Resource": ["arn:aws:secretsmanager:::secret:*/SpyLogic/ApiKey*"] + }, + { + "Sid": "ECSRead", + "Effect": "Allow", + "Action": ["ecs:Describe*", "ecs:List*"], + "Resource": "*" + }, + { + "Sid": "ECSFargate", + "Effect": "Allow", + "Action": [ + "ecs:TagResource", + "ecs:UntagResource", + "ecs:CreateCluster", + "ecs:UpdateCluster", + "ecs:DeleteCluster", + "ecs:CreateService", + "ecs:UpdateService", + "ecs:DeleteService", + "ecs:DeleteTaskDefinitions", + "ecs:RunTask", + "ecs:StartTask", + "ecs:StopTask" + ], + "Resource": [ + "arn:aws:ecs:*:*:cluster/*spylogic*", + "arn:aws:ecs:*:*:service/*spylogic*", + "arn:aws:ecs:*:*:task-definition/*spylogic*", + "arn:aws:ecs:*:*:task/*spylogic*" + ] + }, + { + "Sid": "ECSResourceUnspecified", + "Effect": "Allow", + "Action": ["ecs:RegisterTaskDefinition", "ecs:DeregisterTaskDefinition"], + "Resource": "*" + }, + { + "Sid": "LoadBalancerRead", + "Effect": "Allow", + "Action": ["elasticloadbalancing:Describe*", "elasticloadbalancing:Get*"], + "Resource": "*" + }, + { + "Sid": "LoadBalancerWrite", + "Effect": "Allow", + "Action": [ + "elasticloadbalancing:CreateLoadBalancer", + "elasticloadbalancing:ModifyLoadBalancerAttributes", + "elasticloadbalancing:SetSecurityGroups", + "elasticloadbalancing:SetSubnets", + "elasticloadbalancing:DeleteLoadBalancer", + "elasticloadbalancing:CreateListener", + "elasticloadbalancing:ModifyListener", + "elasticloadbalancing:ModifyListenerAttributes", + "elasticloadbalancing:AddListenerCertificates", + "elasticloadbalancing:RemoveListenerCertificates", + "elasticloadbalancing:DeleteListener", + "elasticloadbalancing:CreateRule", + "elasticloadbalancing:ModifyRule", + "elasticloadbalancing:SetRulePriorities", + "elasticloadbalancing:DeleteRule", + "elasticloadbalancing:CreateTargetGroup", + "elasticloadbalancing:ModifyTargetGroup", + "elasticloadbalancing:ModifyTargetGroupAttributes", + "elasticloadbalancing:RegisterTargets", + "elasticloadbalancing:DeregisterTargets", + "elasticloadbalancing:DeleteTargetGroup", + "elasticloadbalancing:AddTags", + "elasticloadbalancing:RemoveTags" + ], + "Resource": [ + "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*", + "arn:aws:elasticloadbalancing:*:*:listener/app/*", + "arn:aws:elasticloadbalancing:*:*:listener-rule/app/*", + "arn:aws:elasticloadbalancing:*:*:targetgroup/*" + ] + }, + { + "Sid": "EC2Read", + "Effect": "Allow", + "Action": ["ec2:Describe*", "ec2:List*"], + "Resource": "*" + }, + { + "Sid": "VPCNetwork", + "Effect": "Allow", + "Action": [ + "ec2:CreateVpc", + "ec2:ModifyVpcAttribute", + "ec2:DeleteVpc", + "ec2:CreateTags", + "ec2:DeleteTags", + "ec2:CreateRoute", + "ec2:ReplaceRoute", + "ec2:DeleteRoute", + "ec2:CreateRouteTable", + "ec2:AssociateRouteTable", + "ec2:ReplaceRouteTableAssociation", + "ec2:DisassociateRouteTable", + "ec2:DeleteRouteTable", + "ec2:AssociateVpcCidrBlock", + "ec2:DisassociateVpcCidrBlock", + "ec2:CreateSubnet", + "ec2:ModifySubnetAttribute", + "ec2:CreateSubnetCidrReservation", + "ec2:AssociateSubnetCidrBlock", + "ec2:DisassociateSubnetCidrBlock", + "ec2:DeleteSubnetCidrReservation", + "ec2:DeleteSubnet", + "ec2:CreateInternetGateway", + "ec2:AttachInternetGateway", + "ec2:DetachInternetGateway", + "ec2:DeleteInternetGateway", + "ec2:CreateNetworkAcl", + "ec2:DeleteNetworkAcl", + "ec2:CreateNetworkAclEntry", + "ec2:ReplaceNetworkAclEntry", + "ec2:DeleteNetworkAclEntry", + "ec2:CreateNetworkInterface", + "ec2:AttachNetworkInterface", + "ec2:DetachNetworkInterface", + "ec2:DeleteNetworkInterface" + ], + "Resource": [ + "arn:aws:ec2:*:*:image/*", + "arn:aws:ec2:*:*:internet-gateway/*", + "arn:aws:ec2:*:*:network-acl/*", + "arn:aws:ec2:*:*:network-interface/*", + "arn:aws:ec2:*:*:route-table/*", + "arn:aws:ec2:*:*:subnet/*", + "arn:aws:ec2:*:*:volume/*", + "arn:aws:ec2:*:*:vpc/*" + ] + }, + { + "Sid": "EC2Instances", + "Effect": "Allow", + "Action": [ + "ec2:RunInstances", + "ec2:StartInstances", + "ec2:RebootInstances", + "ec2:StopInstances", + "ec2:TerminateInstances", + "ec2:MonitorInstances", + "ec2:UnmonitorInstances", + "ec2:ModifyInstanceAttribute", + "ec2:ResetInstanceAttribute" + ], + "Resource": [ + "arn:aws:ec2:*:*:image/*", + "arn:aws:ec2:*:*:instance/*", + "arn:aws:ec2:*:*:network-interface/*", + "arn:aws:ec2:*:*:security-group/*", + "arn:aws:ec2:*:*:subnet/*", + "arn:aws:ec2:*:*:volume/*" + ] + }, + { + "Sid": "SecurityGroups", + "Effect": "Allow", + "Action": [ + "ec2:CreateSecurityGroup", + "ec2:DeleteSecurityGroup", + "ec2:ModifySecurityGroupRules", + "ec2:AuthorizeSecurityGroupEgress", + "ec2:AuthorizeSecurityGroupIngress", + "ec2:RevokeSecurityGroupEgress", + "ec2:RevokeSecurityGroupIngress", + "ec2:UpdateSecurityGroupRuleDescriptionsEgress", + "ec2:UpdateSecurityGroupRuleDescriptionsIngress", + "ec2:CreateTags", + "ec2:DeleteTags" + ], + "Resource": ["arn:aws:ec2:*:*:security-group/*", "arn:aws:ec2:*:*:security-group-rule/*"] + } + ] +} diff --git a/cloud/permissions/execution_policy_vpc.ts b/cloud/permissions/execution_policy_vpc.ts new file mode 100644 index 00000000..c113b893 --- /dev/null +++ b/cloud/permissions/execution_policy_vpc.ts @@ -0,0 +1,211 @@ +import { Effect, PolicyStatement } from 'aws-cdk-lib/aws-iam'; + +export const vpcStatements: PolicyStatement[] = [ + new PolicyStatement({ + sid: 'IAMInstance', + effect: Effect.ALLOW, + actions: [ + 'iam:CreateInstanceProfile', + 'iam:DeleteInstanceProfile', + 'iam:AddRoleToInstanceProfile', + 'iam:RemoveRoleFromInstanceProfile', + ], + resources: [ + 'arn:aws:iam::*:instance-profile/*spylogicvpc*', + 'arn:aws:iam::*:role/*spylogicvpc*', + ], + }), + new PolicyStatement({ + sid: 'IAMPassRole', + effect: Effect.ALLOW, + actions: ['iam:PassRole'], + resources: ['arn:aws:iam::*:instance-profile/*spylogicvpc*'], + }), + new PolicyStatement({ + sid: 'S3Write', + effect: Effect.ALLOW, + actions: ['s3:PutBucketPolicy', 's3:DeleteBucketPolicy'], + resources: ['arn:aws:s3:::*spylogic*'], + }), + new PolicyStatement({ + sid: 'SecretsRead', + effect: Effect.ALLOW, + actions: ['secretsmanager:DescribeSecret', 'secretsmanager:GetSecretValue'], + resources: ['arn:aws:secretsmanager:::secret:*/SpyLogic/ApiKey*'], + }), + new PolicyStatement({ + sid: 'ECSRead', + effect: Effect.ALLOW, + actions: ['ecs:Describe*', 'ecs:List*'], + resources: ['*'], + }), + new PolicyStatement({ + sid: 'ECSFargate', + effect: Effect.ALLOW, + actions: [ + 'ecs:TagResource', + 'ecs:UntagResource', + 'ecs:CreateCluster', + 'ecs:UpdateCluster', + 'ecs:DeleteCluster', + 'ecs:CreateService', + 'ecs:UpdateService', + 'ecs:DeleteService', + 'ecs:DeleteTaskDefinitions', + 'ecs:RunTask', + 'ecs:StartTask', + 'ecs:StopTask', + ], + resources: [ + 'arn:aws:ecs:*:*:cluster/*spylogic*', + 'arn:aws:ecs:*:*:service/*spylogic*', + 'arn:aws:ecs:*:*:task/*spylogic*', + 'arn:aws:ecs:*:*:task-definition/*spylogic*', + ], + }), + new PolicyStatement({ + sid: 'ECSResourceUnspecified', + effect: Effect.ALLOW, + actions: ['ecs:RegisterTaskDefinition', 'ecs:DeregisterTaskDefinition'], + resources: ['*'], + }), + new PolicyStatement({ + sid: 'LoadBalancerRead', + effect: Effect.ALLOW, + actions: ['elasticloadbalancing:Describe*', 'elasticloadbalancing:Get*'], + resources: ['*'], + }), + new PolicyStatement({ + sid: 'LoadBalancerWrite', + effect: Effect.ALLOW, + actions: [ + 'elasticloadbalancing:CreateLoadBalancer', + 'elasticloadbalancing:ModifyLoadBalancerAttributes', + 'elasticloadbalancing:SetSecurityGroups', + 'elasticloadbalancing:SetSubnets', + 'elasticloadbalancing:DeleteLoadBalancer', + 'elasticloadbalancing:CreateListener', + 'elasticloadbalancing:ModifyListener', + 'elasticloadbalancing:ModifyListenerAttributes', + 'elasticloadbalancing:AddListenerCertificates', + 'elasticloadbalancing:RemoveListenerCertificates', + 'elasticloadbalancing:DeleteListener', + 'elasticloadbalancing:CreateRule', + 'elasticloadbalancing:ModifyRule', + 'elasticloadbalancing:SetRulePriorities', + 'elasticloadbalancing:DeleteRule', + 'elasticloadbalancing:CreateTargetGroup', + 'elasticloadbalancing:ModifyTargetGroup', + 'elasticloadbalancing:ModifyTargetGroupAttributes', + 'elasticloadbalancing:RegisterTargets', + 'elasticloadbalancing:DeregisterTargets', + 'elasticloadbalancing:DeleteTargetGroup', + 'elasticloadbalancing:AddTags', + 'elasticloadbalancing:RemoveTags', + ], + resources: [ + 'arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*', + 'arn:aws:elasticloadbalancing:*:*:listener/app/*', + 'arn:aws:elasticloadbalancing:*:*:listener-rule/app/*', + 'arn:aws:elasticloadbalancing:*:*:targetgroup/*', + ], + }), + new PolicyStatement({ + sid: 'EC2Read', + effect: Effect.ALLOW, + actions: ['ec2:Describe*', 'ec2:List*'], + resources: ['*'], + }), + new PolicyStatement({ + sid: 'VPCNetwork', + effect: Effect.ALLOW, + actions: [ + 'ec2:CreateVpc', + 'ec2:ModifyVpcAttribute', + 'ec2:DeleteVpc', + 'ec2:CreateTags', + 'ec2:DeleteTags', + 'ec2:CreateRoute', + 'ec2:ReplaceRoute', + 'ec2:DeleteRoute', + 'ec2:CreateRouteTable', + 'ec2:AssociateRouteTable', + 'ec2:ReplaceRouteTableAssociation', + 'ec2:DisassociateRouteTable', + 'ec2:DeleteRouteTable', + 'ec2:AssociateVpcCidrBlock', + 'ec2:DisassociateVpcCidrBlock', + 'ec2:CreateSubnet', + 'ec2:ModifySubnetAttribute', + 'ec2:CreateSubnetCidrReservation', + 'ec2:AssociateSubnetCidrBlock', + 'ec2:DisassociateSubnetCidrBlock', + 'ec2:DeleteSubnetCidrReservation', + 'ec2:DeleteSubnet', + 'ec2:CreateInternetGateway', + 'ec2:AttachInternetGateway', + 'ec2:DetachInternetGateway', + 'ec2:DeleteInternetGateway', + 'ec2:CreateNetworkAcl', + 'ec2:DeleteNetworkAcl', + 'ec2:CreateNetworkAclEntry', + 'ec2:ReplaceNetworkAclEntry', + 'ec2:DeleteNetworkAclEntry', + 'ec2:CreateNetworkInterface', + 'ec2:AttachNetworkInterface', + 'ec2:DetachNetworkInterface', + 'ec2:DeleteNetworkInterface', + ], + resources: [ + 'arn:aws:ec2:*:*:image/*', + 'arn:aws:ec2:*:*:internet-gateway/*', + 'arn:aws:ec2:*:*:network-acl/*', + 'arn:aws:ec2:*:*:network-interface/*', + 'arn:aws:ec2:*:*:route-table/*', + 'arn:aws:ec2:*:*:subnet/*', + 'arn:aws:ec2:*:*:volume/*', + 'arn:aws:ec2:*:*:vpc/*', + ], + }), + new PolicyStatement({ + sid: 'EC2Instances', + effect: Effect.ALLOW, + actions: [ + 'ec2:RunInstances', + 'ec2:StartInstances', + 'ec2:RebootInstances', + 'ec2:StopInstances', + 'ec2:TerminateInstances', + 'ec2:MonitorInstances', + 'ec2:UnmonitorInstances', + 'ec2:ModifyInstanceAttribute', + 'ec2:ResetInstanceAttribute', + ], + resources: [ + 'arn:aws:ec2:*:*:image/*', + 'arn:aws:ec2:*:*:instance/*', + 'arn:aws:ec2:*:*:network-interface/*', + 'arn:aws:ec2:*:*:security-group/*', + 'arn:aws:ec2:*:*:subnet/*', + 'arn:aws:ec2:*:*:volume/*', + ], + }), + new PolicyStatement({ + sid: 'SecurityGroups', + effect: Effect.ALLOW, + actions: [ + 'ec2:CreateSecurityGroup', + 'ec2:DeleteSecurityGroup', + 'ec2:ModifySecurityGroupRules', + 'ec2:AuthorizeSecurityGroupEgress', + 'ec2:AuthorizeSecurityGroupIngress', + 'ec2:RevokeSecurityGroupEgress', + 'ec2:RevokeSecurityGroupIngress', + 'ec2:UpdateSecurityGroupRuleDescriptionsEgress', + 'ec2:UpdateSecurityGroupRuleDescriptionsIngress', + 'ec2:CreateTags', + 'ec2:DeleteTags', + ], + resources: ['arn:aws:ec2:*:*:security-group/*', 'arn:aws:ec2:*:*:security-group-rule/*'], + }), +]; diff --git a/cloud/permissions/index.ts b/cloud/permissions/index.ts new file mode 100644 index 00000000..4896e6fb --- /dev/null +++ b/cloud/permissions/index.ts @@ -0,0 +1,5 @@ +export * from './execution_policy_basics'; +export * from './execution_policy_cloudfront'; +export * from './execution_policy_cognito'; +export * from './execution_policy_route53'; +export * from './execution_policy_vpc';