-
Notifications
You must be signed in to change notification settings - Fork 2
230 lines (202 loc) · 7.48 KB
/
docker-security-scan.yml
File metadata and controls
230 lines (202 loc) · 7.48 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
name: Docker Security Scan
on:
push:
branches: [main, develop]
paths:
- "docker/**"
- "templates/docker-compose/**"
- ".github/workflows/docker-security-scan.yml"
pull_request:
paths:
- "docker/**"
- "templates/docker-compose/**"
- ".github/workflows/docker-security-scan.yml"
# Scheduled scans are important because new CVEs appear
# even if the code or images didn’t change
schedule:
- cron: "0 6 * * *" # Daily at 6 AM UTC
workflow_dispatch:
jobs:
scan-project-images:
name: Scan Project-Built Docker Images
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
strategy:
fail-fast: false
matrix:
image:
- dockerfile: docker/deployer/Dockerfile
context: .
name: deployer
- dockerfile: docker/provisioned-instance/Dockerfile
context: docker/provisioned-instance
name: provisioned-instance
- dockerfile: docker/ssh-server/Dockerfile
context: docker/ssh-server
name: ssh-server
steps:
- name: Checkout code
uses: actions/checkout@v4
# Build images locally so Trivy scans exactly
# what this repository produces
- name: Build Docker image
run: |
docker build \
-t torrust-tracker-deployer/${{ matrix.image.name }}:latest \
-f ${{ matrix.image.dockerfile }} \
.
# Human-readable output in logs
# This NEVER fails the job; it’s only for visibility
- name: Display vulnerabilities (table format)
uses: aquasecurity/trivy-action@0.33.1
with:
image-ref: torrust-tracker-deployer/${{ matrix.image.name }}:latest
format: "table"
severity: "HIGH,CRITICAL"
exit-code: "0"
# SARIF generation for GitHub Code Scanning
#
# IMPORTANT:
# - exit-code MUST be 0
# - Trivy sometimes exits with 1 even when no vulns exist
# - GitHub Security UI is responsible for enforcement
- name: Generate SARIF (Code Scanning)
uses: aquasecurity/trivy-action@0.33.1
with:
image-ref: torrust-tracker-deployer/${{ matrix.image.name }}:latest
format: "sarif"
output: "trivy-${{ matrix.image.name }}.sarif"
severity: "HIGH,CRITICAL"
exit-code: "0"
scanners: "vuln"
- name: Upload SARIF artifact
uses: actions/upload-artifact@v4
if: always()
with:
name: sarif-project-${{ matrix.image.name }}-${{ github.run_id }}
path: trivy-${{ matrix.image.name }}.sarif
retention-days: 30
scan-third-party-images:
name: Scan Third-Party Docker Images
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
strategy:
fail-fast: false
matrix:
# These must match docker-compose templates
# in templates/docker-compose/docker-compose.yml.tera
image:
- torrust/tracker:develop
- mysql:8.0
- grafana/grafana:11.4.0
- prom/prometheus:v3.0.1
- caddy:2.10
steps:
- name: Display vulnerabilities (table format)
uses: aquasecurity/trivy-action@0.33.1
with:
image-ref: ${{ matrix.image }}
format: "table"
severity: "HIGH,CRITICAL"
exit-code: "0"
# Third-party images should NEVER block CI.
# We only report findings to GitHub Security.
- name: Generate SARIF (Code Scanning)
uses: aquasecurity/trivy-action@0.33.1
with:
image-ref: ${{ matrix.image }}
format: "sarif"
output: "trivy.sarif"
severity: "HIGH,CRITICAL"
exit-code: "0"
scanners: "vuln"
# Needed to produce stable artifact names
- name: Sanitize image name
id: sanitize
run: |
echo "name=$(echo '${{ matrix.image }}' | tr '/:' '-')" >> "$GITHUB_OUTPUT"
- name: Upload SARIF artifact
uses: actions/upload-artifact@v4
if: always()
with:
name: sarif-third-party-${{ steps.sanitize.outputs.name }}-${{ github.run_id }}
path: trivy.sarif
retention-days: 30
upload-sarif-results:
name: Upload SARIF Results to GitHub Security
runs-on: ubuntu-latest
needs:
- scan-project-images
- scan-third-party-images
# Always run so we don’t lose security visibility
if: always()
permissions:
security-events: write
steps:
- name: Download all SARIF artifacts
uses: actions/download-artifact@v4
with:
pattern: sarif-*-${{ github.run_id }}
# Upload each SARIF file with CodeQL Action using unique categories.
# The category parameter enables proper alert tracking per image.
# Must use CodeQL Action (not gh API) - API doesn't support category field.
#
# VIEWING RESULTS:
# - For pull requests: /security/code-scanning?query=pr:NUMBER+is:open
# - For branches: /security/code-scanning?query=is:open+branch:BRANCH-NAME
# - For main branch: /security/code-scanning?query=is:open+branch:main (default view)
# The default Security tab filters by "is:open branch:main" which only shows
# alerts from the main branch, not from PR branches.
- name: Upload project provisioned-instance SARIF
if: always()
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: sarif-project-provisioned-instance-${{ github.run_id }}/trivy-provisioned-instance.sarif
category: docker-project-provisioned-instance
continue-on-error: true
- name: Upload project ssh-server SARIF
if: always()
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: sarif-project-ssh-server-${{ github.run_id }}/trivy-ssh-server.sarif
category: docker-project-ssh-server
continue-on-error: true
- name: Upload third-party mysql SARIF
if: always()
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: sarif-third-party-mysql-8.0-${{ github.run_id }}/trivy.sarif
category: docker-third-party-mysql-8.0
continue-on-error: true
- name: Upload third-party tracker SARIF
if: always()
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: sarif-third-party-torrust-tracker-develop-${{ github.run_id }}/trivy.sarif
category: docker-third-party-torrust-tracker-develop
continue-on-error: true
- name: Upload third-party grafana SARIF
if: always()
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: sarif-third-party-grafana-grafana-11.4.0-${{ github.run_id }}/trivy.sarif
category: docker-third-party-grafana-grafana-11.4.0
continue-on-error: true
- name: Upload third-party prometheus SARIF
if: always()
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: sarif-third-party-prom-prometheus-v3.0.1-${{ github.run_id }}/trivy.sarif
category: docker-third-party-prom-prometheus-v3.0.1
continue-on-error: true
- name: Upload third-party caddy SARIF
if: always()
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: sarif-third-party-caddy-2.10-${{ github.run_id }}/trivy.sarif
category: docker-third-party-caddy-2.10
continue-on-error: true