|
1 | 1 | --- |
2 | | -name: Trivy Security Scan with Security Hub Integration |
| 2 | +# This is a basic workflow to help you get started with Actions |
3 | 3 |
|
4 | | -'on': |
| 4 | +name: Trivy Scan |
| 5 | + |
| 6 | +# Controls when the action will run. Triggers the workflow on pull request |
| 7 | +# events but only for the develop branch |
| 8 | +on: # yamllint disable-line rule:truthy |
5 | 9 | push: |
6 | | - branches: [main] |
| 10 | + branches: |
| 11 | + - "**" # matches every branch |
| 12 | + - "!main" # excludes main |
7 | 13 | pull_request: |
8 | | - branches: [main] |
9 | | -permissions: |
10 | | - security-events: write |
11 | | - contents: read |
12 | | - id-token: write |
13 | | - actions: read |
| 14 | + branches: |
| 15 | + - main |
14 | 16 |
|
| 17 | +# A workflow run is made up of one or more jobs that can run sequentially or in parallel |
15 | 18 | jobs: |
16 | | - security-scan: |
17 | | - runs-on: ubuntu-latest |
18 | | - env: |
19 | | - AWS_REGION: ${{ secrets.AWS_REGION }} |
20 | | - AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }} |
21 | | - ECR_REPO: ${{ secrets.ECR_REPO }} |
22 | | - IMAGE_TAG: ${{ github.sha }} |
| 19 | + # This workflow contains a single job called "trivy" |
| 20 | + trivy: |
| 21 | + # The type of runner that the job will run on |
| 22 | + runs-on: [self-hosted, linux, codebuild] |
23 | 23 |
|
| 24 | + # Steps represent a sequence of tasks that will be executed as part of the job |
24 | 25 | steps: |
25 | | - - name: Checkout code |
26 | | - uses: actions/checkout@v4 |
| 26 | + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it |
| 27 | + - uses: actions/checkout@v3 |
27 | 28 |
|
28 | | - - name: Set up AWS credentials |
29 | | - uses: aws-actions/configure-aws-credentials@v4.0.2 |
| 29 | + - name: Run Trivy vulnerability scanner in repo mode |
| 30 | + uses: aquasecurity/trivy-action@0.28.0 |
30 | 31 | with: |
31 | | - aws-region: ${{ secrets.AWS_REGION }} |
32 | | - role-to-assume: ${{ secrets.AWS_ROLE_ARN }} |
33 | | - role-session-name: GitHubActions |
34 | | - |
35 | | - - name: Verify AWS credentials |
36 | | - run: | |
37 | | - aws sts get-caller-identity |
38 | | - echo "AWS credentials configured successfully" |
39 | | -
|
40 | | - - name: Build Docker image |
41 | | - run: docker build -t test-image:latest . |
42 | | - |
43 | | - - name: Run Trivy vulnerability scanner |
44 | | - uses: aquasecurity/trivy-action@0.30.0 |
45 | | - continue-on-error: true |
46 | | - with: |
47 | | - image-ref: test-image:latest |
48 | | - severity: HIGH,CRITICAL |
49 | | - exit-code: 1 |
50 | | - format: sarif |
51 | | - output: trivy-results.sarif |
52 | | - |
53 | | - - name: Generate Security Hub findings |
54 | | - if: always() |
55 | | - run: | |
56 | | - # Scan with JSON format first to get structured data |
57 | | - trivy image \ |
58 | | - --severity LOW,MEDIUM,HIGH,CRITICAL \ |
59 | | - --exit-code 0 \ |
60 | | - --format json \ |
61 | | - -o scan-results.json \ |
62 | | - test-image:latest |
63 | | -
|
64 | | - # Create ASFF findings using jq |
65 | | - cat scan-results.json | jq -r --arg account "$AWS_ACCOUNT_ID" --arg region "$AWS_REGION" ' |
66 | | - [ |
67 | | - .Results[]? | select(.Vulnerabilities) | .Vulnerabilities[] | { |
68 | | - "SchemaVersion": "2018-10-08", |
69 | | - "Id": ("trivy-" + .VulnerabilityID + "-" + (.PkgName // "unknown")), |
70 | | - "ProductArn": ("arn:aws:securityhub:" + $region + "::product/aquasecurity/aquasecurity"), |
71 | | - "GeneratorId": "Trivy", |
72 | | - "AwsAccountId": $account, |
73 | | - "Types": ["Software and Configuration Checks/Vulnerabilities/CVE"], |
74 | | - "CreatedAt": (now | strftime("%Y-%m-%dT%H:%M:%SZ")), |
75 | | - "UpdatedAt": (now | strftime("%Y-%m-%dT%H:%M:%SZ")), |
76 | | - "Severity": { |
77 | | - "Label": .Severity |
78 | | - }, |
79 | | - "Title": ("Trivy found " + .VulnerabilityID + " in " + (.PkgName // "unknown package")), |
80 | | - "Description": (.Description // "No description available"), |
81 | | - "Remediation": { |
82 | | - "Recommendation": { |
83 | | - "Text": "Update the package to fix the vulnerability", |
84 | | - "Url": ("https://avd.aquasec.com/nvd/" + .VulnerabilityID) |
85 | | - } |
86 | | - }, |
87 | | - "ProductFields": { |
88 | | - "Product Name": "Trivy" |
89 | | - }, |
90 | | - "Resources": [{ |
91 | | - "Type": "Container", |
92 | | - "Id": "test-image:latest", |
93 | | - "Partition": "aws", |
94 | | - "Region": $region, |
95 | | - "Details": { |
96 | | - "Container": { |
97 | | - "ImageName": "test-image:latest" |
98 | | - }, |
99 | | - "Other": { |
100 | | - "CVE ID": .VulnerabilityID, |
101 | | - "Package Name": (.PkgName // "unknown"), |
102 | | - "Installed Version": (.InstalledVersion // "unknown"), |
103 | | - "Fixed Version": (.FixedVersion // "Not available") |
104 | | - } |
105 | | - } |
106 | | - }], |
107 | | - "RecordState": "ACTIVE" |
108 | | - } |
109 | | - ] |
110 | | - ' > findings.json |
111 | | - env: |
112 | | - AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }} |
113 | | - AWS_REGION: ${{ secrets.AWS_REGION }} |
114 | | - |
115 | | - - name: Push findings to Security Hub |
116 | | - if: always() |
117 | | - continue-on-error: true |
118 | | - run: | |
119 | | - # Check if Security Hub is enabled |
120 | | - if ! aws securityhub describe-hub --region ${{ secrets.AWS_REGION }} >/dev/null 2>&1; then |
121 | | - echo "⚠️ Security Hub is not enabled in region ${{ secrets.AWS_REGION }}" |
122 | | - echo "Enable it with: aws securityhub enable-security-hub --region ${{ secrets.AWS_REGION }}" |
123 | | - exit 0 |
124 | | - fi |
125 | | -
|
126 | | - # Check if findings file exists and has content |
127 | | - if [ -s findings.json ]; then |
128 | | - echo "✅ Findings file generated successfully" |
129 | | -
|
130 | | - # Debug: Show findings count |
131 | | - FINDINGS_COUNT=$(jq length findings.json) |
132 | | - echo "📊 Found $FINDINGS_COUNT findings to import" |
133 | | -
|
134 | | - if [ "$FINDINGS_COUNT" -gt 0 ]; then |
135 | | - # Import findings to Security Hub |
136 | | - aws securityhub batch-import-findings \ |
137 | | - --region ${{ secrets.AWS_REGION }} \ |
138 | | - --findings file://findings.json |
139 | | -
|
140 | | - echo "✅ $FINDINGS_COUNT findings imported to Security Hub successfully" |
141 | | - else |
142 | | - echo "ℹ️ No findings to import" |
143 | | - fi |
144 | | - else |
145 | | - echo "❌ Findings file is empty or does not exist" |
146 | | - fi |
147 | | -
|
148 | | - - name: Display Security Hub findings summary |
149 | | - if: always() |
150 | | - run: | |
151 | | - echo "📊 Security Hub Integration Summary:" |
152 | | - echo "Region: ${{ secrets.AWS_REGION }}" |
153 | | - echo "Account ID: ${{ secrets.AWS_ACCOUNT_ID }}" |
154 | | - echo "Image scanned: test-image:latest" |
155 | | -
|
156 | | - if [ -f findings.json ]; then |
157 | | - FINDINGS_COUNT=$(jq length findings.json 2>/dev/null || echo "0") |
158 | | - echo "✅ Findings file generated successfully" |
159 | | - echo "📄 Total findings: $FINDINGS_COUNT" |
160 | | - echo "📄 File size: $(wc -c < findings.json) bytes" |
161 | | - else |
162 | | - echo "❌ Findings file not found" |
163 | | - fi |
| 32 | + scan-type: "fs" |
| 33 | + scan-ref: "${{ github.workspace }}" |
| 34 | + trivy-config: "${{ github.workspace }}/trivy.yaml" |
0 commit comments