mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 07:40:48 -08:00
feat(k8s): add support for vulnerability detection (#5268)
Signed-off-by: knqyf263 <knqyf263@gmail.com> Signed-off-by: chenk <hen.keinan@gmail.com> Co-authored-by: DmitriyLewen <dmitriy.lewen@smartforce.io> Co-authored-by: chenk <hen.keinan@gmail.com>
This commit is contained in:
@@ -5,6 +5,7 @@ The following packages are supported.
|
||||
|
||||
- [OS packages](#os-packages)
|
||||
- [Language-specific packages](#language-specific-packages)
|
||||
- [Kubernetes components (control plane, node and addons)](#kubernetes-components-control-plane-node-and-addons)
|
||||
|
||||
Trivy also detects known vulnerabilities in Kubernetes components using KBOM (Kubernetes bill of Material) scanning. To learn more, see the [documentation for Kubernetes scanning](../target/kubernetes.md#KBOM).
|
||||
|
||||
@@ -106,9 +107,9 @@ Trivy can detect vulnerabilities in Kubernetes clusters and components.
|
||||
|
||||
### Data Sources
|
||||
|
||||
| Vendor | Source |
|
||||
| ------------- | ------------------------------------------------------------ |
|
||||
| Kubernetes | [Kubernetes Official CVE feed][^1] |
|
||||
| Vendor | Source |
|
||||
| ------------- |---------------------------------------------|
|
||||
| Kubernetes | [Kubernetes Official CVE feed][k8s-cve][^1] |
|
||||
|
||||
[^1]: Some manual triage and correction has been made.
|
||||
|
||||
@@ -195,4 +196,4 @@ Currently, specifying a username and password is not supported.
|
||||
|
||||
[nvd]: https://nvd.nist.gov/vuln
|
||||
|
||||
[Kubernetes Official CVE feed]: https://kubernetes.io/docs/reference/issues-security/official-cve-feed/
|
||||
[k8s-cve]: https://kubernetes.io/docs/reference/issues-security/official-cve-feed/
|
||||
|
||||
4
go.mod
4
go.mod
@@ -23,9 +23,9 @@ require (
|
||||
github.com/aquasecurity/table v1.8.0
|
||||
github.com/aquasecurity/testdocker v0.0.0-20230111101738-e741bda259da
|
||||
github.com/aquasecurity/tml v0.6.1
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20230831170347-f732860d4917
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20231005141211-4fc651f7ac8d
|
||||
github.com/aquasecurity/trivy-java-db v0.0.0-20230209231723-7cddb1406728
|
||||
github.com/aquasecurity/trivy-kubernetes v0.5.7
|
||||
github.com/aquasecurity/trivy-kubernetes v0.5.8-0.20230928134646-b414e546fe6d
|
||||
github.com/aws/aws-sdk-go v1.45.19
|
||||
github.com/aws/aws-sdk-go-v2 v1.21.0
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.38
|
||||
|
||||
8
go.sum
8
go.sum
@@ -343,12 +343,12 @@ github.com/aquasecurity/testdocker v0.0.0-20230111101738-e741bda259da h1:pj/adfN
|
||||
github.com/aquasecurity/testdocker v0.0.0-20230111101738-e741bda259da/go.mod h1:852lbQLpK2nCwlR4ZLYIccxYCfoQao6q9Nl6tjz54v8=
|
||||
github.com/aquasecurity/tml v0.6.1 h1:y2ZlGSfrhnn7t4ZJ/0rotuH+v5Jgv6BDDO5jB6A9gwo=
|
||||
github.com/aquasecurity/tml v0.6.1/go.mod h1:OnYMWY5lvI9ejU7yH9LCberWaaTBW7hBFsITiIMY2yY=
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20230831170347-f732860d4917 h1:MQd7h7yUyA8UlUzhjNMzpUX0NpD7jfxmRfSKwp/Ji3E=
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20230831170347-f732860d4917/go.mod h1:WJ5Qnk5ZNGWvks07GOZe2IOsuXrPfSC5c8hYGOGfrsU=
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20231005141211-4fc651f7ac8d h1:fjI9mkoTUAkbGqpzt9nJsO24RAdfG+ZSiLFj0G2jO8c=
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20231005141211-4fc651f7ac8d/go.mod h1:cj9/QmD9N3OZnKQMp+/DvdV+ym3HyIkd4e+F0ZM3ZGs=
|
||||
github.com/aquasecurity/trivy-java-db v0.0.0-20230209231723-7cddb1406728 h1:0eS+V7SXHgqoT99tV1mtMW6HL4HdoB9qGLMCb1fZp8A=
|
||||
github.com/aquasecurity/trivy-java-db v0.0.0-20230209231723-7cddb1406728/go.mod h1:Ldya37FLi0e/5Cjq2T5Bty7cFkzUDwTcPeQua+2M8i8=
|
||||
github.com/aquasecurity/trivy-kubernetes v0.5.7 h1:+tIrSnIkvweL+cuK0SSiYxF8EvKT3Xk1iuE9EWduV+c=
|
||||
github.com/aquasecurity/trivy-kubernetes v0.5.7/go.mod h1:e1RaMcs2R/C+eP1Pi7JyhDB7Qn1PNRg5rTVwuJL7AiE=
|
||||
github.com/aquasecurity/trivy-kubernetes v0.5.8-0.20230928134646-b414e546fe6d h1:5urHj0NMGflp/M9Ll5QlKfo0Kf6nJ01RED1HRgl0CeE=
|
||||
github.com/aquasecurity/trivy-kubernetes v0.5.8-0.20230928134646-b414e546fe6d/go.mod h1:e1RaMcs2R/C+eP1Pi7JyhDB7Qn1PNRg5rTVwuJL7AiE=
|
||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
|
||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
|
||||
@@ -58,6 +58,15 @@ func TestSBOM(t *testing.T) {
|
||||
},
|
||||
golden: "testdata/fluentd-multiple-lockfiles.json.golden",
|
||||
},
|
||||
{
|
||||
name: "minikube KBOM",
|
||||
args: args{
|
||||
input: "testdata/fixtures/sbom/minikube-kbom.json",
|
||||
format: "json",
|
||||
artifactType: "cyclonedx",
|
||||
},
|
||||
golden: "testdata/minikube-kbom.json.golden",
|
||||
},
|
||||
{
|
||||
name: "centos7 in in-toto attestation",
|
||||
args: args{
|
||||
|
||||
@@ -144,3 +144,8 @@
|
||||
ID: "cbl-mariner"
|
||||
Name: "CBL-Mariner Vulnerability Data"
|
||||
URL: "https://github.com/microsoft/CBL-MarinerVulnerabilityData"
|
||||
- key: k8s::Official Kubernetes CVE Feed
|
||||
value:
|
||||
ID: "k8s"
|
||||
Name: "Official Kubernetes CVE Feed"
|
||||
URL: "https://kubernetes.io/docs/reference/issues-security/official-cve-feed/index.json"
|
||||
|
||||
16
integration/testdata/fixtures/db/k8s.yaml
vendored
Normal file
16
integration/testdata/fixtures/db/k8s.yaml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
- bucket: "k8s::Official Kubernetes CVE Feed"
|
||||
pairs:
|
||||
- bucket: k8s.io/kubelet
|
||||
pairs:
|
||||
- key: CVE-2023-2431
|
||||
value:
|
||||
PatchedVersions:
|
||||
- 1.24.14
|
||||
- 1.25.9
|
||||
- 1.26.4
|
||||
- 1.27.1
|
||||
VulnerableVersions:
|
||||
- "< 1.24.14"
|
||||
- ">= 1.25.0, < 1.25.9"
|
||||
- ">= 1.26.0, < 1.26.4"
|
||||
- ">= 1.27.0, < 1.27.1"
|
||||
@@ -1037,6 +1037,20 @@
|
||||
ghsa: 3.0
|
||||
nvd: 3.0
|
||||
redhat: 3.0
|
||||
- key: CVE-2023-2431
|
||||
value:
|
||||
Title: "Bypass of seccomp profile enforcement "
|
||||
Description: "A security issue was discovered in Kubelet that allows pods to bypass the seccomp profile enforcement..."
|
||||
Severity: LOW
|
||||
VendorSeverity:
|
||||
k8s: 1
|
||||
CVSS:
|
||||
k8s:
|
||||
V3Vector: "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:N"
|
||||
V3Score: 3.4
|
||||
References:
|
||||
- https://github.com/kubernetes/kubernetes/issues/118690
|
||||
- https://www.cve.org/cverecord?id=CVE-2023-2431
|
||||
- key: CVE-2021-3712
|
||||
value:
|
||||
CVSS:
|
||||
|
||||
434
integration/testdata/fixtures/sbom/minikube-kbom.json
vendored
Normal file
434
integration/testdata/fixtures/sbom/minikube-kbom.json
vendored
Normal file
@@ -0,0 +1,434 @@
|
||||
{
|
||||
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.5",
|
||||
"serialNumber": "urn:uuid:e2daaea6-d96f-4b84-960c-0d72c348cd23",
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"timestamp": "2023-09-29T06:25:00+00:00",
|
||||
"tools": [
|
||||
{
|
||||
"vendor": "aquasecurity",
|
||||
"name": "trivy",
|
||||
"version": "0.45.1-15-g7bbd0d097"
|
||||
}
|
||||
],
|
||||
"component": {
|
||||
"bom-ref": "pkg:k8s/k8s.io%2Fkubernetes@1.27.0",
|
||||
"type": "platform",
|
||||
"name": "k8s.io/kubernetes",
|
||||
"version": "1.27.0",
|
||||
"purl": "pkg:k8s/k8s.io%2Fkubernetes@1.27.0",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "minikube"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Type",
|
||||
"value": "cluster"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"bom-ref": "5262e708-f1a3-4fca-a1c3-0a8384f7f4a5",
|
||||
"type": "operating-system",
|
||||
"name": "ubuntu",
|
||||
"version": "22.04.2",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:Class",
|
||||
"value": "os-pkgs"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:Type",
|
||||
"value": "ubuntu"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "a62abb1f-cb38-4fde-90f3-2bda3b87ddb2",
|
||||
"type": "application",
|
||||
"name": "node-core-components",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:Class",
|
||||
"value": "lang-pkgs"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:Type",
|
||||
"value": "golang"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "a6350ac3-52f6-4c5f-a3e3-184b9a634bef",
|
||||
"type": "platform",
|
||||
"name": "minikube",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:Architecture",
|
||||
"value": "arm64"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:HostName",
|
||||
"value": "minikube"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:KernelVersion",
|
||||
"value": "5.15.49-linuxkit-pr"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:NodeRole",
|
||||
"value": "master"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:OperatingSystem",
|
||||
"value": "linux"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "minikube"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Type",
|
||||
"value": "node"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "b19a88a3-017d-4e70-a73a-75f48696ec0f",
|
||||
"type": "application",
|
||||
"name": "kube-dns",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "coredns-5d78c9869d-nd92n"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "b1c502c9-3c6e-43af-822b-1cb55c6c6ff3",
|
||||
"type": "application",
|
||||
"name": "go.etcd.io/etcd/v3",
|
||||
"version": "3.5.7-0",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "etcd-minikube"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Type",
|
||||
"value": "controlPlane"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:golang/docker@24.0.4",
|
||||
"type": "application",
|
||||
"name": "docker",
|
||||
"version": "24.0.4",
|
||||
"purl": "pkg:golang/docker@24.0.4",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "docker"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Type",
|
||||
"value": "node"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:k8s/k8s.io%2Fapiserver@1.27.0",
|
||||
"type": "application",
|
||||
"name": "k8s.io/apiserver",
|
||||
"version": "1.27.0",
|
||||
"purl": "pkg:k8s/k8s.io%2Fapiserver@1.27.0",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "kube-apiserver-minikube"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Type",
|
||||
"value": "controlPlane"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.0",
|
||||
"type": "application",
|
||||
"name": "k8s.io/controller-manager",
|
||||
"version": "1.27.0",
|
||||
"purl": "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.0",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "kube-controller-manager-minikube"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Type",
|
||||
"value": "controlPlane"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:k8s/k8s.io%2Fkube-proxy@1.27.0",
|
||||
"type": "application",
|
||||
"name": "k8s.io/kube-proxy",
|
||||
"version": "1.27.0",
|
||||
"purl": "pkg:k8s/k8s.io%2Fkube-proxy@1.27.0",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "kube-proxy-4wftc"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Type",
|
||||
"value": "node"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.0",
|
||||
"type": "application",
|
||||
"name": "k8s.io/kube-scheduler",
|
||||
"version": "1.27.0",
|
||||
"purl": "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.0",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "kube-scheduler-minikube"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Type",
|
||||
"value": "controlPlane"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:k8s/k8s.io%2Fkubelet@1.27.0",
|
||||
"type": "application",
|
||||
"name": "k8s.io/kubelet",
|
||||
"version": "1.27.0",
|
||||
"purl": "pkg:k8s/k8s.io%2Fkubelet@1.27.0",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "k8s.io/kubelet"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Type",
|
||||
"value": "node"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:oci/coredns@sha256%3Aa0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e?repository_url=registry.k8s.io%2Fcoredns%2Fcoredns",
|
||||
"type": "container",
|
||||
"name": "registry.k8s.io/coredns/coredns",
|
||||
"version": "sha256:a0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e",
|
||||
"purl": "pkg:oci/coredns@sha256%3Aa0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e?repository_url=registry.k8s.io%2Fcoredns%2Fcoredns",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgID",
|
||||
"value": "registry.k8s.io/coredns/coredns:1.10.1"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgType",
|
||||
"value": "oci"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:oci/etcd@sha256%3A51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83?repository_url=registry.k8s.io%2Fetcd",
|
||||
"type": "container",
|
||||
"name": "registry.k8s.io/etcd",
|
||||
"version": "sha256:51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83",
|
||||
"purl": "pkg:oci/etcd@sha256%3A51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83?repository_url=registry.k8s.io%2Fetcd",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgID",
|
||||
"value": "registry.k8s.io/etcd:3.5.7-0"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgType",
|
||||
"value": "oci"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:oci/kube-apiserver@sha256%3A697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d?repository_url=registry.k8s.io%2Fkube-apiserver",
|
||||
"type": "container",
|
||||
"name": "registry.k8s.io/kube-apiserver",
|
||||
"version": "sha256:697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d",
|
||||
"purl": "pkg:oci/kube-apiserver@sha256%3A697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d?repository_url=registry.k8s.io%2Fkube-apiserver",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgID",
|
||||
"value": "registry.k8s.io/kube-apiserver:1.27.0"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgType",
|
||||
"value": "oci"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:oci/kube-controller-manager@sha256%3A6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265?repository_url=registry.k8s.io%2Fkube-controller-manager",
|
||||
"type": "container",
|
||||
"name": "registry.k8s.io/kube-controller-manager",
|
||||
"version": "sha256:6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265",
|
||||
"purl": "pkg:oci/kube-controller-manager@sha256%3A6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265?repository_url=registry.k8s.io%2Fkube-controller-manager",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgID",
|
||||
"value": "registry.k8s.io/kube-controller-manager:1.27.0"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgType",
|
||||
"value": "oci"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:oci/kube-proxy@sha256%3A4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf?repository_url=registry.k8s.io%2Fkube-proxy",
|
||||
"type": "container",
|
||||
"name": "registry.k8s.io/kube-proxy",
|
||||
"version": "sha256:4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf",
|
||||
"purl": "pkg:oci/kube-proxy@sha256%3A4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf?repository_url=registry.k8s.io%2Fkube-proxy",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgID",
|
||||
"value": "registry.k8s.io/kube-proxy:1.27.0"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgType",
|
||||
"value": "oci"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:oci/kube-scheduler@sha256%3A5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af?repository_url=registry.k8s.io%2Fkube-scheduler",
|
||||
"type": "container",
|
||||
"name": "registry.k8s.io/kube-scheduler",
|
||||
"version": "sha256:5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af",
|
||||
"purl": "pkg:oci/kube-scheduler@sha256%3A5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af?repository_url=registry.k8s.io%2Fkube-scheduler",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgID",
|
||||
"value": "registry.k8s.io/kube-scheduler:1.27.0"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgType",
|
||||
"value": "oci"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"dependencies": [
|
||||
{
|
||||
"ref": "5262e708-f1a3-4fca-a1c3-0a8384f7f4a5",
|
||||
"dependsOn": []
|
||||
},
|
||||
{
|
||||
"ref": "a62abb1f-cb38-4fde-90f3-2bda3b87ddb2",
|
||||
"dependsOn": [
|
||||
"pkg:golang/docker@24.0.4",
|
||||
"pkg:k8s/k8s.io%2Fkubelet@1.27.0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "a6350ac3-52f6-4c5f-a3e3-184b9a634bef",
|
||||
"dependsOn": [
|
||||
"5262e708-f1a3-4fca-a1c3-0a8384f7f4a5",
|
||||
"a62abb1f-cb38-4fde-90f3-2bda3b87ddb2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "b19a88a3-017d-4e70-a73a-75f48696ec0f",
|
||||
"dependsOn": [
|
||||
"pkg:oci/coredns@sha256%3Aa0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e?repository_url=registry.k8s.io%2Fcoredns%2Fcoredns"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "b1c502c9-3c6e-43af-822b-1cb55c6c6ff3",
|
||||
"dependsOn": [
|
||||
"pkg:oci/etcd@sha256%3A51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83?repository_url=registry.k8s.io%2Fetcd"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "pkg:golang/docker@24.0.4",
|
||||
"dependsOn": []
|
||||
},
|
||||
{
|
||||
"ref": "pkg:k8s/k8s.io%2Fapiserver@1.27.0",
|
||||
"dependsOn": [
|
||||
"pkg:oci/kube-apiserver@sha256%3A697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d?repository_url=registry.k8s.io%2Fkube-apiserver"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.0",
|
||||
"dependsOn": [
|
||||
"pkg:oci/kube-controller-manager@sha256%3A6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265?repository_url=registry.k8s.io%2Fkube-controller-manager"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "pkg:k8s/k8s.io%2Fkube-proxy@1.27.0",
|
||||
"dependsOn": [
|
||||
"pkg:oci/kube-proxy@sha256%3A4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf?repository_url=registry.k8s.io%2Fkube-proxy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.0",
|
||||
"dependsOn": [
|
||||
"pkg:oci/kube-scheduler@sha256%3A5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af?repository_url=registry.k8s.io%2Fkube-scheduler"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "pkg:k8s/k8s.io%2Fkubelet@1.27.0",
|
||||
"dependsOn": []
|
||||
},
|
||||
{
|
||||
"ref": "pkg:k8s/k8s.io%2Fkubernetes@1.27.0",
|
||||
"dependsOn": [
|
||||
"a6350ac3-52f6-4c5f-a3e3-184b9a634bef",
|
||||
"b19a88a3-017d-4e70-a73a-75f48696ec0f",
|
||||
"b1c502c9-3c6e-43af-822b-1cb55c6c6ff3",
|
||||
"pkg:k8s/k8s.io%2Fapiserver@1.27.0",
|
||||
"pkg:k8s/k8s.io%2Fcontroller-manager@1.27.0",
|
||||
"pkg:k8s/k8s.io%2Fkube-proxy@1.27.0",
|
||||
"pkg:k8s/k8s.io%2Fkube-scheduler@1.27.0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "pkg:oci/coredns@sha256%3Aa0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e?repository_url=registry.k8s.io%2Fcoredns%2Fcoredns",
|
||||
"dependsOn": []
|
||||
},
|
||||
{
|
||||
"ref": "pkg:oci/etcd@sha256%3A51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83?repository_url=registry.k8s.io%2Fetcd",
|
||||
"dependsOn": []
|
||||
},
|
||||
{
|
||||
"ref": "pkg:oci/kube-apiserver@sha256%3A697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d?repository_url=registry.k8s.io%2Fkube-apiserver",
|
||||
"dependsOn": []
|
||||
},
|
||||
{
|
||||
"ref": "pkg:oci/kube-controller-manager@sha256%3A6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265?repository_url=registry.k8s.io%2Fkube-controller-manager",
|
||||
"dependsOn": []
|
||||
},
|
||||
{
|
||||
"ref": "pkg:oci/kube-proxy@sha256%3A4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf?repository_url=registry.k8s.io%2Fkube-proxy",
|
||||
"dependsOn": []
|
||||
},
|
||||
{
|
||||
"ref": "pkg:oci/kube-scheduler@sha256%3A5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af?repository_url=registry.k8s.io%2Fkube-scheduler",
|
||||
"dependsOn": []
|
||||
}
|
||||
],
|
||||
"vulnerabilities": []
|
||||
}
|
||||
65
integration/testdata/minikube-kbom.json.golden
vendored
Normal file
65
integration/testdata/minikube-kbom.json.golden
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"SchemaVersion": 2,
|
||||
"ArtifactName": "testdata/fixtures/sbom/minikube-kbom.json",
|
||||
"ArtifactType": "cyclonedx",
|
||||
"Metadata": {
|
||||
"OS": {
|
||||
"Family": "ubuntu",
|
||||
"Name": "22.04.2",
|
||||
"EOSL": false
|
||||
},
|
||||
"ImageConfig": {
|
||||
"architecture": "",
|
||||
"created": "0001-01-01T00:00:00Z",
|
||||
"os": "",
|
||||
"rootfs": {
|
||||
"type": "",
|
||||
"diff_ids": null
|
||||
},
|
||||
"config": {}
|
||||
}
|
||||
},
|
||||
"Results": [
|
||||
{
|
||||
"Target": "testdata/fixtures/sbom/minikube-kbom.json (ubuntu 22.04.2)",
|
||||
"Class": "os-pkgs",
|
||||
"Type": "ubuntu"
|
||||
},
|
||||
{
|
||||
"Target": "Kubernetes",
|
||||
"Class": "lang-pkgs",
|
||||
"Type": "kubernetes",
|
||||
"Vulnerabilities": [
|
||||
{
|
||||
"VulnerabilityID": "CVE-2023-2431",
|
||||
"PkgName": "k8s.io/kubelet",
|
||||
"InstalledVersion": "1.27.0",
|
||||
"FixedVersion": "1.24.14, 1.25.9, 1.26.4, 1.27.1",
|
||||
"Status": "fixed",
|
||||
"Layer": {},
|
||||
"SeveritySource": "k8s",
|
||||
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2023-2431",
|
||||
"PkgRef": "pkg:k8s/k8s.io%2Fkubelet@1.27.0",
|
||||
"DataSource": {
|
||||
"ID": "k8s",
|
||||
"Name": "Official Kubernetes CVE Feed",
|
||||
"URL": "https://kubernetes.io/docs/reference/issues-security/official-cve-feed/index.json"
|
||||
},
|
||||
"Title": "Bypass of seccomp profile enforcement ",
|
||||
"Description": "A security issue was discovered in Kubelet that allows pods to bypass the seccomp profile enforcement...",
|
||||
"Severity": "LOW",
|
||||
"CVSS": {
|
||||
"k8s": {
|
||||
"V3Vector": "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:N",
|
||||
"V3Score": 3.4
|
||||
}
|
||||
},
|
||||
"References": [
|
||||
"https://github.com/kubernetes/kubernetes/issues/118690",
|
||||
"https://www.cve.org/cverecord?id=CVE-2023-2431"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -65,9 +65,6 @@ func NewDriver(libType ftypes.LangType) (Driver, bool) {
|
||||
// https://www.swift.org/package-manager/#importing-dependencies
|
||||
ecosystem = vulnerability.Swift
|
||||
comparer = compare.GenericComparer{}
|
||||
case ftypes.Bitnami:
|
||||
ecosystem = vulnerability.Bitnami
|
||||
comparer = compare.GenericComparer{}
|
||||
case ftypes.Cocoapods:
|
||||
// CocoaPods uses RubyGems version specifiers
|
||||
// https://guides.cocoapods.org/making/making-a-cocoapod.html#cocoapods-versioning-specifics
|
||||
@@ -76,6 +73,12 @@ func NewDriver(libType ftypes.LangType) (Driver, bool) {
|
||||
case ftypes.CondaPkg:
|
||||
log.Logger.Warn("Conda package is supported for SBOM, not for vulnerability scanning")
|
||||
return Driver{}, false
|
||||
case ftypes.Bitnami:
|
||||
ecosystem = vulnerability.Bitnami
|
||||
comparer = compare.GenericComparer{}
|
||||
case ftypes.K8sUpstream:
|
||||
ecosystem = vulnerability.Kubernetes
|
||||
comparer = compare.GenericComparer{}
|
||||
default:
|
||||
log.Logger.Warnf("The %q library type is not supported for vulnerability scanning", libType)
|
||||
return Driver{}, false
|
||||
|
||||
@@ -71,6 +71,13 @@ const (
|
||||
Pub LangType = "pub"
|
||||
Hex LangType = "hex"
|
||||
Bitnami LangType = "bitnami"
|
||||
|
||||
K8sUpstream LangType = "kubernetes"
|
||||
EKS LangType = "eks" // Amazon Elastic Kubernetes Service
|
||||
GKE LangType = "gke" // Google Kubernetes Engine
|
||||
AKS LangType = "aks" // Azure Kubernetes Service
|
||||
RKE LangType = "rke" // Rancher Kubernetes Engine
|
||||
OCP LangType = "ocp" // Red Hat OpenShift Container Platform
|
||||
)
|
||||
|
||||
// Config files
|
||||
|
||||
@@ -208,6 +208,17 @@ const (
|
||||
func clusterInfoToReportResources(allArtifact []*artifacts.Artifact) (*core.Component, error) {
|
||||
var coreComponents []*core.Component
|
||||
var cInfo *core.Component
|
||||
|
||||
// Find the first node name to identify AKS cluster
|
||||
var nodeName string
|
||||
for _, artifact := range allArtifact {
|
||||
if artifact.Kind != nodeInfo {
|
||||
continue
|
||||
}
|
||||
nodeName = artifact.Name
|
||||
break
|
||||
}
|
||||
|
||||
for _, artifact := range allArtifact {
|
||||
switch artifact.Kind {
|
||||
case pod:
|
||||
@@ -257,6 +268,7 @@ func clusterInfoToReportResources(allArtifact []*artifacts.Artifact) (*core.Comp
|
||||
Type: cdx.ComponentTypeApplication,
|
||||
Properties: toProperties(comp.Properties, k8sCoreComponentNamespace),
|
||||
Components: imageComponents,
|
||||
PackageURL: generatePURL(comp.Name, comp.Version, nodeName),
|
||||
}
|
||||
coreComponents = append(coreComponents, rootComponent)
|
||||
case nodeInfo:
|
||||
@@ -287,6 +299,7 @@ func clusterInfoToReportResources(allArtifact []*artifacts.Artifact) (*core.Comp
|
||||
Type: cdx.ComponentTypePlatform,
|
||||
Properties: cInfo.Properties,
|
||||
Components: coreComponents,
|
||||
PackageURL: generatePURL(cInfo.Name, cInfo.Version, nodeName),
|
||||
}
|
||||
return rootComponent, nil
|
||||
}
|
||||
@@ -313,20 +326,20 @@ func osNameVersion(name string) (string, string) {
|
||||
}
|
||||
|
||||
func runtimeNameVersion(name string) (string, string) {
|
||||
parts := strings.Split(name, "://")
|
||||
if len(parts) == 2 {
|
||||
name := parts[0]
|
||||
switch parts[0] {
|
||||
case "cri-o":
|
||||
name = "github.com/cri-o/cri-o"
|
||||
case "containerd":
|
||||
name = "github.com/containerd/containerd"
|
||||
case "cri-dockerd":
|
||||
name = "github.com/Mirantis/cri-dockerd"
|
||||
}
|
||||
return name, parts[1]
|
||||
runtime, ver, ok := strings.Cut(name, "://")
|
||||
if !ok {
|
||||
return "", ""
|
||||
}
|
||||
return "", ""
|
||||
|
||||
switch runtime {
|
||||
case "cri-o":
|
||||
name = "github.com/cri-o/cri-o"
|
||||
case "containerd":
|
||||
name = "github.com/containerd/containerd"
|
||||
case "cri-dockerd":
|
||||
name = "github.com/Mirantis/cri-dockerd"
|
||||
}
|
||||
return name, ver
|
||||
}
|
||||
|
||||
func nodeComponent(nf bom.NodeInfo) *core.Component {
|
||||
@@ -388,9 +401,7 @@ func nodeComponent(nf bom.NodeInfo) *core.Component {
|
||||
Namespace: k8sCoreComponentNamespace,
|
||||
},
|
||||
},
|
||||
PackageURL: &purl.PackageURL{
|
||||
PackageURL: *packageurl.NewPackageURL(golang, "", kubelet, kubeletVersion, packageurl.Qualifiers{}, ""),
|
||||
},
|
||||
PackageURL: generatePURL(kubelet, kubeletVersion, nf.NodeName),
|
||||
},
|
||||
{
|
||||
Type: cdx.ComponentTypeApplication,
|
||||
@@ -431,3 +442,27 @@ func toProperties(props map[string]string, namespace string) []core.Property {
|
||||
})
|
||||
return properties
|
||||
}
|
||||
|
||||
func generatePURL(name, ver, nodeName string) *purl.PackageURL {
|
||||
// Identify k8s distribution. An empty namespace means upstream.
|
||||
var namespace string
|
||||
switch {
|
||||
case strings.Contains(ver, "eks"):
|
||||
namespace = purl.NamespaceEKS
|
||||
case strings.Contains(ver, "gke"):
|
||||
namespace = purl.NamespaceGKE
|
||||
case strings.Contains(ver, "rke2"):
|
||||
namespace = purl.NamespaceRKE
|
||||
case strings.Contains(ver, "hotfix"):
|
||||
if !strings.Contains(nodeName, "aks") {
|
||||
// Unknown k8s distribution
|
||||
return nil
|
||||
}
|
||||
namespace = purl.NamespaceAKS
|
||||
case strings.Contains(nodeName, "ocp"):
|
||||
namespace = purl.NamespaceOCP
|
||||
}
|
||||
return &purl.PackageURL{
|
||||
PackageURL: *packageurl.NewPackageURL(purl.TypeK8s, namespace, name, ver, nil, ""),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx/core"
|
||||
)
|
||||
|
||||
func TestK8sClusterInfoReport(t *testing.T) {
|
||||
func TestScanner_Scan(t *testing.T) {
|
||||
flagOpts := flag.Options{ReportOptions: flag.ReportOptions{Format: "cyclonedx"}}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -34,31 +34,31 @@ func TestK8sClusterInfoReport(t *testing.T) {
|
||||
Kind: "ClusterInfo",
|
||||
Name: "k8s.io/kubernetes",
|
||||
RawResource: map[string]interface{}{
|
||||
"name": "k8s.io/kubernetes",
|
||||
"version": "1.21.1",
|
||||
"type": "ClusterInfo",
|
||||
"Properties": map[string]string{
|
||||
"Name": "kube-cluster",
|
||||
"Name": "kind-kind",
|
||||
"Type": "cluster",
|
||||
},
|
||||
"Name": "kube-apiserver-kind-control-plane",
|
||||
"Version": "1.21.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
Namespace: "kube-system",
|
||||
Kind: "PodInfo",
|
||||
Name: "kube-apiserver-kind-control-plane",
|
||||
Name: "k8s.io/apiserver",
|
||||
RawResource: map[string]interface{}{
|
||||
"Containers": []interface{}{map[string]interface{}{
|
||||
"Digest": "18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f",
|
||||
"ID": "kube-apiserver:v1.21.1",
|
||||
"Registry": "k8s.gcr.io",
|
||||
"Repository": "kube-apiserver",
|
||||
"Version": "v1.21.1",
|
||||
"Containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"Digest": "18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f",
|
||||
"ID": "kube-apiserver:v1.21.1",
|
||||
"Registry": "k8s.gcr.io",
|
||||
"Repository": "kube-apiserver",
|
||||
"Version": "v1.21.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
"Properties": map[string]string{
|
||||
"ControlPlaneComponents": "kube-apiserver",
|
||||
},
|
||||
"Name": "kube-apiserver-kind-control-plane",
|
||||
"Namespace": "kube-system",
|
||||
"Name": "k8s.io/apiserver",
|
||||
"Version": "1.21.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -83,18 +83,40 @@ func TestK8sClusterInfoReport(t *testing.T) {
|
||||
},
|
||||
want: &core.Component{
|
||||
Type: cdx.ComponentTypePlatform,
|
||||
Name: "kube-apiserver-kind-control-plane",
|
||||
Name: "k8s.io/kubernetes",
|
||||
Version: "1.21.1",
|
||||
Properties: []core.Property{
|
||||
{Name: "Name", Value: "kube-cluster", Namespace: k8sCoreComponentNamespace},
|
||||
{
|
||||
Name: "Name",
|
||||
Value: "kind-kind",
|
||||
Namespace: k8sCoreComponentNamespace,
|
||||
},
|
||||
{
|
||||
Name: "Type",
|
||||
Value: "cluster",
|
||||
Namespace: k8sCoreComponentNamespace,
|
||||
},
|
||||
},
|
||||
PackageURL: &purl.PackageURL{
|
||||
PackageURL: packageurl.PackageURL{
|
||||
Type: purl.TypeK8s,
|
||||
Name: "k8s.io/kubernetes",
|
||||
Version: "1.21.1",
|
||||
},
|
||||
},
|
||||
Components: []*core.Component{
|
||||
{
|
||||
Type: cdx.ComponentTypeApplication,
|
||||
Name: "kube-apiserver-kind-control-plane",
|
||||
Properties: []core.Property{
|
||||
{Name: "ControlPlaneComponents", Value: "kube-apiserver", Namespace: k8sCoreComponentNamespace},
|
||||
Type: cdx.ComponentTypeApplication,
|
||||
Name: "k8s.io/apiserver",
|
||||
Version: "1.21.1",
|
||||
PackageURL: &purl.PackageURL{
|
||||
PackageURL: packageurl.PackageURL{
|
||||
Type: purl.TypeK8s,
|
||||
Name: "k8s.io/apiserver",
|
||||
Version: "1.21.1",
|
||||
},
|
||||
},
|
||||
Properties: []core.Property{},
|
||||
Components: []*core.Component{
|
||||
{
|
||||
Type: cdx.ComponentTypeContainer,
|
||||
@@ -110,15 +132,18 @@ func TestK8sClusterInfoReport(t *testing.T) {
|
||||
Key: "repository_url",
|
||||
Value: "k8s.gcr.io/kube-apiserver",
|
||||
},
|
||||
{
|
||||
Key: "arch",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Properties: []core.Property{
|
||||
{Name: cyc.PropertyPkgID, Value: "k8s.gcr.io/kube-apiserver:1.21.1"},
|
||||
{Name: cyc.PropertyPkgType, Value: "oci"},
|
||||
{
|
||||
Name: cyc.PropertyPkgID,
|
||||
Value: "k8s.gcr.io/kube-apiserver:1.21.1",
|
||||
},
|
||||
{
|
||||
Name: cyc.PropertyPkgType,
|
||||
Value: "oci",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -127,13 +152,36 @@ func TestK8sClusterInfoReport(t *testing.T) {
|
||||
Type: cdx.ComponentTypePlatform,
|
||||
Name: "kind-control-plane",
|
||||
Properties: []core.Property{
|
||||
{Name: "Architecture", Value: "arm64"},
|
||||
{Name: "HostName", Value: "kind-control-plane"},
|
||||
{Name: "KernelVersion", Value: "6.2.15-300.fc38.aarch64"},
|
||||
{Name: "NodeRole", Value: "master"},
|
||||
{Name: "OperatingSystem", Value: "linux"},
|
||||
{Name: k8sComponentName, Value: "kind-control-plane", Namespace: k8sCoreComponentNamespace},
|
||||
{Name: k8sComponentType, Value: "node", Namespace: k8sCoreComponentNamespace},
|
||||
{
|
||||
Name: "Architecture",
|
||||
Value: "arm64",
|
||||
},
|
||||
{
|
||||
Name: "HostName",
|
||||
Value: "kind-control-plane",
|
||||
},
|
||||
{
|
||||
Name: "KernelVersion",
|
||||
Value: "6.2.15-300.fc38.aarch64",
|
||||
},
|
||||
{
|
||||
Name: "NodeRole",
|
||||
Value: "master",
|
||||
},
|
||||
{
|
||||
Name: "OperatingSystem",
|
||||
Value: "linux",
|
||||
},
|
||||
{
|
||||
Name: k8sComponentName,
|
||||
Value: "kind-control-plane",
|
||||
Namespace: k8sCoreComponentNamespace,
|
||||
},
|
||||
{
|
||||
Name: k8sComponentType,
|
||||
Value: "node",
|
||||
Namespace: k8sCoreComponentNamespace,
|
||||
},
|
||||
},
|
||||
Components: []*core.Component{
|
||||
{
|
||||
@@ -141,16 +189,32 @@ func TestK8sClusterInfoReport(t *testing.T) {
|
||||
Name: "ubuntu",
|
||||
Version: "21.04",
|
||||
Properties: []core.Property{
|
||||
{Name: "Class", Value: "os-pkgs", Namespace: ""},
|
||||
{Name: "Type", Value: "ubuntu", Namespace: ""},
|
||||
{
|
||||
Name: "Class",
|
||||
Value: "os-pkgs",
|
||||
Namespace: "",
|
||||
},
|
||||
{
|
||||
Name: "Type",
|
||||
Value: "ubuntu",
|
||||
Namespace: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: cdx.ComponentTypeApplication,
|
||||
Name: "node-core-components",
|
||||
Properties: []core.Property{
|
||||
{Name: "Class", Value: "lang-pkgs", Namespace: ""},
|
||||
{Name: "Type", Value: "golang", Namespace: ""},
|
||||
{
|
||||
Name: "Class",
|
||||
Value: "lang-pkgs",
|
||||
Namespace: "",
|
||||
},
|
||||
{
|
||||
Name: "Type",
|
||||
Value: "golang",
|
||||
Namespace: "",
|
||||
},
|
||||
},
|
||||
Components: []*core.Component{
|
||||
{
|
||||
@@ -158,15 +222,22 @@ func TestK8sClusterInfoReport(t *testing.T) {
|
||||
Name: "k8s.io/kubelet",
|
||||
Version: "1.21.1",
|
||||
Properties: []core.Property{
|
||||
{Name: k8sComponentType, Value: "node", Namespace: k8sCoreComponentNamespace},
|
||||
{Name: k8sComponentName, Value: "k8s.io/kubelet", Namespace: k8sCoreComponentNamespace},
|
||||
{
|
||||
Name: k8sComponentType,
|
||||
Value: "node",
|
||||
Namespace: k8sCoreComponentNamespace,
|
||||
},
|
||||
{
|
||||
Name: k8sComponentName,
|
||||
Value: "k8s.io/kubelet",
|
||||
Namespace: k8sCoreComponentNamespace,
|
||||
},
|
||||
},
|
||||
PackageURL: &purl.PackageURL{
|
||||
PackageURL: packageurl.PackageURL{
|
||||
Type: "golang",
|
||||
Name: "k8s.io/kubelet",
|
||||
Version: "1.21.1",
|
||||
Qualifiers: packageurl.Qualifiers{},
|
||||
Type: "k8s",
|
||||
Name: "k8s.io/kubelet",
|
||||
Version: "1.21.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -175,8 +246,16 @@ func TestK8sClusterInfoReport(t *testing.T) {
|
||||
Name: "github.com/containerd/containerd",
|
||||
Version: "1.5.2",
|
||||
Properties: []core.Property{
|
||||
{Name: k8sComponentType, Value: "node", Namespace: k8sCoreComponentNamespace},
|
||||
{Name: k8sComponentName, Value: "github.com/containerd/containerd", Namespace: k8sCoreComponentNamespace},
|
||||
{
|
||||
Name: k8sComponentType,
|
||||
Value: "node",
|
||||
Namespace: k8sCoreComponentNamespace,
|
||||
},
|
||||
{
|
||||
Name: k8sComponentName,
|
||||
Value: "github.com/containerd/containerd",
|
||||
Namespace: k8sCoreComponentNamespace,
|
||||
},
|
||||
},
|
||||
PackageURL: &purl.PackageURL{
|
||||
PackageURL: packageurl.PackageURL{
|
||||
@@ -262,3 +341,63 @@ func TestTestOsNameVersion(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGeneratePURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
compName string
|
||||
compVersion string
|
||||
nodeName string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "native k8s component",
|
||||
compName: "k8s.io/kubelet",
|
||||
compVersion: "1.24.10",
|
||||
nodeName: "kind-kind",
|
||||
want: "pkg:k8s/k8s.io%2Fkubelet@1.24.10",
|
||||
},
|
||||
|
||||
{
|
||||
name: "GKE",
|
||||
compName: "k8s.io/kubelet",
|
||||
compVersion: "1.24.10-gke.2300",
|
||||
nodeName: "gke-gke1796-default-pool-768cb718-sk1d",
|
||||
want: "pkg:k8s/gke/k8s.io%2Fkubelet@1.24.10-gke.2300",
|
||||
},
|
||||
{
|
||||
name: "AKS",
|
||||
compName: "k8s.io/kubelet",
|
||||
compVersion: "1.24.10-hotfix.20221110",
|
||||
nodeName: "aks-default-23814474-vmss000000",
|
||||
want: "pkg:k8s/aks/k8s.io%2Fkubelet@1.24.10-hotfix.20221110",
|
||||
},
|
||||
{
|
||||
name: "EKS",
|
||||
compName: "k8s.io/kubelet",
|
||||
compVersion: "1.23.17-eks-8ccc7ba",
|
||||
nodeName: "eks-vmss000000",
|
||||
want: "pkg:k8s/eks/k8s.io%2Fkubelet@1.23.17-eks-8ccc7ba",
|
||||
},
|
||||
{
|
||||
name: "Rancher",
|
||||
compName: "k8s.io/kubelet",
|
||||
compVersion: "1.24.11+rke2r1",
|
||||
nodeName: "ip-10-0-5-23",
|
||||
want: "pkg:k8s/rke/k8s.io%2Fkubelet@1.24.11%2Brke2r1",
|
||||
},
|
||||
{
|
||||
name: "OCP",
|
||||
compName: "k8s.io/kubelet",
|
||||
compVersion: "1.26.7+c7ee51f",
|
||||
nodeName: "ocp413vpool14000-p8vnm-master-2",
|
||||
want: "pkg:k8s/ocp/k8s.io%2Fkubelet@1.26.7%2Bc7ee51f",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := generatePURL(tt.compName, tt.compVersion, tt.nodeName)
|
||||
assert.Equal(t, tt.want, got.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,30 @@ import (
|
||||
const (
|
||||
TypeOCI = "oci"
|
||||
TypeDart = "dart"
|
||||
|
||||
// TypeK8s is a custom type for Kubernetes components in PURL.
|
||||
// - namespace: The service provider such as EKS or GKE. It is not case sensitive and must be lowercased.
|
||||
// Known namespaces:
|
||||
// - empty (upstream)
|
||||
// - eks (AWS)
|
||||
// - aks (GCP)
|
||||
// - gke (Azure)
|
||||
// - rke (Rancher)
|
||||
// - name: The k8s component name and is case sensitive.
|
||||
// - version: The combined version and release of a component.
|
||||
//
|
||||
// Examples:
|
||||
// - pkg:k8s/upstream/k8s.io%2Fapiserver@1.24.1
|
||||
// - pkg:k8s/eks/k8s.io%2Fkube-proxy@1.26.2-eksbuild.1
|
||||
TypeK8s = "k8s"
|
||||
|
||||
NamespaceEKS = "eks"
|
||||
NamespaceAKS = "aks"
|
||||
NamespaceGKE = "gke"
|
||||
NamespaceRKE = "rke"
|
||||
NamespaceOCP = "ocp"
|
||||
|
||||
TypeUnknown = "unknown"
|
||||
)
|
||||
|
||||
type PackageURL struct {
|
||||
@@ -71,7 +95,7 @@ func (p *PackageURL) Package() *ftypes.Package {
|
||||
|
||||
// Return packages without namespace.
|
||||
// OS packages are not supposed to have namespace.
|
||||
if p.Namespace == "" || p.IsOSPkg() {
|
||||
if p.Namespace == "" || p.Class() == types.ClassOSPkg {
|
||||
return pkg
|
||||
}
|
||||
|
||||
@@ -88,6 +112,7 @@ func (p *PackageURL) Package() *ftypes.Package {
|
||||
}
|
||||
|
||||
// LangType returns an application type in Trivy
|
||||
// nolint: gocyclo
|
||||
func (p *PackageURL) LangType() ftypes.LangType {
|
||||
switch p.Type {
|
||||
case packageurl.TypeComposer:
|
||||
@@ -120,12 +145,39 @@ func (p *PackageURL) LangType() ftypes.LangType {
|
||||
return ftypes.Pub
|
||||
case packageurl.TypeBitnami:
|
||||
return ftypes.Bitnami
|
||||
case TypeK8s:
|
||||
switch p.Namespace {
|
||||
case NamespaceEKS:
|
||||
return ftypes.EKS
|
||||
case NamespaceGKE:
|
||||
return ftypes.GKE
|
||||
case NamespaceAKS:
|
||||
return ftypes.AKS
|
||||
case NamespaceRKE:
|
||||
return ftypes.RKE
|
||||
case NamespaceOCP:
|
||||
return ftypes.OCP
|
||||
case "":
|
||||
return ftypes.K8sUpstream
|
||||
}
|
||||
return TypeUnknown
|
||||
default:
|
||||
return TypeUnknown
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
func (p *PackageURL) IsOSPkg() bool {
|
||||
return p.Type == packageurl.TypeApk || p.Type == packageurl.TypeDebian || p.Type == packageurl.TypeRPM
|
||||
func (p *PackageURL) Class() types.ResultClass {
|
||||
switch p.Type {
|
||||
case packageurl.TypeApk, packageurl.TypeDebian, packageurl.TypeRPM:
|
||||
// OS packages
|
||||
return types.ClassOSPkg
|
||||
default:
|
||||
if p.LangType() == TypeUnknown {
|
||||
return types.ClassUnknown
|
||||
}
|
||||
// Language-specific packages
|
||||
return types.ClassLangPkg
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PackageURL) BOMRef() string {
|
||||
@@ -221,15 +273,19 @@ func parseOCI(metadata types.Metadata) (packageurl.PackageURL, error) {
|
||||
if index != -1 {
|
||||
name = name[index+1:]
|
||||
}
|
||||
qualifiers := packageurl.Qualifiers{
|
||||
packageurl.Qualifier{
|
||||
|
||||
var qualifiers packageurl.Qualifiers
|
||||
if repoURL := digest.Repository.Name(); repoURL != "" {
|
||||
qualifiers = append(qualifiers, packageurl.Qualifier{
|
||||
Key: "repository_url",
|
||||
Value: digest.Repository.Name(),
|
||||
},
|
||||
packageurl.Qualifier{
|
||||
Value: repoURL,
|
||||
})
|
||||
}
|
||||
if arch := metadata.ImageConfig.Architecture; arch != "" {
|
||||
qualifiers = append(qualifiers, packageurl.Qualifier{
|
||||
Key: "arch",
|
||||
Value: metadata.ImageConfig.Architecture,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return *packageurl.NewPackageURL(packageurl.TypeOCI, "", name, digest.DigestStr(), qualifiers, ""), nil
|
||||
|
||||
@@ -717,3 +717,47 @@ func TestPackage(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackageURL_LangType(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
purl packageurl.PackageURL
|
||||
want ftypes.LangType
|
||||
}{
|
||||
{
|
||||
name: "maven",
|
||||
purl: packageurl.PackageURL{
|
||||
Type: packageurl.TypeMaven,
|
||||
Namespace: "org.springframework",
|
||||
Name: "spring-core",
|
||||
Version: "5.0.4.RELEASE",
|
||||
},
|
||||
want: ftypes.Jar,
|
||||
},
|
||||
{
|
||||
name: "k8s",
|
||||
purl: packageurl.PackageURL{
|
||||
Type: purl.TypeK8s,
|
||||
Name: "kubelet",
|
||||
Version: "1.21.1",
|
||||
},
|
||||
want: ftypes.K8sUpstream,
|
||||
},
|
||||
{
|
||||
name: "eks",
|
||||
purl: packageurl.PackageURL{
|
||||
Type: purl.TypeK8s,
|
||||
Namespace: purl.NamespaceEKS,
|
||||
Name: "kubelet",
|
||||
Version: "1.21.1",
|
||||
},
|
||||
want: ftypes.EKS,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
p := &purl.PackageURL{PackageURL: tt.purl}
|
||||
assert.Equalf(t, tt.want, p.LangType(), "LangType()")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
434
pkg/sbom/cyclonedx/testdata/happy/kbom.json
vendored
Normal file
434
pkg/sbom/cyclonedx/testdata/happy/kbom.json
vendored
Normal file
@@ -0,0 +1,434 @@
|
||||
{
|
||||
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.5",
|
||||
"serialNumber": "urn:uuid:e2daaea6-d96f-4b84-960c-0d72c348cd23",
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"timestamp": "2023-09-29T06:25:00+00:00",
|
||||
"tools": [
|
||||
{
|
||||
"vendor": "aquasecurity",
|
||||
"name": "trivy",
|
||||
"version": "0.45.1-15-g7bbd0d097"
|
||||
}
|
||||
],
|
||||
"component": {
|
||||
"bom-ref": "pkg:k8s/k8s.io%2Fkubernetes@1.27.4",
|
||||
"type": "platform",
|
||||
"name": "k8s.io/kubernetes",
|
||||
"version": "1.27.4",
|
||||
"purl": "pkg:k8s/k8s.io%2Fkubernetes@1.27.4",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "minikube"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Type",
|
||||
"value": "cluster"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"bom-ref": "5262e708-f1a3-4fca-a1c3-0a8384f7f4a5",
|
||||
"type": "operating-system",
|
||||
"name": "ubuntu",
|
||||
"version": "22.04.2",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:Class",
|
||||
"value": "os-pkgs"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:Type",
|
||||
"value": "ubuntu"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "a62abb1f-cb38-4fde-90f3-2bda3b87ddb2",
|
||||
"type": "application",
|
||||
"name": "node-core-components",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:Class",
|
||||
"value": "lang-pkgs"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:Type",
|
||||
"value": "golang"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "a6350ac3-52f6-4c5f-a3e3-184b9a634bef",
|
||||
"type": "platform",
|
||||
"name": "minikube",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:Architecture",
|
||||
"value": "arm64"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:HostName",
|
||||
"value": "minikube"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:KernelVersion",
|
||||
"value": "5.15.49-linuxkit-pr"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:NodeRole",
|
||||
"value": "master"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:OperatingSystem",
|
||||
"value": "linux"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "minikube"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Type",
|
||||
"value": "node"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "b19a88a3-017d-4e70-a73a-75f48696ec0f",
|
||||
"type": "application",
|
||||
"name": "kube-dns",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "coredns-5d78c9869d-nd92n"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "b1c502c9-3c6e-43af-822b-1cb55c6c6ff3",
|
||||
"type": "application",
|
||||
"name": "go.etcd.io/etcd/v3",
|
||||
"version": "3.5.7-0",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "etcd-minikube"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Type",
|
||||
"value": "controlPlane"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:golang/docker@24.0.4",
|
||||
"type": "application",
|
||||
"name": "docker",
|
||||
"version": "24.0.4",
|
||||
"purl": "pkg:golang/docker@24.0.4",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "docker"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Type",
|
||||
"value": "node"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:k8s/k8s.io%2Fapiserver@1.27.4",
|
||||
"type": "application",
|
||||
"name": "k8s.io/apiserver",
|
||||
"version": "1.27.4",
|
||||
"purl": "pkg:k8s/k8s.io%2Fapiserver@1.27.4",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "kube-apiserver-minikube"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Type",
|
||||
"value": "controlPlane"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.4",
|
||||
"type": "application",
|
||||
"name": "k8s.io/controller-manager",
|
||||
"version": "1.27.4",
|
||||
"purl": "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.4",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "kube-controller-manager-minikube"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Type",
|
||||
"value": "controlPlane"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:k8s/k8s.io%2Fkube-proxy@1.27.4",
|
||||
"type": "application",
|
||||
"name": "k8s.io/kube-proxy",
|
||||
"version": "1.27.4",
|
||||
"purl": "pkg:k8s/k8s.io%2Fkube-proxy@1.27.4",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "kube-proxy-4wftc"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Type",
|
||||
"value": "node"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.4",
|
||||
"type": "application",
|
||||
"name": "k8s.io/kube-scheduler",
|
||||
"version": "1.27.4",
|
||||
"purl": "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.4",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "kube-scheduler-minikube"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Type",
|
||||
"value": "controlPlane"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:k8s/k8s.io%2Fkubelet@1.27.4",
|
||||
"type": "application",
|
||||
"name": "k8s.io/kubelet",
|
||||
"version": "1.27.4",
|
||||
"purl": "pkg:k8s/k8s.io%2Fkubelet@1.27.4",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Name",
|
||||
"value": "k8s.io/kubelet"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:resource:Type",
|
||||
"value": "node"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:oci/coredns@sha256%3Aa0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e?repository_url=registry.k8s.io%2Fcoredns%2Fcoredns",
|
||||
"type": "container",
|
||||
"name": "registry.k8s.io/coredns/coredns",
|
||||
"version": "sha256:a0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e",
|
||||
"purl": "pkg:oci/coredns@sha256%3Aa0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e?repository_url=registry.k8s.io%2Fcoredns%2Fcoredns",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgID",
|
||||
"value": "registry.k8s.io/coredns/coredns:1.10.1"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgType",
|
||||
"value": "oci"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:oci/etcd@sha256%3A51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83?repository_url=registry.k8s.io%2Fetcd",
|
||||
"type": "container",
|
||||
"name": "registry.k8s.io/etcd",
|
||||
"version": "sha256:51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83",
|
||||
"purl": "pkg:oci/etcd@sha256%3A51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83?repository_url=registry.k8s.io%2Fetcd",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgID",
|
||||
"value": "registry.k8s.io/etcd:3.5.7-0"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgType",
|
||||
"value": "oci"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:oci/kube-apiserver@sha256%3A697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d?repository_url=registry.k8s.io%2Fkube-apiserver",
|
||||
"type": "container",
|
||||
"name": "registry.k8s.io/kube-apiserver",
|
||||
"version": "sha256:697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d",
|
||||
"purl": "pkg:oci/kube-apiserver@sha256%3A697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d?repository_url=registry.k8s.io%2Fkube-apiserver",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgID",
|
||||
"value": "registry.k8s.io/kube-apiserver:1.27.4"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgType",
|
||||
"value": "oci"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:oci/kube-controller-manager@sha256%3A6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265?repository_url=registry.k8s.io%2Fkube-controller-manager",
|
||||
"type": "container",
|
||||
"name": "registry.k8s.io/kube-controller-manager",
|
||||
"version": "sha256:6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265",
|
||||
"purl": "pkg:oci/kube-controller-manager@sha256%3A6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265?repository_url=registry.k8s.io%2Fkube-controller-manager",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgID",
|
||||
"value": "registry.k8s.io/kube-controller-manager:1.27.4"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgType",
|
||||
"value": "oci"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:oci/kube-proxy@sha256%3A4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf?repository_url=registry.k8s.io%2Fkube-proxy",
|
||||
"type": "container",
|
||||
"name": "registry.k8s.io/kube-proxy",
|
||||
"version": "sha256:4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf",
|
||||
"purl": "pkg:oci/kube-proxy@sha256%3A4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf?repository_url=registry.k8s.io%2Fkube-proxy",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgID",
|
||||
"value": "registry.k8s.io/kube-proxy:1.27.4"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgType",
|
||||
"value": "oci"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:oci/kube-scheduler@sha256%3A5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af?repository_url=registry.k8s.io%2Fkube-scheduler",
|
||||
"type": "container",
|
||||
"name": "registry.k8s.io/kube-scheduler",
|
||||
"version": "sha256:5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af",
|
||||
"purl": "pkg:oci/kube-scheduler@sha256%3A5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af?repository_url=registry.k8s.io%2Fkube-scheduler",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgID",
|
||||
"value": "registry.k8s.io/kube-scheduler:1.27.4"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgType",
|
||||
"value": "oci"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"dependencies": [
|
||||
{
|
||||
"ref": "5262e708-f1a3-4fca-a1c3-0a8384f7f4a5",
|
||||
"dependsOn": []
|
||||
},
|
||||
{
|
||||
"ref": "a62abb1f-cb38-4fde-90f3-2bda3b87ddb2",
|
||||
"dependsOn": [
|
||||
"pkg:golang/docker@24.0.4",
|
||||
"pkg:k8s/k8s.io%2Fkubelet@1.27.4"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "a6350ac3-52f6-4c5f-a3e3-184b9a634bef",
|
||||
"dependsOn": [
|
||||
"5262e708-f1a3-4fca-a1c3-0a8384f7f4a5",
|
||||
"a62abb1f-cb38-4fde-90f3-2bda3b87ddb2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "b19a88a3-017d-4e70-a73a-75f48696ec0f",
|
||||
"dependsOn": [
|
||||
"pkg:oci/coredns@sha256%3Aa0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e?repository_url=registry.k8s.io%2Fcoredns%2Fcoredns"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "b1c502c9-3c6e-43af-822b-1cb55c6c6ff3",
|
||||
"dependsOn": [
|
||||
"pkg:oci/etcd@sha256%3A51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83?repository_url=registry.k8s.io%2Fetcd"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "pkg:golang/docker@24.0.4",
|
||||
"dependsOn": []
|
||||
},
|
||||
{
|
||||
"ref": "pkg:k8s/k8s.io%2Fapiserver@1.27.4",
|
||||
"dependsOn": [
|
||||
"pkg:oci/kube-apiserver@sha256%3A697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d?repository_url=registry.k8s.io%2Fkube-apiserver"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.4",
|
||||
"dependsOn": [
|
||||
"pkg:oci/kube-controller-manager@sha256%3A6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265?repository_url=registry.k8s.io%2Fkube-controller-manager"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "pkg:k8s/k8s.io%2Fkube-proxy@1.27.4",
|
||||
"dependsOn": [
|
||||
"pkg:oci/kube-proxy@sha256%3A4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf?repository_url=registry.k8s.io%2Fkube-proxy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.4",
|
||||
"dependsOn": [
|
||||
"pkg:oci/kube-scheduler@sha256%3A5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af?repository_url=registry.k8s.io%2Fkube-scheduler"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "pkg:k8s/k8s.io%2Fkubelet@1.27.4",
|
||||
"dependsOn": []
|
||||
},
|
||||
{
|
||||
"ref": "pkg:k8s/k8s.io%2Fkubernetes@1.27.4",
|
||||
"dependsOn": [
|
||||
"a6350ac3-52f6-4c5f-a3e3-184b9a634bef",
|
||||
"b19a88a3-017d-4e70-a73a-75f48696ec0f",
|
||||
"b1c502c9-3c6e-43af-822b-1cb55c6c6ff3",
|
||||
"pkg:k8s/k8s.io%2Fapiserver@1.27.4",
|
||||
"pkg:k8s/k8s.io%2Fcontroller-manager@1.27.4",
|
||||
"pkg:k8s/k8s.io%2Fkube-proxy@1.27.4",
|
||||
"pkg:k8s/k8s.io%2Fkube-scheduler@1.27.4"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "pkg:oci/coredns@sha256%3Aa0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e?repository_url=registry.k8s.io%2Fcoredns%2Fcoredns",
|
||||
"dependsOn": []
|
||||
},
|
||||
{
|
||||
"ref": "pkg:oci/etcd@sha256%3A51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83?repository_url=registry.k8s.io%2Fetcd",
|
||||
"dependsOn": []
|
||||
},
|
||||
{
|
||||
"ref": "pkg:oci/kube-apiserver@sha256%3A697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d?repository_url=registry.k8s.io%2Fkube-apiserver",
|
||||
"dependsOn": []
|
||||
},
|
||||
{
|
||||
"ref": "pkg:oci/kube-controller-manager@sha256%3A6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265?repository_url=registry.k8s.io%2Fkube-controller-manager",
|
||||
"dependsOn": []
|
||||
},
|
||||
{
|
||||
"ref": "pkg:oci/kube-proxy@sha256%3A4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf?repository_url=registry.k8s.io%2Fkube-proxy",
|
||||
"dependsOn": []
|
||||
},
|
||||
{
|
||||
"ref": "pkg:oci/kube-scheduler@sha256%3A5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af?repository_url=registry.k8s.io%2Fkube-scheduler",
|
||||
"dependsOn": []
|
||||
}
|
||||
],
|
||||
"vulnerabilities": []
|
||||
}
|
||||
@@ -128,7 +128,7 @@ func (c *BOM) parseSBOM(bom *cdx.BOM) error {
|
||||
if _, ok := seen[ref]; ok {
|
||||
continue
|
||||
}
|
||||
if component.Type == cdx.ComponentTypeLibrary {
|
||||
if component.Type == cdx.ComponentTypeLibrary || component.PackageURL != "" {
|
||||
libComponents = append(libComponents, component)
|
||||
}
|
||||
|
||||
@@ -194,13 +194,17 @@ func parsePkgs(components []cdx.Component, seen map[string]struct{}) ([]ftypes.P
|
||||
var pkgs []ftypes.Package
|
||||
for _, com := range components {
|
||||
seen[com.BOMRef] = struct{}{}
|
||||
_, _, pkg, err := toPackage(com)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrPURLEmpty) {
|
||||
continue
|
||||
}
|
||||
pkgURL, pkg, err := toPackage(com)
|
||||
if errors.Is(err, ErrPURLEmpty) {
|
||||
continue
|
||||
} else if err != nil {
|
||||
return nil, xerrors.Errorf("failed to parse language package: %w", err)
|
||||
}
|
||||
|
||||
// Skip unsupported package types
|
||||
if pkgURL.Class() == types.ClassUnknown {
|
||||
continue
|
||||
}
|
||||
pkgs = append(pkgs, *pkg)
|
||||
}
|
||||
return pkgs, nil
|
||||
@@ -276,21 +280,22 @@ func dependencyMap(deps *[]cdx.Dependency) map[string][]string {
|
||||
}
|
||||
|
||||
func aggregatePkgs(libs []cdx.Component) ([]ftypes.PackageInfo, []ftypes.Application, error) {
|
||||
osPkgMap := make(map[ftypes.OSType]ftypes.Packages)
|
||||
osPkgMap := make(map[string]ftypes.Packages)
|
||||
langPkgMap := make(map[ftypes.LangType]ftypes.Packages)
|
||||
for _, lib := range libs {
|
||||
isOSPkg, pkgType, pkg, err := toPackage(lib)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrPURLEmpty) {
|
||||
continue
|
||||
}
|
||||
pkgURL, pkg, err := toPackage(lib)
|
||||
if errors.Is(err, ErrPURLEmpty) {
|
||||
continue
|
||||
} else if err != nil {
|
||||
return nil, nil, xerrors.Errorf("failed to parse the component: %w", err)
|
||||
}
|
||||
|
||||
if isOSPkg {
|
||||
osPkgMap[pkgType] = append(osPkgMap[pkgType], *pkg)
|
||||
} else {
|
||||
langPkgMap[pkgType] = append(langPkgMap[pkgType], *pkg)
|
||||
switch pkgURL.Class() {
|
||||
case types.ClassOSPkg:
|
||||
osPkgMap[pkgURL.Type] = append(osPkgMap[pkgURL.Type], *pkg)
|
||||
case types.ClassLangPkg:
|
||||
langType := pkgURL.LangType()
|
||||
langPkgMap[langType] = append(langPkgMap[langType], *pkg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,14 +337,14 @@ func toApplication(component cdx.Component) *ftypes.Application {
|
||||
}
|
||||
}
|
||||
|
||||
func toPackage(component cdx.Component) (bool, ftypes.TargetType, *ftypes.Package, error) {
|
||||
func toPackage(component cdx.Component) (*purl.PackageURL, *ftypes.Package, error) {
|
||||
if component.PackageURL == "" {
|
||||
log.Logger.Warnf("Skip the component (BOM-Ref: %s) as the PURL is empty", component.BOMRef)
|
||||
return false, "", nil, ErrPURLEmpty
|
||||
return nil, nil, ErrPURLEmpty
|
||||
}
|
||||
p, err := purl.FromString(component.PackageURL)
|
||||
if err != nil {
|
||||
return false, "", nil, xerrors.Errorf("failed to parse purl: %w", err)
|
||||
return nil, nil, xerrors.Errorf("failed to parse purl: %w", err)
|
||||
}
|
||||
|
||||
pkg := p.Package()
|
||||
@@ -365,7 +370,7 @@ func toPackage(component cdx.Component) (bool, ftypes.TargetType, *ftypes.Packag
|
||||
case PropertySrcEpoch:
|
||||
pkg.SrcEpoch, err = strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return false, "", nil, xerrors.Errorf("failed to parse source epoch: %w", err)
|
||||
return nil, nil, xerrors.Errorf("failed to parse source epoch: %w", err)
|
||||
}
|
||||
case PropertyModularitylabel:
|
||||
pkg.Modularitylabel = value
|
||||
@@ -376,8 +381,7 @@ func toPackage(component cdx.Component) (bool, ftypes.TargetType, *ftypes.Packag
|
||||
}
|
||||
}
|
||||
|
||||
isOSPkg := p.IsOSPkg()
|
||||
if isOSPkg {
|
||||
if p.Class() == types.ClassOSPkg {
|
||||
// Fill source package information for components in third-party SBOMs .
|
||||
if pkg.SrcName == "" {
|
||||
pkg.SrcName = pkg.Name
|
||||
@@ -393,7 +397,7 @@ func toPackage(component cdx.Component) (bool, ftypes.TargetType, *ftypes.Packag
|
||||
}
|
||||
}
|
||||
|
||||
return isOSPkg, p.LangType(), pkg, nil
|
||||
return p, pkg, nil
|
||||
}
|
||||
|
||||
func toTrivyCdxComponent(component cdx.Component) ftypes.Component {
|
||||
|
||||
@@ -130,6 +130,72 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path KBOM",
|
||||
inputFile: "testdata/happy/kbom.json",
|
||||
want: types.SBOM{
|
||||
OS: ftypes.OS{
|
||||
Family: "ubuntu",
|
||||
Name: "22.04.2",
|
||||
},
|
||||
Packages: []ftypes.PackageInfo{
|
||||
{
|
||||
FilePath: "",
|
||||
},
|
||||
},
|
||||
Applications: []ftypes.Application{
|
||||
{
|
||||
Type: ftypes.GoBinary,
|
||||
Libraries: ftypes.Packages{
|
||||
{
|
||||
Name: "docker",
|
||||
Version: "24.0.4",
|
||||
Ref: "pkg:golang/docker@24.0.4",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "golang",
|
||||
FilePath: "node-core-components",
|
||||
},
|
||||
{
|
||||
Type: ftypes.K8sUpstream,
|
||||
Libraries: ftypes.Packages{
|
||||
{
|
||||
Name: "k8s.io/apiserver",
|
||||
Version: "1.27.4",
|
||||
Ref: "pkg:k8s/k8s.io%2Fapiserver@1.27.4",
|
||||
},
|
||||
{
|
||||
Name: "k8s.io/controller-manager",
|
||||
Version: "1.27.4",
|
||||
Ref: "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.4",
|
||||
},
|
||||
{
|
||||
Name: "k8s.io/kube-proxy",
|
||||
Version: "1.27.4",
|
||||
Ref: "pkg:k8s/k8s.io%2Fkube-proxy@1.27.4",
|
||||
},
|
||||
{
|
||||
Name: "k8s.io/kube-scheduler",
|
||||
Version: "1.27.4",
|
||||
Ref: "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.4",
|
||||
},
|
||||
{
|
||||
Name: "k8s.io/kubelet",
|
||||
Version: "1.27.4",
|
||||
Ref: "pkg:k8s/k8s.io%2Fkubelet@1.27.4",
|
||||
},
|
||||
{
|
||||
Name: "k8s.io/kubernetes",
|
||||
Version: "1.27.4",
|
||||
Ref: "pkg:k8s/k8s.io%2Fkubernetes@1.27.4",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with infinity loop",
|
||||
inputFile: "testdata/happy/infinite-loop-bom.json",
|
||||
|
||||
@@ -177,10 +177,10 @@ func (s *SPDX) parsePackages(pkgs map[common.ElementID]*spdx.Package) error {
|
||||
} else if err != nil {
|
||||
return xerrors.Errorf("failed to parse package: %w", err)
|
||||
}
|
||||
switch pkgURL.Type {
|
||||
case packageurl.TypeApk, packageurl.TypeDebian, packageurl.TypeRPM:
|
||||
switch pkgURL.Class() {
|
||||
case types.ClassOSPkg:
|
||||
osPkgs = append(osPkgs, *pkg)
|
||||
default:
|
||||
case types.ClassLangPkg:
|
||||
// Language-specific packages
|
||||
pkgType := pkgURL.LangType()
|
||||
app, ok := apps[pkgType]
|
||||
|
||||
@@ -13,11 +13,12 @@ import (
|
||||
|
||||
var (
|
||||
PkgTargets = map[ftypes.LangType]string{
|
||||
ftypes.PythonPkg: "Python",
|
||||
ftypes.CondaPkg: "Conda",
|
||||
ftypes.GemSpec: "Ruby",
|
||||
ftypes.NodePkg: "Node.js",
|
||||
ftypes.Jar: "Java",
|
||||
ftypes.PythonPkg: "Python",
|
||||
ftypes.CondaPkg: "Conda",
|
||||
ftypes.GemSpec: "Ruby",
|
||||
ftypes.NodePkg: "Node.js",
|
||||
ftypes.Jar: "Java",
|
||||
ftypes.K8sUpstream: "Kubernetes",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ type Compliance = string
|
||||
type Format string
|
||||
|
||||
const (
|
||||
ClassUnknown ResultClass = "unknown"
|
||||
ClassOSPkg ResultClass = "os-pkgs" // For detected packages and vulnerabilities in OS packages
|
||||
ClassLangPkg ResultClass = "lang-pkgs" // For detected packages and vulnerabilities in language-specific packages
|
||||
ClassConfig ResultClass = "config" // For detected misconfigurations
|
||||
|
||||
Reference in New Issue
Block a user