File size: 6,655 Bytes
7c19d46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# =============================================================================
# GitHub Actions — Full DevSecOps Pipeline
# =============================================================================
# Stages: SAST → Build → Scan → Test → Sign → Deploy
# =============================================================================

name: DevSecOps Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  REGISTRY: ecr.aws/devsecops
  IMAGE_NAME: ${{ github.repository }}

permissions:
  id-token: write
  contents: read
  security-events: write

jobs:
  # =========================================================================
  # Stage 1: SAST + Secret Scanning
  # =========================================================================
  sast:
    name: SAST & Secret Scan
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Semgrep SAST
        uses: semgrep/semgrep-action@v1
        with:
          config: >-
            p/security-audit
            p/secrets
            p/owasp-top-ten
          publishToken: ${{ secrets.SEMGREP_TOKEN }}

      - name: Trivy Secret Scan
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: fs
          scanners: secret
          exit-code: 1
          severity: CRITICAL,HIGH

      - name: Checkov IaC Scan
        uses: bridgecrewio/checkov-action@master
        with:
          directory: terraform/
          framework: terraform
          output_format: sarif
          output_file: checkov.sarif
          soft_fail: false

      - name: Upload SARIF
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: .

  # =========================================================================
  # Stage 2: Build
  # =========================================================================
  build:
    name: Build & Push
    needs: sast
    runs-on: ubuntu-latest
    outputs:
      image_tag: ${{ steps.meta.outputs.tags }}
      image_digest: ${{ steps.build.outputs.digest }}
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          role-session-name: github-actions
          aws-region: us-east-1

      - name: Login to ECR
        uses: aws-actions/amazon-ecr-login@v2

      - name: Docker Meta
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=sha,prefix=
            type=ref,event=branch
            type=semver,pattern={{version}}

      - name: Build
        id: build
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
          build-args: |
            BUILD_DATE=${{ github.event.head_commit.timestamp }}

  # =========================================================================
  # Stage 3: Container Security Scan
  # =========================================================================
  scan:
    name: Container Security Scan
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Trivy Vulnerability Scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: ${{ needs.build.outputs.image_tag }}
          format: sarif
          output: trivy.sarif
          exit-code: 1
          severity: CRITICAL,HIGH
          ignore-unfixed: true

      - name: Generate SBOM
        uses: anchore/sbom-action@v0
        with:
          image: ${{ needs.build.outputs.image_tag }}
          format: spdx-json
          output-file: sbom.spdx.json

      - name: Upload SBOM
        uses: actions/upload-artifact@v4
        with:
          name: sbom
          path: sbom.spdx.json

  # =========================================================================
  # Stage 4: Integration Tests + DAST
  # =========================================================================
  test:
    name: Integration Test & DAST
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run Integration Tests
        run: |
          docker compose -f docker-compose.test.yml up --abort-on-container-exit

      - name: OWASP ZAP Full Scan
        uses: zaproxy/action-full-scan@v0.10.0
        with:
          target: https://staging.platform.internal
          rules_file_name: zap-rules.tsv
          cmd_options: '-a -j'
          fail_action: true

  # =========================================================================
  # Stage 5: Sign & Attest
  # =========================================================================
  sign:
    name: Sign & Attest
    needs: [build, scan]
    runs-on: ubuntu-latest
    steps:
      - name: Cosign Install
        uses: sigstore/cosign-installer@v3

      - name: Sign Image
        run: |
          cosign sign --yes ${{ needs.build.outputs.image_tag }}@${{ needs.build.outputs.image_digest }}

      - name: Attest SBOM
        run: |
          cosign attest --yes \
            --predicate sbom.spdx.json \
            --type spdxjson \
            ${{ needs.build.outputs.image_tag }}@${{ needs.build.outputs.image_digest }}

  # =========================================================================
  # Stage 6: Deploy (ArgoCD Sync)
  # =========================================================================
  deploy-staging:
    name: Deploy → Staging
    needs: [sign, test]
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - name: Update Kustomize Image Tag
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          cd k8s/workloads/${{ matrix.workload }}
          kustomize edit set image ${{ env.IMAGE_NAME }}=${{ needs.build.outputs.image_tag }}
          git commit -am "chore: update image tag for staging"
          git push

      - name: ArgoCD Sync
        run: |
          argocd app sync staging-app --grpc-web

  deploy-prod:
    name: Deploy → Production
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: ArgoCD Sync
        run: |
          argocd app sync prod-app --grpc-web

      - name: Smoke Test
        run: |
          curl -sf https://platform.internal/healthz || exit 1