Baseline untested container for scanning and reporting on diffs from trivy scans on target hosts on a schedule.
This commit is contained in:
parent
3c0d12b225
commit
b38983d166
|
@ -0,0 +1,144 @@
|
||||||
|
labels:
|
||||||
|
hostname: "macmini7"
|
||||||
|
clone:
|
||||||
|
git:
|
||||||
|
image: woodpeckerci/plugin-git
|
||||||
|
settings:
|
||||||
|
partial: false
|
||||||
|
depth: 1
|
||||||
|
steps:
|
||||||
|
# Build Step for staging Branch
|
||||||
|
build-staging:
|
||||||
|
name: build-staging
|
||||||
|
image: woodpeckerci/plugin-docker-buildx
|
||||||
|
secrets: [REGISTRY_USER, REGISTRY_PASSWORD]
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
commands:
|
||||||
|
- echo "Building application for staging branch"
|
||||||
|
- echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us
|
||||||
|
- echo compose build
|
||||||
|
- docker compose -f docker-compose.staging.yml build
|
||||||
|
when:
|
||||||
|
branch: main
|
||||||
|
event: push
|
||||||
|
# path:
|
||||||
|
# include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ]
|
||||||
|
|
||||||
|
deploy-new:
|
||||||
|
name: deploy-new
|
||||||
|
when:
|
||||||
|
branch: main
|
||||||
|
# path:
|
||||||
|
# include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ]
|
||||||
|
image: woodpeckerci/plugin-docker-buildx
|
||||||
|
secrets: [REGISTRY_USER, REGISTRY_PASSWORD]
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
commands:
|
||||||
|
- echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us
|
||||||
|
- echo compose push
|
||||||
|
- docker compose -f docker-compose.staging.yml push
|
||||||
|
# - docker stack deploy --with-registry-auth -c ./stack.staging.yml $${CI_REPO_NAME}-staging
|
||||||
|
|
||||||
|
# # Wait for Deploy to Complete
|
||||||
|
# wait-for-deploy-staging:
|
||||||
|
# name: wait-for-deploy-staging
|
||||||
|
# image: woodpeckerci/plugin-git
|
||||||
|
# commands:
|
||||||
|
# - echo "Waiting for staging deploy step to complete rollout."
|
||||||
|
# - sleep 60
|
||||||
|
# when:
|
||||||
|
# - branch: main
|
||||||
|
# - event: push
|
||||||
|
|
||||||
|
# # Run Automated Tests on staging Branch
|
||||||
|
# test-staging:
|
||||||
|
# name: run-tests-staging
|
||||||
|
# image: git.nixc.us/colin/playwright:latest
|
||||||
|
# secrets: [ base_url ]
|
||||||
|
# when:
|
||||||
|
# - branch: main
|
||||||
|
# - event: push
|
||||||
|
# - path:
|
||||||
|
# include: [ 'tests/', 'src/','docker-compose.staging.yml', 'docker-compose.production.yml', '*.tests.ts' ] # Specify paths relevant to tests
|
||||||
|
# volumes:
|
||||||
|
# - /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
|
||||||
|
cleanup-staging:
|
||||||
|
name: cleanup-staging
|
||||||
|
when:
|
||||||
|
branch: main
|
||||||
|
# path:
|
||||||
|
# include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ]
|
||||||
|
image: woodpeckerci/plugin-docker-buildx
|
||||||
|
secrets: [REGISTRY_USER, REGISTRY_PASSWORD]
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
commands:
|
||||||
|
# - docker stack rm $${CI_REPO_NAME}-staging
|
||||||
|
## added fault tolerance for docker stack rm
|
||||||
|
# - for i in {1..5}; do docker stack rm ${CI_REPO_NAME}-staging && break || sleep 10; done
|
||||||
|
- docker compose -f docker-compose.staging.yml down
|
||||||
|
- docker compose -f docker-compose.staging.yml rm -f
|
||||||
|
|
||||||
|
# Build Step for staging Branch
|
||||||
|
build-build-push-production:
|
||||||
|
name: build-build-push-production
|
||||||
|
image: woodpeckerci/plugin-docker-buildx
|
||||||
|
secrets: [REGISTRY_USER, REGISTRY_PASSWORD]
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
commands:
|
||||||
|
- echo "Building application for staging branch"
|
||||||
|
- echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us
|
||||||
|
- echo compose build
|
||||||
|
- docker compose -f docker-compose.production.yml build --no-cache
|
||||||
|
- docker compose -f docker-compose.production.yml push
|
||||||
|
when:
|
||||||
|
branch: main
|
||||||
|
event: [push, cron]
|
||||||
|
# path:
|
||||||
|
# include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ]
|
||||||
|
|
||||||
|
# Deploy to Production Branch
|
||||||
|
deploy-production:
|
||||||
|
name: deploy-production
|
||||||
|
image: woodpeckerci/plugin-docker-buildx
|
||||||
|
secrets: [REGISTRY_USER, REGISTRY_PASSWORD]
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
commands:
|
||||||
|
- echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us
|
||||||
|
# - docker stack deploy --with-registry-auth -c ./stack.production.yml $${CI_REPO_NAME}
|
||||||
|
- docker image rm git.nixc.us/colin/$${CI_REPO_NAME}:production
|
||||||
|
when:
|
||||||
|
branch: main
|
||||||
|
event: [push, cron]
|
||||||
|
# path:
|
||||||
|
# include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ]
|
||||||
|
|
||||||
|
|
||||||
|
# # Wait for Deploy to Complete
|
||||||
|
# wait-for-deploy-production:
|
||||||
|
# name: wait-for-deploy-production
|
||||||
|
# image: woodpeckerci/plugin-git
|
||||||
|
# commands:
|
||||||
|
# - echo "Waiting for deploy step to complete rollout."
|
||||||
|
# - sleep 60
|
||||||
|
# when:
|
||||||
|
# branch: main
|
||||||
|
# event: push
|
||||||
|
|
||||||
|
# # Run Post-Deployment Smoke Tests
|
||||||
|
# post-deploy-smoke-tests-git-nixc-us:
|
||||||
|
# name: run-post-deploy-smoke-tests-git-nixc-us
|
||||||
|
# image: git.nixc.us/colin/playwright:latest
|
||||||
|
# # secrets: [TEST_USER, TEST_PASSWORD]
|
||||||
|
# environment:
|
||||||
|
# - BASE_URL=https://git.nixc.us
|
||||||
|
# when:
|
||||||
|
# branch: main
|
||||||
|
# event: push
|
||||||
|
# # path:
|
||||||
|
# # include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ]
|
|
@ -0,0 +1,95 @@
|
||||||
|
<!-- # build:0 -->
|
||||||
|
# Known Weaknesses and Caveats
|
||||||
|
While this Trivy container is built with reliability in mind, it's important to note that it primarily focuses on scanning and reporting. There isn't an advanced validation mechanism beyond ensuring that the container builds and runs the scans correctly. Future improvements include more robust testing and validation measures.
|
||||||
|
|
||||||
|
## ToDo
|
||||||
|
|
||||||
|
* [ ] Implement more comprehensive testing beyond basic functionality.
|
||||||
|
* [ ] Integrate safe testing with known vulnerable files for end-to-end testing.
|
||||||
|
* [ ] Develop a consistent reporting system for scan results.
|
||||||
|
* [ ] Experiment with and test quarantine measures for identified vulnerabilities.
|
||||||
|
|
||||||
|
## Disclaimer
|
||||||
|
|
||||||
|
Understanding the scope and limitations of a vulnerability scanner like Trivy is crucial. A Trivy scan aims to increase observability and enable actions on detectable vulnerabilities, not guarantee future system security. Positive detections should prompt IT staff to consider appropriate remediation steps.
|
||||||
|
|
||||||
|
## Considerations
|
||||||
|
|
||||||
|
Trivy, running as a Docker container, offers a certain level of security and obscurity. Its cryptographic signature and isolation from typical user space make it a less likely target for tampering by advanced attackers. While it includes a mode for potential quarantine actions, this feature is more theoretical. It has yet to be extensively tested in its current form. Users should exercise caution and use scan logs as a guide for manual file handling if necessary.
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
Create a directory for the Trivy container configuration:
|
||||||
|
```
|
||||||
|
mkdir -p /root/trivy/
|
||||||
|
```
|
||||||
|
Then edit the Docker Compose file:
|
||||||
|
```
|
||||||
|
nano /root/trivy/docker-compose.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment Variables and Defaults
|
||||||
|
|
||||||
|
| Variable | Description | Default Value |
|
||||||
|
|----------------|----------------------------------------------|------------------------|
|
||||||
|
| `TIMEOUT` | Maximum duration for a scan | `120m` |
|
||||||
|
| `SCANNERS` | Scanners to be used | `vuln,misconfig,secret`|
|
||||||
|
| `IGNORE_UNFIXED`| Whether to ignore vulnerabilities without fixes | `false` |
|
||||||
|
| `LOW_PRIORITY` | Run scans with low CPU priority (nice 19) | `true` |
|
||||||
|
|
||||||
|
### Note:
|
||||||
|
By default, the container assumes a low-priority mode for scanning if the `LOW_PRIORITY` environment variable is not explicitly set.
|
||||||
|
|
||||||
|
## docker-compose.yml
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
trivy:
|
||||||
|
image: aquasec/trivy
|
||||||
|
volumes:
|
||||||
|
- /:/mnt:ro
|
||||||
|
- ./logs:/var/log/trivy
|
||||||
|
# Uncomment and modify the following lines to customize environment variables
|
||||||
|
# environment:
|
||||||
|
# TIMEOUT: "120m" # Default scan timeout
|
||||||
|
# SCANNERS: "vuln,misconfig,secret" # Scanners to be used
|
||||||
|
# IGNORE_UNFIXED: "false" # Whether to ignore unfixed vulnerabilities
|
||||||
|
# LOW_PRIORITY: "true" # Run scans with low CPU priority
|
||||||
|
```
|
||||||
|
|
||||||
|
Schedule regular scans using crontab:
|
||||||
|
```
|
||||||
|
crontab -e
|
||||||
|
```
|
||||||
|
Then add one of the following cron examples.
|
||||||
|
|
||||||
|
### Once a Week
|
||||||
|
|
||||||
|
To run the job every Sunday at midnight:
|
||||||
|
|
||||||
|
```cron
|
||||||
|
0 0 * * 0 /usr/bin/docker compose -f /root/trivy/docker-compose.yml up -d --pull --force-recreate trivy
|
||||||
|
```
|
||||||
|
|
||||||
|
### Once Every Two Weeks
|
||||||
|
|
||||||
|
For a bi-weekly schedule, specify two days of the month, like the 1st and 15th:
|
||||||
|
|
||||||
|
```cron
|
||||||
|
0 0 1,15 * * /usr/bin/docker compose -f /root/trivy/docker-compose.yml up -d --pull --force-recreate trivy
|
||||||
|
```
|
||||||
|
|
||||||
|
### Once a Month
|
||||||
|
|
||||||
|
To run the job on the first day of every month at midnight:
|
||||||
|
|
||||||
|
```cron
|
||||||
|
0 0 1 * * /usr/bin/docker compose -f /root/trivy/docker-compose.yml up -d --pull --force-recreate trivy
|
||||||
|
```
|
||||||
|
|
||||||
|
### Notes:
|
||||||
|
|
||||||
|
- Verify that `/usr/bin/docker` is the correct path to your Docker binary. This path might vary.
|
||||||
|
- Replace `/root/trivy` with the directory path where your `docker-compose.yml` file is located.
|
||||||
|
- The cron jobs will update the `trivy` container according to the specified schedule. Ensure this aligns with your maintenance and update policies.
|
|
@ -0,0 +1,8 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
trivy:
|
||||||
|
build:
|
||||||
|
context: ./docker/trivy/
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: git.nixc.us/colin/trivy:production
|
|
@ -0,0 +1,8 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
trivy:
|
||||||
|
build:
|
||||||
|
context: ./docker/trivy/
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: git.nixc.us/colin/trivy:staging
|
|
@ -1,9 +0,0 @@
|
||||||
FROM alpine:latest
|
|
||||||
RUN apk add --no-cache clamav clamav-libunrar
|
|
||||||
RUN freshclam
|
|
||||||
COPY docker-entrypoint.sh /usr/local/bin/
|
|
||||||
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
|
||||||
VOLUME ["/scan"]
|
|
||||||
VOLUME ["/quarantine"]
|
|
||||||
VOLUME ["/var/log/clamav"]
|
|
||||||
ENTRYPOINT ["docker-entrypoint.sh"]
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
FROM aquasec/trivy
|
||||||
|
WORKDIR /app
|
||||||
|
COPY start.sh /start.sh
|
||||||
|
RUN chmod +x /start.sh
|
||||||
|
ENTRYPOINT ["/bin/sh", "/start.sh"]
|
|
@ -0,0 +1,64 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
TIMEOUT=${TIMEOUT:-120m}
|
||||||
|
SCANNERS=${SCANNERS:-vuln,misconfig,secret}
|
||||||
|
IGNORE_UNFIXED=${IGNORE_UNFIXED:-false}
|
||||||
|
LOW_PRIORITY=${LOW_PRIORITY:-true}
|
||||||
|
|
||||||
|
compare_scans() {
|
||||||
|
echo "Comparing scans..."
|
||||||
|
PREVIOUS_LOG="/var/log/trivy/previous_scan.log"
|
||||||
|
CURRENT_LOG="/var/log/trivy/trivy_scan.log"
|
||||||
|
SCAN_DATE=$(date +%Y.%m.%d)
|
||||||
|
DIFF_LOG="/var/log/trivy/scandiff.$SCAN_DATE.log"
|
||||||
|
|
||||||
|
if [ -f "$PREVIOUS_LOG" ]; then
|
||||||
|
echo "Previous scan log found. Comparing with current scan..."
|
||||||
|
diff $PREVIOUS_LOG $CURRENT_LOG > $DIFF_LOG
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "No differences found between scans."
|
||||||
|
report_scan_results false
|
||||||
|
else
|
||||||
|
echo "Differences found. Check $DIFF_LOG for more details."
|
||||||
|
report_scan_results true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "No previous scan log found. Treating all findings as new."
|
||||||
|
cp $CURRENT_LOG $DIFF_LOG
|
||||||
|
report_scan_results true
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Archive current log as previous for next run
|
||||||
|
cp $CURRENT_LOG $PREVIOUS_LOG
|
||||||
|
}
|
||||||
|
|
||||||
|
report_scan_results() {
|
||||||
|
is_diff=$1
|
||||||
|
DIFF_LOG="/var/log/trivy/scandiff.$(date +%Y.%m.%d).log"
|
||||||
|
|
||||||
|
if [ "$is_diff" = true ]; then
|
||||||
|
echo "Scan differences detected:"
|
||||||
|
cat $DIFF_LOG
|
||||||
|
else
|
||||||
|
echo "No differences to report."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_scan() {
|
||||||
|
if [ "$LOW_PRIORITY" = "true" ]; then
|
||||||
|
echo "Running Trivy scan with low priority (nice 19)..."
|
||||||
|
nice -n 19 trivy filesystem --timeout $TIMEOUT --scanners $SCANNERS $( [ "$IGNORE_UNFIXED" = "true" ] && echo '--ignore-unfixed' ) /mnt > $CURRENT_LOG
|
||||||
|
else
|
||||||
|
echo "Running Trivy scan..."
|
||||||
|
trivy filesystem --timeout $TIMEOUT --scanners $SCANNERS $( [ "$IGNORE_UNFIXED" = "true" ] && echo '--ignore-unfixed' ) /mnt > $CURRENT_LOG
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Archive existing log for comparison
|
||||||
|
if [ -f "/var/log/trivy/trivy_scan.log" ]; then
|
||||||
|
mv /var/log/trivy/trivy_scan.log /var/log/trivy/previous_scan.log
|
||||||
|
fi
|
||||||
|
|
||||||
|
run_scan
|
||||||
|
compare_scans
|
Loading…
Reference in New Issue