deploy-stack 0.4.0 → 0.6.0

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 CHANGED
@@ -33,6 +33,8 @@ You retain complete ownership of your infrastructure code without relying on bla
33
33
  * **Remote State with Native S3 Locking:** Automatically creates an encrypted S3 state bucket utilizing modern native S3 concurrency locking.
34
34
  * **Built-in Secrets Sync:** Provides a dedicated CLI workflow to securely push local `.env` variables into AWS Secrets Manager and map them directly into containers at runtime.
35
35
  * **Non-Destructive:** Safely analyzes existing directories and prompts for confirmation before updating any files.
36
+ * **Zero-Config Detection:** Automatically resolves output directories for Vite, Astro, SvelteKit, CRA, and more.
37
+ * **Safe Teardown:** Completely remove all generated AWS resources and empty S3 state buckets with a single `destroy` command.
36
38
 
37
39
  ---
38
40
 
@@ -81,6 +83,12 @@ npx deploy-stack secrets push .env.production
81
83
 
82
84
  ---
83
85
 
86
+ ## šŸ—‘ļø Infrastructure Teardown
87
+ To safely completely remove your ECS cluster, load balancers, and empty the remote S3 state bucket, run:
88
+ `npx deploy-stack destroy`
89
+
90
+ ---
91
+
84
92
  ## šŸ“ Generated File Structure
85
93
 
86
94
  Running the CLI generates a modular architecture tailored to your service:
package/bin/cli.js CHANGED
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import path from 'path';
3
+ import { mainStack } from '../src/commands/init.js';
4
+ import { destroyStack } from '../src/commands/destroy.js';
3
5
  import { runDoctor } from '../src/commands/doctor.js';
4
6
  import { pushSecrets } from '../src/commands/secrets.js';
5
- import { mainStack } from '../src/commands/init.js';
6
7
 
7
8
  // 1. Extract the telemetry flag and set the environment variable
8
9
  const rawArgs = process.argv.slice(2);
