-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcloudformation.html
More file actions
572 lines (543 loc) · 28.4 KB
/
cloudformation.html
File metadata and controls
572 lines (543 loc) · 28.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AWS CloudFormation Security | AWS Security Cards</title>
<meta name="description" content="CloudFormation provisions AWS resources via templates. Attackers abuse CreateStack with PassRole to escalate privileges, extract secrets from templates and outputs, and leverage Custom Resources for arbitrary code execution.">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
background: #0a0e1a;
color: #e2e8f0;
line-height: 1.6;
padding: 2rem;
max-width: 1200px;
margin: 0 auto;
}
a { color: #22d3ee; text-decoration: none; }
a:hover { text-decoration: underline; }
/* Card Image */
.card-image {
border-radius: 1rem;
overflow: hidden;
margin-bottom: 2rem;
border: 1px solid rgba(255,255,255,0.1);
}
.card-image img {
width: 100%;
height: auto;
display: block;
}
/* Header */
.header {
position: relative;
overflow: hidden;
border-radius: 1rem;
background: linear-gradient(135deg, #06b6d415, #0a0e1a, #0ea5e915);
border: 1px solid #06b6d44d;
padding: 2.5rem;
margin-bottom: 2rem;
}
.header::before {
content: '';
position: absolute;
top: 0; right: 0;
width: 24rem; height: 24rem;
background: #06b6d40d;
border-radius: 50%;
filter: blur(3rem);
}
.header-content { position: relative; display: flex; align-items: flex-start; gap: 1.5rem; }
.header-icon { width: 64px; height: 64px; flex-shrink: 0; }
.header-icon img { width: 100%; height: 100%; }
.header-title { font-size: 1.875rem; font-weight: 700; color: #fff; }
.header-badge {
display: inline-block;
padding: 0.25rem 0.75rem;
background: #06b6d433;
color: #06b6d4;
font-size: 0.8rem;
font-weight: 600;
border-radius: 999px;
border: 1px solid #06b6d44d;
margin-left: 0.75rem;
vertical-align: middle;
}
.header-desc { color: #94a3b8; max-width: 42rem; margin-top: 0.5rem; }
/* Stats */
.stats-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 2rem; }
.stat-card {
background: rgba(255,255,255,0.03);
border-radius: 0.5rem;
border: 1px solid rgba(255,255,255,0.06);
padding: 1rem;
text-align: center;
}
.stat-value { font-size: 1.5rem; font-weight: 700; }
.stat-label { font-size: 0.8rem; color: #94a3b8; }
/* Sections */
.section {
background: rgba(255,255,255,0.03);
border-radius: 0.75rem;
border: 1px solid rgba(255,255,255,0.06);
padding: 1.5rem;
margin-bottom: 1.5rem;
}
.section h2 {
font-size: 1.25rem;
font-weight: 700;
color: #fff;
margin-bottom: 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
/* Overview */
.overview-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; }
.overview-grid h4 { font-size: 0.9rem; font-weight: 600; margin-bottom: 0.5rem; }
.overview-grid p { font-size: 0.875rem; color: #94a3b8; margin-bottom: 0.75rem; }
.attack-note {
background: rgba(0,0,0,0.3);
border-radius: 0.5rem;
border: 1px solid rgba(255,255,255,0.06);
padding: 0.75rem;
font-size: 0.875rem;
color: #cbd5e1;
}
/* Risk Gauge */
.risk-gauge { display: flex; align-items: center; gap: 2rem; }
.risk-bar-container { flex: 1; }
.risk-bar {
height: 1rem;
background: #0f172a;
border-radius: 999px;
overflow: hidden;
}
.risk-bar-fill {
height: 100%;
border-radius: 999px;
background: linear-gradient(90deg, #eab308, #f97316, #ef4444);
}
.risk-labels { display: flex; justify-content: space-between; font-size: 0.8rem; color: #94a3b8; margin-top: 0.5rem; }
.risk-score { text-align: center; }
.risk-score-value { font-size: 2.5rem; font-weight: 700; color: #f87171; }
.risk-score-label { font-size: 0.8rem; color: #94a3b8; }
.risk-desc { margin-top: 1rem; font-size: 0.875rem; color: #94a3b8; }
/* Panels Grid */
.panels-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.5rem; margin-bottom: 1.5rem; }
@media (max-width: 1024px) { .panels-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .panels-grid, .stats-row, .overview-grid { grid-template-columns: 1fr; } }
.panel {
background: rgba(255,255,255,0.03);
border-radius: 0.75rem;
border: 1px solid;
padding: 1.5rem;
}
.panel h3 { font-size: 1.1rem; font-weight: 700; margin-bottom: 1rem; display: flex; align-items: center; gap: 0.5rem; }
.panel h4 { font-size: 0.85rem; font-weight: 600; margin-bottom: 0.5rem; margin-top: 1rem; }
.panel ul { list-style: none; padding: 0; }
.panel li {
font-size: 0.85rem;
color: #cbd5e1;
padding: 0.15rem 0;
display: flex;
align-items: flex-start;
gap: 0.5rem;
}
.bullet { margin-top: 0.15rem; }
.note {
margin-top: 1rem;
padding: 0.75rem;
border-radius: 0.5rem;
font-size: 0.85rem;
}
/* Commands */
.cmd-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.cmd-block { margin-top: 0.75rem; }
.cmd-title { font-size: 0.8rem; color: #94a3b8; margin-bottom: 0.25rem; }
pre {
background: rgba(0,0,0,0.5);
border-radius: 0.5rem;
padding: 0.75rem;
font-size: 0.8rem;
color: #4ade80;
overflow-x: auto;
border: 1px solid rgba(255,255,255,0.06);
white-space: pre-wrap;
word-break: break-all;
font-family: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;
}
/* Policies */
.policy-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; }
.policy-card {
border-radius: 0.5rem;
border: 1px solid;
padding: 1rem;
}
.policy-header { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.75rem; font-size: 0.9rem; }
.policy-card pre { margin-bottom: 0.75rem; color: #cbd5e1; }
.policy-desc { font-size: 0.8rem; color: #94a3b8; }
/* Defenses */
.defense-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.defense-card {
background: rgba(255,255,255,0.03);
border-radius: 0.5rem;
border: 1px solid rgba(255,255,255,0.06);
padding: 1rem;
}
.defense-card:hover { border-color: #22d3ee4d; }
.defense-header { display: flex; align-items: flex-start; gap: 0.75rem; }
.defense-icon { font-size: 1.5rem; }
.defense-card h4 { font-size: 0.9rem; font-weight: 600; color: #fff; margin-bottom: 0.25rem; }
.defense-card p { font-size: 0.85rem; color: #94a3b8; margin-bottom: 0.5rem; }
.defense-card pre { color: #22d3ee; }
/* Footer */
.footer { text-align: center; padding: 1.5rem 0; font-size: 0.8rem; color: #64748b; }
.footer a { color: #22d3ee; }
/* Prevent ugly page-break splits */
.card-image,
.header,
.stat-card,
.stats-row,
.section,
.panel,
.cmd-block,
.policy-card,
.defense-card,
.attack-note,
.overview-grid > div,
.risk-gauge,
.note {
break-inside: avoid;
page-break-inside: avoid;
}
.section,
.panels-grid,
.card-image,
.header {
break-before: auto;
page-break-before: auto;
}
/* Keep headings with their content */
h2, h3, h4 {
break-after: avoid;
page-break-after: avoid;
}
@media print {
body { background: #0a0e1a; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
/* Switch panels to 2-col for better page flow */
.panels-grid { grid-template-columns: repeat(2, 1fr); }
/* Switch commands and policies to single column to avoid splits */
.cmd-grid { grid-template-columns: 1fr; }
.policy-grid { grid-template-columns: 1fr; }
.defense-grid { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<!-- Card Image -->
<div class="card-image">
<img src="../images/cloudformation-card.webp" alt="AWS CloudFormation Security" />
</div>
<!-- Header -->
<div class="header">
<div class="header-content">
<div class="header-icon"><img src="../icons/cloudformation.svg" alt="AWS CloudFormation Security" /></div>
<div>
<div>
<span class="header-title">AWS CloudFormation Security</span>
<span class="header-badge">INFRASTRUCTURE AS CODE</span>
</div>
<p class="header-desc">CloudFormation provisions AWS resources via templates. Attackers abuse CreateStack with PassRole to escalate privileges, extract secrets from templates and outputs, and leverage Custom Resources for arbitrary code execution.</p>
</div>
</div>
</div>
<!-- Stats -->
<div class="stats-row">
<div class="stat-card">
<div class="stat-value" style="color: #f87171;">PassRole</div>
<div class="stat-label">Privesc Vector</div>
</div>
<div class="stat-card">
<div class="stat-value" style="color: #4ade80;">StackSets</div>
<div class="stat-label">Multi-Account</div>
</div>
<div class="stat-card">
<div class="stat-value" style="color: #60a5fa;">Custom</div>
<div class="stat-label">Resources (RCE)</div>
</div>
<div class="stat-card">
<div class="stat-value" style="color: #c084fc;">Secrets</div>
<div class="stat-label">In Templates</div>
</div></div>
<!-- Overview -->
<div class="section"><h2><span style="color:#06b6d4;">📋</span> Service Overview</h2><div class="overview-grid">
<div>
<h4 style="color: #06b6d4;">Stack & Template Model</h4>
<p>CloudFormation uses JSON/YAML templates to declaratively provision AWS resources as stacks. Templates may contain hardcoded secrets, IAM policies, and infrastructure details that attackers can extract via GetTemplate.</p>
</div>
<div>
<h4 style="color: #06b6d4;">Service Roles & PassRole</h4>
<p>CloudFormation can assume a service role to create resources. If a user has iam:PassRole and cloudformation:CreateStack, they can pass an AdministratorAccess role and create any resource, effectively escalating to admin.</p>
</div>
<div>
<h4 style="color: #06b6d4;">StackSets & Custom Resources</h4>
<p>StackSets deploy stacks across multiple accounts and regions simultaneously. Custom Resources invoke Lambda functions or SNS topics during stack operations, enabling arbitrary code execution within the deployment pipeline.</p>
</div></div></div>
<!-- Risk Assessment -->
<div class="section">
<h2>Security Risk Assessment</h2>
<div class="risk-gauge">
<div class="risk-bar-container">
<div class="risk-bar">
<div class="risk-bar-fill" style="width: 90%;"></div>
</div>
<div class="risk-labels"><span>Low</span><span>Medium</span><span>High</span><span>Critical</span></div>
</div>
<div class="risk-score">
<div class="risk-score-value">9.0</div>
<div class="risk-score-label">Risk Score</div>
</div>
</div>
<p class="risk-desc">CloudFormation with iam:PassRole is one of the most reliable privilege escalation paths in AWS. Templates leak secrets, StackSets amplify blast radius across accounts, and Custom Resources execute arbitrary code.</p>
</div>
<!-- Main Panels -->
<div class="panels-grid">
<div class="panel" style="border-color: #f8717133;">
<h3 style="color: #f87171;">⚔️ Attack Vectors</h3><h4 style="color: #f87171;">Privilege Escalation via PassRole</h4><ul><li><span class="bullet" style="color: #f87171;">•</span> CreateStack + PassRole with admin service role = full admin</li><li><span class="bullet" style="color: #f87171;">•</span> Service role with AdministratorAccess creates any resource</li><li><span class="bullet" style="color: #f87171;">•</span> Create IAM users/roles/policies via stack templates</li><li><span class="bullet" style="color: #f87171;">•</span> UpdateStack to modify existing infrastructure silently</li><li><span class="bullet" style="color: #f87171;">•</span> StackSets to deploy backdoors across all org accounts</li></ul><h4 style="color: #f87171;">Secret Extraction</h4><ul><li><span class="bullet" style="color: #f87171;">•</span> GetTemplate exposes hardcoded passwords and API keys</li><li><span class="bullet" style="color: #f87171;">•</span> Stack Outputs leak database endpoints, credentials, ARNs</li><li><span class="bullet" style="color: #f87171;">•</span> ListExports reveals cross-stack shared values</li><li><span class="bullet" style="color: #f87171;">•</span> describe-stack-events shows parameter values in logs</li><li><span class="bullet" style="color: #f87171;">•</span> Template stored in S3 may be publicly accessible</li></ul></div>
<div class="panel" style="border-color: #fb923c33;">
<h3 style="color: #fb923c;">⚠️ Misconfigurations</h3><h4 style="color: #fb923c;">Service Role Issues</h4><ul><li><span class="bullet" style="color: #fb923c;">•</span> CloudFormation service role with AdministratorAccess</li><li><span class="bullet" style="color: #fb923c;">•</span> Service role shared across multiple stacks</li><li><span class="bullet" style="color: #fb923c;">•</span> No condition keys restricting CreateStack callers</li><li><span class="bullet" style="color: #fb923c;">•</span> PassRole allowed for any role (Resource: *)</li><li><span class="bullet" style="color: #fb923c;">•</span> Service roles never audited or rotated</li></ul><h4 style="color: #fb923c;">Template & Stack Issues</h4><ul><li><span class="bullet" style="color: #fb923c;">•</span> Secrets hardcoded in template Parameters with NoEcho only</li><li><span class="bullet" style="color: #fb923c;">•</span> Drift detection not enabled or never run</li><li><span class="bullet" style="color: #fb923c;">•</span> Stack policy not configured (any resource can be updated)</li><li><span class="bullet" style="color: #fb923c;">•</span> Termination protection not enabled on critical stacks</li><li><span class="bullet" style="color: #fb923c;">•</span> Outputs exposing database passwords or API keys</li></ul></div>
<div class="panel" style="border-color: #22d3ee33;">
<h3 style="color: #22d3ee;">🔍 Enumeration</h3>
<div class="cmd-block">
<div class="cmd-title">List All Stacks</div>
<pre><code>aws cloudformation describe-stacks</code></pre>
</div>
<div class="cmd-block">
<div class="cmd-title">Get Template (Extract Secrets)</div>
<pre><code>aws cloudformation get-template \\
--stack-name TargetStack</code></pre>
</div>
<div class="cmd-block">
<div class="cmd-title">List Stack Resources</div>
<pre><code>aws cloudformation list-stack-resources \\
--stack-name TargetStack</code></pre>
</div>
<div class="cmd-block">
<div class="cmd-title">List Exports (Cross-Stack Values)</div>
<pre><code>aws cloudformation list-exports</code></pre>
</div>
<div class="cmd-block">
<div class="cmd-title">Describe Stack Events</div>
<pre><code>aws cloudformation describe-stack-events \\
--stack-name TargetStack</code></pre>
</div></div>
<div class="panel" style="border-color: #c084fc33;">
<h3 style="color: #c084fc;">🔓 Privilege Escalation</h3><h4 style="color: #c084fc;">CreateStack + PassRole Chain</h4><ul><li><span class="bullet" style="color: #c084fc;">•</span> iam:PassRole + cloudformation:CreateStack = admin escalation</li><li><span class="bullet" style="color: #c084fc;">•</span> Pass admin role to CFN, template creates backdoor IAM user</li><li><span class="bullet" style="color: #c084fc;">•</span> Template creates Lambda with admin role for persistent access</li><li><span class="bullet" style="color: #c084fc;">•</span> UpdateStack modifies existing resources with elevated role</li><li><span class="bullet" style="color: #c084fc;">•</span> Custom Resource Lambda executes code as the service role</li></ul><h4 style="color: #c084fc;">StackSet Escalation</h4><ul><li><span class="bullet" style="color: #c084fc;">•</span> create-stack-set deploys to every account in the org</li><li><span class="bullet" style="color: #c084fc;">•</span> StackSet admin role trusts CloudFormation service globally</li><li><span class="bullet" style="color: #c084fc;">•</span> Execution role in target accounts often has AdministratorAccess</li><li><span class="bullet" style="color: #c084fc;">•</span> Single template change propagates across all member accounts</li><li><span class="bullet" style="color: #c084fc;">•</span> StackSet drift rarely monitored across org</li></ul></div>
<div class="panel" style="border-color: #facc1533;">
<h3 style="color: #facc15;">⚡ Persistence Techniques</h3><h4 style="color: #facc15;">Infrastructure Persistence</h4><ul><li><span class="bullet" style="color: #facc15;">•</span> Deploy backdoor IAM user/role via stack template</li><li><span class="bullet" style="color: #facc15;">•</span> Create Lambda with reverse shell as Custom Resource</li><li><span class="bullet" style="color: #facc15;">•</span> Deploy EC2 instance with attacker SSH key via stack</li><li><span class="bullet" style="color: #facc15;">•</span> Nested stacks hide malicious resources in child templates</li><li><span class="bullet" style="color: #facc15;">•</span> Stack with DeletionPolicy: Retain keeps resources after delete</li></ul><h4 style="color: #facc15;">Template Tampering</h4><ul><li><span class="bullet" style="color: #facc15;">•</span> Modify S3-hosted templates to inject resources on next update</li><li><span class="bullet" style="color: #facc15;">•</span> Add Custom Resource that phones home on every stack operation</li><li><span class="bullet" style="color: #facc15;">•</span> StackSet with auto-deploy creates resources in new accounts</li><li><span class="bullet" style="color: #facc15;">•</span> CloudFormation macros transform templates at deploy time</li><li><span class="bullet" style="color: #facc15;">•</span> Change Sets can be pre-staged for later execution</li></ul></div>
<div class="panel" style="border-color: #4ade8033;">
<h3 style="color: #4ade80;">🛡️ Detection</h3><h4 style="color: #4ade80;">CloudTrail Events</h4><ul><li><span class="bullet" style="color: #4ade80;">•</span> CreateStack - new stack created with role</li><li><span class="bullet" style="color: #4ade80;">•</span> UpdateStack - stack template or params modified</li><li><span class="bullet" style="color: #4ade80;">•</span> CreateStackSet - multi-account deployment initiated</li><li><span class="bullet" style="color: #4ade80;">•</span> GetTemplate - template contents retrieved</li><li><span class="bullet" style="color: #4ade80;">•</span> SetStackPolicy - stack protection changed</li></ul><h4 style="color: #4ade80;">Indicators of Compromise</h4><ul><li><span class="bullet" style="color: #4ade80;">•</span> Stack created with AdministratorAccess service role</li><li><span class="bullet" style="color: #4ade80;">•</span> GetTemplate calls from unusual principals</li><li><span class="bullet" style="color: #4ade80;">•</span> StackSet deployed to accounts outside normal pattern</li><li><span class="bullet" style="color: #4ade80;">•</span> Custom Resource Lambda created with broad permissions</li><li><span class="bullet" style="color: #4ade80;">•</span> Stack drift detected on IAM resources</li></ul></div></div>
<!-- Exploitation -->
<div class="section"><h2><span style="color:#f87171;">💻</span> Exploitation Commands</h2><div class="cmd-grid">
<div class="cmd-block">
<div class="cmd-title">Privesc: CreateStack with Admin Role</div>
<pre><code>aws cloudformation create-stack \\
--stack-name privesc-stack \\
--template-body file://backdoor-template.yaml \\
--role-arn arn:aws:iam::ACCOUNT:role/CFNAdminRole \\
--capabilities CAPABILITY_NAMED_IAM</code></pre>
</div>
<div class="cmd-block">
<div class="cmd-title">Extract Template Secrets</div>
<pre><code>aws cloudformation get-template \\
--stack-name ProductionStack \\
--template-stage Original</code></pre>
</div>
<div class="cmd-block">
<div class="cmd-title">Enumerate Stack Outputs</div>
<pre><code>aws cloudformation describe-stacks \\
--query 'Stacks[].Outputs[].[OutputKey,OutputValue]' \\
--output table</code></pre>
</div>
<div class="cmd-block">
<div class="cmd-title">Deploy Custom Resource (Code Exec)</div>
<pre><code>aws cloudformation create-stack \\
--stack-name custom-res \\
--template-body file://custom-resource.yaml \\
--role-arn arn:aws:iam::ACCOUNT:role/CFNRole \\
--capabilities CAPABILITY_IAM</code></pre>
</div>
<div class="cmd-block">
<div class="cmd-title">Create StackSet (Multi-Account)</div>
<pre><code>aws cloudformation create-stack-set \\
--stack-set-name backdoor-stackset \\
--template-body file://backdoor.yaml \\
--permission-model SERVICE_MANAGED \\
--auto-deployment Enabled=true,RetainStacksOnAccountRemoval=true \\
--capabilities CAPABILITY_NAMED_IAM</code></pre>
</div>
<div class="cmd-block">
<div class="cmd-title">List All Exports Across Stacks</div>
<pre><code>aws cloudformation list-exports \\
--query 'Exports[].[Name,Value]' \\
--output table</code></pre>
</div></div></div>
<!-- Policies -->
<div class="section"><h2><span style="color:#4ade80;">📜</span> Policy Examples</h2><div class="policy-grid">
<div class="policy-card" style="border-color: #ef444433; background: rgba(239,68,68,0.05);">
<div class="policy-header">
<span style="color: #f87171; font-size: 1.2em;">✗</span>
<span style="color: #f87171; font-weight: 600;">Dangerous - PassRole to Any Role</span>
</div>
<pre><code>{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"cloudformation:CreateStack",
"cloudformation:UpdateStack",
"iam:PassRole"
],
"Resource": "*"
}]
}</code></pre>
<p class="policy-desc">CreateStack + PassRole with no resource constraint allows passing AdministratorAccess role to CloudFormation for full privilege escalation</p>
</div>
<div class="policy-card" style="border-color: #22c55e33; background: rgba(34,197,94,0.05);">
<div class="policy-header">
<span style="color: #4ade80; font-size: 1.2em;">✓</span>
<span style="color: #4ade80; font-weight: 600;">Secure - Scoped PassRole</span>
</div>
<pre><code>{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::ACCOUNT:role/CFN-LimitedRole",
"Condition": {
"StringEquals": {
"iam:PassedToService": "cloudformation.amazonaws.com"
}
}
}]
}</code></pre>
<p class="policy-desc">PassRole restricted to a specific least-privilege role and only for CloudFormation service</p>
</div>
<div class="policy-card" style="border-color: #ef444433; background: rgba(239,68,68,0.05);">
<div class="policy-header">
<span style="color: #f87171; font-size: 1.2em;">✗</span>
<span style="color: #f87171; font-weight: 600;">Dangerous - Full CloudFormation Access</span>
</div>
<pre><code>{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "cloudformation:*",
"Resource": "*"
}]
}</code></pre>
<p class="policy-desc">Full access allows GetTemplate (secret extraction), CreateStackSet (multi-account compromise), and stack deletion</p>
</div>
<div class="policy-card" style="border-color: #22c55e33; background: rgba(34,197,94,0.05);">
<div class="policy-header">
<span style="color: #4ade80; font-size: 1.2em;">✓</span>
<span style="color: #4ade80; font-weight: 600;">Secure - SCP Deny CreateStack Without Conditions</span>
</div>
<pre><code>{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyCFNWithoutApprovedRole",
"Effect": "Deny",
"Action": [
"cloudformation:CreateStack",
"cloudformation:CreateStackSet"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"cloudformation:RoleArn": [
"arn:aws:iam::*:role/Approved-CFN-Role"
]
}
}
}]
}</code></pre>
<p class="policy-desc">SCP enforces only approved service roles can be used with CloudFormation stack creation</p>
</div></div></div>
<!-- Defenses -->
<div class="section"><h2><span style="color:#4ade80;">🛡️</span> Defense Recommendations</h2><div class="defense-grid">
<div class="defense-card">
<div class="defense-header">
<span class="defense-icon">🔐</span>
<div>
<h4>Least-Privilege Service Roles</h4>
<p>Never use AdministratorAccess for CloudFormation service roles. Scope to only the resources the stack needs.</p>
<pre><code>aws iam create-role --role-name CFN-LimitedRole \\
--assume-role-policy-document file://cfn-trust.json
# Trust: {"Service": "cloudformation.amazonaws.com"}</code></pre>
</div>
</div>
</div>
<div class="defense-card">
<div class="defense-header">
<span class="defense-icon">🚫</span>
<div>
<h4>SCP Restrict CreateStack</h4>
<p>Use Organization SCPs to deny CreateStack unless a pre-approved service role is specified.</p>
</div>
</div>
</div>
<div class="defense-card">
<div class="defense-header">
<span class="defense-icon">📡</span>
<div>
<h4>Enable Drift Detection</h4>
<p>Run drift detection regularly to catch out-of-band changes to stack resources, especially IAM.</p>
<pre><code>aws cloudformation detect-stack-drift \\
--stack-name ProductionStack</code></pre>
</div>
</div>
</div>
<div class="defense-card">
<div class="defense-header">
<span class="defense-icon">🔒</span>
<div>
<h4>Enable Stack Policies</h4>
<p>Prevent updates to critical resources like IAM roles and security groups within stacks.</p>
<pre><code>aws cloudformation set-stack-policy --stack-name Prod \\
--stack-policy-body '{"Statement":[{"Effect":"Deny","Action":"Update:*","Principal":"*","Resource":"LogicalResourceId/AdminRole"}]}'</code></pre>
</div>
</div>
</div>
<div class="defense-card">
<div class="defense-header">
<span class="defense-icon">🔍</span>
<div>
<h4>Template Scanning</h4>
<p>Scan templates with cfn-lint, cfn-nag, or Checkov before deployment to catch secrets and misconfigurations.</p>
<pre><code>cfn_nag_scan --input-path template.yaml</code></pre>
</div>
</div>
</div>
<div class="defense-card">
<div class="defense-header">
<span class="defense-icon">🛡️</span>
<div>
<h4>Enable Termination Protection</h4>
<p>Prevent accidental or malicious deletion of critical stacks.</p>
<pre><code>aws cloudformation update-termination-protection \\
--enable-termination-protection \\
--stack-name ProductionStack</code></pre>
</div>
</div>
</div></div></div>
<!-- Footer -->
<div class="footer">
<p>AWS CloudFormation Security Card</p>
<p style="margin-top:0.25rem;">Always obtain proper authorization before testing</p>
</div>
</body>
</html>