create-aws-project 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +118 -0
- package/dist/__tests__/generator/replace-tokens.spec.d.ts +1 -0
- package/dist/__tests__/generator/replace-tokens.spec.js +281 -0
- package/dist/__tests__/generator.spec.d.ts +1 -0
- package/dist/__tests__/generator.spec.js +162 -0
- package/dist/__tests__/validation/project-name.spec.d.ts +1 -0
- package/dist/__tests__/validation/project-name.spec.js +57 -0
- package/dist/__tests__/wizard.spec.d.ts +1 -0
- package/dist/__tests__/wizard.spec.js +232 -0
- package/dist/aws/iam.d.ts +75 -0
- package/dist/aws/iam.js +264 -0
- package/dist/aws/organizations.d.ts +79 -0
- package/dist/aws/organizations.js +168 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +206 -0
- package/dist/commands/setup-github.d.ts +4 -0
- package/dist/commands/setup-github.js +185 -0
- package/dist/generator/copy-file.d.ts +15 -0
- package/dist/generator/copy-file.js +56 -0
- package/dist/generator/generate-project.d.ts +14 -0
- package/dist/generator/generate-project.js +81 -0
- package/dist/generator/index.d.ts +4 -0
- package/dist/generator/index.js +3 -0
- package/dist/generator/replace-tokens.d.ts +29 -0
- package/dist/generator/replace-tokens.js +68 -0
- package/dist/github/secrets.d.ts +109 -0
- package/dist/github/secrets.js +275 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -0
- package/dist/prompts/auth.d.ts +3 -0
- package/dist/prompts/auth.js +23 -0
- package/dist/prompts/aws-config.d.ts +2 -0
- package/dist/prompts/aws-config.js +14 -0
- package/dist/prompts/features.d.ts +2 -0
- package/dist/prompts/features.js +10 -0
- package/dist/prompts/github-setup.d.ts +53 -0
- package/dist/prompts/github-setup.js +208 -0
- package/dist/prompts/org-structure.d.ts +9 -0
- package/dist/prompts/org-structure.js +93 -0
- package/dist/prompts/platforms.d.ts +2 -0
- package/dist/prompts/platforms.js +12 -0
- package/dist/prompts/project-name.d.ts +2 -0
- package/dist/prompts/project-name.js +8 -0
- package/dist/prompts/theme.d.ts +2 -0
- package/dist/prompts/theme.js +14 -0
- package/dist/templates/index.d.ts +4 -0
- package/dist/templates/index.js +2 -0
- package/dist/templates/manifest.d.ts +11 -0
- package/dist/templates/manifest.js +99 -0
- package/dist/templates/tokens.d.ts +39 -0
- package/dist/templates/tokens.js +37 -0
- package/dist/templates/types.d.ts +52 -0
- package/dist/templates/types.js +1 -0
- package/dist/types.d.ts +27 -0
- package/dist/types.js +1 -0
- package/dist/validation/project-name.d.ts +1 -0
- package/dist/validation/project-name.js +12 -0
- package/dist/wizard.d.ts +2 -0
- package/dist/wizard.js +81 -0
- package/package.json +68 -0
- package/templates/.github/actions/build-and-test/action.yml +24 -0
- package/templates/.github/actions/deploy-cdk/action.yml +46 -0
- package/templates/.github/actions/deploy-web/action.yml +72 -0
- package/templates/.github/actions/setup/action.yml +29 -0
- package/templates/.github/pull_request_template.md +15 -0
- package/templates/.github/workflows/deploy-dev.yml +80 -0
- package/templates/.github/workflows/deploy-prod.yml +67 -0
- package/templates/.github/workflows/deploy-stage.yml +77 -0
- package/templates/.github/workflows/pull-request.yml +72 -0
- package/templates/.vscode/extensions.json +7 -0
- package/templates/.vscode/settings.json +67 -0
- package/templates/apps/api/.eslintrc.json +18 -0
- package/templates/apps/api/cdk/app.ts +93 -0
- package/templates/apps/api/cdk/auth/cognito-stack.ts +164 -0
- package/templates/apps/api/cdk/cdk.json +73 -0
- package/templates/apps/api/cdk/deployment-user-stack.ts +187 -0
- package/templates/apps/api/cdk/org-stack.ts +67 -0
- package/templates/apps/api/cdk/static-stack.ts +361 -0
- package/templates/apps/api/cdk/tsconfig.json +39 -0
- package/templates/apps/api/cdk/user-stack.ts +255 -0
- package/templates/apps/api/jest.config.ts +38 -0
- package/templates/apps/api/lambdas.yml +84 -0
- package/templates/apps/api/project.json.template +58 -0
- package/templates/apps/api/src/__tests__/setup.ts +10 -0
- package/templates/apps/api/src/handlers/users/create-user.ts +52 -0
- package/templates/apps/api/src/handlers/users/delete-user.ts +45 -0
- package/templates/apps/api/src/handlers/users/get-me.ts +72 -0
- package/templates/apps/api/src/handlers/users/get-user.ts +45 -0
- package/templates/apps/api/src/handlers/users/get-users.ts +23 -0
- package/templates/apps/api/src/handlers/users/index.ts +17 -0
- package/templates/apps/api/src/handlers/users/update-user.ts +72 -0
- package/templates/apps/api/src/lib/dynamo/dynamo-model.ts +504 -0
- package/templates/apps/api/src/lib/dynamo/index.ts +12 -0
- package/templates/apps/api/src/lib/dynamo/utils.ts +39 -0
- package/templates/apps/api/src/middleware/auth0-auth.ts +97 -0
- package/templates/apps/api/src/middleware/cognito-auth.ts +90 -0
- package/templates/apps/api/src/models/UserModel.ts +109 -0
- package/templates/apps/api/src/schemas/user.schema.ts +44 -0
- package/templates/apps/api/src/services/user-service.ts +108 -0
- package/templates/apps/api/src/utils/auth-context.ts +60 -0
- package/templates/apps/api/src/utils/common/helpers.ts +26 -0
- package/templates/apps/api/src/utils/lambda-handler.ts +148 -0
- package/templates/apps/api/src/utils/response.ts +52 -0
- package/templates/apps/api/src/utils/validator.ts +75 -0
- package/templates/apps/api/tsconfig.app.json +15 -0
- package/templates/apps/api/tsconfig.json +19 -0
- package/templates/apps/api/tsconfig.spec.json +17 -0
- package/templates/apps/mobile/.env.example +5 -0
- package/templates/apps/mobile/.eslintrc.json +33 -0
- package/templates/apps/mobile/app.json +33 -0
- package/templates/apps/mobile/assets/.gitkeep +0 -0
- package/templates/apps/mobile/babel.config.js +19 -0
- package/templates/apps/mobile/index.js +7 -0
- package/templates/apps/mobile/jest.config.ts +22 -0
- package/templates/apps/mobile/metro.config.js +35 -0
- package/templates/apps/mobile/package.json +22 -0
- package/templates/apps/mobile/project.json.template +64 -0
- package/templates/apps/mobile/src/App.tsx +367 -0
- package/templates/apps/mobile/src/__tests__/App.spec.tsx +46 -0
- package/templates/apps/mobile/src/__tests__/store/user-store.spec.ts +156 -0
- package/templates/apps/mobile/src/config/api.ts +16 -0
- package/templates/apps/mobile/src/store/user-store.ts +56 -0
- package/templates/apps/mobile/src/test-setup.ts +10 -0
- package/templates/apps/mobile/tsconfig.json +22 -0
- package/templates/apps/web/.env.example +13 -0
- package/templates/apps/web/.eslintrc.json +26 -0
- package/templates/apps/web/index.html +13 -0
- package/templates/apps/web/jest.config.ts +24 -0
- package/templates/apps/web/package.json +15 -0
- package/templates/apps/web/project.json.template +66 -0
- package/templates/apps/web/src/App.tsx +352 -0
- package/templates/apps/web/src/__mocks__/config/api.ts +41 -0
- package/templates/apps/web/src/__tests__/App.spec.tsx +240 -0
- package/templates/apps/web/src/__tests__/store/user-store.spec.ts +185 -0
- package/templates/apps/web/src/auth/auth0-provider.tsx +103 -0
- package/templates/apps/web/src/auth/cognito-provider.tsx +143 -0
- package/templates/apps/web/src/auth/index.ts +7 -0
- package/templates/apps/web/src/auth/use-auth.ts +16 -0
- package/templates/apps/web/src/config/amplify-config.ts +31 -0
- package/templates/apps/web/src/config/api.ts +38 -0
- package/templates/apps/web/src/config/auth0-config.ts +17 -0
- package/templates/apps/web/src/main.tsx +41 -0
- package/templates/apps/web/src/store/user-store.ts +56 -0
- package/templates/apps/web/src/styles.css +165 -0
- package/templates/apps/web/src/test-setup.ts +1 -0
- package/templates/apps/web/src/theme/index.ts +30 -0
- package/templates/apps/web/src/vite-env.d.ts +19 -0
- package/templates/apps/web/tsconfig.app.json +24 -0
- package/templates/apps/web/tsconfig.json +22 -0
- package/templates/apps/web/tsconfig.spec.json +28 -0
- package/templates/apps/web/vite.config.ts +87 -0
- package/templates/manifest.json +28 -0
- package/templates/packages/api-client/.eslintrc.json +18 -0
- package/templates/packages/api-client/jest.config.ts +13 -0
- package/templates/packages/api-client/package.json +8 -0
- package/templates/packages/api-client/project.json.template +34 -0
- package/templates/packages/api-client/src/__tests__/api-client.spec.ts +408 -0
- package/templates/packages/api-client/src/api-client.ts +201 -0
- package/templates/packages/api-client/src/config.ts +193 -0
- package/templates/packages/api-client/src/index.ts +9 -0
- package/templates/packages/api-client/tsconfig.json +22 -0
- package/templates/packages/api-client/tsconfig.lib.json +11 -0
- package/templates/packages/api-client/tsconfig.spec.json +14 -0
- package/templates/packages/common-types/.eslintrc.json +18 -0
- package/templates/packages/common-types/package.json +6 -0
- package/templates/packages/common-types/project.json.template +26 -0
- package/templates/packages/common-types/src/api.types.ts +24 -0
- package/templates/packages/common-types/src/auth.types.ts +36 -0
- package/templates/packages/common-types/src/common.types.ts +46 -0
- package/templates/packages/common-types/src/index.ts +19 -0
- package/templates/packages/common-types/src/lambda.types.ts +39 -0
- package/templates/packages/common-types/src/user.types.ts +31 -0
- package/templates/packages/common-types/tsconfig.json +19 -0
- package/templates/packages/common-types/tsconfig.lib.json +11 -0
- package/templates/root/.editorconfig +23 -0
- package/templates/root/.nvmrc +1 -0
- package/templates/root/eslint.config.js +61 -0
- package/templates/root/jest.preset.js +16 -0
- package/templates/root/nx.json +29 -0
- package/templates/root/package.json +131 -0
- package/templates/root/tsconfig.base.json +29 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"typescript.tsdk": "node_modules/typescript/lib",
|
|
3
|
+
"typescript.enablePromptUseWorkspaceTsdk": true,
|
|
4
|
+
"editor.formatOnSave": true,
|
|
5
|
+
"editor.codeActionsOnSave": {
|
|
6
|
+
"source.fixAll": "explicit"
|
|
7
|
+
},
|
|
8
|
+
"editor.tabSize": 2,
|
|
9
|
+
"editor.insertSpaces": true,
|
|
10
|
+
"editor.detectIndentation": false,
|
|
11
|
+
"[typescript]": {
|
|
12
|
+
"editor.tabSize": 2,
|
|
13
|
+
"editor.insertSpaces": true
|
|
14
|
+
},
|
|
15
|
+
"[typescriptreact]": {
|
|
16
|
+
"editor.tabSize": 2,
|
|
17
|
+
"editor.insertSpaces": true
|
|
18
|
+
},
|
|
19
|
+
"[javascript]": {
|
|
20
|
+
"editor.tabSize": 2,
|
|
21
|
+
"editor.insertSpaces": true
|
|
22
|
+
},
|
|
23
|
+
"[javascriptreact]": {
|
|
24
|
+
"editor.tabSize": 2,
|
|
25
|
+
"editor.insertSpaces": true
|
|
26
|
+
},
|
|
27
|
+
"[json]": {
|
|
28
|
+
"editor.tabSize": 2,
|
|
29
|
+
"editor.insertSpaces": true
|
|
30
|
+
},
|
|
31
|
+
"[jsonc]": {
|
|
32
|
+
"editor.tabSize": 2,
|
|
33
|
+
"editor.insertSpaces": true
|
|
34
|
+
},
|
|
35
|
+
"[html]": {
|
|
36
|
+
"editor.tabSize": 2,
|
|
37
|
+
"editor.insertSpaces": true
|
|
38
|
+
},
|
|
39
|
+
"[css]": {
|
|
40
|
+
"editor.tabSize": 2,
|
|
41
|
+
"editor.insertSpaces": true
|
|
42
|
+
},
|
|
43
|
+
"[scss]": {
|
|
44
|
+
"editor.tabSize": 2,
|
|
45
|
+
"editor.insertSpaces": true
|
|
46
|
+
},
|
|
47
|
+
"[yaml]": {
|
|
48
|
+
"editor.tabSize": 2,
|
|
49
|
+
"editor.insertSpaces": true
|
|
50
|
+
},
|
|
51
|
+
"[markdown]": {
|
|
52
|
+
"editor.tabSize": 2,
|
|
53
|
+
"editor.insertSpaces": true
|
|
54
|
+
},
|
|
55
|
+
"files.exclude": {
|
|
56
|
+
"**/.git": true,
|
|
57
|
+
"**/.DS_Store": true,
|
|
58
|
+
"**/node_modules": true,
|
|
59
|
+
"**/dist": true,
|
|
60
|
+
"**/.nx": true
|
|
61
|
+
},
|
|
62
|
+
"search.exclude": {
|
|
63
|
+
"**/node_modules": true,
|
|
64
|
+
"**/dist": true,
|
|
65
|
+
"**/.nx": true
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": ["../../.eslintrc.js"],
|
|
3
|
+
"ignorePatterns": ["!**/*"],
|
|
4
|
+
"overrides": [
|
|
5
|
+
{
|
|
6
|
+
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
|
7
|
+
"rules": {}
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"files": ["*.ts", "*.tsx"],
|
|
11
|
+
"rules": {}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"files": ["*.js", "*.jsx"],
|
|
15
|
+
"rules": {}
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import 'source-map-support/register';
|
|
3
|
+
import * as cdk from 'aws-cdk-lib';
|
|
4
|
+
import { StaticStack } from './static-stack';
|
|
5
|
+
import { UserStack } from './user-stack';
|
|
6
|
+
import { DeploymentUserStack } from './deployment-user-stack';
|
|
7
|
+
// {{#if AUTH_COGNITO}}
|
|
8
|
+
import { CognitoStack } from './auth/cognito-stack';
|
|
9
|
+
// {{/if AUTH_COGNITO}}
|
|
10
|
+
|
|
11
|
+
const appName = '{{PROJECT_NAME_PASCAL}}';
|
|
12
|
+
|
|
13
|
+
// {{#if ORG_ENABLED}}
|
|
14
|
+
// Multi-account configuration from AWS Organizations
|
|
15
|
+
const accountIds: Record<string, string> = {
|
|
16
|
+
dev: '{{DEV_ACCOUNT_ID}}',
|
|
17
|
+
stage: '{{STAGE_ACCOUNT_ID}}',
|
|
18
|
+
prod: '{{PROD_ACCOUNT_ID}}',
|
|
19
|
+
};
|
|
20
|
+
// {{/if ORG_ENABLED}}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* AWS CDK App for {{PROJECT_NAME_TITLE}}
|
|
24
|
+
*
|
|
25
|
+
* This app creates the infrastructure for the project including:
|
|
26
|
+
* - S3 bucket for static web content
|
|
27
|
+
* - API Gateway for Lambda functions
|
|
28
|
+
* - CloudFront distribution with both S3 and API Gateway origins
|
|
29
|
+
* - Lambda functions with API Gateway integrations (from lambdas.yml)
|
|
30
|
+
* - GitHub deployment IAM users (optional, via --context deployUser=true)
|
|
31
|
+
*
|
|
32
|
+
* Deploy commands:
|
|
33
|
+
* npx cdk deploy --all # Deploy all stacks
|
|
34
|
+
* npx cdk deploy {{PROJECT_NAME_PASCAL}}-DeployUser-dev # Deploy just the deploy user
|
|
35
|
+
*/
|
|
36
|
+
const app = new cdk.App();
|
|
37
|
+
|
|
38
|
+
// Get environment from context or default to 'dev'
|
|
39
|
+
const environmentName = app.node.tryGetContext('environment') || 'dev';
|
|
40
|
+
|
|
41
|
+
// Get AWS account and region from environment or use defaults
|
|
42
|
+
const env = {
|
|
43
|
+
// {{#if ORG_ENABLED}}
|
|
44
|
+
account: accountIds[environmentName] || process.env.CDK_DEFAULT_ACCOUNT,
|
|
45
|
+
// {{/if ORG_ENABLED}}
|
|
46
|
+
// {{#unless ORG_ENABLED}}
|
|
47
|
+
account: process.env.CDK_DEFAULT_ACCOUNT || process.env.AWS_ACCOUNT_ID,
|
|
48
|
+
// {{/unless ORG_ENABLED}}
|
|
49
|
+
region: process.env.CDK_DEFAULT_REGION || process.env.AWS_REGION || '{{AWS_REGION}}',
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Common tags for all resources
|
|
53
|
+
const tags = {
|
|
54
|
+
Project: '{{PROJECT_NAME_TITLE}}',
|
|
55
|
+
Environment: environmentName,
|
|
56
|
+
ManagedBy: 'CDK',
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// Create the static stack (CloudFront, S3, API Gateway)
|
|
60
|
+
const staticStack = new StaticStack(app, `${appName}-Static-${environmentName}`, {
|
|
61
|
+
env,
|
|
62
|
+
environmentName,
|
|
63
|
+
description: `{{PROJECT_NAME_TITLE}} static infrastructure for ${environmentName} environment`,
|
|
64
|
+
tags,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Create the user stack (Lambda functions from lambdas.yml)
|
|
68
|
+
// Note: UserStack automatically depends on StaticStack because it uses staticStack.api
|
|
69
|
+
new UserStack(app, `${appName}-Users-${environmentName}`, {
|
|
70
|
+
env,
|
|
71
|
+
environmentName,
|
|
72
|
+
api: staticStack.api,
|
|
73
|
+
description: `{{PROJECT_NAME_TITLE}} user Lambda functions for ${environmentName} environment`,
|
|
74
|
+
tags,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Create the deployment user stack (GitHub Actions IAM user)
|
|
78
|
+
new DeploymentUserStack(app, `${appName}-DeployUser-${environmentName}`, {
|
|
79
|
+
env,
|
|
80
|
+
environmentName,
|
|
81
|
+
description: `GitHub Actions deployment user for ${environmentName} environment`,
|
|
82
|
+
tags,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// {{#if AUTH_COGNITO}}
|
|
86
|
+
// Create the Cognito authentication stack
|
|
87
|
+
new CognitoStack(app, `${appName}-Cognito-${environmentName}`, {
|
|
88
|
+
stage: environmentName,
|
|
89
|
+
env,
|
|
90
|
+
description: `{{PROJECT_NAME_TITLE}} Cognito authentication for ${environmentName} environment`,
|
|
91
|
+
tags,
|
|
92
|
+
});
|
|
93
|
+
// {{/if AUTH_COGNITO}}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import * as cdk from 'aws-cdk-lib';
|
|
2
|
+
import * as cognito from 'aws-cdk-lib/aws-cognito';
|
|
3
|
+
import * as iam from 'aws-cdk-lib/aws-iam';
|
|
4
|
+
import { Construct } from 'constructs';
|
|
5
|
+
|
|
6
|
+
export interface CognitoStackProps extends cdk.StackProps {
|
|
7
|
+
stage: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Cognito Stack for {{PROJECT_NAME_TITLE}}
|
|
12
|
+
*
|
|
13
|
+
* Creates Cognito User Pool infrastructure for authentication including:
|
|
14
|
+
* - User Pool with email sign-in and self-registration
|
|
15
|
+
* - User Pool Client for SPA/mobile applications
|
|
16
|
+
* - Optional Identity Pool for federated identities (when social login enabled)
|
|
17
|
+
* - Optional MFA configuration
|
|
18
|
+
*/
|
|
19
|
+
export class CognitoStack extends cdk.Stack {
|
|
20
|
+
public readonly userPool: cognito.UserPool;
|
|
21
|
+
public readonly userPoolClient: cognito.UserPoolClient;
|
|
22
|
+
public readonly identityPool?: cognito.CfnIdentityPool;
|
|
23
|
+
|
|
24
|
+
constructor(scope: Construct, id: string, props: CognitoStackProps) {
|
|
25
|
+
super(scope, id, props);
|
|
26
|
+
|
|
27
|
+
const { stage } = props;
|
|
28
|
+
|
|
29
|
+
// Create User Pool
|
|
30
|
+
this.userPool = new cognito.UserPool(this, 'UserPool', {
|
|
31
|
+
userPoolName: `{{PROJECT_NAME}}-${stage}-user-pool`,
|
|
32
|
+
signInCaseSensitive: false,
|
|
33
|
+
selfSignUpEnabled: true,
|
|
34
|
+
signInAliases: {
|
|
35
|
+
email: true,
|
|
36
|
+
},
|
|
37
|
+
autoVerify: {
|
|
38
|
+
email: true,
|
|
39
|
+
},
|
|
40
|
+
standardAttributes: {
|
|
41
|
+
email: {
|
|
42
|
+
required: true,
|
|
43
|
+
mutable: true,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
passwordPolicy: {
|
|
47
|
+
minLength: 8,
|
|
48
|
+
requireLowercase: true,
|
|
49
|
+
requireUppercase: true,
|
|
50
|
+
requireDigits: true,
|
|
51
|
+
requireSymbols: false,
|
|
52
|
+
},
|
|
53
|
+
accountRecovery: cognito.AccountRecovery.EMAIL_ONLY,
|
|
54
|
+
removalPolicy: stage === 'prod' ? cdk.RemovalPolicy.RETAIN : cdk.RemovalPolicy.DESTROY,
|
|
55
|
+
// {{#if AUTH_MFA}}
|
|
56
|
+
mfa: cognito.Mfa.OPTIONAL,
|
|
57
|
+
mfaSecondFactor: {
|
|
58
|
+
sms: false,
|
|
59
|
+
otp: true,
|
|
60
|
+
},
|
|
61
|
+
// {{/if AUTH_MFA}}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Create User Pool Client (for SPA/mobile)
|
|
65
|
+
this.userPoolClient = new cognito.UserPoolClient(this, 'UserPoolClient', {
|
|
66
|
+
userPool: this.userPool,
|
|
67
|
+
userPoolClientName: `{{PROJECT_NAME}}-${stage}-client`,
|
|
68
|
+
authFlows: {
|
|
69
|
+
userPassword: true,
|
|
70
|
+
userSrp: true,
|
|
71
|
+
},
|
|
72
|
+
generateSecret: false,
|
|
73
|
+
preventUserExistenceErrors: true,
|
|
74
|
+
accessTokenValidity: cdk.Duration.hours(1),
|
|
75
|
+
idTokenValidity: cdk.Duration.hours(1),
|
|
76
|
+
refreshTokenValidity: cdk.Duration.days(30),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// {{#if AUTH_SOCIAL_LOGIN}}
|
|
80
|
+
// Create Identity Pool for federated identities
|
|
81
|
+
this.identityPool = new cognito.CfnIdentityPool(this, 'IdentityPool', {
|
|
82
|
+
identityPoolName: `{{PROJECT_NAME}}_${stage}_identity_pool`,
|
|
83
|
+
allowUnauthenticatedIdentities: false,
|
|
84
|
+
cognitoIdentityProviders: [
|
|
85
|
+
{
|
|
86
|
+
clientId: this.userPoolClient.userPoolClientId,
|
|
87
|
+
providerName: this.userPool.userPoolProviderName,
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Create authenticated role for Identity Pool
|
|
93
|
+
const authenticatedRole = new iam.Role(this, 'AuthenticatedRole', {
|
|
94
|
+
assumedBy: new iam.FederatedPrincipal(
|
|
95
|
+
'cognito-identity.amazonaws.com',
|
|
96
|
+
{
|
|
97
|
+
StringEquals: {
|
|
98
|
+
'cognito-identity.amazonaws.com:aud': this.identityPool.ref,
|
|
99
|
+
},
|
|
100
|
+
'ForAnyValue:StringLike': {
|
|
101
|
+
'cognito-identity.amazonaws.com:amr': 'authenticated',
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
'sts:AssumeRoleWithWebIdentity'
|
|
105
|
+
),
|
|
106
|
+
description: 'Role for authenticated users',
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Create unauthenticated role for Identity Pool
|
|
110
|
+
const unauthenticatedRole = new iam.Role(this, 'UnauthenticatedRole', {
|
|
111
|
+
assumedBy: new iam.FederatedPrincipal(
|
|
112
|
+
'cognito-identity.amazonaws.com',
|
|
113
|
+
{
|
|
114
|
+
StringEquals: {
|
|
115
|
+
'cognito-identity.amazonaws.com:aud': this.identityPool.ref,
|
|
116
|
+
},
|
|
117
|
+
'ForAnyValue:StringLike': {
|
|
118
|
+
'cognito-identity.amazonaws.com:amr': 'unauthenticated',
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
'sts:AssumeRoleWithWebIdentity'
|
|
122
|
+
),
|
|
123
|
+
description: 'Role for unauthenticated users',
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// Attach roles to Identity Pool
|
|
127
|
+
new cognito.CfnIdentityPoolRoleAttachment(this, 'IdentityPoolRoles', {
|
|
128
|
+
identityPoolId: this.identityPool.ref,
|
|
129
|
+
roles: {
|
|
130
|
+
authenticated: authenticatedRole.roleArn,
|
|
131
|
+
unauthenticated: unauthenticatedRole.roleArn,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Output Identity Pool ID
|
|
136
|
+
new cdk.CfnOutput(this, 'IdentityPoolId', {
|
|
137
|
+
value: this.identityPool.ref,
|
|
138
|
+
description: 'Cognito Identity Pool ID',
|
|
139
|
+
exportName: `${stage}-identity-pool-id`,
|
|
140
|
+
});
|
|
141
|
+
// {{/if AUTH_SOCIAL_LOGIN}}
|
|
142
|
+
|
|
143
|
+
// Output User Pool ID
|
|
144
|
+
new cdk.CfnOutput(this, 'UserPoolId', {
|
|
145
|
+
value: this.userPool.userPoolId,
|
|
146
|
+
description: 'Cognito User Pool ID',
|
|
147
|
+
exportName: `${stage}-user-pool-id`,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Output User Pool Client ID
|
|
151
|
+
new cdk.CfnOutput(this, 'UserPoolClientId', {
|
|
152
|
+
value: this.userPoolClient.userPoolClientId,
|
|
153
|
+
description: 'Cognito User Pool Client ID',
|
|
154
|
+
exportName: `${stage}-user-pool-client-id`,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Output Cognito Region
|
|
158
|
+
new cdk.CfnOutput(this, 'CognitoRegion', {
|
|
159
|
+
value: this.region,
|
|
160
|
+
description: 'AWS Region for Cognito',
|
|
161
|
+
exportName: `${stage}-cognito-region`,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"app": "npx ts-node --prefer-ts-exts app.ts",
|
|
3
|
+
"watch": {
|
|
4
|
+
"include": [
|
|
5
|
+
"**"
|
|
6
|
+
],
|
|
7
|
+
"exclude": [
|
|
8
|
+
"README.md",
|
|
9
|
+
"cdk*.json",
|
|
10
|
+
"**/*.d.ts",
|
|
11
|
+
"**/*.js",
|
|
12
|
+
"tsconfig.json",
|
|
13
|
+
"package*.json",
|
|
14
|
+
"yarn.lock",
|
|
15
|
+
"node_modules",
|
|
16
|
+
"test"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"context": {
|
|
20
|
+
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
|
|
21
|
+
"@aws-cdk/core:checkSecretUsage": true,
|
|
22
|
+
"@aws-cdk/core:target-partitions": [
|
|
23
|
+
"aws",
|
|
24
|
+
"aws-cn"
|
|
25
|
+
],
|
|
26
|
+
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
|
|
27
|
+
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
|
|
28
|
+
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
|
|
29
|
+
"@aws-cdk/aws-iam:minimizePolicies": true,
|
|
30
|
+
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
|
|
31
|
+
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
|
|
32
|
+
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
|
|
33
|
+
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
|
|
34
|
+
"@aws-cdk/aws-apigateway:disableCloudWatchRole": false,
|
|
35
|
+
"@aws-cdk/core:enablePartitionLiterals": true,
|
|
36
|
+
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
|
|
37
|
+
"@aws-cdk/aws-iam:standardizedServicePrincipals": true,
|
|
38
|
+
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
|
|
39
|
+
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
|
|
40
|
+
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
|
|
41
|
+
"@aws-cdk/aws-route53-patters:useCertificate": true,
|
|
42
|
+
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
|
|
43
|
+
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
|
|
44
|
+
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
|
|
45
|
+
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
|
|
46
|
+
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
|
|
47
|
+
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
|
|
48
|
+
"@aws-cdk/aws-redshift:columnId": true,
|
|
49
|
+
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
|
|
50
|
+
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
|
|
51
|
+
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
|
|
52
|
+
"@aws-cdk/aws-kms:aliasNameRef": true,
|
|
53
|
+
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
|
|
54
|
+
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
|
|
55
|
+
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
|
|
56
|
+
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
|
|
57
|
+
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
|
|
58
|
+
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
|
|
59
|
+
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
|
|
60
|
+
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
|
|
61
|
+
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
|
|
62
|
+
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true,
|
|
63
|
+
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true,
|
|
64
|
+
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true,
|
|
65
|
+
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true,
|
|
66
|
+
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true,
|
|
67
|
+
"@aws-cdk/aws-eks:nodegroupNameAttribute": true,
|
|
68
|
+
"@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true,
|
|
69
|
+
"@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true,
|
|
70
|
+
"@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false,
|
|
71
|
+
"@aws-cdk/aws-s3:keepNotificationInImportedBucket": false
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { Stack, StackProps, CfnOutput, SecretValue } from 'aws-cdk-lib';
|
|
2
|
+
import * as iam from 'aws-cdk-lib/aws-iam';
|
|
3
|
+
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
|
|
4
|
+
import { Construct } from 'constructs';
|
|
5
|
+
|
|
6
|
+
export interface DeploymentUserStackProps extends StackProps {
|
|
7
|
+
environmentName: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Stack that creates IAM users for GitHub Actions deployments.
|
|
12
|
+
*
|
|
13
|
+
* This stack should be deployed to each target account (dev, stage, prod)
|
|
14
|
+
* to create the necessary IAM user with permissions for CDK deployments.
|
|
15
|
+
*
|
|
16
|
+
* The access keys are stored in AWS Secrets Manager for secure retrieval.
|
|
17
|
+
*
|
|
18
|
+
* This uses least-privilege permissions based on what CDK actually needs.
|
|
19
|
+
*/
|
|
20
|
+
export class DeploymentUserStack extends Stack {
|
|
21
|
+
constructor(scope: Construct, id: string, props: DeploymentUserStackProps) {
|
|
22
|
+
super(scope, id, props);
|
|
23
|
+
|
|
24
|
+
const { environmentName } = props;
|
|
25
|
+
const accountId = this.account;
|
|
26
|
+
const region = this.region;
|
|
27
|
+
|
|
28
|
+
// Create IAM user for GitHub Actions deployments
|
|
29
|
+
const deployUser = new iam.User(this, 'GitHubDeployUser', {
|
|
30
|
+
userName: `github-deploy-${environmentName}`,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Policy for CDK deployments - least privilege permissions
|
|
34
|
+
const cdkDeployPolicy = new iam.ManagedPolicy(this, 'CdkDeployPolicy', {
|
|
35
|
+
managedPolicyName: `github-deploy-policy-${environmentName}`,
|
|
36
|
+
description: `Policy for GitHub Actions CDK deployments in ${environmentName}`,
|
|
37
|
+
statements: [
|
|
38
|
+
// CloudFormation - specific actions only
|
|
39
|
+
new iam.PolicyStatement({
|
|
40
|
+
sid: 'CloudFormationPermissions',
|
|
41
|
+
effect: iam.Effect.ALLOW,
|
|
42
|
+
actions: [
|
|
43
|
+
'cloudformation:CreateChangeSet',
|
|
44
|
+
'cloudformation:DeleteChangeSet',
|
|
45
|
+
'cloudformation:DescribeChangeSet',
|
|
46
|
+
'cloudformation:DescribeStacks',
|
|
47
|
+
'cloudformation:ExecuteChangeSet',
|
|
48
|
+
'cloudformation:CreateStack',
|
|
49
|
+
'cloudformation:UpdateStack',
|
|
50
|
+
'cloudformation:RollbackStack',
|
|
51
|
+
'cloudformation:ContinueUpdateRollback',
|
|
52
|
+
'cloudformation:DescribeStackEvents',
|
|
53
|
+
'cloudformation:GetTemplate',
|
|
54
|
+
'cloudformation:DeleteStack',
|
|
55
|
+
'cloudformation:UpdateTerminationProtection',
|
|
56
|
+
'cloudformation:GetTemplateSummary',
|
|
57
|
+
'cloudformation:CreateStackRefactor',
|
|
58
|
+
'cloudformation:DescribeStackRefactor',
|
|
59
|
+
'cloudformation:ExecuteStackRefactor',
|
|
60
|
+
'cloudformation:ListStackRefactorActions',
|
|
61
|
+
'cloudformation:ListStackRefactors',
|
|
62
|
+
'cloudformation:ListStacks',
|
|
63
|
+
],
|
|
64
|
+
resources: ['*'],
|
|
65
|
+
}),
|
|
66
|
+
// CloudFront - limited to listing and invalidation
|
|
67
|
+
new iam.PolicyStatement({
|
|
68
|
+
sid: 'CloudFrontPermissions',
|
|
69
|
+
effect: iam.Effect.ALLOW,
|
|
70
|
+
actions: [
|
|
71
|
+
'cloudfront:ListDistributions',
|
|
72
|
+
'cloudfront:CreateInvalidation',
|
|
73
|
+
],
|
|
74
|
+
resources: ['*'],
|
|
75
|
+
}),
|
|
76
|
+
// SSM - read CDK bootstrap version parameter
|
|
77
|
+
new iam.PolicyStatement({
|
|
78
|
+
sid: 'ReadVersion',
|
|
79
|
+
effect: iam.Effect.ALLOW,
|
|
80
|
+
actions: [
|
|
81
|
+
'ssm:GetParameter',
|
|
82
|
+
'ssm:GetParameters',
|
|
83
|
+
],
|
|
84
|
+
resources: [
|
|
85
|
+
`arn:aws:ssm:${region}:${accountId}:parameter/cdk-bootstrap/*`,
|
|
86
|
+
],
|
|
87
|
+
}),
|
|
88
|
+
// S3 - CDK assets and web deployment (scoped to account)
|
|
89
|
+
new iam.PolicyStatement({
|
|
90
|
+
sid: 'S3Permissions',
|
|
91
|
+
effect: iam.Effect.ALLOW,
|
|
92
|
+
actions: [
|
|
93
|
+
's3:GetObject*',
|
|
94
|
+
's3:GetBucket*',
|
|
95
|
+
's3:List*',
|
|
96
|
+
's3:Abort*',
|
|
97
|
+
's3:DeleteObject*',
|
|
98
|
+
's3:PutObject*',
|
|
99
|
+
's3:ListAllMyBuckets',
|
|
100
|
+
],
|
|
101
|
+
resources: ['*'],
|
|
102
|
+
conditions: {
|
|
103
|
+
StringEquals: {
|
|
104
|
+
's3:ResourceAccount': accountId,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
}),
|
|
108
|
+
// KMS - for S3 encryption
|
|
109
|
+
new iam.PolicyStatement({
|
|
110
|
+
sid: 'KMSPermissions',
|
|
111
|
+
effect: iam.Effect.ALLOW,
|
|
112
|
+
actions: [
|
|
113
|
+
'kms:Decrypt',
|
|
114
|
+
'kms:DescribeKey',
|
|
115
|
+
'kms:Encrypt',
|
|
116
|
+
'kms:ReEncrypt*',
|
|
117
|
+
'kms:GenerateDataKey*',
|
|
118
|
+
],
|
|
119
|
+
resources: ['*'],
|
|
120
|
+
conditions: {
|
|
121
|
+
StringEquals: {
|
|
122
|
+
'kms:ViaService': `s3.${region}.amazonaws.com`,
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
}),
|
|
126
|
+
// IAM PassRole - for CloudFormation execution role
|
|
127
|
+
new iam.PolicyStatement({
|
|
128
|
+
sid: 'IAMPassRole',
|
|
129
|
+
effect: iam.Effect.ALLOW,
|
|
130
|
+
actions: ['iam:PassRole'],
|
|
131
|
+
resources: [
|
|
132
|
+
`arn:aws:iam::${accountId}:role/cdk-*-cfn-exec-role-${accountId}-${region}`,
|
|
133
|
+
],
|
|
134
|
+
}),
|
|
135
|
+
// STS - for CDK operations
|
|
136
|
+
new iam.PolicyStatement({
|
|
137
|
+
sid: 'STSPermissions',
|
|
138
|
+
effect: iam.Effect.ALLOW,
|
|
139
|
+
actions: ['sts:GetCallerIdentity'],
|
|
140
|
+
resources: ['*'],
|
|
141
|
+
}),
|
|
142
|
+
],
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
deployUser.addManagedPolicy(cdkDeployPolicy);
|
|
146
|
+
|
|
147
|
+
// Create access key for the user
|
|
148
|
+
const accessKey = new iam.AccessKey(this, 'GitHubDeployAccessKey', {
|
|
149
|
+
user: deployUser,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Store access keys in Secrets Manager
|
|
153
|
+
const accessKeySecret = new secretsmanager.Secret(this, 'GitHubDeployCredentials', {
|
|
154
|
+
secretName: `github-deploy-credentials-${environmentName}`,
|
|
155
|
+
description: `GitHub Actions deployment credentials for ${environmentName}`,
|
|
156
|
+
secretObjectValue: {
|
|
157
|
+
accessKeyId: SecretValue.unsafePlainText(accessKey.accessKeyId),
|
|
158
|
+
secretAccessKey: accessKey.secretAccessKey,
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Outputs
|
|
163
|
+
new CfnOutput(this, 'DeployUserName', {
|
|
164
|
+
value: deployUser.userName,
|
|
165
|
+
description: `GitHub deploy user name for ${environmentName}`,
|
|
166
|
+
exportName: `GitHubDeployUserName-${environmentName}`,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
new CfnOutput(this, 'DeployUserArn', {
|
|
170
|
+
value: deployUser.userArn,
|
|
171
|
+
description: `GitHub deploy user ARN for ${environmentName}`,
|
|
172
|
+
exportName: `GitHubDeployUserArn-${environmentName}`,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
new CfnOutput(this, 'CredentialsSecretArn', {
|
|
176
|
+
value: accessKeySecret.secretArn,
|
|
177
|
+
description: `Secret ARN containing deploy credentials for ${environmentName}`,
|
|
178
|
+
exportName: `GitHubDeployCredentialsArn-${environmentName}`,
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
new CfnOutput(this, 'AccessKeyId', {
|
|
182
|
+
value: accessKey.accessKeyId,
|
|
183
|
+
description: `Access Key ID for ${environmentName} (use Secrets Manager for secret key)`,
|
|
184
|
+
exportName: `GitHubDeployAccessKeyId-${environmentName}`,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Stack, StackProps, CfnOutput } from "aws-cdk-lib";
|
|
2
|
+
import { Construct } from "constructs";
|
|
3
|
+
import {
|
|
4
|
+
Organization,
|
|
5
|
+
OrganizationalUnit,
|
|
6
|
+
Account,
|
|
7
|
+
} from "@pepperize/cdk-organizations";
|
|
8
|
+
|
|
9
|
+
export interface OrgStackProps extends StackProps {
|
|
10
|
+
devEmail: string;
|
|
11
|
+
stageEmail: string;
|
|
12
|
+
prodEmail: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class OrgStack extends Stack {
|
|
16
|
+
constructor(scope: Construct, id: string, props: OrgStackProps) {
|
|
17
|
+
super(scope, id, props);
|
|
18
|
+
|
|
19
|
+
const org = new Organization(this, "Org");
|
|
20
|
+
|
|
21
|
+
const nonProd = new OrganizationalUnit(this, "NonProdOu", {
|
|
22
|
+
organizationalUnitName: "nonprod",
|
|
23
|
+
parent: org.root,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const prod = new OrganizationalUnit(this, "ProdOu", {
|
|
27
|
+
organizationalUnitName: "prod",
|
|
28
|
+
parent: org.root,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const dev = new Account(this, "DevAccount", {
|
|
32
|
+
accountName: "dev",
|
|
33
|
+
email: props.devEmail,
|
|
34
|
+
parent: nonProd,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const stage = new Account(this, "StageAccount", {
|
|
38
|
+
accountName: "stage",
|
|
39
|
+
email: props.stageEmail,
|
|
40
|
+
parent: nonProd,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const prodAccount = new Account(this, "ProdAccount", {
|
|
44
|
+
accountName: "prod",
|
|
45
|
+
email: props.prodEmail,
|
|
46
|
+
parent: prod,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
new CfnOutput(this, "DevAccountId", {
|
|
50
|
+
value: dev.accountId,
|
|
51
|
+
description: "Dev Account ID",
|
|
52
|
+
exportName: "DevAccountId",
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
new CfnOutput(this, "StageAccountId", {
|
|
56
|
+
value: stage.accountId,
|
|
57
|
+
description: "Stage Account ID",
|
|
58
|
+
exportName: "StageAccountId",
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
new CfnOutput(this, "ProdAccountId", {
|
|
62
|
+
value: prodAccount.accountId,
|
|
63
|
+
description: "Prod Account ID",
|
|
64
|
+
exportName: "ProdAccountId",
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|