diff --git a/.github/workflows/docker-security-scan.yml b/.github/workflows/docker-security-scan.yml index a31ca8b..8ad990d 100644 --- a/.github/workflows/docker-security-scan.yml +++ b/.github/workflows/docker-security-scan.yml @@ -31,9 +31,15 @@ on: required: false type: number default: 1 + upload_sarif: + description: 'Upload SARIF results to GitHub Security tab' + required: false + type: boolean + default: true permissions: contents: read + security-events: write jobs: scan: @@ -63,6 +69,7 @@ jobs: cache-to: type=gha,mode=max - name: Run Trivy vulnerability scanner + id: scan uses: aquasecurity/trivy-action@v0.36.0 with: image-ref: '${{ inputs.image_name }}:scan' @@ -70,3 +77,26 @@ jobs: exit-code: '${{ inputs.exit_code }}' severity: '${{ inputs.severity }}' ignore-unfixed: true + continue-on-error: true + + - name: Generate SARIF report + if: inputs.upload_sarif + uses: aquasecurity/trivy-action@v0.36.0 + with: + image-ref: '${{ inputs.image_name }}:scan' + format: 'sarif' + output: 'results.sarif' + severity: '${{ inputs.severity }}' + ignore-unfixed: true + + - name: Upload SARIF to GitHub Security tab + if: inputs.upload_sarif && hashFiles('results.sarif') != '' + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: results.sarif + category: trivy-docker-${{ inputs.image_name }} + continue-on-error: true + + - name: Fail if vulnerabilities found + if: steps.scan.outcome == 'failure' + run: exit 1 diff --git a/.github/workflows/ecr-security-scan.yml b/.github/workflows/ecr-security-scan.yml index ed695f5..d5b5322 100644 --- a/.github/workflows/ecr-security-scan.yml +++ b/.github/workflows/ecr-security-scan.yml @@ -17,6 +17,11 @@ on: required: false type: string default: 'CRITICAL,HIGH' + upload_sarif: + description: 'Upload SARIF results to GitHub Security tab' + required: false + type: boolean + default: true secrets: aws_role_arn: description: 'AWS IAM Role ARN for OIDC authentication' @@ -28,6 +33,7 @@ on: permissions: id-token: write contents: read + security-events: write jobs: scan: @@ -88,6 +94,11 @@ jobs: # Run Trivy and capture output RESULT=$(trivy image --severity "${SEVERITY}" --ignore-unfixed --format json "${FULL_IMAGE}" 2>/dev/null || echo "{}") + if [ "${{ inputs.upload_sarif }}" == "true" ]; then + mkdir -p sarif-results + trivy image --severity "${SEVERITY}" --ignore-unfixed --format sarif --output "sarif-results/${IMAGE_NAME}.sarif" "${FULL_IMAGE}" 2>/dev/null || true + fi + # Count vulnerabilities CRITICAL=$(echo "$RESULT" | jq '[.Results[]?.Vulnerabilities[]? | select(.Severity == "CRITICAL")] | length' 2>/dev/null || echo "0") HIGH=$(echo "$RESULT" | jq '[.Results[]?.Vulnerabilities[]? | select(.Severity == "HIGH")] | length' 2>/dev/null || echo "0") @@ -106,6 +117,14 @@ jobs: REPORT_ESCAPED=$(echo -e "$REPORT" | sed 's/"/\\"/g' | tr '\n' '|' | sed 's/|/\\n/g') echo "report=${REPORT_ESCAPED}" >> "$GITHUB_OUTPUT" + - name: Upload SARIF to GitHub Security tab + if: inputs.upload_sarif && hashFiles('sarif-results/') != '' + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: sarif-results/ + category: trivy-ecr + continue-on-error: true + - name: Send Slack alert if: steps.scan.outputs.vulnerabilities_found == 'true' run: | diff --git a/README.md b/README.md index 7ed11b8..a106048 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ with: ### docker-security-scan -Scans Docker images for security vulnerabilities using Trivy before deployment. Builds the image locally and checks for known CVEs with configurable severity thresholds. Use this in CI pipelines to prevent deploying vulnerable containers. +Scans Docker images for security vulnerabilities using Trivy before deployment. Builds the image locally and checks for known CVEs with configurable severity thresholds. Generates SARIF reports for the GitHub Security tab. Use this in CI pipelines to prevent deploying vulnerable containers. **Inputs** @@ -135,6 +135,7 @@ Scans Docker images for security vulnerabilities using Trivy before deployment. | severity | Minimum severity to report (CRITICAL,HIGH,MEDIUM,LOW) | No | CRITICAL,HIGH | | build_args | Docker build arguments (multiline, one per line: KEY=VALUE) | No | '' | | exit_code | Exit code when vulnerabilities are found (0 to not fail) | No | 1 | +| upload_sarif | Upload SARIF results to GitHub Security tab | No | true | **Secrets required** - None @@ -151,11 +152,12 @@ with: build_args: | NODE_VERSION=20 BUILD_ENV=production + upload_sarif: true ``` ### ecr-security-scan -Scans published ECR images for vulnerabilities on a schedule or manually. Finds the latest semver tag for each specified image, scans for critical/high vulnerabilities, and sends Slack alerts if issues are found. Use this for continuous security monitoring of production images. +Scans published ECR images for vulnerabilities on a schedule or manually. Finds the latest semver tag for each specified image, scans for critical/high vulnerabilities, sends Slack alerts if issues are found, and generates SARIF reports for the GitHub Security tab. Use this for continuous security monitoring of production images. **Inputs** @@ -164,6 +166,7 @@ Scans published ECR images for vulnerabilities on a schedule or manually. Finds | image_names | JSON array of image names to scan (e.g., ["k8s-logs-controller", "k8s-traffic-manager"]) | Yes | - | | ecr_registry | ECR registry URL | No | public.ecr.aws/nullplatform | | severity | Minimum severity to report (CRITICAL,HIGH,MEDIUM,LOW) | No | CRITICAL,HIGH | +| upload_sarif | Upload SARIF results to GitHub Security tab | No | true | **Secrets required** - `aws_role_arn`: AWS IAM Role ARN for OIDC authentication @@ -177,6 +180,7 @@ with: image_names: '["my-app", "my-worker"]' ecr_registry: 'public.ecr.aws/myorg' severity: 'CRITICAL,HIGH' + upload_sarif: true secrets: aws_role_arn: ${{ secrets.AWS_ROLE_ARN }} slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}