@intentius/chant-lexicon-aws 0.0.6 → 0.0.9
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/dist/integrity.json +25 -10
- package/dist/manifest.json +1 -1
- package/dist/meta.json +9444 -4597
- package/dist/rules/cf-refs.ts +99 -0
- package/dist/rules/ext001.ts +32 -25
- package/dist/rules/hardcoded-region.ts +1 -0
- package/dist/rules/iam-wildcard.ts +1 -0
- package/dist/rules/s3-encryption.ts +3 -3
- package/dist/rules/waw016.ts +86 -0
- package/dist/rules/waw017.ts +53 -0
- package/dist/rules/waw018.ts +71 -0
- package/dist/rules/waw019.ts +82 -0
- package/dist/rules/waw020.ts +64 -0
- package/dist/rules/waw021.ts +53 -0
- package/dist/rules/waw022.ts +43 -0
- package/dist/rules/waw023.ts +47 -0
- package/dist/rules/waw024.ts +54 -0
- package/dist/rules/waw025.ts +43 -0
- package/dist/rules/waw026.ts +46 -0
- package/dist/rules/waw027.ts +50 -0
- package/dist/rules/waw028.ts +47 -0
- package/dist/rules/waw029.ts +62 -0
- package/dist/rules/waw030.ts +246 -0
- package/dist/skills/chant-aws.md +430 -0
- package/dist/types/index.d.ts +58525 -58501
- package/package.json +2 -2
- package/src/actions/actions.test.ts +75 -0
- package/src/actions/dynamodb.ts +36 -0
- package/src/actions/ecr.ts +9 -0
- package/src/actions/ecs.ts +5 -0
- package/src/actions/iam.ts +3 -0
- package/src/actions/index.ts +9 -0
- package/src/actions/lambda.ts +11 -0
- package/src/actions/logs.ts +4 -0
- package/src/actions/s3.ts +34 -0
- package/src/actions/sns.ts +5 -0
- package/src/actions/sqs.ts +15 -0
- package/src/codegen/__snapshots__/snapshot.test.ts.snap +20 -20
- package/src/codegen/docs-links.test.ts +143 -0
- package/src/codegen/docs.ts +294 -124
- package/src/codegen/generate-lexicon.ts +8 -0
- package/src/codegen/generate-typescript.ts +25 -1
- package/src/codegen/generate.ts +1 -13
- package/src/codegen/package.ts +2 -0
- package/src/codegen/typecheck.test.ts +1 -1
- package/src/composites/composites.test.ts +442 -0
- package/src/composites/fargate-alb.ts +253 -0
- package/src/composites/index.ts +20 -0
- package/src/composites/lambda-api.ts +20 -0
- package/src/composites/lambda-dynamodb.ts +64 -0
- package/src/composites/lambda-eventbridge.ts +36 -0
- package/src/composites/lambda-function.ts +76 -0
- package/src/composites/lambda-s3.ts +72 -0
- package/src/composites/lambda-sns.ts +30 -0
- package/src/composites/lambda-sqs.ts +44 -0
- package/src/composites/scheduled-lambda.ts +37 -0
- package/src/composites/vpc-default.ts +148 -0
- package/src/default-tags.test.ts +38 -0
- package/src/default-tags.ts +77 -0
- package/src/generated/index.d.ts +58525 -58501
- package/src/generated/index.ts +1351 -1351
- package/src/generated/lexicon-aws.json +9444 -4597
- package/src/import/generator.test.ts +5 -5
- package/src/import/generator.ts +4 -4
- package/src/import/roundtrip-fixtures.test.ts +2 -1
- package/src/import/roundtrip.test.ts +5 -5
- package/src/index.ts +21 -0
- package/src/integration.test.ts +92 -21
- package/src/intrinsics.ts +24 -13
- package/src/lint/post-synth/cf-refs.ts +99 -0
- package/src/lint/post-synth/ext001.test.ts +214 -31
- package/src/lint/post-synth/ext001.ts +32 -25
- package/src/lint/post-synth/waw013.test.ts +120 -0
- package/src/lint/post-synth/waw014.test.ts +121 -0
- package/src/lint/post-synth/waw015.test.ts +147 -0
- package/src/lint/post-synth/waw016.test.ts +141 -0
- package/src/lint/post-synth/waw016.ts +86 -0
- package/src/lint/post-synth/waw017.test.ts +130 -0
- package/src/lint/post-synth/waw017.ts +53 -0
- package/src/lint/post-synth/waw018.test.ts +109 -0
- package/src/lint/post-synth/waw018.ts +71 -0
- package/src/lint/post-synth/waw019.test.ts +138 -0
- package/src/lint/post-synth/waw019.ts +82 -0
- package/src/lint/post-synth/waw020.test.ts +125 -0
- package/src/lint/post-synth/waw020.ts +64 -0
- package/src/lint/post-synth/waw021.test.ts +81 -0
- package/src/lint/post-synth/waw021.ts +53 -0
- package/src/lint/post-synth/waw022.test.ts +54 -0
- package/src/lint/post-synth/waw022.ts +43 -0
- package/src/lint/post-synth/waw023.test.ts +53 -0
- package/src/lint/post-synth/waw023.ts +47 -0
- package/src/lint/post-synth/waw024.test.ts +64 -0
- package/src/lint/post-synth/waw024.ts +54 -0
- package/src/lint/post-synth/waw025.test.ts +42 -0
- package/src/lint/post-synth/waw025.ts +43 -0
- package/src/lint/post-synth/waw026.test.ts +54 -0
- package/src/lint/post-synth/waw026.ts +46 -0
- package/src/lint/post-synth/waw027.test.ts +63 -0
- package/src/lint/post-synth/waw027.ts +50 -0
- package/src/lint/post-synth/waw028.test.ts +68 -0
- package/src/lint/post-synth/waw028.ts +47 -0
- package/src/lint/post-synth/waw029.test.ts +179 -0
- package/src/lint/post-synth/waw029.ts +62 -0
- package/src/lint/post-synth/waw030.test.ts +800 -0
- package/src/lint/post-synth/waw030.ts +246 -0
- package/src/lint/rules/hardcoded-region.ts +1 -0
- package/src/lint/rules/iam-wildcard.ts +1 -0
- package/src/lint/rules/rules.test.ts +8 -8
- package/src/lint/rules/s3-encryption.ts +3 -3
- package/src/lsp/completions.ts +2 -0
- package/src/lsp/hover.ts +17 -0
- package/src/nested-stack-integration.test.ts +100 -0
- package/src/nested-stack.ts +2 -2
- package/src/plugin.test.ts +13 -15
- package/src/plugin.ts +552 -114
- package/src/serializer.test.ts +370 -43
- package/src/serializer.ts +69 -17
- package/src/spec/fetch.ts +10 -0
- package/src/spec/parse.test.ts +141 -0
- package/src/spec/parse.ts +40 -0
- package/src/taggable.ts +44 -0
- package/src/testdata/nested-stacks/app.ts +26 -0
- package/src/testdata/nested-stacks/network/outputs.ts +17 -0
- package/src/testdata/nested-stacks/network/security.ts +17 -0
- package/src/testdata/nested-stacks/network/vpc.ts +54 -0
- package/dist/skills/aws-cloudformation.md +0 -41
- package/src/codegen/rollback.test.ts +0 -80
- package/src/codegen/rollback.ts +0 -20
package/src/plugin.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { createRequire } from "module";
|
|
1
2
|
import type { LexiconPlugin, IntrinsicDef, SkillDefinition } from "@intentius/chant/lexicon";
|
|
3
|
+
const require = createRequire(import.meta.url);
|
|
2
4
|
import type { LintRule } from "@intentius/chant/lint/rule";
|
|
3
5
|
import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
|
|
4
6
|
import type { TemplateParser } from "@intentius/chant/import/parser";
|
|
@@ -52,40 +54,40 @@ export const awsPlugin: LexiconPlugin = {
|
|
|
52
54
|
];
|
|
53
55
|
},
|
|
54
56
|
|
|
55
|
-
initTemplates()
|
|
56
|
-
return {
|
|
57
|
+
initTemplates() {
|
|
58
|
+
return { src: {
|
|
57
59
|
"config.ts": `/**
|
|
58
60
|
* Shared bucket configuration — encryption, versioning, public access
|
|
59
61
|
*/
|
|
60
62
|
|
|
61
|
-
import
|
|
63
|
+
import { ServerSideEncryptionByDefault, ServerSideEncryptionRule, BucketEncryption, PublicAccessBlockConfiguration, VersioningConfiguration } from "@intentius/chant-lexicon-aws";
|
|
62
64
|
|
|
63
65
|
// Encryption default — AES256 server-side encryption
|
|
64
|
-
export const encryptionDefault = new
|
|
65
|
-
|
|
66
|
+
export const encryptionDefault = new ServerSideEncryptionByDefault({
|
|
67
|
+
SSEAlgorithm: "AES256",
|
|
66
68
|
});
|
|
67
69
|
|
|
68
70
|
// Encryption rule wrapping the default
|
|
69
|
-
export const encryptionRule = new
|
|
70
|
-
|
|
71
|
+
export const encryptionRule = new ServerSideEncryptionRule({
|
|
72
|
+
ServerSideEncryptionByDefault: encryptionDefault,
|
|
71
73
|
});
|
|
72
74
|
|
|
73
75
|
// Bucket encryption configuration
|
|
74
|
-
export const bucketEncryption = new
|
|
75
|
-
|
|
76
|
+
export const bucketEncryption = new BucketEncryption({
|
|
77
|
+
ServerSideEncryptionConfiguration: [encryptionRule],
|
|
76
78
|
});
|
|
77
79
|
|
|
78
80
|
// Public access block — deny all public access
|
|
79
|
-
export const publicAccessBlock = new
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
export const publicAccessBlock = new PublicAccessBlockConfiguration({
|
|
82
|
+
BlockPublicAcls: true,
|
|
83
|
+
BlockPublicPolicy: true,
|
|
84
|
+
IgnorePublicAcls: true,
|
|
85
|
+
RestrictPublicBuckets: true,
|
|
84
86
|
});
|
|
85
87
|
|
|
86
88
|
// Versioning — enabled
|
|
87
|
-
export const versioningEnabled = new
|
|
88
|
-
|
|
89
|
+
export const versioningEnabled = new VersioningConfiguration({
|
|
90
|
+
Status: "Enabled",
|
|
89
91
|
});
|
|
90
92
|
`,
|
|
91
93
|
"data-bucket.ts": `/**
|
|
@@ -96,28 +98,30 @@ import { Bucket, Sub, AWS } from "@intentius/chant-lexicon-aws";
|
|
|
96
98
|
import { versioningEnabled, bucketEncryption, publicAccessBlock } from "./config";
|
|
97
99
|
|
|
98
100
|
export const dataBucket = new Bucket({
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
BucketName: Sub\`\${AWS.StackName}-\${AWS.AccountId}-data\`,
|
|
102
|
+
VersioningConfiguration: versioningEnabled,
|
|
103
|
+
BucketEncryption: bucketEncryption,
|
|
104
|
+
PublicAccessBlockConfiguration: publicAccessBlock,
|
|
103
105
|
});
|
|
104
106
|
`,
|
|
105
107
|
"logs-bucket.ts": `/**
|
|
106
108
|
* Logs bucket — log delivery with encryption and versioning
|
|
109
|
+
*
|
|
110
|
+
* Note: AccessControl is a legacy property. Use a bucket policy to grant
|
|
111
|
+
* log delivery access instead (s3:PutObject permission for the logging service principal).
|
|
107
112
|
*/
|
|
108
113
|
|
|
109
114
|
import { Bucket, Sub, AWS } from "@intentius/chant-lexicon-aws";
|
|
110
115
|
import { versioningEnabled, bucketEncryption, publicAccessBlock } from "./config";
|
|
111
116
|
|
|
112
117
|
export const logsBucket = new Bucket({
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
publicAccessBlockConfiguration: publicAccessBlock,
|
|
118
|
+
BucketName: Sub\`\${AWS.StackName}-\${AWS.AccountId}-logs\`,
|
|
119
|
+
VersioningConfiguration: versioningEnabled,
|
|
120
|
+
BucketEncryption: bucketEncryption,
|
|
121
|
+
PublicAccessBlockConfiguration: publicAccessBlock,
|
|
118
122
|
});
|
|
119
123
|
`,
|
|
120
|
-
};
|
|
124
|
+
} };
|
|
121
125
|
},
|
|
122
126
|
|
|
123
127
|
detectTemplate(data: unknown): boolean {
|
|
@@ -161,7 +165,26 @@ export const logsBucket = new Bucket({
|
|
|
161
165
|
const { waw013 } = require("./lint/post-synth/waw013");
|
|
162
166
|
const { waw014 } = require("./lint/post-synth/waw014");
|
|
163
167
|
const { waw015 } = require("./lint/post-synth/waw015");
|
|
164
|
-
|
|
168
|
+
const { waw016 } = require("./lint/post-synth/waw016");
|
|
169
|
+
const { waw017 } = require("./lint/post-synth/waw017");
|
|
170
|
+
const { waw018 } = require("./lint/post-synth/waw018");
|
|
171
|
+
const { waw019 } = require("./lint/post-synth/waw019");
|
|
172
|
+
const { waw020 } = require("./lint/post-synth/waw020");
|
|
173
|
+
const { waw021 } = require("./lint/post-synth/waw021");
|
|
174
|
+
const { waw022 } = require("./lint/post-synth/waw022");
|
|
175
|
+
const { waw023 } = require("./lint/post-synth/waw023");
|
|
176
|
+
const { waw024 } = require("./lint/post-synth/waw024");
|
|
177
|
+
const { waw025 } = require("./lint/post-synth/waw025");
|
|
178
|
+
const { waw026 } = require("./lint/post-synth/waw026");
|
|
179
|
+
const { waw027 } = require("./lint/post-synth/waw027");
|
|
180
|
+
const { waw028 } = require("./lint/post-synth/waw028");
|
|
181
|
+
const { waw029 } = require("./lint/post-synth/waw029");
|
|
182
|
+
const { waw030 } = require("./lint/post-synth/waw030");
|
|
183
|
+
return [
|
|
184
|
+
waw010, waw011, cor020, ext001, waw013, waw014, waw015, waw016, waw017,
|
|
185
|
+
waw018, waw019, waw020, waw021, waw022, waw023, waw024, waw025,
|
|
186
|
+
waw026, waw027, waw028, waw029, waw030,
|
|
187
|
+
];
|
|
165
188
|
},
|
|
166
189
|
|
|
167
190
|
async generate(options?: { verbose?: boolean }): Promise<void> {
|
|
@@ -229,44 +252,17 @@ export const logsBucket = new Bucket({
|
|
|
229
252
|
|
|
230
253
|
console.error(`Packaged ${stats.resources} resources, ${stats.ruleCount} rules, ${stats.skillCount} skills`);
|
|
231
254
|
|
|
232
|
-
// Produce .tgz via
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
const packErr = await new Response(packProc.stderr).text();
|
|
240
|
-
const packExit = await packProc.exited;
|
|
255
|
+
// Produce .tgz via pack command
|
|
256
|
+
const { getRuntime } = await import("@intentius/chant/runtime-adapter");
|
|
257
|
+
const rt = getRuntime();
|
|
258
|
+
const { stdout: packOut, stderr: packErr, exitCode: packExit } = await rt.spawn(
|
|
259
|
+
rt.commands.packCmd,
|
|
260
|
+
{ cwd: pkgDir },
|
|
261
|
+
);
|
|
241
262
|
if (packExit === 0) {
|
|
242
263
|
console.error(`Tarball: ${packOut.trim()}`);
|
|
243
264
|
} else {
|
|
244
|
-
console.error(
|
|
245
|
-
}
|
|
246
|
-
},
|
|
247
|
-
|
|
248
|
-
async rollback(options?: { restore?: string; verbose?: boolean }): Promise<void> {
|
|
249
|
-
const { listSnapshots, restoreSnapshot } = await import("./codegen/rollback");
|
|
250
|
-
const { join, dirname } = await import("path");
|
|
251
|
-
const { fileURLToPath } = await import("url");
|
|
252
|
-
|
|
253
|
-
const pkgDir = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
254
|
-
const snapshotsDir = join(pkgDir, ".snapshots");
|
|
255
|
-
|
|
256
|
-
if (options?.restore) {
|
|
257
|
-
const generatedDir = join(pkgDir, "src", "generated");
|
|
258
|
-
restoreSnapshot(String(options.restore), generatedDir);
|
|
259
|
-
console.error(`Restored snapshot: ${options.restore}`);
|
|
260
|
-
} else {
|
|
261
|
-
const snapshots = listSnapshots(snapshotsDir);
|
|
262
|
-
if (snapshots.length === 0) {
|
|
263
|
-
console.error("No snapshots available.");
|
|
264
|
-
} else {
|
|
265
|
-
console.error(`Available snapshots (${snapshots.length}):`);
|
|
266
|
-
for (const s of snapshots) {
|
|
267
|
-
console.error(` ${s.timestamp} ${s.resourceCount} resources ${s.path}`);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
265
|
+
console.error(`${rt.commands.packCmd.join(" ")} failed: ${packErr}`);
|
|
270
266
|
}
|
|
271
267
|
},
|
|
272
268
|
|
|
@@ -278,53 +274,455 @@ export const logsBucket = new Bucket({
|
|
|
278
274
|
skills(): SkillDefinition[] {
|
|
279
275
|
return [
|
|
280
276
|
{
|
|
281
|
-
name: "aws
|
|
282
|
-
description: "AWS CloudFormation
|
|
277
|
+
name: "chant-aws",
|
|
278
|
+
description: "AWS CloudFormation lifecycle — build, diff, deploy, rollback, and troubleshoot from a chant project",
|
|
283
279
|
content: `---
|
|
284
|
-
|
|
285
|
-
description:
|
|
280
|
+
skill: chant-aws
|
|
281
|
+
description: Build, validate, and deploy CloudFormation templates from a chant project
|
|
282
|
+
user-invocable: true
|
|
286
283
|
---
|
|
287
284
|
|
|
288
|
-
# AWS CloudFormation
|
|
285
|
+
# AWS CloudFormation Operational Playbook
|
|
286
|
+
|
|
287
|
+
## How chant and CloudFormation relate
|
|
288
|
+
|
|
289
|
+
chant is a **synthesis-only** tool — it compiles TypeScript source files into CloudFormation JSON (or YAML). chant does NOT call AWS APIs. Your job as an agent is to bridge the two:
|
|
290
|
+
|
|
291
|
+
- Use **chant** for: build, lint, diff (local template comparison)
|
|
292
|
+
- Use **AWS CLI** for: validate-template, deploy, change sets, rollback, drift detection, and all stack operations
|
|
293
|
+
|
|
294
|
+
The source of truth for infrastructure is the TypeScript in \`src/\`. The generated template (\`stack.json\`) is an intermediate artifact.
|
|
295
|
+
|
|
296
|
+
## Build and validate
|
|
297
|
+
|
|
298
|
+
### Build the template
|
|
299
|
+
|
|
300
|
+
\`\`\`bash
|
|
301
|
+
chant build src/ --output stack.json
|
|
302
|
+
\`\`\`
|
|
303
|
+
|
|
304
|
+
Options:
|
|
305
|
+
- \`--format yaml\` — emit YAML instead of JSON
|
|
306
|
+
- \`--watch\` — rebuild on source changes
|
|
307
|
+
|
|
308
|
+
### Lint the source
|
|
309
|
+
|
|
310
|
+
\`\`\`bash
|
|
311
|
+
chant lint src/
|
|
312
|
+
\`\`\`
|
|
313
|
+
|
|
314
|
+
Options:
|
|
315
|
+
- \`--fix\` — auto-fix violations where possible
|
|
316
|
+
- \`--format sarif\` — SARIF output for CI integration
|
|
317
|
+
- \`--watch\` — re-lint on changes
|
|
318
|
+
|
|
319
|
+
### Validate with CloudFormation
|
|
320
|
+
|
|
321
|
+
\`\`\`bash
|
|
322
|
+
aws cloudformation validate-template --template-body file://stack.json
|
|
323
|
+
\`\`\`
|
|
324
|
+
|
|
325
|
+
### What each step catches
|
|
326
|
+
|
|
327
|
+
| Step | Catches | When to run |
|
|
328
|
+
|------|---------|-------------|
|
|
329
|
+
| \`chant lint\` | Best-practice violations, security anti-patterns, naming issues | Every edit |
|
|
330
|
+
| \`chant build\` | TypeScript errors, missing properties, type mismatches | Before deploy |
|
|
331
|
+
| \`validate-template\` | CloudFormation schema errors, invalid intrinsic usage | Before deploy |
|
|
332
|
+
|
|
333
|
+
Always run all three before deploying. Lint catches things validate-template cannot (and vice versa).
|
|
334
|
+
|
|
335
|
+
## Diffing and change preview
|
|
336
|
+
|
|
337
|
+
This is the most critical section for production safety. **Never deploy to production without previewing changes.**
|
|
338
|
+
|
|
339
|
+
### Local diff
|
|
340
|
+
|
|
341
|
+
Compare your proposed template against what is currently deployed:
|
|
342
|
+
|
|
343
|
+
\`\`\`bash
|
|
344
|
+
# Get the currently deployed template
|
|
345
|
+
aws cloudformation get-template --stack-name <stack-name> --query TemplateBody --output json > deployed.json
|
|
346
|
+
|
|
347
|
+
# Build the proposed template
|
|
348
|
+
chant build src/ --output proposed.json
|
|
349
|
+
|
|
350
|
+
# Diff them
|
|
351
|
+
diff deployed.json proposed.json
|
|
352
|
+
\`\`\`
|
|
353
|
+
|
|
354
|
+
### Change sets (recommended for production)
|
|
355
|
+
|
|
356
|
+
Change sets let you preview exactly what CloudFormation will do before it does it.
|
|
357
|
+
|
|
358
|
+
\`\`\`bash
|
|
359
|
+
# 1. Create the change set
|
|
360
|
+
aws cloudformation create-change-set \\
|
|
361
|
+
--stack-name <stack-name> \\
|
|
362
|
+
--template-body file://stack.json \\
|
|
363
|
+
--change-set-name review-$(date +%s) \\
|
|
364
|
+
--capabilities CAPABILITY_NAMED_IAM
|
|
365
|
+
|
|
366
|
+
# 2. Wait for it to compute
|
|
367
|
+
aws cloudformation wait change-set-create-complete \\
|
|
368
|
+
--stack-name <stack-name> \\
|
|
369
|
+
--change-set-name review-<id>
|
|
370
|
+
|
|
371
|
+
# 3. Review the changes
|
|
372
|
+
aws cloudformation describe-change-set \\
|
|
373
|
+
--stack-name <stack-name> \\
|
|
374
|
+
--change-set-name review-<id>
|
|
375
|
+
|
|
376
|
+
# 4a. Execute if changes look safe
|
|
377
|
+
aws cloudformation execute-change-set \\
|
|
378
|
+
--stack-name <stack-name> \\
|
|
379
|
+
--change-set-name review-<id>
|
|
380
|
+
|
|
381
|
+
# 4b. Or delete if you want to abort
|
|
382
|
+
aws cloudformation delete-change-set \\
|
|
383
|
+
--stack-name <stack-name> \\
|
|
384
|
+
--change-set-name review-<id>
|
|
385
|
+
\`\`\`
|
|
386
|
+
|
|
387
|
+
### Interpreting change set results
|
|
388
|
+
|
|
389
|
+
Each resource change has an **Action** and a **Replacement** value. Read them together:
|
|
390
|
+
|
|
391
|
+
| Action | Replacement | Risk | Meaning |
|
|
392
|
+
|--------|-------------|------|---------|
|
|
393
|
+
| Add | — | Low | New resource will be created |
|
|
394
|
+
| Modify | False | Low | In-place update, no disruption |
|
|
395
|
+
| Modify | Conditional | **MEDIUM** | May replace depending on property — investigate further |
|
|
396
|
+
| Modify | True | **HIGH** | Resource will be DESTROYED and recreated — **data loss risk** |
|
|
397
|
+
| Remove | — | **HIGH** | Resource will be deleted |
|
|
398
|
+
|
|
399
|
+
### Properties that always cause replacement
|
|
400
|
+
|
|
401
|
+
These property changes ALWAYS destroy and recreate the resource:
|
|
402
|
+
- \`BucketName\` on S3 buckets
|
|
403
|
+
- \`TableName\` on DynamoDB tables
|
|
404
|
+
- \`DBInstanceIdentifier\` on RDS instances
|
|
405
|
+
- \`FunctionName\` on Lambda functions
|
|
406
|
+
- \`CidrBlock\` on VPCs and subnets
|
|
407
|
+
- \`ClusterIdentifier\` on Redshift clusters
|
|
408
|
+
- \`DomainName\` on Elasticsearch/OpenSearch domains
|
|
409
|
+
- \`TopicName\` on SNS topics
|
|
410
|
+
- \`QueueName\` on SQS queues
|
|
411
|
+
|
|
412
|
+
**CRITICAL**: When you see \`Replacement: True\` on any stateful resource (databases, S3 buckets, queues with messages, DynamoDB tables), ALWAYS flag this to the user and get explicit confirmation before executing. This will destroy the existing resource and all its data.
|
|
413
|
+
|
|
414
|
+
## Deploying a new stack
|
|
415
|
+
|
|
416
|
+
\`\`\`bash
|
|
417
|
+
aws cloudformation deploy \\
|
|
418
|
+
--template-file stack.json \\
|
|
419
|
+
--stack-name <stack-name> \\
|
|
420
|
+
--capabilities CAPABILITY_NAMED_IAM \\
|
|
421
|
+
--parameter-overrides Env=prod Version=1.0 \\
|
|
422
|
+
--tags Project=myapp Environment=prod
|
|
423
|
+
\`\`\`
|
|
424
|
+
|
|
425
|
+
### Capabilities
|
|
426
|
+
|
|
427
|
+
| Capability | When needed |
|
|
428
|
+
|------------|-------------|
|
|
429
|
+
| \`CAPABILITY_IAM\` | Template creates IAM resources with auto-generated names |
|
|
430
|
+
| \`CAPABILITY_NAMED_IAM\` | Template creates IAM resources with custom names (use this by default — it's a superset) |
|
|
431
|
+
| \`CAPABILITY_AUTO_EXPAND\` | Template uses macros or nested stacks with transforms |
|
|
432
|
+
|
|
433
|
+
**Recommendation**: Default to \`CAPABILITY_NAMED_IAM\` unless the template also uses macros, in which case use \`--capabilities CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND\`.
|
|
434
|
+
|
|
435
|
+
### Monitoring deployment
|
|
436
|
+
|
|
437
|
+
\`\`\`bash
|
|
438
|
+
# Wait for completion (blocks until done)
|
|
439
|
+
aws cloudformation wait stack-create-complete --stack-name <stack-name>
|
|
440
|
+
|
|
441
|
+
# Or poll events in real-time
|
|
442
|
+
watch -n 5 "aws cloudformation describe-stack-events --stack-name <stack-name> --max-items 10 --query 'StackEvents[].{Time:Timestamp,Resource:LogicalResourceId,Status:ResourceStatus,Reason:ResourceStatusReason}' --output table"
|
|
443
|
+
\`\`\`
|
|
444
|
+
|
|
445
|
+
### Getting outputs
|
|
446
|
+
|
|
447
|
+
\`\`\`bash
|
|
448
|
+
aws cloudformation describe-stacks \\
|
|
449
|
+
--stack-name <stack-name> \\
|
|
450
|
+
--query 'Stacks[0].Outputs'
|
|
451
|
+
\`\`\`
|
|
452
|
+
|
|
453
|
+
## Updating an existing stack
|
|
454
|
+
|
|
455
|
+
### Safe path — change set workflow (production / stateful stacks)
|
|
456
|
+
|
|
457
|
+
1. Build: \`chant build src/ --output stack.json\`
|
|
458
|
+
2. Create change set (see Diffing section above)
|
|
459
|
+
3. Review every resource change — pay special attention to Replacement values
|
|
460
|
+
4. Get user confirmation for any destructive changes
|
|
461
|
+
5. Execute the change set
|
|
462
|
+
6. Monitor: \`aws cloudformation wait stack-update-complete --stack-name <stack-name>\`
|
|
463
|
+
|
|
464
|
+
### Fast path — direct deploy (dev / stateless stacks)
|
|
465
|
+
|
|
466
|
+
\`\`\`bash
|
|
467
|
+
aws cloudformation deploy \\
|
|
468
|
+
--template-file stack.json \\
|
|
469
|
+
--stack-name <stack-name> \\
|
|
470
|
+
--capabilities CAPABILITY_NAMED_IAM \\
|
|
471
|
+
--no-fail-on-empty-changeset
|
|
472
|
+
\`\`\`
|
|
473
|
+
|
|
474
|
+
The \`--no-fail-on-empty-changeset\` flag prevents a non-zero exit code when there are no changes (useful in CI).
|
|
475
|
+
|
|
476
|
+
### Updating parameters only (no template change)
|
|
477
|
+
|
|
478
|
+
\`\`\`bash
|
|
479
|
+
aws cloudformation deploy \\
|
|
480
|
+
--stack-name <stack-name> \\
|
|
481
|
+
--use-previous-template \\
|
|
482
|
+
--capabilities CAPABILITY_NAMED_IAM \\
|
|
483
|
+
--parameter-overrides Env=staging
|
|
484
|
+
\`\`\`
|
|
485
|
+
|
|
486
|
+
### Which path to use
|
|
487
|
+
|
|
488
|
+
| Scenario | Path |
|
|
489
|
+
|----------|------|
|
|
490
|
+
| Production stack with databases/storage | Safe path (change set) |
|
|
491
|
+
| Any stack with \`Replacement: True\` changes | Safe path (change set) |
|
|
492
|
+
| Dev/test stack, stateless resources only | Fast path (direct deploy) |
|
|
493
|
+
| CI/CD automated pipeline with approval gate | Safe path (change set with manual approval) |
|
|
494
|
+
| Parameter-only change, no template diff | Fast path with \`--use-previous-template\` |
|
|
495
|
+
|
|
496
|
+
## Rollback and recovery
|
|
497
|
+
|
|
498
|
+
### Stack states reference
|
|
499
|
+
|
|
500
|
+
| State | Meaning | Action |
|
|
501
|
+
|-------|---------|--------|
|
|
502
|
+
| \`CREATE_COMPLETE\` | Stack created successfully | None — healthy |
|
|
503
|
+
| \`UPDATE_COMPLETE\` | Update succeeded | None — healthy |
|
|
504
|
+
| \`DELETE_COMPLETE\` | Stack deleted | Gone — recreate if needed |
|
|
505
|
+
| \`CREATE_IN_PROGRESS\` | Creation underway | Wait |
|
|
506
|
+
| \`UPDATE_IN_PROGRESS\` | Update underway | Wait |
|
|
507
|
+
| \`DELETE_IN_PROGRESS\` | Deletion underway | Wait |
|
|
508
|
+
| \`ROLLBACK_IN_PROGRESS\` | Create failed, rolling back | Wait |
|
|
509
|
+
| \`UPDATE_ROLLBACK_IN_PROGRESS\` | Update failed, rolling back | Wait |
|
|
510
|
+
| \`CREATE_FAILED\` | Creation failed (rare) | Check events, delete stack |
|
|
511
|
+
| \`ROLLBACK_COMPLETE\` | Create failed, rollback finished | **Must delete and recreate** — cannot update |
|
|
512
|
+
| \`ROLLBACK_FAILED\` | Create rollback failed | Check events, may need manual cleanup |
|
|
513
|
+
| \`UPDATE_ROLLBACK_COMPLETE\` | Update failed, rolled back to previous | Healthy — fix template and try again |
|
|
514
|
+
| \`UPDATE_ROLLBACK_FAILED\` | Update rollback itself failed | **See recovery steps below** |
|
|
515
|
+
| \`DELETE_FAILED\` | Deletion failed | Check events, retry or use retain |
|
|
289
516
|
|
|
290
|
-
|
|
517
|
+
### Recovering from UPDATE_ROLLBACK_FAILED
|
|
291
518
|
|
|
292
|
-
|
|
293
|
-
- \`AWS::Lambda::Function\` — Serverless compute
|
|
294
|
-
- \`AWS::DynamoDB::Table\` — NoSQL database
|
|
295
|
-
- \`AWS::IAM::Role\` — Identity and access management
|
|
296
|
-
- \`AWS::SNS::Topic\` — Pub/sub messaging
|
|
297
|
-
- \`AWS::SQS::Queue\` — Message queue
|
|
298
|
-
- \`AWS::EC2::SecurityGroup\` — Network firewall rules
|
|
519
|
+
This is the most common "stuck" state. A resource that CloudFormation tried to roll back could not be restored.
|
|
299
520
|
|
|
300
|
-
|
|
521
|
+
**Step 1**: Identify the stuck resource:
|
|
301
522
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
523
|
+
\`\`\`bash
|
|
524
|
+
aws cloudformation describe-stack-events \\
|
|
525
|
+
--stack-name <stack-name> \\
|
|
526
|
+
--query "StackEvents[?ResourceStatus=='UPDATE_FAILED'].[LogicalResourceId,ResourceStatusReason]" \\
|
|
527
|
+
--output table
|
|
528
|
+
\`\`\`
|
|
308
529
|
|
|
309
|
-
|
|
530
|
+
**Step 2a** — Try continuing the rollback:
|
|
310
531
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
532
|
+
\`\`\`bash
|
|
533
|
+
aws cloudformation continue-update-rollback --stack-name <stack-name>
|
|
534
|
+
aws cloudformation wait stack-update-complete --stack-name <stack-name>
|
|
535
|
+
\`\`\`
|
|
315
536
|
|
|
316
|
-
|
|
537
|
+
**Step 2b** — If that fails, skip the stuck resources:
|
|
317
538
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
539
|
+
\`\`\`bash
|
|
540
|
+
aws cloudformation continue-update-rollback \\
|
|
541
|
+
--stack-name <stack-name> \\
|
|
542
|
+
--resources-to-skip LogicalResourceId1 LogicalResourceId2
|
|
543
|
+
\`\`\`
|
|
544
|
+
|
|
545
|
+
**WARNING**: Skipping resources causes state divergence — CloudFormation's view of the stack will no longer match reality. You may need to manually clean up skipped resources or import them back later.
|
|
546
|
+
|
|
547
|
+
### Recovering from ROLLBACK_COMPLETE
|
|
548
|
+
|
|
549
|
+
A stack in \`ROLLBACK_COMPLETE\` cannot be updated. You must delete it and create a new one:
|
|
550
|
+
|
|
551
|
+
\`\`\`bash
|
|
552
|
+
aws cloudformation delete-stack --stack-name <stack-name>
|
|
553
|
+
aws cloudformation wait stack-delete-complete --stack-name <stack-name>
|
|
554
|
+
# Then deploy fresh
|
|
555
|
+
aws cloudformation deploy --template-file stack.json --stack-name <stack-name> --capabilities CAPABILITY_NAMED_IAM
|
|
556
|
+
\`\`\`
|
|
557
|
+
|
|
558
|
+
## Stack lifecycle operations
|
|
559
|
+
|
|
560
|
+
### Delete a stack
|
|
561
|
+
|
|
562
|
+
\`\`\`bash
|
|
563
|
+
aws cloudformation delete-stack --stack-name <stack-name>
|
|
564
|
+
aws cloudformation wait stack-delete-complete --stack-name <stack-name>
|
|
565
|
+
\`\`\`
|
|
566
|
+
|
|
567
|
+
If deletion fails because a resource cannot be deleted (e.g., non-empty S3 bucket), use retain:
|
|
568
|
+
|
|
569
|
+
\`\`\`bash
|
|
570
|
+
aws cloudformation delete-stack \\
|
|
571
|
+
--stack-name <stack-name> \\
|
|
572
|
+
--retain-resources BucketLogicalId
|
|
573
|
+
\`\`\`
|
|
574
|
+
|
|
575
|
+
To protect a stack from accidental deletion:
|
|
576
|
+
|
|
577
|
+
\`\`\`bash
|
|
578
|
+
aws cloudformation update-termination-protection \\
|
|
579
|
+
--enable-termination-protection \\
|
|
580
|
+
--stack-name <stack-name>
|
|
581
|
+
\`\`\`
|
|
582
|
+
|
|
583
|
+
### Drift detection
|
|
584
|
+
|
|
585
|
+
Detect whether resources have been modified outside of CloudFormation:
|
|
586
|
+
|
|
587
|
+
\`\`\`bash
|
|
588
|
+
# Start detection
|
|
589
|
+
DRIFT_ID=$(aws cloudformation detect-stack-drift --stack-name <stack-name> --query StackDriftDetectionId --output text)
|
|
590
|
+
|
|
591
|
+
# Check status
|
|
592
|
+
aws cloudformation describe-stack-drift-detection-status --stack-drift-detection-id $DRIFT_ID
|
|
593
|
+
|
|
594
|
+
# View drifted resources
|
|
595
|
+
aws cloudformation describe-stack-resource-drifts \\
|
|
596
|
+
--stack-name <stack-name> \\
|
|
597
|
+
--stack-resource-drift-status-filters MODIFIED DELETED
|
|
598
|
+
\`\`\`
|
|
599
|
+
|
|
600
|
+
### Import existing resources
|
|
601
|
+
|
|
602
|
+
Bring resources that were created outside CloudFormation under stack management:
|
|
603
|
+
|
|
604
|
+
\`\`\`bash
|
|
605
|
+
aws cloudformation create-change-set \\
|
|
606
|
+
--stack-name <stack-name> \\
|
|
607
|
+
--template-body file://stack.json \\
|
|
608
|
+
--change-set-name import-resources \\
|
|
609
|
+
--change-set-type IMPORT \\
|
|
610
|
+
--resources-to-import '[{"ResourceType":"AWS::S3::Bucket","LogicalResourceId":"MyBucket","ResourceIdentifier":{"BucketName":"existing-bucket-name"}}]'
|
|
611
|
+
\`\`\`
|
|
612
|
+
|
|
613
|
+
## Troubleshooting decision tree
|
|
614
|
+
|
|
615
|
+
When a deployment fails, follow this diagnostic flow:
|
|
616
|
+
|
|
617
|
+
### Step 1: Check the stack status
|
|
618
|
+
|
|
619
|
+
\`\`\`bash
|
|
620
|
+
aws cloudformation describe-stacks --stack-name <stack-name> --query 'Stacks[0].StackStatus' --output text
|
|
621
|
+
\`\`\`
|
|
622
|
+
|
|
623
|
+
### Step 2: Branch on status
|
|
624
|
+
|
|
625
|
+
- **\`*_IN_PROGRESS\`** → Wait. Do not take action while an operation is in progress.
|
|
626
|
+
- **\`*_FAILED\` or \`*_ROLLBACK_*\`** → Read the events (Step 3).
|
|
627
|
+
- **\`*_COMPLETE\`** → Stack is stable. If behavior is wrong, check resource configuration.
|
|
628
|
+
|
|
629
|
+
### Step 3: Read the failure events
|
|
630
|
+
|
|
631
|
+
\`\`\`bash
|
|
632
|
+
aws cloudformation describe-stack-events \\
|
|
633
|
+
--stack-name <stack-name> \\
|
|
634
|
+
--query "StackEvents[?contains(ResourceStatus, 'FAILED')].[LogicalResourceId,ResourceStatusReason]" \\
|
|
635
|
+
--output table
|
|
636
|
+
\`\`\`
|
|
637
|
+
|
|
638
|
+
### Step 4: Diagnose by error pattern
|
|
639
|
+
|
|
640
|
+
| Error pattern | Likely cause | Fix |
|
|
641
|
+
|---------------|-------------|-----|
|
|
642
|
+
| "already exists" | Resource name collision — another stack or manual creation owns this name | Use dynamic names: \`Sub\\\`\\\${AWS.StackName}-myresource\\\`\` |
|
|
643
|
+
| "not authorized" or "AccessDenied" | Missing IAM permissions, SCP restriction, or wrong \`--capabilities\` | Check IAM policy, add \`--capabilities CAPABILITY_NAMED_IAM\` |
|
|
644
|
+
| "limit exceeded" or "LimitExceededException" | AWS service quota hit | Request quota increase or reduce resource count |
|
|
645
|
+
| "Template error" or "Template format error" | Invalid template syntax | Run \`aws cloudformation validate-template\` and \`chant lint src/\` |
|
|
646
|
+
| "Circular dependency" | Two resources reference each other | Break the cycle — extract one reference to an output or parameter |
|
|
647
|
+
| "is in UPDATE_ROLLBACK_FAILED state and can not be updated" | Stuck rollback | See UPDATE_ROLLBACK_FAILED recovery above |
|
|
648
|
+
| "is in ROLLBACK_COMPLETE state and can not be updated" | Failed creation, rolled back | Delete the stack and recreate |
|
|
649
|
+
| "No updates are to be performed" | Template unchanged | Use \`--no-fail-on-empty-changeset\` or verify your changes are in the built template |
|
|
650
|
+
| "Resource is not in the state" | Resource was modified outside CF | Run drift detection, then update or import |
|
|
651
|
+
| "Maximum number of addresses has been reached" | EIP limit (default 5) | Request EIP quota increase |
|
|
652
|
+
|
|
653
|
+
## Quick reference
|
|
654
|
+
|
|
655
|
+
### Stack info commands
|
|
656
|
+
|
|
657
|
+
\`\`\`bash
|
|
658
|
+
# List all stacks
|
|
659
|
+
aws cloudformation list-stacks --stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE
|
|
660
|
+
|
|
661
|
+
# Describe a stack (status, params, outputs, tags)
|
|
662
|
+
aws cloudformation describe-stacks --stack-name <stack-name>
|
|
663
|
+
|
|
664
|
+
# List resources in a stack
|
|
665
|
+
aws cloudformation list-stack-resources --stack-name <stack-name>
|
|
666
|
+
|
|
667
|
+
# Get outputs only
|
|
668
|
+
aws cloudformation describe-stacks --stack-name <stack-name> --query 'Stacks[0].Outputs'
|
|
669
|
+
|
|
670
|
+
# Recent events
|
|
671
|
+
aws cloudformation describe-stack-events --stack-name <stack-name> --max-items 20
|
|
672
|
+
|
|
673
|
+
# Get deployed template
|
|
674
|
+
aws cloudformation get-template --stack-name <stack-name> --query TemplateBody
|
|
675
|
+
\`\`\`
|
|
676
|
+
|
|
677
|
+
### Full build-to-deploy pipeline
|
|
678
|
+
|
|
679
|
+
\`\`\`bash
|
|
680
|
+
# 1. Lint
|
|
681
|
+
chant lint src/
|
|
682
|
+
|
|
683
|
+
# 2. Build
|
|
684
|
+
chant build src/ --output stack.json
|
|
685
|
+
|
|
686
|
+
# 3. Validate
|
|
687
|
+
aws cloudformation validate-template --template-body file://stack.json
|
|
688
|
+
|
|
689
|
+
# 4. Create change set
|
|
690
|
+
aws cloudformation create-change-set \\
|
|
691
|
+
--stack-name <stack-name> \\
|
|
692
|
+
--template-body file://stack.json \\
|
|
693
|
+
--change-set-name deploy-$(date +%s) \\
|
|
694
|
+
--capabilities CAPABILITY_NAMED_IAM
|
|
695
|
+
|
|
696
|
+
# 5. Review changes
|
|
697
|
+
aws cloudformation describe-change-set \\
|
|
698
|
+
--stack-name <stack-name> \\
|
|
699
|
+
--change-set-name deploy-<id>
|
|
700
|
+
|
|
701
|
+
# 6. Execute (after user confirms)
|
|
702
|
+
aws cloudformation execute-change-set \\
|
|
703
|
+
--stack-name <stack-name> \\
|
|
704
|
+
--change-set-name deploy-<id>
|
|
705
|
+
|
|
706
|
+
# 7. Wait for completion
|
|
707
|
+
aws cloudformation wait stack-update-complete --stack-name <stack-name>
|
|
708
|
+
\`\`\`
|
|
324
709
|
`,
|
|
325
710
|
triggers: [
|
|
326
711
|
{ type: "file-pattern", value: "**/*.aws.ts" },
|
|
712
|
+
{ type: "file-pattern", value: "**/stack.json" },
|
|
713
|
+
{ type: "file-pattern", value: "**/template.yaml" },
|
|
327
714
|
{ type: "context", value: "aws" },
|
|
715
|
+
{ type: "context", value: "cloudformation" },
|
|
716
|
+
{ type: "context", value: "deploy" },
|
|
717
|
+
],
|
|
718
|
+
preConditions: [
|
|
719
|
+
"AWS CLI is installed and configured (aws sts get-caller-identity succeeds)",
|
|
720
|
+
"chant CLI is installed (chant --version succeeds)",
|
|
721
|
+
"Project has chant source files in src/",
|
|
722
|
+
],
|
|
723
|
+
postConditions: [
|
|
724
|
+
"Stack is in a stable state (*_COMPLETE)",
|
|
725
|
+
"No failed resources in stack events",
|
|
328
726
|
],
|
|
329
727
|
parameters: [
|
|
330
728
|
{
|
|
@@ -353,6 +751,46 @@ description: AWS CloudFormation best practices and common patterns
|
|
|
353
751
|
},
|
|
354
752
|
})`,
|
|
355
753
|
},
|
|
754
|
+
{
|
|
755
|
+
title: "Deploy a new stack",
|
|
756
|
+
description: "Build a chant project and deploy it as a new CloudFormation stack",
|
|
757
|
+
input: "Deploy this project as a new stack called my-app-prod",
|
|
758
|
+
output: `chant lint src/
|
|
759
|
+
chant build src/ --output stack.json
|
|
760
|
+
aws cloudformation validate-template --template-body file://stack.json
|
|
761
|
+
aws cloudformation deploy \\
|
|
762
|
+
--template-file stack.json \\
|
|
763
|
+
--stack-name my-app-prod \\
|
|
764
|
+
--capabilities CAPABILITY_NAMED_IAM`,
|
|
765
|
+
},
|
|
766
|
+
{
|
|
767
|
+
title: "Preview changes before updating",
|
|
768
|
+
description: "Create a change set to review what will change before applying an update",
|
|
769
|
+
input: "Show me what will change if I deploy this update to my-app-prod",
|
|
770
|
+
output: `chant build src/ --output stack.json
|
|
771
|
+
aws cloudformation create-change-set \\
|
|
772
|
+
--stack-name my-app-prod \\
|
|
773
|
+
--template-body file://stack.json \\
|
|
774
|
+
--change-set-name review-$(date +%s) \\
|
|
775
|
+
--capabilities CAPABILITY_NAMED_IAM
|
|
776
|
+
# Wait for change set to compute, then review:
|
|
777
|
+
aws cloudformation describe-change-set \\
|
|
778
|
+
--stack-name my-app-prod \\
|
|
779
|
+
--change-set-name review-<id>`,
|
|
780
|
+
},
|
|
781
|
+
{
|
|
782
|
+
title: "Fix a stuck rollback",
|
|
783
|
+
description: "Recover a stack stuck in UPDATE_ROLLBACK_FAILED state",
|
|
784
|
+
input: "My stack my-app-prod is stuck in UPDATE_ROLLBACK_FAILED, help me fix it",
|
|
785
|
+
output: `# Identify the stuck resource
|
|
786
|
+
aws cloudformation describe-stack-events \\
|
|
787
|
+
--stack-name my-app-prod \\
|
|
788
|
+
--query "StackEvents[?ResourceStatus=='UPDATE_FAILED'].[LogicalResourceId,ResourceStatusReason]" \\
|
|
789
|
+
--output table
|
|
790
|
+
# Attempt to continue the rollback
|
|
791
|
+
aws cloudformation continue-update-rollback --stack-name my-app-prod
|
|
792
|
+
aws cloudformation wait stack-update-complete --stack-name my-app-prod`,
|
|
793
|
+
},
|
|
356
794
|
],
|
|
357
795
|
},
|
|
358
796
|
];
|
|
@@ -424,31 +862,31 @@ description: AWS CloudFormation best practices and common patterns
|
|
|
424
862
|
description: "AWS S3 bucket with versioning and encryption",
|
|
425
863
|
mimeType: "text/typescript",
|
|
426
864
|
async handler(): Promise<string> {
|
|
427
|
-
return `import
|
|
865
|
+
return `import { ServerSideEncryptionByDefault, ServerSideEncryptionRule, BucketEncryption, VersioningConfiguration, Bucket, Sub, AWS } from "@intentius/chant-lexicon-aws";
|
|
428
866
|
|
|
429
867
|
// Encryption configuration
|
|
430
|
-
export const encryptionDefault = new
|
|
431
|
-
|
|
868
|
+
export const encryptionDefault = new ServerSideEncryptionByDefault({
|
|
869
|
+
SSEAlgorithm: "AES256",
|
|
432
870
|
});
|
|
433
871
|
|
|
434
|
-
export const encryptionRule = new
|
|
435
|
-
|
|
872
|
+
export const encryptionRule = new ServerSideEncryptionRule({
|
|
873
|
+
ServerSideEncryptionByDefault: encryptionDefault,
|
|
436
874
|
});
|
|
437
875
|
|
|
438
|
-
export const bucketEncryption = new
|
|
439
|
-
|
|
876
|
+
export const bucketEncryption = new BucketEncryption({
|
|
877
|
+
ServerSideEncryptionConfiguration: [encryptionRule],
|
|
440
878
|
});
|
|
441
879
|
|
|
442
880
|
// Versioning
|
|
443
|
-
export const versioningEnabled = new
|
|
444
|
-
|
|
881
|
+
export const versioningEnabled = new VersioningConfiguration({
|
|
882
|
+
Status: "Enabled",
|
|
445
883
|
});
|
|
446
884
|
|
|
447
|
-
// Create a versioned bucket with encryption
|
|
448
|
-
export const dataBucket = new
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
885
|
+
// Create a versioned bucket with encryption (AccountId ensures global uniqueness)
|
|
886
|
+
export const dataBucket = new Bucket({
|
|
887
|
+
BucketName: Sub\`\${AWS.StackName}-\${AWS.AccountId}-data\`,
|
|
888
|
+
VersioningConfiguration: versioningEnabled,
|
|
889
|
+
BucketEncryption: bucketEncryption,
|
|
452
890
|
});
|
|
453
891
|
`;
|
|
454
892
|
},
|
|
@@ -459,17 +897,17 @@ export const dataBucket = new aws.Bucket({
|
|
|
459
897
|
description: "Using AttrRefs for cross-resource references",
|
|
460
898
|
mimeType: "text/typescript",
|
|
461
899
|
async handler(): Promise<string> {
|
|
462
|
-
return `import
|
|
900
|
+
return `import { Bucket, VersioningConfiguration, Role } from "@intentius/chant-lexicon-aws";
|
|
463
901
|
|
|
464
902
|
// Create a bucket
|
|
465
|
-
export const dataBucket = new
|
|
466
|
-
|
|
467
|
-
|
|
903
|
+
export const dataBucket = new Bucket({
|
|
904
|
+
BucketName: "my-data-bucket",
|
|
905
|
+
VersioningConfiguration: new VersioningConfiguration({ Status: "Enabled" }),
|
|
468
906
|
});
|
|
469
907
|
|
|
470
908
|
// Create a role that references the bucket's ARN
|
|
471
|
-
export const role = new
|
|
472
|
-
|
|
909
|
+
export const role = new Role({
|
|
910
|
+
AssumeRolePolicyDocument: {
|
|
473
911
|
Version: "2012-10-17",
|
|
474
912
|
Statement: [{
|
|
475
913
|
Effect: "Allow",
|