diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 3b52b3db9..000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: CodeQL -on: - push: - branches: - - master - pull_request: - branches: - - master - schedule: - - cron: "0 16 * * 6" -jobs: - analyse: - name: Analyse - runs-on: ubuntu-18.04 - steps: - - name: Checkout code - uses: actions/checkout@v2 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - name: Checkout head of the pull request - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: go - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - name: Perform CodeQL analysis - uses: github/codeql-action/analyze@v1 diff --git a/Makefile b/Makefile index aed33d2b5..330649e76 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,8 @@ itests-starboard: check-env get-ginkgo github.com/aquasecurity/starboard/pkg/kubehunter,\ github.com/aquasecurity/starboard/pkg/polaris,\ github.com/aquasecurity/starboard/pkg/polaris/crd,\ - github.com/aquasecurity/starboard/pkg/find/vulnerabilities/trivy,\ + github.com/aquasecurity/starboard/pkg/trivy,\ + github.com/aquasecurity/starboard/pkg/find/vulnerabilities,\ github.com/aquasecurity/starboard/pkg/vulnerabilityreport \ ./itest/starboard @@ -82,7 +83,8 @@ itests-starboard-operator: check-env get-ginkgo github.com/aquasecurity/starboard/pkg/operator/controller/job,\ github.com/aquasecurity/starboard/pkg/operator/controller/pod,\ github.com/aquasecurity/starboard/pkg/operator/logs,\ - github.com/aquasecurity/starboard/pkg/operator/trivy \ + github.com/aquasecurity/starboard/pkg/trivy,\ + github.com/aquasecurity/starboard/pkg/vulnerabilityreport \ ./itest/starboard-operator check-env: diff --git a/README.md b/README.md index 9e10f2cab..0e3f9e5dc 100644 --- a/README.md +++ b/README.md @@ -268,10 +268,12 @@ The following table lists available configuration parameters. | CONFIGMAP KEY | DEFAULT | DESCRIPTION | | --------------------- | ------------------------------------------------------ | ----------- | -| `trivy.httpProxy` | N/A | The HTTP proxy used by Trivy to download the vulnerabilities database from GitHub | -| `trivy.githubToken` | N/A | The GitHub personal access token used by Trivy to download the vulnerabilities database from GitHub | +| `trivy.httpProxy` | N/A | The HTTP proxy used by Trivy to download the vulnerabilities database from GitHub. Only applicable if Trivy runs in the `Standalone` mode. | +| `trivy.githubToken` | N/A | The GitHub personal access token used by Trivy to download the vulnerabilities database from GitHub. Only applicable if Trivy runs in the `Standalone` mode. | | `trivy.severity` | `UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL` | A comma separated list of severity levels reported by Trivy | -| `trivy.imageRef` | `docker.io/aquasec/trivy:0.9.1` | Trivy image reference | +| `trivy.imageRef` | `docker.io/aquasec/trivy:0.12.0` | Trivy image reference | +| `trivy.mode` | `Standalone` | Trivy client mode. Either `Standalone` or `ClientServer`. | +| `trivy.serverURL` | `http://trivy-server.trivy-server:4954` | The endpoint URL of the Trivy server. This parameter is required when Trivy runs in the `ClientServer` mode. | | `polaris.config.yaml` | [Check the default value here][default-polaris-config] | Polaris configuration file | > **Note:** You can find it handy to delete a configuration key, which was not created by default by the @@ -415,10 +417,7 @@ Configuration of the operator is done via environment variables at startup. | `OPERATOR_NAMESPACE` | N/A | See [Install modes](#install-modes) | | `OPERATOR_TARGET_NAMESPACES` | N/A | See [Install modes](#install-modes) | | `OPERATOR_SCANNER_TRIVY_ENABLED` | `true` | The flag to enable Trivy vulnerability scanner | -| `OPERATOR_SCANNER_TRIVY_VERSION` | `0.11.0` | The version of Trivy to be used | -| `OPERATOR_SCANNER_TRIVY_IMAGE` | `aquasec/trivy:0.11.0` | The Docker image of Trivy to be used | | `OPERATOR_SCANNER_AQUA_CSP_ENABLED` | `false` | The flag to enable Aqua vulnerability scanner | -| `OPERATOR_SCANNER_AQUA_CSP_VERSION` | `5.0` | The version of Aqua scanner to be used | | `OPERATOR_SCANNER_AQUA_CSP_IMAGE` | `aquasec/scanner:5.0` | The Docker image of Aqua scanner to be used | | `OPERATOR_LOG_DEV_MODE` | `false` | The flag to use (or not use) development mode (more human-readable output, extra stack traces and logging information, etc). | | `OPERATOR_SCAN_JOB_TIMEOUT` | `5m` | The length of time to wait before giving up on a scan job | diff --git a/deploy/init/03-starboard.cm.yaml b/deploy/init/03-starboard.cm.yaml index 40ecff290..b3ad50c31 100644 --- a/deploy/init/03-starboard.cm.yaml +++ b/deploy/init/03-starboard.cm.yaml @@ -7,7 +7,9 @@ metadata: namespace: starboard data: trivy.severity: UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL - trivy.imageRef: docker.io/aquasec/trivy:0.9.1 + trivy.imageRef: docker.io/aquasec/trivy:0.12.0 + trivy.mode: Standalone + trivy.serverURL: http://trivy-server.trivy-server:4954 kube-bench.imageRef: docker.io/aquasec/kube-bench:0.4.0 polaris.config.yaml: | checks: diff --git a/deploy/trivy-server/01-trivy-server.ns.yaml b/deploy/trivy-server/01-trivy-server.ns.yaml new file mode 100644 index 000000000..46b3358fe --- /dev/null +++ b/deploy/trivy-server/01-trivy-server.ns.yaml @@ -0,0 +1,5 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: trivy-server diff --git a/deploy/trivy-server/02-trivy-server.sa.yaml b/deploy/trivy-server/02-trivy-server.sa.yaml new file mode 100644 index 000000000..a5ac537a3 --- /dev/null +++ b/deploy/trivy-server/02-trivy-server.sa.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: trivy-server + namespace: trivy-server diff --git a/deploy/trivy-server/03-trivy-server.deployment.yaml b/deploy/trivy-server/03-trivy-server.deployment.yaml new file mode 100644 index 000000000..4e93be1bf --- /dev/null +++ b/deploy/trivy-server/03-trivy-server.deployment.yaml @@ -0,0 +1,38 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: trivy-server + name: trivy-server + namespace: trivy-server +spec: + replicas: 1 + selector: + matchLabels: + app: trivy-server + template: + metadata: + labels: + app: trivy-server + spec: + serviceAccountName: trivy-server + automountServiceAccountToken: false + volumes: + - name: trivy-cache + emptyDir: {} + containers: + - name: trivy-server + image: docker.io/aquasec/trivy:0.12.0 + command: + - trivy + - server + - --debug + - --listen + - 0.0.0.0:4954 + volumeMounts: + - name: trivy-cache + mountPath: /root/.cache/trivy + ports: + - containerPort: 4954 + name: twirp diff --git a/deploy/trivy-server/04-trivy-server.svc.yaml b/deploy/trivy-server/04-trivy-server.svc.yaml new file mode 100644 index 000000000..4b282cd75 --- /dev/null +++ b/deploy/trivy-server/04-trivy-server.svc.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: trivy-server + namespace: trivy-server + labels: + app: trivy-server +spec: + type: ClusterIP + selector: + app: trivy-server + ports: + - protocol: TCP + port: 4954 + targetPort: 4954 diff --git a/deploy/trivy-server/README.md b/deploy/trivy-server/README.md new file mode 100644 index 000000000..7e4451f4c --- /dev/null +++ b/deploy/trivy-server/README.md @@ -0,0 +1,16 @@ +# Trivy Server + +> **Note:** This is just for testing Trivy in client-server mode. We should move away the YAML Manifests from this repository. +> Maybe even provide a Helm chart for Trivy server. + +## Deploy with Static YAML Manifests + +``` +$ kubectl apply -f deploy/trivy-server +``` + +``` +$ kubectl run trivy-client -it --rm --image aquasec/trivy:0.12.0 --command -- sh +/ # trivy client --format json --remote http://trivy-server.trivy-server:4954 wordpress:4.9 +/ # trivy client --format json --remote http://trivy-server.trivy-server:4954 wordpress:5.5 +``` diff --git a/docs/design/starboard-trivy-clientserver.excalidraw b/docs/design/starboard-trivy-clientserver.excalidraw new file mode 100644 index 000000000..431e4f054 --- /dev/null +++ b/docs/design/starboard-trivy-clientserver.excalidraw @@ -0,0 +1,2692 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "rectangle", + "version": 676, + "versionNonce": 2040490026, + "isDeleted": false, + "id": "2zcTzKxfvspcvH1gAxn6D", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 557.421875, + "y": 419.15234375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 257.50390625, + "height": 63.15625, + "seed": 439588342, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "bchwcZRmyIw3S38xIZDWv" + ] + }, + { + "type": "text", + "version": 454, + "versionNonce": 9045878, + "isDeleted": false, + "id": "FsSKMvnttAAlNn19RvCwT", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 604.7734375, + "y": 438.521484375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 162, + "height": 25, + "seed": 382917174, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Deployment: app", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 564, + "versionNonce": 714396394, + "isDeleted": false, + "id": "vJpTF1Zoq5fm_CXo29RWm", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 662.71875, + "y": 519.23828125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 336.85546875, + "height": 59.7109375, + "seed": 1789968234, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "bchwcZRmyIw3S38xIZDWv", + "vgpDXOyLLqyDEdP-ZUkIQ", + "8r6AHavBXyGDRtZh0lh6X", + "vc9ul_c_FFwQkadvvz_2S" + ] + }, + { + "type": "text", + "version": 615, + "versionNonce": 335915190, + "isDeleted": false, + "id": "tPFHoaUPD1IjmpxWvFVyz", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 680.21875, + "y": 538.6796875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 268, + "height": 25, + "seed": 642409514, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "ReplicaSet: app-5fcdc7d5c7", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 1061, + "versionNonce": 1460594090, + "isDeleted": false, + "id": "Z8HYEbUAolbhNLvGrA0Ux", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 875.984375, + "y": 627.6875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 374.89453124999994, + "height": 519.08203125, + "seed": 1996746666, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "gQf0Pk1RBVrZqQJKPyvCa", + "rtdh2joD7z4OpTZZQFuw3", + "vgpDXOyLLqyDEdP-ZUkIQ", + "8r6AHavBXyGDRtZh0lh6X" + ] + }, + { + "type": "text", + "version": 785, + "versionNonce": 301670902, + "isDeleted": false, + "id": "FhlxiQk8g8amnkluVluwC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 914.0546875, + "y": 657.15625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 264, + "height": 25, + "seed": 1633791990, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Pod: app-5fcdc7d5c7-dtm8b", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 764, + "versionNonce": 2016977002, + "isDeleted": false, + "id": "UJ1VkrcPCCIv8Z2Vv6iBp", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 912.21875, + "y": 717.625, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 286.5546875, + "height": 52.91796875, + "seed": 227414902, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "PwKCJjAqH5_gkyT2L1wy5" + ] + }, + { + "type": "text", + "version": 746, + "versionNonce": 1030714166, + "isDeleted": false, + "id": "McH3kOxMiN50WfXAxksFi", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 985.3359375, + "y": 730.26953125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 140, + "height": 25, + "seed": 1124618358, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "init container 1", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 796, + "versionNonce": 702350122, + "isDeleted": false, + "id": "-F8_Q2CX1BUtkMqW1j96l", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 916.42578125, + "y": 791.9296875, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 285.45703125, + "height": 47.98828125, + "seed": 96365418, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "x3DRj4mEa3CAaCPvK0JlN" + ] + }, + { + "type": "text", + "version": 697, + "versionNonce": 818388086, + "isDeleted": false, + "id": "1C5KHPPhvyDANP6M6Q8d4", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1006.69140625, + "y": 803.7265625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 151, + "height": 25, + "seed": 1343723306, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "init container 2", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 759, + "versionNonce": 1449594346, + "isDeleted": false, + "id": "pC-tAN9Q1okEI-7CymMPt", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 922.6015625, + "y": 884.37109375, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 278.09765625, + "height": 67.66796875, + "seed": 81782454, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "vVEqkxRKSHp6QryskV90i" + ] + }, + { + "type": "text", + "version": 783, + "versionNonce": 1908972982, + "isDeleted": false, + "id": "exZSEqZ3a3-BKmf9xwHqf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1012.67578125, + "y": 905.9765625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 101, + "height": 25, + "seed": 2116617386, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "container 1", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 795, + "versionNonce": 1658962090, + "isDeleted": false, + "id": "peJbEMj3MxEgdcAmkYb0D", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 922.9140625, + "y": 975.7890625, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 280.89453125, + "height": 65.2421875, + "seed": 838299050, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "T0sXvUKRGNVhmBQ1GI4_m" + ] + }, + { + "type": "text", + "version": 720, + "versionNonce": 93812470, + "isDeleted": false, + "id": "9S9rnW_ES5A_cnTGJt-76", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1006.861328125, + "y": 995.91015625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 113, + "height": 25, + "seed": 642653930, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "container 2", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle" + }, + { + "type": "rectangle", + "version": 813, + "versionNonce": 1526209386, + "isDeleted": false, + "id": "sb0hVmoIg41camtq428Oo", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 925.171875, + "y": 1058.26953125, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 278.2734375, + "height": 59.68359375, + "seed": 528437546, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "abE83CCSbnnv0B_nebnqq" + ] + }, + { + "type": "text", + "version": 714, + "versionNonce": 79243318, + "isDeleted": false, + "id": "saUtkC4mhMHiX7NzW1OW4", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1008.234375, + "y": 1075.611328125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 112, + "height": 25, + "seed": 498182966, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "container 3", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle" + }, + { + "type": "rectangle", + "version": 298, + "versionNonce": 485826090, + "isDeleted": false, + "id": "ux-MijhrKWxzx3aBxOi2-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1479.6484375, + "y": 543.91796875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 472.890625, + "height": 638.33203125, + "seed": 1740072746, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [] + }, + { + "type": "text", + "version": 227, + "versionNonce": 789754230, + "isDeleted": false, + "id": "7vc7YDO86mroOlUiRQ9Mn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1513.28125, + "y": 566.3515625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 242, + "height": 25, + "seed": 214185910, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Job: some-uuid-goes-here", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 482, + "versionNonce": 96717034, + "isDeleted": false, + "id": "8Ilz98ZilT6ouLqI17p5A", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1511.19921875, + "y": 623.22265625, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 415.29296875, + "height": 518.94921875, + "seed": 1680351222, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [] + }, + { + "type": "text", + "version": 142, + "versionNonce": 2145981110, + "isDeleted": false, + "id": "AmKoTYwF7k-4nq-Z_qLvx", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1563.7109375, + "y": 648.65625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 78, + "height": 25, + "seed": 553792490, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "PodSpec", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 219, + "versionNonce": 737445750, + "isDeleted": false, + "id": "hI3VMcGgYLy-YFmKmOscS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1561.68359375, + "y": 699.1640625, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 303.64843749999994, + "height": 74.21875, + "seed": 1068673386, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "PwKCJjAqH5_gkyT2L1wy5", + "lu570Gln9QPiLj2MxAsaW", + "17bx5KvBPx51VKhsBJrlu", + "t4Brg6J6A5S0aFdcHd-y1" + ] + }, + { + "type": "text", + "version": 72, + "versionNonce": 1219184246, + "isDeleted": false, + "id": "5weO47P2LdFdUL8wlS3rd", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1576.458984375, + "y": 723.7734375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 278, + "height": 25, + "seed": 1292594538, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "container for init container 1", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle" + }, + { + "type": "rectangle", + "version": 201, + "versionNonce": 1839932790, + "isDeleted": false, + "id": "OYQSaJMgpc4vp96JjAaZL", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1562.49609375, + "y": 787.77734375, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 305.76171875000006, + "height": 63.4921875, + "seed": 1583551350, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "x3DRj4mEa3CAaCPvK0JlN", + "nTVx3aec_IFiPVsj7XK-b", + "vq-_k7K1YIpQx44TFH1dy" + ] + }, + { + "type": "text", + "version": 82, + "versionNonce": 1671890870, + "isDeleted": false, + "id": "jfWzR-c1o0vVA-HLRSPbY", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1573.025390625, + "y": 807.0234375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 290, + "height": 25, + "seed": 1190727542, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "container for init container 2", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle" + }, + { + "type": "rectangle", + "version": 233, + "versionNonce": 322933738, + "isDeleted": false, + "id": "9Pb5mHfThK9qomtZ2VipC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1580.4921875, + "y": 904.9296875, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 280.4062500000001, + "height": 53.3515625, + "seed": 169508714, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "vVEqkxRKSHp6QryskV90i", + "YTFS1ozx0oRq8nhpK62AK", + "YIUGoeMa4nWwuoDD7XcWE" + ] + }, + { + "type": "text", + "version": 221, + "versionNonce": 1142464758, + "isDeleted": false, + "id": "y9CmGYkVn0joznJMLfAEA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1613.1953125, + "y": 918.22265625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 239, + "height": 25, + "seed": 895136426, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "container for container 1", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 183, + "versionNonce": 1066398826, + "isDeleted": false, + "id": "mNUT4H1nM5z16h_WpY5es", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1583.21875, + "y": 974.96875, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 276.99218749999994, + "height": 55.73828125, + "seed": 684783338, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "T0sXvUKRGNVhmBQ1GI4_m", + "zyrHI3VsVcNzpHhKUC7PT", + "bFqFkqKuElN8wqX7QpC8r" + ] + }, + { + "type": "text", + "version": 118, + "versionNonce": 1837437494, + "isDeleted": false, + "id": "hlA2RD1B4rOh7HwE2l2wG", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1600.53125, + "y": 992.609375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 251, + "height": 25, + "seed": 217017526, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "container for container 2", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 182, + "versionNonce": 719441002, + "isDeleted": false, + "id": "9UcPXJlHcid22jXT5y4jE", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1583.62890625, + "y": 1050.17578125, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 276.2734375, + "height": 52.78125, + "seed": 819103850, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "abE83CCSbnnv0B_nebnqq", + "GZ0ewJ6BrZGIjDdP5lxxQ", + "Wwoq-EptjcLv-5LfZTgHC" + ] + }, + { + "type": "text", + "version": 119, + "versionNonce": 718363510, + "isDeleted": false, + "id": "03MscJpVYiTRxxe1D0trw", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1610.6953125, + "y": 1058.46484375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 250, + "height": 25, + "seed": 448352950, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "container for container 3", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 1855, + "versionNonce": 1708935018, + "isDeleted": false, + "id": "fXhvVEVcGNjdpiXgfaOd8", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1984.66015625, + "y": 939.552734375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 644, + "height": 250, + "seed": 540907626, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Each (regular) container of the pod created by\nthe scan job will run trivy in client-server mode\nand pass to it the image ref of the corresponding\nworkload container's image:\n\ntrivy client --remote $(SERVER_URL) \ntrivy client --remote $(SERVER_URL) \ntrivy client --remote $(SERVER_URL) \ntrivy client --remote $(SERVER_URL) \ntrivy client --remote $(SERVER_URL) ", + "baseline": 243, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 490, + "versionNonce": 196414390, + "isDeleted": false, + "id": "p5Ohccd4-soclwsgvA94-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1409.4921875, + "y": 454.4609375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 1253.4140625, + "height": 754.41015625, + "seed": 492875254, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [] + }, + { + "type": "arrow", + "version": 778, + "versionNonce": 263556202, + "isDeleted": false, + "id": "bchwcZRmyIw3S38xIZDWv", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 659.68359375, + "y": 567.690817811125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 84.9319972722792, + "height": 77.01894281112504, + "seed": 845012842, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "startBinding": { + "elementId": "vJpTF1Zoq5fm_CXo29RWm", + "focus": -0.9533169192267669, + "gap": 3.03515625 + }, + "endBinding": { + "elementId": "2zcTzKxfvspcvH1gAxn6D", + "focus": 0.950437357873753, + "gap": 8.36328125 + }, + "points": [ + [ + 0, + 0 + ], + [ + -84.9319972722792, + -77.01894281112504 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "rectangle", + "version": 576, + "versionNonce": 428295990, + "isDeleted": false, + "id": "2_oLye4AI2AnotXJGnsiW", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 783.30859375, + "y": 1221.671875, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 553.6796874999998, + "height": 58.78515625, + "seed": 669404534, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "lu570Gln9QPiLj2MxAsaW", + "17bx5KvBPx51VKhsBJrlu" + ] + }, + { + "type": "text", + "version": 410, + "versionNonce": 450653994, + "isDeleted": false, + "id": "JgE78vdkE_YliqGhlt12x", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 800.1640625, + "y": 1235.31640625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 492, + "height": 25, + "seed": 313096502, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "vc9ul_c_FFwQkadvvz_2S" + ], + "fontSize": 20, + "fontFamily": 1, + "text": "VulnerabilityReport: app-5fcdc7d5c7-init container 1", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 643, + "versionNonce": 1657073782, + "isDeleted": false, + "id": "MUN_ild1OSjDtTHULafVn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 787.59765625, + "y": 1298.830078125, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 553.6796874999998, + "height": 58.78515625, + "seed": 536248438, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "nTVx3aec_IFiPVsj7XK-b" + ] + }, + { + "type": "text", + "version": 481, + "versionNonce": 1285093866, + "isDeleted": false, + "id": "ynTqn21bEwC_hlFMgxvdS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 804.60546875, + "y": 1312.474609375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 503, + "height": 25, + "seed": 1627941354, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "VulnerabilityReport: app-5fcdc7d5c7-init container 2", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 695, + "versionNonce": 553349558, + "isDeleted": false, + "id": "nl_vUWOrB3oU4bqJ5UO0i", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 789.453125, + "y": 1369.419921875, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 553.6796874999998, + "height": 58.78515625, + "seed": 1953325098, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "YTFS1ozx0oRq8nhpK62AK" + ] + }, + { + "type": "text", + "version": 559, + "versionNonce": 334900394, + "isDeleted": false, + "id": "XXvQJIBJMWmwVfZE9fpcT", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 806.27734375, + "y": 1383.064453125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 453, + "height": 25, + "seed": 1538756470, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "VulnerabilityReport: app-5fcdc7d5c7-container 1", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 496, + "versionNonce": 1867500278, + "isDeleted": false, + "id": "XGJfIAmhM56vmn95B8F0S", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 791.90234375, + "y": 1446.130859375, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 553.6796874999998, + "height": 58.78515625, + "seed": 95421098, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "zyrHI3VsVcNzpHhKUC7PT" + ] + }, + { + "type": "text", + "version": 359, + "versionNonce": 1184827242, + "isDeleted": false, + "id": "LXp8CsZaN6bzeCeUHlfxj", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 808.91015625, + "y": 1459.775390625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 464, + "height": 25, + "seed": 1866880246, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "VulnerabilityReport: app-5fcdc7d5c7-container 2", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 542, + "versionNonce": 1011285046, + "isDeleted": false, + "id": "dedTXRl0XN5yFz7KNxTSO", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 790.47265625, + "y": 1522.677734375, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 553.6796874999998, + "height": 58.78515625, + "seed": 2137730230, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "GZ0ewJ6BrZGIjDdP5lxxQ" + ] + }, + { + "type": "text", + "version": 405, + "versionNonce": 1289652778, + "isDeleted": false, + "id": "y7iDaNAqOKHsnQ19ZqQRa", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 807.48046875, + "y": 1536.322265625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 464, + "height": 25, + "seed": 1639162282, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "VulnerabilityReport: app-5fcdc7d5c7-container 3", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 912, + "versionNonce": 1573258614, + "isDeleted": false, + "id": "PwKCJjAqH5_gkyT2L1wy5", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1203.1328125, + "y": 745.0754820337202, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 351.4843750000002, + "height": 6.672541307797019, + "seed": 1512280374, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "UJ1VkrcPCCIv8Z2Vv6iBp", + "focus": 0.13082513502686008, + "gap": 4.359375 + }, + "endBinding": { + "elementId": "hI3VMcGgYLy-YFmKmOscS", + "focus": 0.022176142561223914, + "gap": 7.06640625 + }, + "points": [ + [ + 0, + 0 + ], + [ + 351.4843750000002, + -6.672541307797019 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 893, + "versionNonce": 1302312170, + "isDeleted": false, + "id": "x3DRj4mEa3CAaCPvK0JlN", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1207.8046875, + "y": 817.5838885052679, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 347.1875000000002, + "height": 4.79968231326302, + "seed": 200305078, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "-F8_Q2CX1BUtkMqW1j96l", + "focus": -0.015220731040753156, + "gap": 5.921875 + }, + "endBinding": { + "elementId": "OYQSaJMgpc4vp96JjAaZL", + "focus": -0.14995359560994803, + "gap": 7.50390625 + }, + "points": [ + [ + 0, + 0 + ], + [ + 347.1875000000002, + 4.79968231326302 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 949, + "versionNonce": 621930166, + "isDeleted": false, + "id": "vVEqkxRKSHp6QryskV90i", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1204.203125, + "y": 916.5267530978466, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 369.66015625, + "height": 13.914920373884684, + "seed": 491556470, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "pC-tAN9Q1okEI-7CymMPt", + "gap": 3.50390625, + "focus": -0.1804452292995827 + }, + "endBinding": { + "elementId": "9Pb5mHfThK9qomtZ2VipC", + "gap": 6.62890625, + "focus": -0.13655286703598196 + }, + "points": [ + [ + 0, + 0 + ], + [ + 369.66015625, + 13.914920373884684 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 971, + "versionNonce": 1517127594, + "isDeleted": false, + "id": "T0sXvUKRGNVhmBQ1GI4_m", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1213.5078125, + "y": 1009.1266280518233, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 368.37109375, + "height": 2.647283889434334, + "seed": 352974134, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "peJbEMj3MxEgdcAmkYb0D", + "gap": 9.69921875, + "focus": -0.010771100602347409 + }, + "endBinding": { + "elementId": "mNUT4H1nM5z16h_WpY5es", + "gap": 1.33984375, + "focus": -0.34440119295781213 + }, + "points": [ + [ + 0, + 0 + ], + [ + 368.37109375, + 2.647283889434334 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 905, + "versionNonce": 1926209526, + "isDeleted": false, + "id": "abE83CCSbnnv0B_nebnqq", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1209.8984375, + "y": 1088.3245533896368, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 367.83984375, + "height": 12.310498146972577, + "seed": 1580857910, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "sb0hVmoIg41camtq428Oo", + "gap": 6.453125, + "focus": 0.1474116319262928 + }, + "endBinding": { + "elementId": "9UcPXJlHcid22jXT5y4jE", + "gap": 5.890625, + "focus": 0.17323067100506717 + }, + "points": [ + [ + 0, + 0 + ], + [ + 367.83984375, + -12.310498146972577 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "text", + "version": 357, + "versionNonce": 460522090, + "isDeleted": false, + "id": "VYTicavnfty33jy7uDif1", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1018.0078125, + "y": 579.6640625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 125, + "height": 25, + "seed": 763663734, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "controlled by", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 325, + "versionNonce": 1258565942, + "isDeleted": false, + "id": "E-VIJs1DaWm8FdfOHLuPr", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 503.66015625, + "y": 536.58203125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 125, + "height": 25, + "seed": 1314052458, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "controlled by", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 813, + "versionNonce": 2071668010, + "isDeleted": false, + "id": "nTVx3aec_IFiPVsj7XK-b", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1555.26171875, + "y": 803.4319687646107, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 210.431640625, + "height": 523.20613556021, + "seed": 368626806, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "OYQSaJMgpc4vp96JjAaZL", + "focus": 1.005662737566369, + "gap": 7.234375 + }, + "endBinding": { + "elementId": "MUN_ild1OSjDtTHULafVn", + "focus": 0.96914670356047, + "gap": 3.552734375 + }, + "points": [ + [ + 0, + 0 + ], + [ + -210.431640625, + 523.20613556021 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 177, + "versionNonce": 1762957942, + "isDeleted": false, + "id": "17bx5KvBPx51VKhsBJrlu", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1555.8125, + "y": 722.6210937499998, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 210.78125, + "height": 504.5811170719219, + "seed": 1746632758, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "hI3VMcGgYLy-YFmKmOscS", + "focus": 0.9765084802280298, + "gap": 5.87109375 + }, + "endBinding": { + "elementId": "2_oLye4AI2AnotXJGnsiW", + "focus": 0.9508732350289565, + "gap": 8.042968750000114 + }, + "points": [ + [ + 0, + 0 + ], + [ + -210.78125, + 504.5811170719219 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 171, + "versionNonce": 1408298986, + "isDeleted": false, + "id": "YTFS1ozx0oRq8nhpK62AK", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1572.7929687500002, + "y": 931.8864414829819, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 224.31250000000023, + "height": 460.4232982016432, + "seed": 875737014, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "9Pb5mHfThK9qomtZ2VipC", + "gap": 7.69921875, + "focus": 0.9645562972522097 + }, + "endBinding": { + "elementId": "nl_vUWOrB3oU4bqJ5UO0i", + "gap": 5.347656250000114, + "focus": 0.9583042830491013 + }, + "points": [ + [ + 0, + 0 + ], + [ + -224.31250000000023, + 460.4232982016432 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 201, + "versionNonce": 1405475766, + "isDeleted": false, + "id": "zyrHI3VsVcNzpHhKUC7PT", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1577.578125, + "y": 1010.9752170670826, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 226.21875, + "height": 457.2410441006672, + "seed": 1705963510, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "mNUT4H1nM5z16h_WpY5es", + "gap": 5.640625, + "focus": 0.9200658355960962 + }, + "endBinding": { + "elementId": "XGJfIAmhM56vmn95B8F0S", + "gap": 5.777343750000114, + "focus": 0.9575136078582848 + }, + "points": [ + [ + 0, + 0 + ], + [ + -226.21875, + 457.2410441006672 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 165, + "versionNonce": 417292970, + "isDeleted": false, + "id": "GZ0ewJ6BrZGIjDdP5lxxQ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1574.2929687500002, + "y": 1080.415767726428, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 223.77343750000023, + "height": 472.4490221240949, + "seed": 2045358646, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "9UcPXJlHcid22jXT5y4jE", + "gap": 9.4140625, + "focus": 0.9674033095583 + }, + "endBinding": { + "elementId": "dedTXRl0XN5yFz7KNxTSO", + "gap": 6.367187500000114, + "focus": 0.9753124844368333 + }, + "points": [ + [ + 0, + 0 + ], + [ + -223.77343750000023, + 472.4490221240949 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "text", + "version": 385, + "versionNonce": 1899820278, + "isDeleted": false, + "id": "CIC7K5kIM2cVlCdnBW_5A", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1453.26171875, + "y": 1356.3125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 433, + "height": 150, + "seed": 792520694, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "We parse the logs of each container of the\npod created by the scan job, convert from\nthe Trivy model and save it as an instance\nof the VulnerabilityReport resource.\nIn other words, vulnerability reports are\npartitioned by workload containers.", + "baseline": 143, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 669, + "versionNonce": 82935146, + "isDeleted": false, + "id": "4JDHNT94kBH7cNCV56Cds", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 556.296875, + "y": 187.41015625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 361, + "height": 175, + "seed": 1929438390, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Imagine that your app is controlled\nby a Kubernetes Deployment and\nits PodSpec has 2 init containers\nand 3 (regular) containers.\n\nIn Starboard we scan it by creating\na scan Job and parsing job logs.", + "baseline": 168, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 454, + "versionNonce": 452912694, + "isDeleted": false, + "id": "8r6AHavBXyGDRtZh0lh6X", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1077.07421875, + "y": 621.05859375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 291.7265625, + "height": 38.16015625, + "seed": 669882602, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "Z8HYEbUAolbhNLvGrA0Ux", + "focus": 0.9433003744961849, + "gap": 6.62890625 + }, + "endBinding": { + "elementId": "vJpTF1Zoq5fm_CXo29RWm", + "focus": 0.7669631771179715, + "gap": 3.94921875 + }, + "points": [ + [ + 0, + 0 + ], + [ + -291.7265625, + -38.16015625 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 99, + "versionNonce": 1165115434, + "isDeleted": false, + "id": "vc9ul_c_FFwQkadvvz_2S", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 876.39816394962, + "y": 1224.87109375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 117.06457809985534, + "height": 641.4609375, + "seed": 876033002, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "JgE78vdkE_YliqGhlt12x", + "focus": -0.6668993060443487, + "gap": 10.4453125 + }, + "endBinding": { + "elementId": "vJpTF1Zoq5fm_CXo29RWm", + "focus": 0.4490292827945962, + "gap": 4.4609375 + }, + "points": [ + [ + 0, + 0 + ], + [ + -117.06457809985534, + -641.4609375 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "text", + "version": 41, + "versionNonce": 837857142, + "isDeleted": false, + "id": "yhhj6k5e9X4n9ubGJowEE", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 702.8984375, + "y": 872.890625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 86, + "height": 25, + "seed": 932759274, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "owned by", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 479, + "versionNonce": 90262006, + "isDeleted": false, + "id": "bGBp9QaZkdzSeoKm2b6iX", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2072.62109375, + "y": 549.29296875, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 514.921875, + "height": 129.19921875, + "seed": 1546300726, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "t4Brg6J6A5S0aFdcHd-y1", + "vq-_k7K1YIpQx44TFH1dy", + "YIUGoeMa4nWwuoDD7XcWE", + "bFqFkqKuElN8wqX7QpC8r", + "Wwoq-EptjcLv-5LfZTgHC", + "orYLPxj_Q85F-Qe7Y_DkC", + "gQ91H34aCC9zQApf-JZ2h" + ] + }, + { + "type": "text", + "version": 206, + "versionNonce": 1050803370, + "isDeleted": false, + "id": "-P2sHI5Q72juz98DJ05Dj", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1436.4375, + "y": 475.52734375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 313, + "height": 25, + "seed": 903146102, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Namespace: starboard-operator", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 378, + "versionNonce": 508520810, + "isDeleted": false, + "id": "qio4lw3e6rLgUFDyoHEq0", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2097.0078125, + "y": 565.482421875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 271, + "height": 25, + "seed": 1897215094, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Secret: starboard-operator", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 354, + "versionNonce": 848056502, + "isDeleted": false, + "id": "2GVH7fQ4bEEu57lacs64_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2090.015625, + "y": 612.6640625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 483, + "height": 50, + "seed": 80709430, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "trivy.serverURL: https://api-dev.aquasec.com/vs/v1\ntrivy.serverAPIToken: ******", + "baseline": 43, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 417, + "versionNonce": 715294262, + "isDeleted": false, + "id": "napQEGHuVbev1mxDABTmJ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2251.31640625, + "y": 698.6875, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 345, + "height": 100, + "seed": 546430518, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "We have a secret to store config\nof remote Trivy server. We can use\nenv value from secret to create\ncontainer command as shown below.", + "baseline": 93, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 148, + "versionNonce": 192235050, + "isDeleted": false, + "id": "t4Brg6J6A5S0aFdcHd-y1", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1875.875, + "y": 742.6594294702824, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 194.453125, + "height": 110.68119360186745, + "seed": 1137059062, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "hI3VMcGgYLy-YFmKmOscS", + "focus": 0.8000704812216826, + "gap": 10.54296875 + }, + "endBinding": { + "elementId": "bGBp9QaZkdzSeoKm2b6iX", + "focus": 0.6145758808749083, + "gap": 2.29296875 + }, + "points": [ + [ + 0, + 0 + ], + [ + 194.453125, + -110.68119360186745 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 376, + "versionNonce": 33485034, + "isDeleted": false, + "id": "vq-_k7K1YIpQx44TFH1dy", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1878.984375, + "y": 813.1024166069419, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 188.89854909975747, + "height": 123.9219772167562, + "seed": 1061847850, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "OYQSaJMgpc4vp96JjAaZL", + "focus": 0.7644938743691578, + "gap": 10.7265625 + }, + "endBinding": { + "elementId": "bGBp9QaZkdzSeoKm2b6iX", + "focus": 0.41422258822766955, + "gap": 11.69140625 + }, + "points": [ + [ + 0, + 0 + ], + [ + 188.89854909975747, + -123.9219772167562 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 180, + "versionNonce": 931480490, + "isDeleted": false, + "id": "YIUGoeMa4nWwuoDD7XcWE", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1870.703125, + "y": 936.0008463198731, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 219.74611779594306, + "height": 246.17662756987306, + "seed": 1676460022, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "9Pb5mHfThK9qomtZ2VipC", + "focus": 0.9386145746934619, + "gap": 9.8046875 + }, + "endBinding": { + "elementId": "bGBp9QaZkdzSeoKm2b6iX", + "focus": 0.5453503912233465, + "gap": 11.33203125 + }, + "points": [ + [ + 0, + 0 + ], + [ + 219.74611779594306, + -246.17662756987306 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 151, + "versionNonce": 1983069802, + "isDeleted": false, + "id": "bFqFkqKuElN8wqX7QpC8r", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1868.73828125, + "y": 1012.1294012465178, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 235.93407628698333, + "height": 319.0747137465178, + "seed": 870785386, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "mNUT4H1nM5z16h_WpY5es", + "focus": 0.9673213099566278, + "gap": 8.52734375 + }, + "endBinding": { + "elementId": "bGBp9QaZkdzSeoKm2b6iX", + "focus": 0.5467214439530373, + "gap": 14.5625 + }, + "points": [ + [ + 0, + 0 + ], + [ + 235.93407628698333, + -319.0747137465178 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 139, + "versionNonce": 181657898, + "isDeleted": false, + "id": "Wwoq-EptjcLv-5LfZTgHC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1867.0873775512462, + "y": 1103.1453010695393, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 251.8701554595766, + "height": 412.3913948195393, + "seed": 1190748650, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "9UcPXJlHcid22jXT5y4jE", + "focus": 1.0473274209515526, + "gap": 7.1875 + }, + "endBinding": { + "elementId": "bGBp9QaZkdzSeoKm2b6iX", + "focus": 0.5529555038263079, + "gap": 12.26171875 + }, + "points": [ + [ + 0, + 0 + ], + [ + 251.8701554595766, + -412.3913948195393 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "text", + "version": 414, + "versionNonce": 1054409846, + "isDeleted": false, + "id": "4Ep4c4KYvgPen1JtESlQZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1969.5234375, + "y": 827.64453125, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 288, + "height": 40, + "seed": 1412607018, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 16, + "fontFamily": 1, + "text": "Set the value of SERVER_URL\nfrom the starboard-operator secret", + "baseline": 34, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 519, + "versionNonce": 835754806, + "isDeleted": false, + "id": "2JznR0lsJ17JbB1UG9xAB", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1695.72265625, + "y": 221.9375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 348.20312499999994, + "height": 156.05078125000003, + "seed": 1277185910, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "gQ91H34aCC9zQApf-JZ2h" + ] + }, + { + "type": "text", + "version": 382, + "versionNonce": 953667254, + "isDeleted": false, + "id": "XtBY_OSpegQ4xj8W5cPWJ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1736.822265625, + "y": 242.72265625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 213, + "height": 25, + "seed": 1533491318, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Trivy (Remove) Server", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle" + }, + { + "type": "rectangle", + "version": 454, + "versionNonce": 1649584182, + "isDeleted": false, + "id": "8BIUyxUq-I8sBKiB9HlTF", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2213.8125, + "y": 221.69921875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 375.8515625000001, + "height": 150.76171875, + "seed": 92543030, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "orYLPxj_Q85F-Qe7Y_DkC" + ] + }, + { + "type": "text", + "version": 466, + "versionNonce": 1704495094, + "isDeleted": false, + "id": "aZvlydIUzUVR7y3qg6tVI", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2255.7109375, + "y": 246.63671875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 104, + "height": 25, + "seed": 1493207146, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Aqua Wave", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 825, + "versionNonce": 1141676650, + "isDeleted": false, + "id": "kM5FH44dXPc52CFPYXsBN", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1739.103515625, + "y": 286.56640625, + "strokeColor": "#000000", + "backgroundColor": "#228be6", + "width": 254.83203125, + "height": 59.6640625, + "seed": 1364251178, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "N2pn_BY-2QZPDsCVd4fpL" + ] + }, + { + "type": "text", + "version": 615, + "versionNonce": 1148197174, + "isDeleted": false, + "id": "kl8o_6rOHRnrtZDxW7aR5", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1766.880859375, + "y": 303.95703125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 208, + "height": 25, + "seed": 1182547318, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Trivy DB / Bolt DB", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 848, + "versionNonce": 749018154, + "isDeleted": false, + "id": "tzVLiDarDEdw5iwm88uxl", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2268.447265625, + "y": 286.70703125, + "strokeColor": "#000000", + "backgroundColor": "#228be6", + "width": 254.83203125, + "height": 59.6640625, + "seed": 1412117482, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "N2pn_BY-2QZPDsCVd4fpL" + ] + }, + { + "type": "text", + "version": 575, + "versionNonce": 1921819882, + "isDeleted": false, + "id": "4N7dcZyEUA5e3h3APzSNv", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2283.037109375, + "y": 302.2578125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 208, + "height": 25, + "seed": 1044502454, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Trivy DB / Bolt DB", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 308, + "versionNonce": 1319358582, + "isDeleted": false, + "id": "IpqT21LAh9feTSrpqAGs-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2077.015625, + "y": 285.765625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 81, + "height": 25, + "seed": 7927850, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "-- OR --", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 467, + "versionNonce": 1086135466, + "isDeleted": false, + "id": "cciAITpRvxrRCxdl2r_YB", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1697.26171875, + "y": 165.75, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 329, + "height": 50, + "seed": 1899211626, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Self-hosted Trivy server. May\nor may not require authentication", + "baseline": 43, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 398, + "versionNonce": 868219562, + "isDeleted": false, + "id": "1YinTo1YdqSH08h9Y2Sem", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2232.26171875, + "y": 161.93359375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 408, + "height": 50, + "seed": 1497611434, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Trivy server that's part\nof Aqua SaaS solution. Requires API key", + "baseline": 43, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 93, + "versionNonce": 749881578, + "isDeleted": false, + "id": "orYLPxj_Q85F-Qe7Y_DkC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2292.97265625, + "y": 537.36328125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 71.77734375, + "height": 153.7578125, + "seed": 940475626, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "bGBp9QaZkdzSeoKm2b6iX", + "focus": -0.25323519177994264, + "gap": 11.9296875 + }, + "endBinding": { + "elementId": "8BIUyxUq-I8sBKiB9HlTF", + "focus": -0.015254770220889774, + "gap": 11.14453125 + }, + "points": [ + [ + 0, + 0 + ], + [ + 71.77734375, + -153.7578125 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 50, + "versionNonce": 1940453482, + "isDeleted": false, + "id": "gQ91H34aCC9zQApf-JZ2h", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2271.77734375, + "y": 525.859375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 295.9140625, + "height": 132.5390625, + "seed": 1645058986, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "bGBp9QaZkdzSeoKm2b6iX", + "focus": 0.3441540976055893, + "gap": 23.43359375 + }, + "endBinding": { + "elementId": "2JznR0lsJ17JbB1UG9xAB", + "focus": 0.2939831035497699, + "gap": 15.33203125 + }, + "points": [ + [ + 0, + 0 + ], + [ + -295.9140625, + -132.5390625 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "text", + "version": 85, + "versionNonce": 1385554486, + "isDeleted": false, + "id": "HJbQ0ac1W9Y-IgYCdMZqV", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2107.92578125, + "y": 415.25, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 215, + "height": 25, + "seed": 1321452662, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "configure Trivy server", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + } +} \ No newline at end of file diff --git a/docs/design/starboard-trivy-clientserver.png b/docs/design/starboard-trivy-clientserver.png new file mode 100644 index 000000000..85072334d Binary files /dev/null and b/docs/design/starboard-trivy-clientserver.png differ diff --git a/docs/design/starboard-trivy-standalone.excalidraw b/docs/design/starboard-trivy-standalone.excalidraw new file mode 100644 index 000000000..c4bd5c119 --- /dev/null +++ b/docs/design/starboard-trivy-standalone.excalidraw @@ -0,0 +1,2191 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "rectangle", + "version": 674, + "versionNonce": 114131562, + "isDeleted": false, + "id": "2zcTzKxfvspcvH1gAxn6D", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 557.421875, + "y": 419.15234375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 257.50390625, + "height": 63.15625, + "seed": 439588342, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "bchwcZRmyIw3S38xIZDWv" + ] + }, + { + "type": "text", + "version": 452, + "versionNonce": 949072182, + "isDeleted": false, + "id": "FsSKMvnttAAlNn19RvCwT", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 604.7734375, + "y": 438.521484375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 162, + "height": 25, + "seed": 382917174, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Deployment: app", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 562, + "versionNonce": 394634538, + "isDeleted": false, + "id": "vJpTF1Zoq5fm_CXo29RWm", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 662.71875, + "y": 519.23828125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 336.85546875, + "height": 59.7109375, + "seed": 1789968234, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "bchwcZRmyIw3S38xIZDWv", + "vgpDXOyLLqyDEdP-ZUkIQ", + "8r6AHavBXyGDRtZh0lh6X", + "vc9ul_c_FFwQkadvvz_2S" + ] + }, + { + "type": "text", + "version": 613, + "versionNonce": 1223826038, + "isDeleted": false, + "id": "tPFHoaUPD1IjmpxWvFVyz", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 680.21875, + "y": 538.6796875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 268, + "height": 25, + "seed": 642409514, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "ReplicaSet: app-5fcdc7d5c7", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 1059, + "versionNonce": 179007466, + "isDeleted": false, + "id": "Z8HYEbUAolbhNLvGrA0Ux", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 875.984375, + "y": 627.6875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 374.89453124999994, + "height": 519.08203125, + "seed": 1996746666, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "gQf0Pk1RBVrZqQJKPyvCa", + "rtdh2joD7z4OpTZZQFuw3", + "vgpDXOyLLqyDEdP-ZUkIQ", + "8r6AHavBXyGDRtZh0lh6X" + ] + }, + { + "type": "text", + "version": 783, + "versionNonce": 1542675382, + "isDeleted": false, + "id": "FhlxiQk8g8amnkluVluwC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 914.0546875, + "y": 657.15625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 264, + "height": 25, + "seed": 1633791990, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Pod: app-5fcdc7d5c7-dtm8b", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 762, + "versionNonce": 340386474, + "isDeleted": false, + "id": "UJ1VkrcPCCIv8Z2Vv6iBp", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 912.21875, + "y": 717.625, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 286.5546875, + "height": 52.91796875, + "seed": 227414902, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "PwKCJjAqH5_gkyT2L1wy5" + ] + }, + { + "type": "text", + "version": 744, + "versionNonce": 398095606, + "isDeleted": false, + "id": "McH3kOxMiN50WfXAxksFi", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 985.3359375, + "y": 730.26953125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 140, + "height": 25, + "seed": 1124618358, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "init container 1", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 794, + "versionNonce": 789314922, + "isDeleted": false, + "id": "-F8_Q2CX1BUtkMqW1j96l", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 916.42578125, + "y": 791.9296875, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 285.45703125, + "height": 47.98828125, + "seed": 96365418, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "x3DRj4mEa3CAaCPvK0JlN" + ] + }, + { + "type": "text", + "version": 695, + "versionNonce": 365717046, + "isDeleted": false, + "id": "1C5KHPPhvyDANP6M6Q8d4", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1006.69140625, + "y": 803.7265625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 151, + "height": 25, + "seed": 1343723306, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "init container 2", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 757, + "versionNonce": 1211940906, + "isDeleted": false, + "id": "pC-tAN9Q1okEI-7CymMPt", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 922.6015625, + "y": 884.37109375, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 278.09765625, + "height": 67.66796875, + "seed": 81782454, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "vVEqkxRKSHp6QryskV90i" + ] + }, + { + "type": "text", + "version": 781, + "versionNonce": 1997418358, + "isDeleted": false, + "id": "exZSEqZ3a3-BKmf9xwHqf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1012.67578125, + "y": 905.9765625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 101, + "height": 25, + "seed": 2116617386, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "container 1", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 793, + "versionNonce": 1808214762, + "isDeleted": false, + "id": "peJbEMj3MxEgdcAmkYb0D", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 922.9140625, + "y": 975.7890625, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 280.89453125, + "height": 65.2421875, + "seed": 838299050, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "T0sXvUKRGNVhmBQ1GI4_m" + ] + }, + { + "type": "text", + "version": 718, + "versionNonce": 2009387190, + "isDeleted": false, + "id": "9S9rnW_ES5A_cnTGJt-76", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1006.861328125, + "y": 995.91015625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 113, + "height": 25, + "seed": 642653930, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "container 2", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle" + }, + { + "type": "rectangle", + "version": 811, + "versionNonce": 1882602922, + "isDeleted": false, + "id": "sb0hVmoIg41camtq428Oo", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 925.171875, + "y": 1058.26953125, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 278.2734375, + "height": 59.68359375, + "seed": 528437546, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "abE83CCSbnnv0B_nebnqq" + ] + }, + { + "type": "text", + "version": 712, + "versionNonce": 60115446, + "isDeleted": false, + "id": "saUtkC4mhMHiX7NzW1OW4", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1008.234375, + "y": 1075.611328125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 112, + "height": 25, + "seed": 498182966, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "container 3", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle" + }, + { + "type": "rectangle", + "version": 225, + "versionNonce": 582285418, + "isDeleted": false, + "id": "ux-MijhrKWxzx3aBxOi2-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1479.6484375, + "y": 370.18359375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 472.890625, + "height": 811.9921875, + "seed": 1740072746, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [] + }, + { + "type": "text", + "version": 153, + "versionNonce": 1233427254, + "isDeleted": false, + "id": "7vc7YDO86mroOlUiRQ9Mn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1513.65625, + "y": 389.3984375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 242, + "height": 25, + "seed": 214185910, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Job: some-uuid-goes-here", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 347, + "versionNonce": 1930320682, + "isDeleted": false, + "id": "8Ilz98ZilT6ouLqI17p5A", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1509.23046875, + "y": 450.99609375, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 415.29296875, + "height": 687.9765625, + "seed": 1680351222, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [] + }, + { + "type": "text", + "version": 48, + "versionNonce": 531457514, + "isDeleted": false, + "id": "AmKoTYwF7k-4nq-Z_qLvx", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1549, + "y": 460, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 78, + "height": 25, + "seed": 553792490, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "PodSpec", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 384, + "versionNonce": 724462390, + "isDeleted": false, + "id": "T3XotZFUflqc2LOFDOogS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1548.21875, + "y": 502.546875, + "strokeColor": "#000000", + "backgroundColor": "#12b886", + "width": 327.0195312500001, + "height": 73.30468750000004, + "seed": 742099690, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "N2pn_BY-2QZPDsCVd4fpL" + ] + }, + { + "type": "text", + "version": 108, + "versionNonce": 1335485674, + "isDeleted": false, + "id": "UxeVPh0n6eHeTGZjyBfWR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1592.529296875, + "y": 512.84765625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 202, + "height": 50, + "seed": 1714391530, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "init container uuid\n(download Trivy DB)", + "baseline": 43, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 109, + "versionNonce": 470675626, + "isDeleted": false, + "id": "-LiKmXtX3cDoQptT-q44o", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1629.203125, + "y": 595.87109375, + "strokeColor": "#000000", + "backgroundColor": "#be4bdb", + "width": 183.5546875, + "height": 72.44140625, + "seed": 599187562, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [] + }, + { + "type": "text", + "version": 68, + "versionNonce": 1761234998, + "isDeleted": false, + "id": "aSaCjh_QkCpez2PYnIwYv", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1639.48046875, + "y": 619.591796875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 163, + "height": 50, + "seed": 174589046, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Volume: emptyDir\nTRIVY DB", + "baseline": 43, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 216, + "versionNonce": 1991931434, + "isDeleted": false, + "id": "hI3VMcGgYLy-YFmKmOscS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1561.68359375, + "y": 699.1640625, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 303.64843749999994, + "height": 74.21875, + "seed": 1068673386, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "PwKCJjAqH5_gkyT2L1wy5", + "lu570Gln9QPiLj2MxAsaW", + "17bx5KvBPx51VKhsBJrlu" + ] + }, + { + "type": "text", + "version": 70, + "versionNonce": 1089395062, + "isDeleted": false, + "id": "5weO47P2LdFdUL8wlS3rd", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1576.458984375, + "y": 723.7734375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 278, + "height": 25, + "seed": 1292594538, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "container for init container 1", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle" + }, + { + "type": "rectangle", + "version": 198, + "versionNonce": 756949226, + "isDeleted": false, + "id": "OYQSaJMgpc4vp96JjAaZL", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1562.49609375, + "y": 787.77734375, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 305.76171875000006, + "height": 63.4921875, + "seed": 1583551350, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "x3DRj4mEa3CAaCPvK0JlN", + "nTVx3aec_IFiPVsj7XK-b" + ] + }, + { + "type": "text", + "version": 80, + "versionNonce": 1409301174, + "isDeleted": false, + "id": "jfWzR-c1o0vVA-HLRSPbY", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1573.025390625, + "y": 807.0234375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 290, + "height": 25, + "seed": 1190727542, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "container for init container 2", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle" + }, + { + "type": "rectangle", + "version": 230, + "versionNonce": 389968810, + "isDeleted": false, + "id": "9Pb5mHfThK9qomtZ2VipC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1580.4921875, + "y": 904.9296875, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 280.4062500000001, + "height": 53.3515625, + "seed": 169508714, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "vVEqkxRKSHp6QryskV90i", + "YTFS1ozx0oRq8nhpK62AK" + ] + }, + { + "type": "text", + "version": 219, + "versionNonce": 1490252790, + "isDeleted": false, + "id": "y9CmGYkVn0joznJMLfAEA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1613.1953125, + "y": 918.22265625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 239, + "height": 25, + "seed": 895136426, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "container for container 1", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 180, + "versionNonce": 1732669034, + "isDeleted": false, + "id": "mNUT4H1nM5z16h_WpY5es", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1583.21875, + "y": 974.96875, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 276.99218749999994, + "height": 55.73828125, + "seed": 684783338, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "T0sXvUKRGNVhmBQ1GI4_m", + "zyrHI3VsVcNzpHhKUC7PT" + ] + }, + { + "type": "text", + "version": 116, + "versionNonce": 1768785206, + "isDeleted": false, + "id": "hlA2RD1B4rOh7HwE2l2wG", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1600.53125, + "y": 992.609375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 251, + "height": 25, + "seed": 217017526, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "container for container 2", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 179, + "versionNonce": 1375801642, + "isDeleted": false, + "id": "9UcPXJlHcid22jXT5y4jE", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1583.62890625, + "y": 1050.17578125, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 276.2734375, + "height": 52.78125, + "seed": 819103850, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "abE83CCSbnnv0B_nebnqq", + "GZ0ewJ6BrZGIjDdP5lxxQ" + ] + }, + { + "type": "text", + "version": 117, + "versionNonce": 389246582, + "isDeleted": false, + "id": "03MscJpVYiTRxxe1D0trw", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1610.6953125, + "y": 1058.46484375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 250, + "height": 25, + "seed": 448352950, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "container for container 3", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 514, + "versionNonce": 66782774, + "isDeleted": false, + "id": "MaS-kmcdSzg6NVmxzlQ92", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1983.75, + "y": 445.41015625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 522, + "height": 125, + "seed": 199462570, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "The init container of the pod created by a scan job\nwill just download Trivy DB from GitHub\nand save it in the shared emptyDir volume\n\ntrivy --download-db-only --cache-dir /data", + "baseline": 118, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 1169, + "versionNonce": 359011318, + "isDeleted": false, + "id": "fXhvVEVcGNjdpiXgfaOd8", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1989.1328125, + "y": 781.130859375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 524, + "height": 250, + "seed": 540907626, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Each (regular) container of the pod created by\nthe scan job will run trivy with the --skip-update flag\nand pass to it the image ref of the corresponding\nworkload container's image:\n\ntrivy --skip-update \ntrivy --skip-update \ntrivy --skip-update \ntrivy --skip-update \ntrivy --skip-update ", + "baseline": 243, + "textAlign": "center", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 302, + "versionNonce": 501133802, + "isDeleted": false, + "id": "p5Ohccd4-soclwsgvA94-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1415.46484375, + "y": 172.94140625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 1153.7265625, + "height": 1035.76953125, + "seed": 492875254, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [] + }, + { + "type": "text", + "version": 361, + "versionNonce": 1008126838, + "isDeleted": false, + "id": "J7Oq9C_r5l0dUSpupESJd", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1471.4609375, + "y": 203.70703125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 467, + "height": 100, + "seed": 827532202, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Each scan job is ephemeral and pulls Trivy DB\nin its init container. Once the scan is complete\nthe scan job is terminated and the Trivy DB\nfile cached on the emptyDir volume is gone", + "baseline": 93, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 776, + "versionNonce": 262084330, + "isDeleted": false, + "id": "bchwcZRmyIw3S38xIZDWv", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 659.68359375, + "y": 567.690817811125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 84.9319972722792, + "height": 77.01894281112504, + "seed": 845012842, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "startBinding": { + "elementId": "vJpTF1Zoq5fm_CXo29RWm", + "focus": -0.9533169192267669, + "gap": 3.03515625 + }, + "endBinding": { + "elementId": "2zcTzKxfvspcvH1gAxn6D", + "focus": 0.950437357873753, + "gap": 8.36328125 + }, + "points": [ + [ + 0, + 0 + ], + [ + -84.9319972722792, + -77.01894281112504 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "rectangle", + "version": 574, + "versionNonce": 1304927734, + "isDeleted": false, + "id": "2_oLye4AI2AnotXJGnsiW", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 783.30859375, + "y": 1221.671875, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 553.6796874999998, + "height": 58.78515625, + "seed": 669404534, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "lu570Gln9QPiLj2MxAsaW", + "17bx5KvBPx51VKhsBJrlu" + ] + }, + { + "type": "text", + "version": 408, + "versionNonce": 176284778, + "isDeleted": false, + "id": "JgE78vdkE_YliqGhlt12x", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 800.1640625, + "y": 1235.31640625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 492, + "height": 25, + "seed": 313096502, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "vc9ul_c_FFwQkadvvz_2S" + ], + "fontSize": 20, + "fontFamily": 1, + "text": "VulnerabilityReport: app-5fcdc7d5c7-init container 1", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 641, + "versionNonce": 1112305462, + "isDeleted": false, + "id": "MUN_ild1OSjDtTHULafVn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 787.59765625, + "y": 1298.830078125, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 553.6796874999998, + "height": 58.78515625, + "seed": 536248438, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "nTVx3aec_IFiPVsj7XK-b" + ] + }, + { + "type": "text", + "version": 479, + "versionNonce": 710788906, + "isDeleted": false, + "id": "ynTqn21bEwC_hlFMgxvdS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 804.60546875, + "y": 1312.474609375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 503, + "height": 25, + "seed": 1627941354, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "VulnerabilityReport: app-5fcdc7d5c7-init container 2", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 693, + "versionNonce": 145037430, + "isDeleted": false, + "id": "nl_vUWOrB3oU4bqJ5UO0i", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 789.453125, + "y": 1369.419921875, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 553.6796874999998, + "height": 58.78515625, + "seed": 1953325098, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "YTFS1ozx0oRq8nhpK62AK" + ] + }, + { + "type": "text", + "version": 557, + "versionNonce": 305091050, + "isDeleted": false, + "id": "XXvQJIBJMWmwVfZE9fpcT", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 806.27734375, + "y": 1383.064453125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 453, + "height": 25, + "seed": 1538756470, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "VulnerabilityReport: app-5fcdc7d5c7-container 1", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 494, + "versionNonce": 1754700214, + "isDeleted": false, + "id": "XGJfIAmhM56vmn95B8F0S", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 791.90234375, + "y": 1446.130859375, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 553.6796874999998, + "height": 58.78515625, + "seed": 95421098, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "zyrHI3VsVcNzpHhKUC7PT" + ] + }, + { + "type": "text", + "version": 357, + "versionNonce": 83985578, + "isDeleted": false, + "id": "LXp8CsZaN6bzeCeUHlfxj", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 808.91015625, + "y": 1459.775390625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 464, + "height": 25, + "seed": 1866880246, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "VulnerabilityReport: app-5fcdc7d5c7-container 2", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 540, + "versionNonce": 1766191862, + "isDeleted": false, + "id": "dedTXRl0XN5yFz7KNxTSO", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 790.47265625, + "y": 1522.677734375, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 553.6796874999998, + "height": 58.78515625, + "seed": 2137730230, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "GZ0ewJ6BrZGIjDdP5lxxQ" + ] + }, + { + "type": "text", + "version": 403, + "versionNonce": 746545002, + "isDeleted": false, + "id": "y7iDaNAqOKHsnQ19ZqQRa", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 807.48046875, + "y": 1536.322265625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 464, + "height": 25, + "seed": 1639162282, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "VulnerabilityReport: app-5fcdc7d5c7-container 3", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 910, + "versionNonce": 1698178102, + "isDeleted": false, + "id": "PwKCJjAqH5_gkyT2L1wy5", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1203.1328125, + "y": 745.0754820337202, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 351.4843750000002, + "height": 6.672541307797019, + "seed": 1512280374, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "UJ1VkrcPCCIv8Z2Vv6iBp", + "focus": 0.13082513502686008, + "gap": 4.359375 + }, + "endBinding": { + "elementId": "hI3VMcGgYLy-YFmKmOscS", + "focus": 0.022176142561223914, + "gap": 7.06640625 + }, + "points": [ + [ + 0, + 0 + ], + [ + 351.4843750000002, + -6.672541307797019 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 891, + "versionNonce": 1156833834, + "isDeleted": false, + "id": "x3DRj4mEa3CAaCPvK0JlN", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1207.8046875, + "y": 817.5838885052679, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 347.1875000000002, + "height": 4.79968231326302, + "seed": 200305078, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "-F8_Q2CX1BUtkMqW1j96l", + "focus": -0.015220731040753156, + "gap": 5.921875 + }, + "endBinding": { + "elementId": "OYQSaJMgpc4vp96JjAaZL", + "focus": -0.14995359560994803, + "gap": 7.50390625 + }, + "points": [ + [ + 0, + 0 + ], + [ + 347.1875000000002, + 4.79968231326302 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 947, + "versionNonce": 508702070, + "isDeleted": false, + "id": "vVEqkxRKSHp6QryskV90i", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1204.203125, + "y": 916.5267530978466, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 369.66015625, + "height": 13.914920373884684, + "seed": 491556470, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "pC-tAN9Q1okEI-7CymMPt", + "gap": 3.50390625, + "focus": -0.1804452292995827 + }, + "endBinding": { + "elementId": "9Pb5mHfThK9qomtZ2VipC", + "gap": 6.62890625, + "focus": -0.13655286703598196 + }, + "points": [ + [ + 0, + 0 + ], + [ + 369.66015625, + 13.914920373884684 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 969, + "versionNonce": 1229589738, + "isDeleted": false, + "id": "T0sXvUKRGNVhmBQ1GI4_m", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1213.5078125, + "y": 1009.1266280518233, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 368.37109375, + "height": 2.647283889434334, + "seed": 352974134, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "peJbEMj3MxEgdcAmkYb0D", + "gap": 9.69921875, + "focus": -0.010771100602347409 + }, + "endBinding": { + "elementId": "mNUT4H1nM5z16h_WpY5es", + "gap": 1.33984375, + "focus": -0.34440119295781213 + }, + "points": [ + [ + 0, + 0 + ], + [ + 368.37109375, + 2.647283889434334 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 903, + "versionNonce": 1373179574, + "isDeleted": false, + "id": "abE83CCSbnnv0B_nebnqq", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1209.8984375, + "y": 1088.3245533896368, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 367.83984375, + "height": 12.310498146972577, + "seed": 1580857910, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "sb0hVmoIg41camtq428Oo", + "gap": 6.453125, + "focus": 0.1474116319262928 + }, + "endBinding": { + "elementId": "9UcPXJlHcid22jXT5y4jE", + "gap": 5.890625, + "focus": 0.17323067100506717 + }, + "points": [ + [ + 0, + 0 + ], + [ + 367.83984375, + -12.310498146972577 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "text", + "version": 355, + "versionNonce": 520937386, + "isDeleted": false, + "id": "VYTicavnfty33jy7uDif1", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1018.0078125, + "y": 579.6640625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 125, + "height": 25, + "seed": 763663734, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "controlled by", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 323, + "versionNonce": 1282525174, + "isDeleted": false, + "id": "E-VIJs1DaWm8FdfOHLuPr", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 503.66015625, + "y": 536.58203125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 125, + "height": 25, + "seed": 1314052458, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "controlled by", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 811, + "versionNonce": 2116114742, + "isDeleted": false, + "id": "nTVx3aec_IFiPVsj7XK-b", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1555.26171875, + "y": 803.4319687646107, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 210.431640625, + "height": 523.20613556021, + "seed": 368626806, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "OYQSaJMgpc4vp96JjAaZL", + "focus": 1.005662737566369, + "gap": 7.234375 + }, + "endBinding": { + "elementId": "MUN_ild1OSjDtTHULafVn", + "focus": 0.96914670356047, + "gap": 3.552734375 + }, + "points": [ + [ + 0, + 0 + ], + [ + -210.431640625, + 523.20613556021 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 175, + "versionNonce": 1914993962, + "isDeleted": false, + "id": "17bx5KvBPx51VKhsBJrlu", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1555.8125, + "y": 722.6210937499998, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 210.78125, + "height": 504.5811170719219, + "seed": 1746632758, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "hI3VMcGgYLy-YFmKmOscS", + "focus": 0.9765084802280298, + "gap": 5.87109375 + }, + "endBinding": { + "elementId": "2_oLye4AI2AnotXJGnsiW", + "focus": 0.9508732350289565, + "gap": 8.042968750000114 + }, + "points": [ + [ + 0, + 0 + ], + [ + -210.78125, + 504.5811170719219 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 169, + "versionNonce": 239911542, + "isDeleted": false, + "id": "YTFS1ozx0oRq8nhpK62AK", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1572.7929687500002, + "y": 931.8864414829819, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 224.31250000000023, + "height": 460.4232982016432, + "seed": 875737014, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "9Pb5mHfThK9qomtZ2VipC", + "gap": 7.69921875, + "focus": 0.9645562972522097 + }, + "endBinding": { + "elementId": "nl_vUWOrB3oU4bqJ5UO0i", + "gap": 5.347656250000114, + "focus": 0.9583042830491013 + }, + "points": [ + [ + 0, + 0 + ], + [ + -224.31250000000023, + 460.4232982016432 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 199, + "versionNonce": 1538213866, + "isDeleted": false, + "id": "zyrHI3VsVcNzpHhKUC7PT", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1577.578125, + "y": 1010.9752170670826, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 226.21875, + "height": 457.2410441006672, + "seed": 1705963510, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "mNUT4H1nM5z16h_WpY5es", + "gap": 5.640625, + "focus": 0.9200658355960962 + }, + "endBinding": { + "elementId": "XGJfIAmhM56vmn95B8F0S", + "gap": 5.777343750000114, + "focus": 0.9575136078582848 + }, + "points": [ + [ + 0, + 0 + ], + [ + -226.21875, + 457.2410441006672 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 163, + "versionNonce": 1874396086, + "isDeleted": false, + "id": "GZ0ewJ6BrZGIjDdP5lxxQ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1574.2929687500002, + "y": 1080.415767726428, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 223.77343750000023, + "height": 472.4490221240949, + "seed": 2045358646, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "9UcPXJlHcid22jXT5y4jE", + "gap": 9.4140625, + "focus": 0.9674033095583 + }, + "endBinding": { + "elementId": "dedTXRl0XN5yFz7KNxTSO", + "gap": 6.367187500000114, + "focus": 0.9753124844368333 + }, + "points": [ + [ + 0, + 0 + ], + [ + -223.77343750000023, + 472.4490221240949 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "text", + "version": 383, + "versionNonce": 1192409770, + "isDeleted": false, + "id": "CIC7K5kIM2cVlCdnBW_5A", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1453.26171875, + "y": 1356.3125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 433, + "height": 150, + "seed": 792520694, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "We parse the logs of each container of the\npod created by the scan job, convert from\nthe Trivy model and save it as an instance\nof the VulnerabilityReport resource.\nIn other words, vulnerability reports are\npartitioned by workload containers.", + "baseline": 143, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 667, + "versionNonce": 994928566, + "isDeleted": false, + "id": "4JDHNT94kBH7cNCV56Cds", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 556.296875, + "y": 187.41015625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 361, + "height": 175, + "seed": 1929438390, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Imagine that your app is controlled\nby a Kubernetes Deployment and\nits PodSpec has 2 init containers\nand 3 (regular) containers.\n\nIn Starboard we scan it by creating\na scan Job and parsing job logs.", + "baseline": 168, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 452, + "versionNonce": 1648889398, + "isDeleted": false, + "id": "8r6AHavBXyGDRtZh0lh6X", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1077.07421875, + "y": 621.05859375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 291.7265625, + "height": 38.16015625, + "seed": 669882602, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "Z8HYEbUAolbhNLvGrA0Ux", + "focus": 0.9433003744961849, + "gap": 6.62890625 + }, + "endBinding": { + "elementId": "vJpTF1Zoq5fm_CXo29RWm", + "focus": 0.7669631771179715, + "gap": 3.94921875 + }, + "points": [ + [ + 0, + 0 + ], + [ + -291.7265625, + -38.16015625 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "arrow", + "version": 97, + "versionNonce": 1157025898, + "isDeleted": false, + "id": "vc9ul_c_FFwQkadvvz_2S", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 876.39816394962, + "y": 1224.87109375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 117.06457809985534, + "height": 641.4609375, + "seed": 876033002, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "JgE78vdkE_YliqGhlt12x", + "focus": -0.6668993060443487, + "gap": 10.4453125 + }, + "endBinding": { + "elementId": "vJpTF1Zoq5fm_CXo29RWm", + "focus": 0.4490292827945962, + "gap": 4.4609375 + }, + "points": [ + [ + 0, + 0 + ], + [ + -117.06457809985534, + -641.4609375 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "text", + "version": 39, + "versionNonce": 1189888822, + "isDeleted": false, + "id": "yhhj6k5e9X4n9ubGJowEE", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 702.8984375, + "y": 872.890625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 86, + "height": 25, + "seed": 932759274, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "owned by", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "rectangle", + "version": 463, + "versionNonce": 677321270, + "isDeleted": false, + "id": "dAsHYXYxJv185JqmzfB4N", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1077.77734375, + "y": 223.703125, + "strokeColor": "#000000", + "backgroundColor": "#228be6", + "width": 254.83203125, + "height": 59.6640625, + "seed": 51437994, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "N2pn_BY-2QZPDsCVd4fpL" + ] + }, + { + "type": "text", + "version": 439, + "versionNonce": 1657205738, + "isDeleted": false, + "id": "sKd3VxwZns4yEG1b9WiLZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1017.98828125, + "y": 179.36328125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 374, + "height": 25, + "seed": 687481130, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "http://github.com/aquasecurity/tirvy-db", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "text", + "version": 254, + "versionNonce": 1212290998, + "isDeleted": false, + "id": "ad1R0Tkg4PjHbQkzNV2IB", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1105.5546875, + "y": 241.09375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 208, + "height": 25, + "seed": 1143014838, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Trivy DB / Bolt DB", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top" + }, + { + "type": "arrow", + "version": 643, + "versionNonce": 220881782, + "isDeleted": false, + "id": "N2pn_BY-2QZPDsCVd4fpL", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1544.337782336254, + "y": 540.4352409432399, + "strokeColor": "#000000", + "backgroundColor": "#228be6", + "width": 342.7419383704557, + "height": 250.90013070192998, + "seed": 1517522614, + "groupIds": [], + "strokeSharpness": "round", + "boundElementIds": [], + "startBinding": { + "elementId": "T3XotZFUflqc2LOFDOogS", + "gap": 3.880967663746049, + "focus": -0.7916723821934804 + }, + "endBinding": { + "elementId": "dAsHYXYxJv185JqmzfB4N", + "gap": 6.167922741309965, + "focus": 0.3138243510594517 + }, + "points": [ + [ + 0, + 0 + ], + [ + -342.7419383704557, + -250.90013070192998 + ] + ], + "lastCommittedPoint": null + }, + { + "type": "text", + "version": 219, + "versionNonce": 1858980650, + "isDeleted": false, + "id": "SO-FzLuGORrwDwrEoplk8", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1180.38671875, + "y": 395.41796875, + "strokeColor": "#000000", + "backgroundColor": "#228be6", + "width": 167, + "height": 75, + "seed": 76230314, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 1, + "text": "Download from\nGitHub is subject\nto rate limit", + "baseline": 68, + "textAlign": "left", + "verticalAlign": "top" + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + } +} \ No newline at end of file diff --git a/docs/design/starboard-trivy-standalone.png b/docs/design/starboard-trivy-standalone.png new file mode 100644 index 000000000..a7187bcf0 Binary files /dev/null and b/docs/design/starboard-trivy-standalone.png differ diff --git a/itest/starboard/starboard_cli_test.go b/itest/starboard/starboard_cli_test.go index eb7acc133..0e619d7d7 100644 --- a/itest/starboard/starboard_cli_test.go +++ b/itest/starboard/starboard_cli_test.go @@ -224,7 +224,7 @@ var _ = Describe("Starboard CLI", func() { "Scanner": Equal(v1alpha1.Scanner{ Name: "Trivy", Vendor: "Aqua Security", - Version: "0.9.1", + Version: "0.12.0", }), }), }), @@ -289,7 +289,7 @@ var _ = Describe("Starboard CLI", func() { "Scanner": Equal(v1alpha1.Scanner{ Name: "Trivy", Vendor: "Aqua Security", - Version: "0.9.1", + Version: "0.12.0", }), }), }), @@ -312,7 +312,7 @@ var _ = Describe("Starboard CLI", func() { "Scanner": Equal(v1alpha1.Scanner{ Name: "Trivy", Vendor: "Aqua Security", - Version: "0.9.1", + Version: "0.12.0", }), }), }), @@ -395,7 +395,7 @@ var _ = Describe("Starboard CLI", func() { "Scanner": Equal(v1alpha1.Scanner{ Name: "Trivy", Vendor: "Aqua Security", - Version: "0.9.1", + Version: "0.12.0", }), }), }), @@ -490,7 +490,7 @@ var _ = Describe("Starboard CLI", func() { "Scanner": Equal(v1alpha1.Scanner{ Name: "Trivy", Vendor: "Aqua Security", - Version: "0.9.1", + Version: "0.12.0", }), }), }), @@ -581,7 +581,7 @@ var _ = Describe("Starboard CLI", func() { "Scanner": Equal(v1alpha1.Scanner{ Name: "Trivy", Vendor: "Aqua Security", - Version: "0.9.1", + Version: "0.12.0", }), }), }), @@ -672,7 +672,7 @@ var _ = Describe("Starboard CLI", func() { "Scanner": Equal(v1alpha1.Scanner{ Name: "Trivy", Vendor: "Aqua Security", - Version: "0.9.1", + Version: "0.12.0", }), }), }), @@ -714,7 +714,7 @@ var _ = Describe("Starboard CLI", func() { Scanner: v1alpha1.Scanner{ Name: "Trivy", Vendor: "Aqua Security", - Version: "0.9.1", + Version: "0.12.0", }, Registry: v1alpha1.Registry{ Server: "index.docker.io", diff --git a/pkg/cmd/find_vulnerabilities.go b/pkg/cmd/find_vulnerabilities.go index 6b4460621..efd0cbd96 100644 --- a/pkg/cmd/find_vulnerabilities.go +++ b/pkg/cmd/find_vulnerabilities.go @@ -4,12 +4,13 @@ import ( "context" "fmt" + "github.com/aquasecurity/starboard/pkg/find/vulnerabilities" + "github.com/aquasecurity/starboard/pkg/vulnerabilityreport" starboardapi "github.com/aquasecurity/starboard/pkg/generated/clientset/versioned" "github.com/aquasecurity/starboard/pkg/starboard" - "github.com/aquasecurity/starboard/pkg/find/vulnerabilities/trivy" "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/client-go/kubernetes" @@ -82,7 +83,7 @@ NAME is the name of a particular Kubernetes workload. return err } scheme := starboard.NewScheme() - reports, err := trivy.NewScanner(scheme, config, opts, kubernetesClientset).Scan(ctx, workload) + reports, err := vulnerabilities.NewScanner(scheme, config, opts, kubernetesClientset).Scan(ctx, workload) if err != nil { return err } diff --git a/pkg/find/vulnerabilities/scanner.go b/pkg/find/vulnerabilities/scanner.go new file mode 100644 index 000000000..bf49ae453 --- /dev/null +++ b/pkg/find/vulnerabilities/scanner.go @@ -0,0 +1,192 @@ +package vulnerabilities + +import ( + "context" + "fmt" + "io" + + "github.com/aquasecurity/starboard/pkg/resources" + + "github.com/aquasecurity/starboard/pkg/ext" + + "github.com/aquasecurity/starboard/pkg/trivy" + + "github.com/aquasecurity/starboard/pkg/vulnerabilityreport" + "k8s.io/apimachinery/pkg/runtime" + + "github.com/aquasecurity/starboard/pkg/starboard" + + "github.com/aquasecurity/starboard/pkg/scanners" + "k8s.io/klog" + + "github.com/aquasecurity/starboard/pkg/kube" + "github.com/aquasecurity/starboard/pkg/runner" + + sec "github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1" + "github.com/aquasecurity/starboard/pkg/kube/pod" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/utils/pointer" +) + +// NewScanner constructs a new vulnerability Scanner with the specified options and Kubernetes client Interface. +func NewScanner(scheme *runtime.Scheme, config starboard.TrivyConfig, opts kube.ScannerOpts, clientset kubernetes.Interface) *Scanner { + idGenerator := ext.NewGoogleUUIDGenerator() + return &Scanner{ + scheme: scheme, + config: config, + opts: opts, + clientset: clientset, + pods: pod.NewPodManager(clientset), + converter: trivy.DefaultConverter, + idGenerator: idGenerator, + delegate: trivy.NewScanner(idGenerator, config), + } +} + +type Scanner struct { + scheme *runtime.Scheme + config starboard.TrivyConfig + opts kube.ScannerOpts + clientset kubernetes.Interface + pods *pod.Manager + converter trivy.Converter + idGenerator ext.IDGenerator + delegate vulnerabilityreport.Scanner +} + +func (s *Scanner) Scan(ctx context.Context, workload kube.Object) ([]sec.VulnerabilityReport, error) { + klog.V(3).Infof("Getting Pod template for workload: %v", workload) + podSpec, owner, err := s.pods.GetPodSpecByWorkload(ctx, workload) + if err != nil { + return nil, fmt.Errorf("getting Pod template: %w", err) + } + + reports, err := s.ScanByPodSpec(ctx, workload, podSpec, owner) + if err != nil { + return nil, err + } + return reports, nil +} + +func (s *Scanner) ScanByPodSpec(ctx context.Context, workload kube.Object, spec corev1.PodSpec, owner metav1.Object) ([]sec.VulnerabilityReport, error) { + klog.V(3).Infof("Scanning with options: %+v", s.opts) + + job, err := s.PrepareScanJob(workload, spec) + if err != nil { + return nil, fmt.Errorf("preparing scan job: %w", err) + } + + err = runner.New().Run(ctx, kube.NewRunnableJob(s.clientset, job)) + if err != nil { + s.pods.LogRunnerErrors(ctx, job) + return nil, fmt.Errorf("running scan job: %w", err) + } + + defer func() { + if !s.opts.DeleteScanJob { + klog.V(3).Infof("Skipping scan job deletion: %s/%s", job.Namespace, job.Name) + return + } + klog.V(3).Infof("Deleting scan job: %s/%s", job.Namespace, job.Name) + background := metav1.DeletePropagationBackground + _ = s.clientset.BatchV1().Jobs(job.Namespace).Delete(ctx, job.Name, metav1.DeleteOptions{ + PropagationPolicy: &background, + }) + }() + + klog.V(3).Infof("Scan job completed: %s/%s", job.Namespace, job.Name) + + job, err = s.clientset.BatchV1().Jobs(job.Namespace).Get(ctx, job.Name, metav1.GetOptions{}) + if err != nil { + return nil, fmt.Errorf("getting scan job: %w", err) + } + + return s.GetVulnerabilityReportsByScanJob(ctx, job, owner) +} + +func (s *Scanner) PrepareScanJob(workload kube.Object, spec corev1.PodSpec) (*batchv1.Job, error) { + templateSpec, err := s.delegate.GetPodSpec(spec) + if err != nil { + return nil, err + } + + templateSpec.ServiceAccountName = starboard.ServiceAccountName + + containerImagesAsJSON, err := resources.GetContainerImagesFromPodSpec(spec).AsJSON() + if err != nil { + return nil, err + } + + return &batchv1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: s.idGenerator.GenerateID(), + Namespace: starboard.NamespaceName, + Labels: map[string]string{ + kube.LabelResourceKind: string(workload.Kind), + kube.LabelResourceName: workload.Name, + kube.LabelResourceNamespace: workload.Namespace, + }, + Annotations: map[string]string{ + kube.AnnotationContainerImages: containerImagesAsJSON, + }, + }, + Spec: batchv1.JobSpec{ + BackoffLimit: pointer.Int32Ptr(0), + Completions: pointer.Int32Ptr(1), + ActiveDeadlineSeconds: scanners.GetActiveDeadlineSeconds(s.opts.ScanJobTimeout), + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + kube.LabelResourceKind: string(workload.Kind), + kube.LabelResourceName: workload.Name, + kube.LabelResourceNamespace: workload.Namespace, + }, + }, + Spec: templateSpec, + }, + }, + }, nil +} + +func (s *Scanner) GetVulnerabilityReportsByScanJob(ctx context.Context, job *batchv1.Job, owner metav1.Object) ([]sec.VulnerabilityReport, error) { + var reports []sec.VulnerabilityReport + + var containerImagesAsJSON string + var ok bool + + if containerImagesAsJSON, ok = job.Annotations[kube.AnnotationContainerImages]; !ok { + return nil, fmt.Errorf("scan job does not have required annotation: %s", kube.AnnotationContainerImages) + } + containerImages := kube.ContainerImages{} + err := containerImages.FromJSON(containerImagesAsJSON) + if err != nil { + return nil, fmt.Errorf("reading scan job annotation: %s: %w", kube.AnnotationContainerImages, err) + } + + for _, c := range job.Spec.Template.Spec.Containers { + klog.V(3).Infof("Getting logs for %s container in job: %s/%s", c.Name, job.Namespace, job.Name) + var logReader io.ReadCloser + logReader, err = s.pods.GetContainerLogsByJob(ctx, job, c.Name) + if err != nil { + return nil, err + } + result, err := s.converter.Convert(s.config, containerImages[c.Name], logReader) + + report, err := vulnerabilityreport.NewBuilder(s.scheme). + Owner(owner). + Container(c.Name). + ScanResult(result). + PodSpecHash("").Get() + if err != nil { + return nil, err + } + + reports = append(reports, report) + + _ = logReader.Close() + } + return reports, nil +} diff --git a/pkg/find/vulnerabilities/scanner_test.go b/pkg/find/vulnerabilities/scanner_test.go new file mode 100644 index 000000000..44af330ae --- /dev/null +++ b/pkg/find/vulnerabilities/scanner_test.go @@ -0,0 +1 @@ +package vulnerabilities_test diff --git a/pkg/find/vulnerabilities/trivy/scanner.go b/pkg/find/vulnerabilities/trivy/scanner.go deleted file mode 100644 index 195363372..000000000 --- a/pkg/find/vulnerabilities/trivy/scanner.go +++ /dev/null @@ -1,394 +0,0 @@ -package trivy - -import ( - "context" - "fmt" - "io" - - "github.com/aquasecurity/starboard/pkg/vulnerabilityreport" - "k8s.io/apimachinery/pkg/runtime" - - "github.com/aquasecurity/starboard/pkg/starboard" - - "github.com/aquasecurity/starboard/pkg/docker" - "github.com/aquasecurity/starboard/pkg/kube/secrets" - "github.com/aquasecurity/starboard/pkg/scanners" - "k8s.io/klog" - - "github.com/aquasecurity/starboard/pkg/kube" - "github.com/aquasecurity/starboard/pkg/runner" - - sec "github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1" - "github.com/aquasecurity/starboard/pkg/kube/pod" - "github.com/google/uuid" - batch "k8s.io/api/batch/v1" - core "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" - meta "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/utils/pointer" -) - -type Config interface { - GetTrivyImageRef() string -} - -// NewScanner constructs a new vulnerability Scanner with the specified options and Kubernetes client Interface. -func NewScanner(scheme *runtime.Scheme, config Config, opts kube.ScannerOpts, clientset kubernetes.Interface) *Scanner { - return &Scanner{ - scheme: scheme, - config: config, - opts: opts, - clientset: clientset, - pods: pod.NewPodManager(clientset), - converter: DefaultConverter, - } -} - -type Scanner struct { - scheme *runtime.Scheme - config Config - opts kube.ScannerOpts - clientset kubernetes.Interface - pods *pod.Manager - converter Converter -} - -func (s *Scanner) Scan(ctx context.Context, workload kube.Object) ([]sec.VulnerabilityReport, error) { - klog.V(3).Infof("Getting Pod template for workload: %v", workload) - podSpec, owner, err := s.pods.GetPodSpecByWorkload(ctx, workload) - if err != nil { - return nil, fmt.Errorf("getting Pod template: %w", err) - } - - reports, err := s.ScanByPodSpec(ctx, workload, podSpec, owner) - if err != nil { - return nil, err - } - return reports, nil -} - -func (s *Scanner) ScanByPodSpec(ctx context.Context, workload kube.Object, spec core.PodSpec, owner meta.Object) ([]sec.VulnerabilityReport, error) { - klog.V(3).Infof("Scanning with options: %+v", s.opts) - - imagePullSecrets, err := s.pods.GetImagePullSecrets(ctx, workload.Namespace, spec) - if err != nil { - return nil, err - } - - auths, err := secrets.MapContainerImagesToAuths(spec, imagePullSecrets) - if err != nil { - return nil, err - } - - job, imagePullSecret, err := s.PrepareScanJob(ctx, workload, spec, auths) - if err != nil { - return nil, fmt.Errorf("preparing scan job: %w", err) - } - - if imagePullSecret != nil { - klog.V(3).Infof("Creating image pull secret: %s/%s", starboard.NamespaceName, imagePullSecret.Name) - _, err = s.clientset.CoreV1().Secrets(starboard.NamespaceName).Create(ctx, imagePullSecret, meta.CreateOptions{}) - if err != nil { - return nil, err - } - } - - err = runner.New().Run(ctx, kube.NewRunnableJob(s.clientset, job)) - if err != nil { - s.pods.LogRunnerErrors(ctx, job) - return nil, fmt.Errorf("running scan job: %w", err) - } - - defer func() { - if !s.opts.DeleteScanJob { - klog.V(3).Infof("Skipping scan job deletion: %s/%s", job.Namespace, job.Name) - return - } - klog.V(3).Infof("Deleting scan job: %s/%s", job.Namespace, job.Name) - background := meta.DeletePropagationBackground - _ = s.clientset.BatchV1().Jobs(job.Namespace).Delete(ctx, job.Name, meta.DeleteOptions{ - PropagationPolicy: &background, - }) - - if imagePullSecret != nil { - klog.V(3).Infof("Deleting image pull secret: %s/%s", imagePullSecret.Namespace, imagePullSecret.Name) - _ = s.clientset.CoreV1().Secrets(imagePullSecret.Namespace).Delete(ctx, imagePullSecret.Name, meta.DeleteOptions{}) - } - }() - - klog.V(3).Infof("Scan job completed: %s/%s", job.Namespace, job.Name) - - job, err = s.clientset.BatchV1().Jobs(job.Namespace).Get(ctx, job.Name, meta.GetOptions{}) - if err != nil { - return nil, fmt.Errorf("getting scan job: %w", err) - } - - return s.GetVulnerabilityReportsByScanJob(ctx, job, owner) -} - -func (s *Scanner) PrepareScanJob(_ context.Context, workload kube.Object, spec core.PodSpec, credentials map[string]docker.Auth) (*batch.Job, *core.Secret, error) { - jobName := fmt.Sprintf(uuid.New().String()) - - initContainerName := jobName - imagePullSecretName := jobName - imagePullSecretData := make(map[string][]byte) - var imagePullSecret *core.Secret - - initContainers := []core.Container{ - { - Name: initContainerName, - Image: s.config.GetTrivyImageRef(), - ImagePullPolicy: core.PullIfNotPresent, - TerminationMessagePolicy: core.TerminationMessageFallbackToLogsOnError, - Env: []core.EnvVar{ - { - Name: "HTTP_PROXY", - ValueFrom: &core.EnvVarSource{ - ConfigMapKeyRef: &core.ConfigMapKeySelector{ - LocalObjectReference: core.LocalObjectReference{ - Name: starboard.ConfigMapName, - }, - Key: "trivy.httpProxy", - Optional: pointer.BoolPtr(true), - }, - }, - }, - { - Name: "GITHUB_TOKEN", - ValueFrom: &core.EnvVarSource{ - ConfigMapKeyRef: &core.ConfigMapKeySelector{ - LocalObjectReference: core.LocalObjectReference{ - Name: starboard.ConfigMapName, - }, - Key: "trivy.githubToken", - Optional: pointer.BoolPtr(true), - }, - }, - }, - }, - Command: []string{ - "trivy", - }, - Args: []string{ - "--download-db-only", - "--cache-dir", - "/var/lib/trivy", - }, - VolumeMounts: []core.VolumeMount{ - { - Name: "data", - ReadOnly: false, - MountPath: "/var/lib/trivy", - }, - }, - }, - } - - containerImages := kube.ContainerImages{} - - scanJobContainers := make([]core.Container, len(spec.Containers)) - for i, c := range spec.Containers { - containerImages[c.Name] = c.Image - - var envs []core.EnvVar - - envs = append(envs, - core.EnvVar{ - Name: "TRIVY_SEVERITY", - ValueFrom: &core.EnvVarSource{ - ConfigMapKeyRef: &core.ConfigMapKeySelector{ - LocalObjectReference: core.LocalObjectReference{ - Name: starboard.ConfigMapName, - }, - Key: "trivy.severity", - Optional: pointer.BoolPtr(true), - }, - }, - }, core.EnvVar{ - Name: "HTTP_PROXY", - ValueFrom: &core.EnvVarSource{ - ConfigMapKeyRef: &core.ConfigMapKeySelector{ - LocalObjectReference: core.LocalObjectReference{ - Name: starboard.ConfigMapName, - }, - Key: "trivy.httpProxy", - Optional: pointer.BoolPtr(true), - }, - }, - }, - ) - - if dockerConfig, ok := credentials[c.Image]; ok { - registryUsernameKey := fmt.Sprintf("%s.username", c.Name) - registryPasswordKey := fmt.Sprintf("%s.password", c.Name) - - imagePullSecretData[registryUsernameKey] = []byte(dockerConfig.Username) - imagePullSecretData[registryPasswordKey] = []byte(dockerConfig.Password) - - envs = append(envs, core.EnvVar{ - Name: "TRIVY_USERNAME", - ValueFrom: &core.EnvVarSource{ - SecretKeyRef: &core.SecretKeySelector{ - LocalObjectReference: core.LocalObjectReference{ - Name: imagePullSecretName, - }, - Key: registryUsernameKey, - }, - }, - }, core.EnvVar{ - Name: "TRIVY_PASSWORD", - ValueFrom: &core.EnvVarSource{ - SecretKeyRef: &core.SecretKeySelector{ - LocalObjectReference: core.LocalObjectReference{ - Name: imagePullSecretName, - }, - Key: registryPasswordKey, - }, - }, - }) - } - - scanJobContainers[i] = core.Container{ - Name: c.Name, - Image: s.config.GetTrivyImageRef(), - ImagePullPolicy: core.PullIfNotPresent, - TerminationMessagePolicy: core.TerminationMessageFallbackToLogsOnError, - Env: envs, - Command: []string{ - "trivy", - }, - Args: []string{ - "--skip-update", - "--cache-dir", - "/var/lib/trivy", - "--no-progress", - "--format", - "json", - c.Image, - }, - Resources: core.ResourceRequirements{ - Limits: core.ResourceList{ - core.ResourceCPU: resource.MustParse("500m"), - core.ResourceMemory: resource.MustParse("500M"), - }, - Requests: core.ResourceList{ - core.ResourceCPU: resource.MustParse("100m"), - core.ResourceMemory: resource.MustParse("100M"), - }, - }, - VolumeMounts: []core.VolumeMount{ - { - Name: "data", - ReadOnly: false, - MountPath: "/var/lib/trivy", - }, - }, - } - } - - containerImagesAsJSON, err := containerImages.AsJSON() - if err != nil { - return nil, nil, err - } - - if len(imagePullSecretData) > 0 { - imagePullSecret = &core.Secret{ - ObjectMeta: meta.ObjectMeta{ - Name: imagePullSecretName, - Namespace: starboard.NamespaceName, - Labels: map[string]string{ - kube.LabelResourceKind: string(workload.Kind), - kube.LabelResourceName: workload.Name, - kube.LabelResourceNamespace: workload.Namespace, - }, - }, - Data: imagePullSecretData, - } - } - - return &batch.Job{ - ObjectMeta: meta.ObjectMeta{ - Name: jobName, - Namespace: starboard.NamespaceName, - Labels: map[string]string{ - kube.LabelResourceKind: string(workload.Kind), - kube.LabelResourceName: workload.Name, - kube.LabelResourceNamespace: workload.Namespace, - }, - Annotations: map[string]string{ - kube.AnnotationContainerImages: containerImagesAsJSON, - }, - }, - Spec: batch.JobSpec{ - BackoffLimit: pointer.Int32Ptr(0), - Completions: pointer.Int32Ptr(1), - ActiveDeadlineSeconds: scanners.GetActiveDeadlineSeconds(s.opts.ScanJobTimeout), - Template: core.PodTemplateSpec{ - ObjectMeta: meta.ObjectMeta{ - Labels: map[string]string{ - kube.LabelResourceKind: string(workload.Kind), - kube.LabelResourceName: workload.Name, - kube.LabelResourceNamespace: workload.Namespace, - }, - }, - Spec: core.PodSpec{ - ServiceAccountName: starboard.ServiceAccountName, - Volumes: []core.Volume{ - { - Name: "data", - VolumeSource: core.VolumeSource{ - EmptyDir: &core.EmptyDirVolumeSource{ - Medium: core.StorageMediumDefault, - }, - }, - }, - }, - RestartPolicy: core.RestartPolicyNever, - InitContainers: initContainers, - Containers: scanJobContainers, - }, - }, - }, - }, imagePullSecret, nil -} - -func (s *Scanner) GetVulnerabilityReportsByScanJob(ctx context.Context, job *batch.Job, owner meta.Object) ([]sec.VulnerabilityReport, error) { - var reports []sec.VulnerabilityReport - - var containerImagesAsJSON string - var ok bool - - if containerImagesAsJSON, ok = job.Annotations[kube.AnnotationContainerImages]; !ok { - return nil, fmt.Errorf("scan job does not have required annotation: %s", kube.AnnotationContainerImages) - } - containerImages := kube.ContainerImages{} - err := containerImages.FromJSON(containerImagesAsJSON) - if err != nil { - return nil, fmt.Errorf("reading scan job annotation: %s: %w", kube.AnnotationContainerImages, err) - } - - for _, c := range job.Spec.Template.Spec.Containers { - klog.V(3).Infof("Getting logs for %s container in job: %s/%s", c.Name, job.Namespace, job.Name) - var logReader io.ReadCloser - logReader, err = s.pods.GetContainerLogsByJob(ctx, job, c.Name) - if err != nil { - return nil, err - } - result, err := s.converter.Convert(s.config, containerImages[c.Name], logReader) - - report, err := vulnerabilityreport.NewBuilder(s.scheme). - Owner(owner). - Container(c.Name). - ScanResult(result). - PodSpecHash("").Get() - if err != nil { - return nil, err - } - - reports = append(reports, report) - - _ = logReader.Close() - } - return reports, nil -} diff --git a/pkg/operator/controller/job/job_controller.go b/pkg/operator/controller/job/job_controller.go index 7fd2df640..876c21af0 100644 --- a/pkg/operator/controller/job/job_controller.go +++ b/pkg/operator/controller/job/job_controller.go @@ -4,14 +4,14 @@ import ( "context" "fmt" - "github.com/aquasecurity/starboard/pkg/operator/controller" - - "github.com/aquasecurity/starboard/pkg/resources" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/aquasecurity/starboard/pkg/operator/controller" + "github.com/aquasecurity/starboard/pkg/kube" pods "github.com/aquasecurity/starboard/pkg/kube/pod" "github.com/aquasecurity/starboard/pkg/operator/etc" + "github.com/aquasecurity/starboard/pkg/resources" "k8s.io/apimachinery/pkg/api/errors" batchv1 "k8s.io/api/batch/v1" diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go index 715721045..803e4bd39 100644 --- a/pkg/operator/operator.go +++ b/pkg/operator/operator.go @@ -5,6 +5,8 @@ import ( "errors" "fmt" + "github.com/aquasecurity/starboard/pkg/trivy" + "github.com/aquasecurity/starboard/pkg/ext" "github.com/aquasecurity/starboard/pkg/operator/aqua" "github.com/aquasecurity/starboard/pkg/operator/controller" @@ -12,7 +14,6 @@ import ( "github.com/aquasecurity/starboard/pkg/operator/controller/pod" "github.com/aquasecurity/starboard/pkg/operator/etc" "github.com/aquasecurity/starboard/pkg/operator/logs" - "github.com/aquasecurity/starboard/pkg/operator/trivy" "github.com/aquasecurity/starboard/pkg/starboard" "github.com/aquasecurity/starboard/pkg/vulnerabilityreport" "k8s.io/client-go/kubernetes" @@ -172,7 +173,10 @@ func getEnabledScanner(buildInfo starboard.BuildInfo, idGenerator ext.IDGenerato return nil, fmt.Errorf("invalid configuration: none vulnerability scanner enabled") } if config.ScannerTrivy.Enabled { - setupLog.Info("Using Trivy as vulnerability scanner", "image", starboardConfig.GetTrivyImageRef()) + setupLog.Info("Using Trivy as vulnerability scanner", + "trivyImageRef", starboardConfig.GetTrivyImageRef(), + "trivyMode", starboardConfig.GetTrivyMode(), + "trivyServerURL", starboardConfig.GetTrivyServerURL()) return trivy.NewScanner(idGenerator, starboardConfig), nil } if config.ScannerAquaCSP.Enabled { diff --git a/pkg/operator/trivy/scanner.go b/pkg/operator/trivy/scanner.go deleted file mode 100644 index b0ec6ba7a..000000000 --- a/pkg/operator/trivy/scanner.go +++ /dev/null @@ -1,184 +0,0 @@ -package trivy - -import ( - "io" - - "github.com/aquasecurity/starboard/pkg/vulnerabilityreport" - - "github.com/aquasecurity/starboard/pkg/starboard" - - "github.com/aquasecurity/starboard/pkg/ext" - - "github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1" - "github.com/aquasecurity/starboard/pkg/find/vulnerabilities/trivy" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" - "k8s.io/utils/pointer" -) - -type trivyScanner struct { - idGenerator ext.IDGenerator - config trivy.Config -} - -// NewScanner constructs a new VulnerabilityScanner, which is using an official -// Trivy container image to scan pod containers. -func NewScanner(idGenerator ext.IDGenerator, config trivy.Config) vulnerabilityreport.Scanner { - return &trivyScanner{ - idGenerator: idGenerator, - config: config, - } -} - -func (s *trivyScanner) GetPodSpec(spec corev1.PodSpec) (corev1.PodSpec, error) { - initContainers := []corev1.Container{ - { - Name: s.idGenerator.GenerateID(), - Image: s.config.GetTrivyImageRef(), - ImagePullPolicy: corev1.PullIfNotPresent, - TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError, - Env: []corev1.EnvVar{ - { - Name: "HTTP_PROXY", - ValueFrom: &corev1.EnvVarSource{ - ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: starboard.ConfigMapName, - }, - Key: "trivy.httpProxy", - Optional: pointer.BoolPtr(true), - }, - }, - }, - { - Name: "GITHUB_TOKEN", - ValueFrom: &corev1.EnvVarSource{ - ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: starboard.ConfigMapName, - }, - Key: "trivy.githubToken", - Optional: pointer.BoolPtr(true), - }, - }, - }, - }, - Command: []string{ - "trivy", - }, - Args: []string{ - "--download-db-only", - "--cache-dir", - "/var/lib/trivy", - }, - Resources: corev1.ResourceRequirements{ - Requests: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("100m"), - corev1.ResourceMemory: resource.MustParse("100M"), - }, - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("500M"), - }, - }, - VolumeMounts: []corev1.VolumeMount{ - { - Name: "data", - ReadOnly: false, - MountPath: "/var/lib/trivy", - }, - }, - }, - } - - containers := make([]corev1.Container, len(spec.Containers)) - for i, c := range spec.Containers { - - containers[i] = corev1.Container{ - Name: c.Name, - Image: s.config.GetTrivyImageRef(), - ImagePullPolicy: corev1.PullIfNotPresent, - TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError, - Env: []corev1.EnvVar{ - { - Name: "TRIVY_SEVERITY", - ValueFrom: &corev1.EnvVarSource{ - ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: starboard.ConfigMapName, - }, - Key: "trivy.severity", - Optional: pointer.BoolPtr(true), - }, - }, - }, - { - Name: "HTTP_PROXY", - ValueFrom: &corev1.EnvVarSource{ - ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: starboard.ConfigMapName, - }, - Key: "trivy.httpProxy", - Optional: pointer.BoolPtr(true), - }, - }, - }, - }, - Command: []string{ - "trivy", - }, - Args: []string{ - "--skip-update", - "--cache-dir", - "/var/lib/trivy", - "--no-progress", - "--format", - "json", - c.Image, - }, - Resources: corev1.ResourceRequirements{ - Requests: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("100m"), - corev1.ResourceMemory: resource.MustParse("100M"), - }, - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("500M"), - }, - }, - VolumeMounts: []corev1.VolumeMount{ - { - Name: "data", - ReadOnly: false, - MountPath: "/var/lib/trivy", - }, - }, - } - } - - return corev1.PodSpec{ - RestartPolicy: corev1.RestartPolicyNever, - AutomountServiceAccountToken: pointer.BoolPtr(false), - Volumes: []corev1.Volume{ - { - Name: "data", - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{ - Medium: corev1.StorageMediumDefault, - }, - }, - }, - }, - InitContainers: initContainers, - Containers: containers, - }, nil -} - -func (s *trivyScanner) ParseVulnerabilityScanResult(imageRef string, logsReader io.ReadCloser) (v1alpha1.VulnerabilityScanResult, error) { - result, err := trivy.DefaultConverter.Convert(s.config, imageRef, logsReader) - if err != nil { - return v1alpha1.VulnerabilityScanResult{}, err - } - return result, nil -} diff --git a/pkg/starboard/config.go b/pkg/starboard/config.go index f05152cad..f51e92be6 100644 --- a/pkg/starboard/config.go +++ b/pkg/starboard/config.go @@ -222,6 +222,20 @@ type BuildInfo struct { Date string } +// TrivyMode describes mode in which Trivy client operates. +type TrivyMode string + +const ( + Standalone TrivyMode = "Standalone" + ClientServer TrivyMode = "ClientServer" +) + +type TrivyConfig interface { + GetTrivyImageRef() string + GetTrivyMode() TrivyMode + GetTrivyServerURL() string +} + // ConfigData holds Starboard configuration settings as a set // of key-value pairs. type ConfigData map[string]string @@ -237,7 +251,9 @@ type ConfigManager interface { func GetDefaultConfig() ConfigData { return map[string]string{ "trivy.severity": "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL", - "trivy.imageRef": "docker.io/aquasec/trivy:0.9.1", + "trivy.imageRef": "docker.io/aquasec/trivy:0.12.0", + "trivy.mode": "Standalone", + "trivy.serverURL": "http://trivy-server.trivy-server:4954", "kube-bench.imageRef": "docker.io/aquasec/kube-bench:0.4.0", "polaris.config.yaml": polarisConfigYAML, } @@ -247,7 +263,21 @@ func (c ConfigData) GetTrivyImageRef() string { if imageRef, ok := c["trivy.imageRef"]; ok { return imageRef } - return "docker.io/aquasec/trivy:0.9.1" + return "docker.io/aquasec/trivy:0.12.0" +} + +func (c ConfigData) GetTrivyMode() TrivyMode { + if mode, ok := c["trivy.mode"]; ok { + return TrivyMode(mode) + } + return Standalone +} + +func (c ConfigData) GetTrivyServerURL() string { + if url, ok := c["trivy.serverURL"]; ok { + return url + } + return "http://trivy-server.trivy-server:4954" } // GetKubeBenchImageRef returns Docker image of kube-bench scanner. diff --git a/pkg/starboard/config_test.go b/pkg/starboard/config_test.go index 083a3cd47..debfb516c 100644 --- a/pkg/starboard/config_test.go +++ b/pkg/starboard/config_test.go @@ -59,7 +59,7 @@ func TestConfigData_GetTrivyImageRef(t *testing.T) { { name: "Should return default image reference", configData: starboard.ConfigData{}, - expectedImageRef: "docker.io/aquasec/trivy:0.9.1", + expectedImageRef: "docker.io/aquasec/trivy:0.12.0", }, { name: "Should return image reference from config data", diff --git a/pkg/find/vulnerabilities/trivy/converter.go b/pkg/trivy/converter.go similarity index 70% rename from pkg/find/vulnerabilities/trivy/converter.go rename to pkg/trivy/converter.go index 48b395c48..235f07b4e 100644 --- a/pkg/find/vulnerabilities/trivy/converter.go +++ b/pkg/trivy/converter.go @@ -3,8 +3,6 @@ package trivy import ( "encoding/json" "io" - "io/ioutil" - "strings" "github.com/aquasecurity/starboard/pkg/starboard" @@ -17,7 +15,7 @@ import ( // Convert converts the vulnerabilities model used by Trivy // to a generic model defined by the Custom Security Resource Specification. type Converter interface { - Convert(config Config, imageRef string, reader io.Reader) (starboardv1alpha1.VulnerabilityScanResult, error) + Convert(config starboard.TrivyConfig, imageRef string, reader io.Reader) (starboardv1alpha1.VulnerabilityScanResult, error) } type converter struct { @@ -29,40 +27,16 @@ func NewConverter() Converter { return &converter{} } -func (c *converter) Convert(config Config, imageRef string, reader io.Reader) (report starboardv1alpha1.VulnerabilityScanResult, err error) { +func (c *converter) Convert(config starboard.TrivyConfig, imageRef string, reader io.Reader) (report starboardv1alpha1.VulnerabilityScanResult, err error) { var scanReports []ScanReport - skipReader, err := c.skippingNoisyOutputReader(reader) - if err != nil { - return - } - err = json.NewDecoder(skipReader).Decode(&scanReports) + err = json.NewDecoder(reader).Decode(&scanReports) if err != nil { return } return c.convert(config, imageRef, scanReports) } -// TODO Normally I'd use Trivy with the --quiet flag, but in case of errors it does suppress the error message. -// TODO Therefore, as a workaround I do sanitize the input reader before we start parsing the JSON output. -func (c *converter) skippingNoisyOutputReader(input io.Reader) (io.Reader, error) { - inputAsBytes, err := ioutil.ReadAll(input) - if err != nil { - return nil, err - } - inputAsString := string(inputAsBytes) - - index := strings.Index(inputAsString, "\n[") - if index > 0 { - return strings.NewReader(inputAsString[index:]), nil - } - index = strings.LastIndex(inputAsString, "null") - if index > 0 { - return strings.NewReader(inputAsString[index:]), nil - } - return strings.NewReader(inputAsString), nil -} - -func (c *converter) convert(config Config, imageRef string, reports []ScanReport) (starboardv1alpha1.VulnerabilityScanResult, error) { +func (c *converter) convert(config starboard.TrivyConfig, imageRef string, reports []ScanReport) (starboardv1alpha1.VulnerabilityScanResult, error) { vulnerabilities := make([]starboardv1alpha1.Vulnerability, 0) for _, report := range reports { diff --git a/pkg/find/vulnerabilities/trivy/converter_test.go b/pkg/trivy/converter_test.go similarity index 85% rename from pkg/find/vulnerabilities/trivy/converter_test.go rename to pkg/trivy/converter_test.go index 77034902e..590cb4a74 100644 --- a/pkg/find/vulnerabilities/trivy/converter_test.go +++ b/pkg/trivy/converter_test.go @@ -2,13 +2,12 @@ package trivy_test import ( "errors" - "fmt" "strings" "testing" - "github.com/aquasecurity/starboard/pkg/starboard" + "github.com/aquasecurity/starboard/pkg/trivy" - "github.com/aquasecurity/starboard/pkg/find/vulnerabilities/trivy" + "github.com/aquasecurity/starboard/pkg/starboard" starboardv1alpha1 "github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1" "github.com/stretchr/testify/assert" @@ -106,13 +105,6 @@ func TestConverter_Convert(t *testing.T) { expectedError error expectedReport starboardv1alpha1.VulnerabilityScanResult }{ - { - name: "Should convert vulnerability report in JSON format when input is noisy", - imageRef: "alpine:3.10.2", - input: fmt.Sprintf("2020-06-17T23:37:45.320+0200 INFO Detecting Alpine vulnerabilities...\n%s", sampleReportAsString), - expectedError: nil, - expectedReport: sampleReport, - }, { name: "Should convert vulnerability report in JSON format when input is quiet", imageRef: "alpine:3.10.2", @@ -121,10 +113,9 @@ func TestConverter_Convert(t *testing.T) { expectedReport: sampleReport, }, { - name: "Should convert vulnerability report in JSON format when OS is not detected", - imageRef: "core.harbor.domain/library/nginx@sha256:d20aa6d1cae56fd17cd458f4807e0de462caf2336f0b70b5eeb69fcaaf30dd9c", - input: `2020-06-21T23:10:15.162+0200 WARN OS is not detected and vulnerabilities in OS packages are not detected. -null`, + name: "Should convert vulnerability report in JSON format when OS is not detected", + imageRef: "core.harbor.domain/library/nginx@sha256:d20aa6d1cae56fd17cd458f4807e0de462caf2336f0b70b5eeb69fcaaf30dd9c", + input: `null`, expectedError: nil, expectedReport: starboardv1alpha1.VulnerabilityScanResult{ Scanner: starboardv1alpha1.Scanner{ diff --git a/pkg/find/vulnerabilities/trivy/model.go b/pkg/trivy/model.go similarity index 100% rename from pkg/find/vulnerabilities/trivy/model.go rename to pkg/trivy/model.go diff --git a/pkg/find/vulnerabilities/trivy/model_test.go b/pkg/trivy/model_test.go similarity index 100% rename from pkg/find/vulnerabilities/trivy/model_test.go rename to pkg/trivy/model_test.go diff --git a/pkg/trivy/scanner.go b/pkg/trivy/scanner.go new file mode 100644 index 000000000..8e44f67a2 --- /dev/null +++ b/pkg/trivy/scanner.go @@ -0,0 +1,254 @@ +package trivy + +import ( + "fmt" + "io" + + "github.com/aquasecurity/starboard/pkg/vulnerabilityreport" + + "github.com/aquasecurity/starboard/pkg/starboard" + + "github.com/aquasecurity/starboard/pkg/ext" + + "github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/utils/pointer" +) + +var ( + defaultResourceRequirements = corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("100m"), + corev1.ResourceMemory: resource.MustParse("100M"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("500M"), + }, + } +) + +type trivyScanner struct { + idGenerator ext.IDGenerator + config starboard.TrivyConfig +} + +// NewScanner constructs a new vulnerabilityreport.Scanner, which is using an official +// Trivy container image to scan Kubernetes workloads. +// +// This vulnerabilityreport.Scanner supports both trivy.Standalone and trivy.ClientServer +// client modes depending on the current starboard.TrivyConfig. +// +// The trivy.ClientServer more is usually more performant, however it requires a Trivy server +// to be hosted and accessible at the configurable URL. +func NewScanner(idGenerator ext.IDGenerator, config starboard.TrivyConfig) vulnerabilityreport.Scanner { + return &trivyScanner{ + idGenerator: idGenerator, + config: config, + } +} + +func (s *trivyScanner) GetPodSpec(spec corev1.PodSpec) (corev1.PodSpec, error) { + switch s.config.GetTrivyMode() { + case starboard.Standalone: + return s.getPodSpecForStandaloneMode(spec) + case starboard.ClientServer: + return s.getPodSpecForClientServerMode(spec) + default: + return corev1.PodSpec{}, fmt.Errorf("unrecognized trivy mode: %v", s.config.GetTrivyMode()) + } +} + +// In the Standalone mode there is the init container responsible for downloading +// the latest Trivy DB file from GitHub and storing it to the empty volume shared +// with main containers. In other words, the init container runs the following +// Trivy command: +// +// trivy --download-db-only --cache-dir /var/lib/trivy +// +// The number of main containers correspond to the number of containers +// defined for the scanned workload. What's more, each container runs the Trivy +// scan command and skips the database update: +// +// trivy --skip-update --cache-dir /var/lib/trivy --format json +func (s *trivyScanner) getPodSpecForStandaloneMode(spec corev1.PodSpec) (corev1.PodSpec, error) { + initContainer := corev1.Container{ + Name: s.idGenerator.GenerateID(), + Image: s.config.GetTrivyImageRef(), + ImagePullPolicy: corev1.PullIfNotPresent, + TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError, + Env: []corev1.EnvVar{ + { + Name: "HTTP_PROXY", + ValueFrom: &corev1.EnvVarSource{ + ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: starboard.ConfigMapName, + }, + Key: "trivy.httpProxy", + Optional: pointer.BoolPtr(true), + }, + }, + }, + { + Name: "GITHUB_TOKEN", + ValueFrom: &corev1.EnvVarSource{ + ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: starboard.ConfigMapName, + }, + Key: "trivy.githubToken", + Optional: pointer.BoolPtr(true), + }, + }, + }, + }, + Command: []string{ + "trivy", + }, + Args: []string{ + "--download-db-only", + "--cache-dir", + "/var/lib/trivy", + }, + Resources: defaultResourceRequirements, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "data", + MountPath: "/var/lib/trivy", + ReadOnly: false, + }, + }, + } + + var containers []corev1.Container + + for _, c := range spec.Containers { + containers = append(containers, corev1.Container{ + Name: c.Name, + Image: s.config.GetTrivyImageRef(), + ImagePullPolicy: corev1.PullIfNotPresent, + TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError, + Env: []corev1.EnvVar{ + { + Name: "TRIVY_SEVERITY", + ValueFrom: &corev1.EnvVarSource{ + ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: starboard.ConfigMapName, + }, + Key: "trivy.severity", + Optional: pointer.BoolPtr(true), + }, + }, + }, + { + Name: "HTTP_PROXY", + ValueFrom: &corev1.EnvVarSource{ + ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: starboard.ConfigMapName, + }, + Key: "trivy.httpProxy", + Optional: pointer.BoolPtr(true), + }, + }, + }, + }, + Command: []string{ + "trivy", + }, + Args: []string{ + "--skip-update", + "--cache-dir", + "/var/lib/trivy", + "--quiet", + "--format", + "json", + c.Image, + }, + Resources: defaultResourceRequirements, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "data", + ReadOnly: false, + MountPath: "/var/lib/trivy", + }, + }, + }) + } + + return corev1.PodSpec{ + RestartPolicy: corev1.RestartPolicyNever, + AutomountServiceAccountToken: pointer.BoolPtr(false), + Volumes: []corev1.Volume{ + { + Name: "data", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{ + Medium: corev1.StorageMediumDefault, + }, + }, + }, + }, + InitContainers: []corev1.Container{initContainer}, + Containers: containers, + }, nil +} + +// In the ClientServer mode the number of containers of the pod created by the scan job +// equals the number of containers defined for the scanned workload. +// Each container runs Trivy scan command pointing to a remote Trivy server: +// +// trivy client --remote http://trivy-server.trivy-server:4954 --format json +func (s *trivyScanner) getPodSpecForClientServerMode(spec corev1.PodSpec) (corev1.PodSpec, error) { + var containers []corev1.Container + for _, container := range spec.Containers { + containers = append(containers, corev1.Container{ + Name: container.Name, + Image: s.config.GetTrivyImageRef(), + ImagePullPolicy: corev1.PullIfNotPresent, + Env: []corev1.EnvVar{ + { + Name: "TRIVY_SEVERITY", + ValueFrom: &corev1.EnvVarSource{ + ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: starboard.ConfigMapName, + }, + Key: "trivy.severity", + Optional: pointer.BoolPtr(true), + }, + }, + }, + }, + Command: []string{ + "trivy", + }, + Args: []string{ + "client", + "--quiet", + "--format", + "json", + "--remote", + s.config.GetTrivyServerURL(), + container.Image, + }, + Resources: defaultResourceRequirements, + }) + } + return corev1.PodSpec{ + RestartPolicy: corev1.RestartPolicyNever, + AutomountServiceAccountToken: pointer.BoolPtr(false), + Containers: containers, + }, nil +} + +func (s *trivyScanner) ParseVulnerabilityScanResult(imageRef string, logsReader io.ReadCloser) (v1alpha1.VulnerabilityScanResult, error) { + result, err := DefaultConverter.Convert(s.config, imageRef, logsReader) + if err != nil { + return v1alpha1.VulnerabilityScanResult{}, err + } + return result, nil +} diff --git a/pkg/find/vulnerabilities/trivy/scanner_test.go b/pkg/trivy/scanner_test.go similarity index 100% rename from pkg/find/vulnerabilities/trivy/scanner_test.go rename to pkg/trivy/scanner_test.go