@@ -22,6 +23,8 @@ if (args[0] === 'secrets' && args[1] === 'push') {
22
23
  pushSecrets(envFile, projectName).catch(console.error);
23
24
  } else if (args[0] === 'doctor') {
24
25
  runDoctor().catch(console.error);
26
+ } else if (args[0] === 'destroy') {
27
+ destroyStack().catch(console.error);
25
28
  } else {
26
29
  mainStack().catch(console.error);
27
30
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deploy-stack",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Provision production-ready AWS infrastructure and CI/CD pipelines in seconds.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,77 @@
1
+ import fsSync from 'fs';
2
+ import path from 'path';
3
+ import { intro, outro, confirm, spinner, cancel } from '@clack/prompts';
4
+ import color from 'picocolors';
5
+ import { execSync } from 'child_process';
6
+ import { teardownStateBucket } from '../utils/aws.js';
7
+ import { checkDependency } from '../utils/system.js';
8
+ import { trackEvent, flushTelemetry } from '../core/telemetry.js';
9
+
10
+ export async function destroyStack() {
11
+ intro(color.bgRed(color.white(' deploy-stack destroy šŸ—‘ļø ')));
12
+
13
+ const tfDirPath = path.join(process.cwd(), 'terraform');
14
+ const backendFilePath = path.join(tfDirPath, 'backend.tf');
15
+
16
+ if (!fsSync.existsSync(backendFilePath)) {
17
+ console.error(color.red('āœ– No terraform/backend.tf found in the current directory.'));
18
+ console.log(color.yellow('Are you in the root of a deploy-stack project?'));
19
+ process.exit(1);
20
+ }
21
+
22
+ const hasTerraform = await checkDependency('terraform');
23
+ if (!hasTerraform) {
24
+ console.error(color.red('āœ– Terraform is not installed.'));
25
+ process.exit(1);
26
+ }
27
+
28
+ const proceed = await confirm({
29
+ message: color.red('āš ļø WARNING: This will permanently destroy all AWS resources associated with this project. Are you absolutely sure?'),
30
+ initialValue: false,
31
+ });
32
+
33
+ if (!proceed) {
34
+ cancel('Destruction cancelled. Your infrastructure is safe.');
35
+ process.exit(0);
36
+ }
37
+
38
+ const s = spinner();
39
+
40
+ // 1. Extract Bucket and Region from backend.tf
41
+ const backendContent = fsSync.readFileSync(backendFilePath, 'utf-8');
42
+ const bucketMatch = backendContent.match(/bucket\s*=\s*"([^"]+)"/);
43
+ const regionMatch = backendContent.match(/region\s*=\s*"([^"]+)"/);
44
+
45
+ const bucketName = bucketMatch ? bucketMatch[1] : null;
46
+ const region = regionMatch ? regionMatch[1] : 'us-east-1';
47
+
48
+ // 2. Execute Terraform Destroy
49
+ console.log(color.cyan('\nInitiating Terraform destroy (this may take a few minutes)...\n'));
50
+ try {
51
+ execSync('terraform destroy -auto-approve', { cwd: tfDirPath, stdio: 'inherit' });
52
+ } catch (error) {
53
+ console.error(color.red('\nāœ– Terraform destroy failed. Please check the output above.'));
54
+ process.exit(1);
55
+ }
56
+
57
+ // 3. Clean up the S3 State Bucket
58
+ if (bucketName) {
59
+ s.start(`Emptying and deleting S3 state bucket: ${bucketName}...`);
60
+ try {
61
+ await teardownStateBucket(region, bucketName);
62
+ s.stop(`S3 bucket ${bucketName} successfully deleted.`);
63
+ } catch (error) {
64
+ s.stop(`āŒ Failed to delete S3 bucket. You may need to delete it manually in the AWS Console.`);
65
+ console.error(color.red(`AWS Error: ${error.message}`));
66
+ }
67
+ }
68
+
69
+ trackEvent('project_destroyed', {
70
+ region,
71
+ bucket: bucketName,
72
+ success: true
73
+ });
74
+ await flushTelemetry();
75
+
76
+ outro(color.green('āœ… Infrastructure successfully destroyed. Your AWS bill is safe.'));
77
+ }
@@ -232,6 +232,7 @@ export async function mainStack() {
232
232
  trackEvent('project_provisioned', {
233
233
  projectName: actualProjectName,
234
234
  framework: finalFramework,
235
+ specific_framework: detectedFramework?.name || finalFramework,
235
236
  region: project.region,
236
237
  size: project.size,
237
238
  setup_mode: setupType,
@@ -260,6 +261,11 @@ export async function mainStack() {
260
261
  outro(`
261
262
  ${color.green('āœ… Project provisioned successfully!')}
262
263
 
264
+ ${color.blue('šŸ›”ļø DevSecOps Enabled:')}
265
+ Automated Trivy vulnerability scanning for your Docker container
266
+ and Terraform has been added to your CI/CD pipeline.
267
+ Check the 'Summary' page of your GitHub Actions runs for reports.
268
+
263
269
  ${frameworkWarnings}
264
270
 
265
271
  Next steps:
package/src/utils/aws.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { STSClient, GetCallerIdentityCommand } from '@aws-sdk/client-sts';
2
- import { S3Client, CreateBucketCommand, PutBucketVersioningCommand } from '@aws-sdk/client-s3';
2
+ import { S3Client, CreateBucketCommand, PutBucketVersioningCommand, PutBucketTaggingCommand } from '@aws-sdk/client-s3';
3
+ import { DeleteBucketCommand, ListObjectVersionsCommand, DeleteObjectsCommand } from "@aws-sdk/client-s3";
3
4
 
4
5
  export async function provisionStateBucket(region, projectName) {
5
6
  const stsClient = new STSClient({ region });
@@ -23,6 +24,15 @@ export async function provisionStateBucket(region, projectName) {
23
24
  CreateBucketConfiguration: region === 'us-east-1' ? undefined : { LocationConstraint: region }
24
25
  }));
25
26
 
27
+ await s3Client.send(new PutBucketTaggingCommand({
28
+ Bucket: stateBucketName,
29
+ Tagging: {
30
+ TagSet: [
31
+ { Key: "ManagedBy", Value: "deploy-stack" }
32
+ ]
33
+ }
34
+ }));
35
+
26
36
  await s3Client.send(new PutBucketVersioningCommand({
27
37
  Bucket: stateBucketName,
28
38
  VersioningConfiguration: { Status: 'Enabled' }
@@ -35,4 +45,36 @@ export async function provisionStateBucket(region, projectName) {
35
45
  }
36
46
 
37
47
  return { awsAccountId, stateBucketName };
48
+ }
49
+
50
+ export async function teardownStateBucket(region, bucketName) {
51
+ const client = new S3Client({ region });
52
+
53
+ try {
54
+ // 1. Fetch all object versions and delete markers
55
+ const listCommand = new ListObjectVersionsCommand({ Bucket: bucketName });
56
+ const { Versions, DeleteMarkers } = await client.send(listCommand);
57
+
58
+ const objectsToDelete = [];
59
+ if (Versions) objectsToDelete.push(...Versions.map(v => ({ Key: v.Key, VersionId: v.VersionId })));
60
+ if (DeleteMarkers) objectsToDelete.push(...DeleteMarkers.map(v => ({ Key: v.Key, VersionId: v.VersionId })));
61
+
62
+ // 2. Delete all contents if any exist
63
+ if (objectsToDelete.length > 0) {
64
+ const deleteCommand = new DeleteObjectsCommand({
65
+ Bucket: bucketName,
66
+ Delete: { Objects: objectsToDelete }
67
+ });
68
+ await client.send(deleteCommand);
69
+ }
70
+
71
+ // 3. Delete the now-empty bucket
72
+ const deleteBucketCommand = new DeleteBucketCommand({ Bucket: bucketName });
73
+ await client.send(deleteBucketCommand);
74
+
75
+ return true;
76
+ } catch (error) {
77
+ if (error.name === 'NoSuchBucket') return true; // Already deleted
78
+ throw error;
79
+ }
38
80
  }
@@ -29,7 +29,7 @@ This infrastructure provisions a highly available Application Load Balancer (ALB
29
29
  ```
30
30
 
31
31
  3. **Automated CI/CD (Keyless via OIDC):**
32
- Push this repository to GitHub. Your deployment pipeline uses AWS IAM OpenID Connect (OIDC) to authenticate securely with temporary credentials—**no long-lived AWS secret keys are required in GitHub Secrets**. Every push to `main` will automatically build, package, and deploy your application.
32
+ Push this repository to GitHub. Your deployment pipeline uses AWS IAM OpenID Connect (OIDC) to authenticate securely with temporary credentials—**no long-lived AWS secret keys are required in GitHub Secrets**. Every push to `{{DEPLOY_BRANCH}}` will automatically build, package, and deploy your application.
33
33
 
34
34
  ### āš ļø Troubleshooting: OIDC Provider Already Exists
35
35
  AWS only permits one GitHub Actions OIDC provider per AWS account. If `terraform apply` fails with an `EntityAlreadyExists` error regarding the OIDC provider, it indicates GitHub Actions was previously configured in this account.
@@ -48,13 +48,11 @@ Re-run `terraform apply` to link directly to your existing provider.
48
48
 
49
49
  If you are done testing and want to stop all AWS billing, you must destroy the infrastructure.
50
50
 
51
- Because our Terraform configuration is set to force-delete the ECR image repository (even if images are present), teardown is a single, clean command:
52
-
51
+ Run the automated teardown command from the root of your project:
53
52
  ```bash
54
- cd terraform
55
- terraform destroy
53
+ npx deploy-stack destroy
56
54
  ```
57
- *Type `yes` when prompted. This will permanently delete the Load Balancer, ECS cluster, log groups, and associated networking components.*
55
+ *Type `yes` when prompted. This will execute a safe Terraform teardown of your Load Balancer, ECS cluster, and networking components, followed by automatically emptying and deleting your remote S3 state bucket.*
58
56
 
59
57
  ## āš ļø Critical Application Prerequisites
60
58
 
@@ -94,8 +92,19 @@ Make sure your app is configured correctly:
94
92
  * **Express.js:** `app.listen(port, '0.0.0.0', () => ...)`
95
93
  * **FastAPI:** `uvicorn.run(app, host="0.0.0.0", port=8000)`
96
94
 
97
- ### 4. Static Sites (Vite, Astro, React, Vue)
95
+ ### 4. Static Sites (Vite, Astro, React, Vue, SvelteKit)
98
96
 
99
97
  If you are deploying a static site, your application is served via a highly optimized, unprivileged Nginx container.
100
- 1. **Build Folder:** Different frameworks output compiled assets to different folders. Open your `Dockerfile` and ensure the `COPY --from=builder` command points to the correct folder (`dist`, `build`, or `out`).
101
- 2. **Health Checks:** You do not need to configure a custom `/health` route. Nginx will automatically return a `200 OK` when AWS pings the root `/` index page.
98
+ * **Zero-Config Build:** The CLI automatically detected your framework's output folder (`dist`, `build`, etc.) and pre-configured your Dockerfile.
99
+ * **Health Checks:** You do not need to configure a custom `/health` route. Nginx will automatically return a `200 OK` when AWS pings the root `/` index page.
100
+
101
+ ## šŸ›”ļø Security Scanning
102
+
103
+ This pipeline includes automated DevSecOps guardrails using [Trivy](https://trivy.dev/).
104
+ Every time you push code, the pipeline will scan both your Docker container and your
105
+ Terraform configurations for vulnerabilities and misconfigurations.
106
+
107
+ To view the security reports:
108
+ 1. Navigate to the **Actions** tab in GitHub.
109
+ 2. Click on the latest deployment run.
110
+ 3. Scroll down the **Summary** page to view the generated vulnerability tables.
@@ -21,10 +21,17 @@ ENV NODE_ENV=production
21
21
  ENV PORT={{PORT}}
22
22
  ENV HOSTNAME="0.0.0.0"
23
23
 
24
- # Copy the standalone output from the builder stage
25
- COPY --from=builder /app/.next/standalone ./
26
- COPY --from=builder /app/.next/static ./.next/static
27
- COPY --from=builder /app/public ./public
24
+ # Create an unprivileged user and group
25
+ RUN addgroup -g 1001 -S nodejs && \
26
+ adduser -S nextjs -u 1001 -G nodejs
27
+
28
+ # Copy the standalone output and assign ownership to the unprivileged user
29
+ COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
30
+ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
31
+ COPY --from=builder --chown=nextjs:nodejs /app/public ./public
32
+
33
+ # Switch to the unprivileged user before executing
34
+ USER nextjs
28
35
 
29
36
  EXPOSE {{PORT}}
30
37
 
@@ -5,16 +5,14 @@ ENV NODE_ENV=production
5
5
 
6
6
  WORKDIR /app
7
7
 
8
- # 2. Copy only dependency files first to cache the npm install layer
9
- COPY package*.json ./
8
+ # 2. Copy dependency manifests with non-root ownership
9
+ COPY --chown=node:node package*.json ./
10
+ RUN npm ci --omit=dev
10
11
 
11
- # 3. Use npm ci for strict, deterministic, and faster CI/CD installs
12
- RUN npm ci
12
+ # 3. Copy application code with non-root ownership
13
+ COPY --chown=node:node . .
13
14
 
14
- # 4. Copy the rest of the application source code
15
- COPY . .
16
-
17
- # 5. DevSecOps best practice: do not run the container as root
15
+ # 4. DevSecOps best practice: do not run the container as root
18
16
  USER node
19
17
 
20
18
  EXPOSE {{PORT}}
@@ -13,10 +13,8 @@ RUN adduser --disabled-password --gecos '' appuser
13
13
  COPY requirements.txt .
14
14
  RUN pip install --no-cache-dir -r requirements.txt
15
15
 
16
- COPY . .
17
-
18
- # Secure file permissions
19
- RUN chown -R appuser:appuser /app
16
+ # Copy with ownership
17
+ COPY --chown=appuser:appuser . .
20
18
 
21
19
  # Drop root privileges
22
20
  USER appuser
@@ -11,7 +11,7 @@ COPY . .
11
11
  RUN npm run build
12
12
 
13
13
  # STAGE 2: Serve with Hardened Nginx
14
- FROM nginx:alpine
14
+ FROM nginxinc/nginx-unprivileged:alpine
15
15
 
16
16
  # Adjusts BUILD_DIR to match your framework's output folder
17
17
  COPY --from=builder /app/{{BUILD_DIR}} /usr/share/nginx/html
@@ -28,18 +28,5 @@ RUN echo "server {" > /etc/nginx/conf.d/default.conf && \
28
28
  echo " }" >> /etc/nginx/conf.d/default.conf && \
29
29
  echo "}" >> /etc/nginx/conf.d/default.conf
30
30
 
31
- # Silence unprivileged user directive warning in main config
32
- RUN sed -i 's/^user\s\+nginx;/# user nginx;/' /etc/nginx/nginx.conf
33
-
34
- # DevSecOps Hardening: Drop root privileges for the Nginx process
35
- RUN chown -R nginx:nginx /usr/share/nginx/html && \
36
- chown -R nginx:nginx /var/cache/nginx && \
37
- chown -R nginx:nginx /var/log/nginx && \
38
- chown -R nginx:nginx /etc/nginx/conf.d && \
39
- touch /var/run/nginx.pid && \
40
- chown -R nginx:nginx /var/run/nginx.pid
41
-
42
- USER nginx
43
-
44
31
  EXPOSE {{PORT}}
45
32
  CMD ["nginx", "-g", "daemon off;"]
@@ -4,6 +4,8 @@ on:
4
4
  push:
5
5
  branches:
6
6
  - {{DEPLOY_BRANCH}}
7
+ schedule:
8
+ - cron: '0 0 * * 0'
7
9
 
8
10
  env:
9
11
  AWS_REGION: {{REGION}}
@@ -24,6 +26,29 @@ jobs:
24
26
  - name: Checkout Code
25
27
  uses: actions/checkout@v4
26
28
 
29
+ # --- 1. IaC SECURITY SCAN ---
30
+ - name: Scan Terraform for Misconfigurations
31
+ uses: aquasecurity/trivy-action@master
32
+ with:
33
+ scan-type: 'fs'
34
+ scan-ref: 'terraform/'
35
+ scanners: 'vuln,secret,misconfig'
36
+ format: 'table'
37
+ exit-code: '0' # Informational only, will not break the build
38
+ severity: 'CRITICAL,HIGH'
39
+ output: 'trivy-iac-summary.txt'
40
+
41
+ - name: Publish IaC Summary
42
+ if: always()
43
+ run: |
44
+ if [ -f trivy-iac-summary.txt ]; then
45
+ echo "### šŸ—ļø Terraform Misconfiguration Scan" >> $GITHUB_STEP_SUMMARY
46
+ echo '```' >> $GITHUB_STEP_SUMMARY
47
+ cat trivy-iac-summary.txt >> $GITHUB_STEP_SUMMARY
48
+ echo '```' >> $GITHUB_STEP_SUMMARY
49
+ fi
50
+
51
+ # --- 2. DEPLOYMENT PREP ---
27
52
  - name: Configure AWS Credentials
28
53
  uses: aws-actions/configure-aws-credentials@v4
29
54
  with:
@@ -34,13 +59,43 @@ jobs:
34
59
  id: login-ecr
35
60
  uses: aws-actions/amazon-ecr-login@v2
36
61
 
37
- - name: Build, tag, and push image to Amazon ECR
62
+ # --- 3. BUILD ---
63
+ - name: Build Docker image
38
64
  id: build-image
39
65
  env:
40
66
  ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
41
67
  IMAGE_TAG: latest
42
68
  run: |
43
69
  docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
70
+
71
+ # --- 4. CONTAINER SECURITY SCAN ---
72
+ - name: Scan Container for Vulnerabilities (SARIF Output)
73
+ uses: aquasecurity/trivy-action@master
74
+ with:
75
+ image-ref: '${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:latest'
76
+ format: 'table'
77
+ output: 'trivy-container-summary.txt'
78
+ exit-code: '0' # Informational only, will not break the build
79
+ ignore-unfixed: true
80
+ vuln-type: 'os,library'
81
+ severity: 'CRITICAL,HIGH'
82
+
83
+ - name: Publish Container Summary
84
+ if: always()
85
+ run: |
86
+ if [ -f trivy-container-summary.txt ]; then
87
+ echo "### šŸ›”ļø Container Security Scan Results" >> $GITHUB_STEP_SUMMARY
88
+ echo '```' >> $GITHUB_STEP_SUMMARY
89
+ cat trivy-container-summary.txt >> $GITHUB_STEP_SUMMARY
90
+ echo '```' >> $GITHUB_STEP_SUMMARY
91
+ fi
92
+
93
+ # --- 5. DEPLOY ---
94
+ - name: Push image to Amazon ECR
95
+ env:
96
+ ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
97
+ IMAGE_TAG: latest
98
+ run: |
44
99
  docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
45
100
  echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
46
101
 
@@ -8,6 +8,7 @@ data "aws_cloudfront_origin_request_policy" "all_viewer" {
8
8
  name = "Managed-AllViewerExceptHostHeader"
9
9
  }
10
10
 
11
+ # trivy:ignore:AVD-AWS-0011 - WAF is omitted by default to prevent unexpected monthly costs for users
11
12
  resource "aws_cloudfront_distribution" "cdn" {
12
13
  enabled = true
13
14
  is_ipv6_enabled = true
@@ -17,8 +17,13 @@ resource "aws_cloudwatch_log_group" "app_logs" {
17
17
  # --- ECR Repository ---
18
18
  resource "aws_ecr_repository" "app" {
19
19
  name = "{{PROJECT_NAME}}-repo"
20
+ # trivy:ignore:AVD-AWS-0031 - Mutable tags allow the CI/CD pipeline to reuse the 'latest' tag for simplified deployments
20
21
  image_tag_mutability = "MUTABLE"
21
22
  force_delete = true
23
+
24
+ image_scanning_configuration {
25
+ scan_on_push = true
26
+ }
22
27
  }
23
28
 
24
29
  # --- IAM: Execution Role ---
@@ -100,11 +105,13 @@ resource "aws_ecs_task_definition" "app" {
100
105
  }
101
106
 
102
107
  # --- Application Load Balancer ---
108
+ # trivy:ignore:AVD-AWS-0053 - This ALB is intended to be publicly facing behind CloudFront
103
109
  resource "aws_lb" "main" {
104
110
  name = "{{PROJECT_NAME}}-alb"
105
111
  load_balancer_type = "application"
106
112
  security_groups = [aws_security_group.alb.id]
107
113
  subnets = aws_subnet.public[*].id
114
+ drop_invalid_header_fields = true
108
115
  }
109
116
 
110
117
  resource "aws_lb_target_group" "app" {
@@ -124,6 +131,7 @@ resource "aws_lb_target_group" "app" {
124
131
  }
125
132
  }
126
133
 
134
+ # trivy:ignore:AVD-AWS-0054 - CloudFront handles HTTPS edge termination; ALB uses HTTP to avoid complex ACM DNS validation for users
127
135
  resource "aws_lb_listener" "http" {
128
136
  load_balancer_arn = aws_lb.main.arn
129
137
  port = "80"
@@ -19,6 +19,7 @@ resource "aws_internet_gateway" "main" {
19
19
  }
20
20
 
21
21
  # Create 2 Public Subnets
22
+ # trivy:ignore:AVD-AWS-0164 - Public subnets are used to avoid the $30/mo cost of a NAT Gateway for outbound container traffic
22
23
  resource "aws_subnet" "public" {
23
24
  count = 2
24
25
  vpc_id = aws_vpc.main.id
@@ -64,6 +65,7 @@ resource "aws_security_group" "alb" {
64
65
  from_port = 0
65
66
  to_port = 0
66
67
  protocol = "-1"
68
+ # trivy:ignore:AVD-AWS-0104 - Allow ALB to route out to standard AWS services
67
69
  cidr_blocks = ["0.0.0.0/0"]
68
70
  }
69
71
  }
@@ -85,6 +87,7 @@ resource "aws_security_group" "ecs_tasks" {
85
87
  from_port = 0
86
88
  to_port = 0
87
89
  protocol = "-1"
90
+ # trivy:ignore:AVD-AWS-0104 - Allow containers to pull images and hit external APIs
88
91
  cidr_blocks = ["0.0.0.0/0"]
89
92
  }
90
93
  }