deploy-stack 0.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deploy-stack",
3
- "version": "0.5.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": {
@@ -261,6 +261,11 @@ export async function mainStack() {
261
261
  outro(`
262
262
  ${color.green('✅ Project provisioned successfully!')}
263
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
+
264
269
  ${frameworkWarnings}
265
270
 
266
271
  Next steps:
@@ -96,4 +96,15 @@ Make sure your app is configured correctly:
96
96
 
97
97
  If you are deploying a static site, your application is served via a highly optimized, unprivileged Nginx container.
98
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.
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
  }