-
Notifications
You must be signed in to change notification settings - Fork 2
feat: add RapiDAST DAST scanning workflow #1997
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| apiVersion: bpfman.io/v1alpha1 | ||
| kind: BpfApplication | ||
| metadata: | ||
| name: rapidast-oobtkube-test | ||
| namespace: bpfman | ||
| labels: | ||
| app.kubernetes.io/name: rapidast-oobtkube-test | ||
| app.kubernetes.io/component: dast-scan | ||
| annotations: | ||
| description: "Enriched BpfApplication CR for oobtkube blind command injection testing" | ||
| spec: | ||
| nodeSelector: | ||
| matchLabels: | ||
| kubernetes.io/os: linux | ||
| matchExpressions: | ||
| - key: node-role.kubernetes.io/worker | ||
| operator: Exists | ||
| byteCode: | ||
| image: | ||
| url: "quay.io/bpfman-bytecode/xdp_pass:latest" | ||
| imagePullPolicy: IfNotPresent | ||
| imagePullSecret: | ||
| name: "bpfman-registry-secret" | ||
| namespace: "bpfman" | ||
| mapOwnerSelector: | ||
| matchLabels: | ||
| bpfman.io/ownedByApp: rapidast-oobtkube-test | ||
| matchExpressions: | ||
| - key: bpfman.io/mapOwner | ||
| operator: In | ||
| values: | ||
| - "rapidast-test-maps" | ||
| - "shared-maps" | ||
| programs: | ||
| - name: xdp_pass_func | ||
| type: XDP | ||
| xdp: | ||
| links: | ||
| - interfaceSelector: | ||
| interfaces: | ||
| - "eth0" | ||
| - "net1" | ||
| priority: 50 | ||
| proceedOn: | ||
| - Pass | ||
| - DispatcherReturn | ||
| - name: tc_ingress_func | ||
| type: TC | ||
| tc: | ||
| links: | ||
| - direction: Ingress | ||
| interfaceSelector: | ||
| interfaces: | ||
| - "eth0" | ||
| networkNamespaces: | ||
| pods: | ||
| matchLabels: | ||
| app: bpfman-agent | ||
| priority: 100 | ||
| proceedOn: | ||
| - Pipe | ||
| - DispatcherReturn | ||
| - name: uprobe_ssl_func | ||
| type: UProbe | ||
| uprobe: | ||
| links: | ||
| - target: "/usr/lib/x86_64-linux-gnu/libssl.so.3" | ||
| containers: | ||
| containerNames: | ||
| - "bpfman-agent" | ||
| pods: | ||
| matchLabels: | ||
| app: bpfman-agent |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| config: | ||
| configVersion: 6 | ||
| base_results_dir: /opt/rapidast/results | ||
|
|
||
| application: | ||
| shortName: "bpfman-operator-oobtkube" | ||
| url: "https://localhost" | ||
|
|
||
| general: | ||
| container: | ||
| type: none | ||
|
|
||
| scanners: | ||
| generic_oobtkube: | ||
| results: "/opt/rapidast/results/oobtkube-results.sarif" | ||
| inline: | | ||
| python3.12 oobtkube.py --find-all --log-level debug -d 300 -p 6000 -i $POD_IP -f /tmp/bpfapplication-cr.yaml -o /opt/rapidast/results/oobtkube-results.sarif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| config: | ||
| configVersion: 6 | ||
| base_results_dir: /opt/rapidast/results | ||
| results: | ||
| exclusions: | ||
| rules: | ||
| - name: "Exclude findings below Important" | ||
| cel_expression: ".result.level != 'error' && .result.level != 'warning'" | ||
|
|
||
| application: | ||
| shortName: "bpfman-operator-metrics" | ||
| url: "https://127.0.0.1:8443" | ||
|
|
||
| general: | ||
| authentication: | ||
| type: http_header | ||
| parameters: | ||
| name: Authorization | ||
| value_from_var: AUTH_TOKEN | ||
| container: | ||
| type: none | ||
|
|
||
| scanners: | ||
| zap: | ||
| spider: | ||
| maxDuration: 2 | ||
| url: "https://127.0.0.1:8443/metrics" | ||
| passiveScan: | ||
| disabledRules: "2,10015,10024,10027,10054,10096,10109,10112" | ||
| activeScan: | ||
| policy: "API-scan-minimal" | ||
| report: | ||
| format: ["json", "html", "sarif"] | ||
| miscOptions: | ||
| enableUI: false | ||
| updateAddons: false |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,179 @@ | ||
| name: RapiDAST DAST Scan | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| schedule: | ||
| - cron: "0 0 * * 0" # Sunday midnight UTC | ||
|
|
||
| jobs: | ||
| rapidast-dast-scan: | ||
| name: RapiDAST Security Scan | ||
| runs-on: ubuntu-24.04 | ||
| env: | ||
| BPFMAN_AGENT_IMG: quay.io/bpfman/bpfman-agent:int-test | ||
| BPFMAN_OPERATOR_IMG: quay.io/bpfman/bpfman-operator:int-test | ||
| steps: | ||
| - name: Free disk space | ||
| run: | | ||
| sudo rm -rf /usr/share/dotnet | ||
| sudo rm -rf /opt/ghc | ||
| sudo rm -rf "/usr/local/share/boost" | ||
| sudo rm -rf "$AGENT_TOOLSDIRECTORY" | ||
| sudo rm -rf /usr/local/lib/android | ||
|
|
||
| - name: Checkout bpfman-operator | ||
| uses: actions/checkout@v6 | ||
| with: | ||
|
Comment on lines
+25
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: fd -type f -name "rapidast.yml" .github/Repository: openshift/bpfman-operator Length of output: 240 🏁 Script executed: fd -t f -name "rapidast.yml" .github/Repository: openshift/bpfman-operator Length of output: 300 🏁 Script executed: fd "rapidast.yml" .github/Repository: openshift/bpfman-operator Length of output: 100 🏁 Script executed: cat -n .github/workflows/rapidast.yml | head -150Repository: openshift/bpfman-operator Length of output: 6164 🏁 Script executed: cat -n .github/workflows/rapidast.yml | tail -20Repository: openshift/bpfman-operator Length of output: 920 🏁 Script executed: rg 'uses:' .github/workflows/rapidast.ymlRepository: openshift/bpfman-operator Length of output: 281 Pin all GitHub Actions to full commit SHAs. Lines 25, 30, 36, 44, 133, and 141 use mutable tags ( Replace all action tags with full commit SHAs:
🧰 Tools🪛 zizmor (1.25.2)[error] 25-25: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy) (unpinned-uses) 🤖 Prompt for AI AgentsSources: Coding guidelines, Linters/SAST tools |
||
| fetch-depth: 0 | ||
|
|
||
|
Comment on lines
+24
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Disable checkout credential persistence.
Suggested hardening - name: Checkout bpfman-operator
uses: actions/checkout@v6
with:
fetch-depth: 0
+ persist-credentials: falseAs per coding guidelines, 🧰 Tools🪛 zizmor (1.25.2)[warning] 24-27: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false (artipacked) [error] 25-25: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy) (unpinned-uses) 🤖 Prompt for AI AgentsSources: Coding guidelines, Linters/SAST tools |
||
| - name: Install Go | ||
| uses: actions/setup-go@v6 | ||
| with: | ||
| go-version: "1.25" | ||
| cache: false | ||
|
|
||
| - name: Restore Go module cache | ||
| uses: actions/cache@v5 | ||
| with: | ||
| path: ~/go/pkg/mod | ||
| key: go-mod-${{ hashFiles('**/go.sum') }} | ||
| restore-keys: | | ||
| go-mod- | ||
|
|
||
| - name: Restore Go build cache | ||
| uses: actions/cache@v5 | ||
| with: | ||
| path: ~/.cache/go-build | ||
| key: go-build-${{ github.sha }} | ||
| restore-keys: | | ||
| go-build- | ||
|
|
||
| - name: Build operator and agent images | ||
| run: make build-images | ||
|
|
||
| - name: Deploy operator on Kind cluster | ||
| run: make run-on-kind | ||
|
|
||
| - name: Wait for operator pods to be ready | ||
| run: | | ||
| echo "Waiting for bpfman-operator deployment..." | ||
| kubectl rollout status deployment/bpfman-operator -n bpfman --timeout=120s | ||
| echo "Waiting for bpfman-daemon daemonset..." | ||
| kubectl rollout status daemonset/bpfman-daemon -n bpfman --timeout=120s | ||
| echo "All pods ready:" | ||
| kubectl get pods -n bpfman | ||
|
|
||
| # --- ZAP Scan --- | ||
|
|
||
| - name: Port-forward metrics service | ||
| run: | | ||
| kubectl port-forward svc/controller-manager-metrics-service 8443:8443 -n bpfman & | ||
| echo $! > /tmp/port-forward.pid | ||
| sleep 3 | ||
| echo "Port-forward PID: $(cat /tmp/port-forward.pid)" | ||
|
|
||
| - name: Create service account token for auth | ||
| id: sa-token | ||
| run: | | ||
| TOKEN=$(kubectl create token default -n bpfman --duration=30m) | ||
| echo "::add-mask::${TOKEN}" | ||
| echo "AUTH_TOKEN=Bearer ${TOKEN}" >> "$GITHUB_ENV" | ||
|
|
||
| - name: Run RapiDAST ZAP scan | ||
| continue-on-error: true | ||
| run: | | ||
| mkdir -p /tmp/rapidast-results/zap | ||
| docker run --rm \ | ||
| --network host \ | ||
| -v "${{ github.workspace }}/.github/rapidast/zap-config.yaml:/opt/rapidast/config.yaml:ro" \ | ||
| -v "/tmp/rapidast-results/zap:/opt/rapidast/results" \ | ||
| -e "AUTH_TOKEN=${AUTH_TOKEN}" \ | ||
| quay.io/redhatproductsecurity/rapidast:development \ | ||
| rapidast.py --config /opt/rapidast/config.yaml | ||
|
|
||
| - name: Stop port-forward | ||
| if: always() | ||
| run: | | ||
| if [ -f /tmp/port-forward.pid ]; then | ||
| kill "$(cat /tmp/port-forward.pid)" 2>/dev/null || true | ||
| fi | ||
|
|
||
| # --- oobtkube Scan --- | ||
|
|
||
| - name: Apply enriched BpfApplication CR | ||
| continue-on-error: true | ||
| run: | | ||
| kubectl apply -f .github/rapidast/bpfapplication-oobtkube-cr.yaml | ||
|
|
||
| - name: Get operator pod IP for oobtkube | ||
| id: pod-ip | ||
| run: | | ||
| POD_NAME=$(kubectl get pods -n bpfman -l control-plane=controller-manager -o jsonpath='{.items[0].metadata.name}') | ||
| POD_IP=$(kubectl get pod "${POD_NAME}" -n bpfman -o jsonpath='{.status.podIP}') | ||
| echo "POD_IP=${POD_IP}" >> "$GITHUB_ENV" | ||
| echo "Operator pod: ${POD_NAME} at ${POD_IP}" | ||
|
|
||
| - name: Run RapiDAST oobtkube scan | ||
| continue-on-error: true | ||
| run: | | ||
| mkdir -p /tmp/rapidast-results/oobtkube | ||
| docker run --rm \ | ||
| --network host \ | ||
| -v "${{ github.workspace }}/.github/rapidast/oobtkube-config.yaml:/opt/rapidast/config.yaml:ro" \ | ||
| -v "${{ github.workspace }}/.github/rapidast/bpfapplication-oobtkube-cr.yaml:/tmp/bpfapplication-cr.yaml:ro" \ | ||
| -v "/tmp/rapidast-results/oobtkube:/opt/rapidast/results" \ | ||
| -e "POD_IP=${POD_IP}" \ | ||
| quay.io/redhatproductsecurity/rapidast:development \ | ||
| rapidast.py --config /opt/rapidast/config.yaml | ||
|
|
||
| # --- Results --- | ||
|
|
||
| - name: Upload ZAP scan results | ||
| if: always() | ||
| uses: actions/upload-artifact@v6 | ||
| with: | ||
| name: rapidast-zap-results | ||
| path: /tmp/rapidast-results/zap/ | ||
| if-no-files-found: warn | ||
|
|
||
| - name: Upload oobtkube scan results | ||
| if: always() | ||
| uses: actions/upload-artifact@v6 | ||
| with: | ||
| name: rapidast-oobtkube-results | ||
| path: /tmp/rapidast-results/oobtkube/ | ||
| if-no-files-found: warn | ||
|
|
||
|
Comment on lines
+131
to
+146
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sign scan artifacts before upload (Sigstore/cosign). Artifacts are uploaded unsigned, so downstream consumers cannot verify provenance/integrity. As per coding guidelines, 🧰 Tools🪛 zizmor (1.25.2)[error] 133-133: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy) (unpinned-uses) [error] 141-141: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy) (unpinned-uses) 🤖 Prompt for AI AgentsSource: Coding guidelines |
||
| - name: Generate scan summary | ||
| if: always() | ||
| run: | | ||
| ZAP_REPORT="/tmp/rapidast-results/zap/bpfman-operator-metrics/zap/zap-report.json" | ||
| OOBT_REPORT="/tmp/rapidast-results/oobtkube/oobtkube-results.sarif" | ||
|
|
||
| if [ -f "$ZAP_REPORT" ]; then | ||
| ZAP_ALERTS=$(jq '.site[].alerts | length' "$ZAP_REPORT" 2>/dev/null || echo "N/A") | ||
| ZAP_LINE="- **Alerts found**: ${ZAP_ALERTS} | ||
| - Full report available in workflow artifacts" | ||
| else | ||
| ZAP_LINE="- No ZAP report found (scan may have failed or produced no results)" | ||
| fi | ||
|
|
||
| if [ -f "$OOBT_REPORT" ]; then | ||
| OOBT_RESULTS=$(jq '.runs[0].results | length' "$OOBT_REPORT" 2>/dev/null || echo "N/A") | ||
| OOBT_LINE="- **Injection detections**: ${OOBT_RESULTS}" | ||
| else | ||
| OOBT_LINE="- No oobtkube report found (scan may have failed or produced no results)" | ||
| fi | ||
|
|
||
| cat >> "$GITHUB_STEP_SUMMARY" <<EOF | ||
| ## RapiDAST DAST Scan Results | ||
|
|
||
| ### ZAP Scan (metrics endpoint) | ||
| ${ZAP_LINE} | ||
|
|
||
| ### oobtkube Scan (BpfApplication CRD injection) | ||
| ${OOBT_LINE} | ||
|
|
||
| --- | ||
| *Scan powered by [RapiDAST](https://github.com/RedHatProductSecurity/rapidast) \`development\` image* | ||
| EOF | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Define explicit least-privilege
GITHUB_TOKENpermissions.No
permissionsblock is set, so token scopes default broader than necessary for this job.Suggested hardening
name: RapiDAST DAST Scan on: workflow_dispatch: schedule: - cron: "0 0 * * 0" # Sunday midnight UTC +permissions: + contents: read + jobs: rapidast-dast-scan: name: RapiDAST Security ScanAs per coding guidelines,
.github/workflows/**/*: "Least privilege: minimize GITHUB_TOKEN permissions".🤖 Prompt for AI Agents
Source: Coding guidelines