Compare commits

...

13 Commits

Author SHA1 Message Date
Matthias Bertschy
3cf45cffd8 Merge pull request #1716 from kubescape/fixfix
fix generated ValidatingAdmissionPolicyBinding
2024-07-15 16:35:27 +02:00
Matthias Bertschy
ac0d982531 fix generated ValidatingAdmissionPolicyBinding
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2024-07-15 16:05:27 +02:00
Matthias Bertschy
99e22efe7b Merge pull request #1450 from kubescape/update-docs
update docs
2024-07-15 13:03:33 +02:00
Oshrat Nir
aedeb8f9cb Update README.md
update time and relative timezone

Signed-off-by: Oshrat Nir <45561829+Oshratn@users.noreply.github.com>
2024-07-15 13:50:20 +03:00
Oshrat Nir
824e76200e Update README.md
Co-authored-by: Matthias Bertschy <matthias.bertschy@gmail.com>
Signed-off-by: Oshrat Nir <45561829+Oshratn@users.noreply.github.com>
2024-07-15 13:44:52 +03:00
Oshrat Nir
8342f96a62 Merge branch 'master' into update-docs
Signed-off-by: Oshrat Nir <45561829+Oshratn@users.noreply.github.com>
2024-07-15 13:41:25 +03:00
Oshrat Nir
b824d52345 Update README.md
Updated with runtime security, bi-weekly meetings and messaging in general.

Signed-off-by: Oshrat Nir <45561829+Oshratn@users.noreply.github.com>
2024-07-15 13:33:16 +03:00
Matthias Bertschy
11b6567db4 Merge pull request #1713 from kubescape/fixfix
use proper params in pager call
2024-07-10 12:41:04 +02:00
Matthias Bertschy
c7d3105ca5 use proper params in pager call
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2024-07-10 11:58:06 +02:00
Matthias Bertschy
f1c15cd2b5 Merge pull request #1710 from ttimonen/ttimonen/handler
Simplify the concurrency in http handler for scan.
2024-07-08 22:27:34 +02:00
ttimonen
7507f58306 refactor(handler) Simplify the scan http handler concurrency.
In particular,
Replace scanResponseChan struct with a reply channel in req.
This removes one chokepoint with tracking a map of channel with a mutex wrapping by not sharing data across different requests and
 makes it easier to reason about the correctness of the behavior.

Other changes are mostly cosmetic to group your operations related to
the primitives you are operating on, reducing the average lifetime of
a local variable (matters mostly for humans; compilers are very good at this nowadays).

Also this is net benefical by reducing LOCs by 45.

Signed-off-by: ttimonen <toni.timonen@iki.fi>
2024-07-07 22:44:35 +00:00
ttimonen
48ad56a2ef Implement unit-test for scan handler.
It plays wtih channels and goroutines, so having it
behave correctly is not completely trivial and test
worthy.

Signed-off-by: ttimonen <toni.timonen@iki.fi>
2024-07-07 22:40:58 +00:00
David Wertenteil
a423b41e68 update docs
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-10-23 09:49:57 +03:00
9 changed files with 381 additions and 255 deletions

View File

@@ -20,13 +20,23 @@
<img alt="Kubescape logo" align="right" src="https://raw.githubusercontent.com/cncf/artwork/master/projects/kubescape/stacked/color/kubescape-stacked-color.svg" width="150">
</picture>
_An open-source Kubernetes security platform for your clusters, CI/CD pipelines, and IDE that seperates out the security signal from the scanner noise_
_Comprehensive Kubernetes Security from Development to Runtime_
Kubescape is an open-source Kubernetes security platform, built for use in your day-to-day workflow, by fitting into your clusters, CI/CD pipelines and IDE. It serves as a one-stop-shop for Kuberenetes security and includes vulnerability and misconfiguration scanning. You can run scans via the CLI, or add the Kubescape Helm chart, which gives an in-depth view of what is going on in the cluster.
Kubescape is an open-source Kubernetes security platform that provides comprehensive security coverage from left to right across the entire development and deployment lifecycle. It offers hardening, posture management, and runtime security capabilities to ensure robust protection for Kubernetes environments.
Kubescape includes misconfiguration and vulnerability scanning as well as risk analysis and security compliance indicators. All results are presented in context and users get many cues on what to do based on scan results.Targeted at the DevSecOps practitioner or platform engineer, it offers an easy-to-use CLI interface, flexible output formats, and automated scanning capabilities. It saves Kubernetes users and admins precious time, effort, and resources.
**Key features of Kubescape include**
Kubescape scans clusters, YAML files, and Helm charts. It detects misconfigurations according to multiple frameworks (including [NSA-CISA](https://www.armosec.io/blog/kubernetes-hardening-guidance-summary-by-armo/?utm_source=github&utm_medium=repository), [MITRE ATT&CK®](https://www.microsoft.com/security/blog/2021/03/23/secure-containerized-environments-with-updated-threat-matrix-for-kubernetes/) and the [CIS Benchmark](https://www.armosec.io/blog/cis-kubernetes-benchmark-framework-scanning-tools-comparison/?utm_source=github&utm_medium=repository)).
**Shift-left security**: Kubescape enables developers to scan for misconfigurations as early as the manifest file submission stage, promoting a proactive approach to security.
**IDE and CI/CD integration**: The tool integrates seamlessly with popular IDEs like VSCode and Lens, as well as CI/CD platforms such as GitHub and GitLab, allowing for security checks throughout the development process.
**Cluster scanning**: Kubescape can scan active Kubernetes clusters for vulnerabilities, misconfigurations, and security issues
**Multiple framework support**: Kubescape can test against various security frameworks, including NSA, MITRE, SOC2, and more.
**YAML and Helm chart validation**: The tool checks YAML files and Helm charts for correct configuration according to the frameworks above, without requiring an active cluster.
**Kubernetes hardening**: Kubescape ensures proactive identification and rapid remediation of misconfigurations and vulnerabilities through manual, recurring, or event-triggered scans.
**Runtime security**: Kubescape extends its protection to the runtime environment, providing continuous monitoring and threat detection for deployed applications.
**Compliance management**: The tool aids in maintaining compliance with recognized frameworks and standards, simplifying the process of meeting regulatory requirements.
**Multi-cloud support**: Kubescape offers frictionless security across various cloud providers and Kubernetes distributions.
By providing this comprehensive security coverage from development to production, Kubescape enables organizations to implement a robust security posture throughout their Kubernetes deployment, addressing potential vulnerabilities and threats at every stage of the application lifecycle.
Kubescape was created by [ARMO](https://www.armosec.io/?utm_source=github&utm_medium=repository) and is a [Cloud Native Computing Foundation (CNCF) sandbox project](https://www.cncf.io/sandbox-projects/).
@@ -68,10 +78,12 @@ Kubescape can be used as a GitHub Action. This is a great way to integrate Kubes
## Under the hood
Kubescape uses [Open Policy Agent](https://github.com/open-policy-agent/opa) to verify Kubernetes objects against [a library of posture controls](https://github.com/kubescape/regolibrary).
For image scanning, it uses [Grype](https://github.com/anchore/grype).
For image patching, it uses [Copacetic](https://github.com/project-copacetic/copacetic).
By default, the results are printed in a console-friendly manner, but they can be:
* exported to JSON or junit XML
* exported to JSON, junit XML or SARIF
* rendered to HTML or PDF
* submitted to a [cloud service](docs/providers.md)
@@ -79,9 +91,10 @@ It retrieves Kubernetes objects from the API server and runs a set of [Rego snip
## Community
Kubescape is an open source project, we welcome your feedback and ideas for improvement. We are part of the Kubernetes community and are building more tests and controls as the ecosystem develops.
Kubescape is an open source project, we welcome your feedback and ideas for improvement. We are part of the cloud-native community and are enhancing the project as the ecosystem develops.
We hold [community meetings](https://zoom.us/j/95174063585) on Zoom, every second week on Tuesdays, at 15:00 CET. ([See that in your local time zone](https://time.is/compare/1500_in_CET)).
We hold [community meetings](https://zoom.us/j/95174063585) on Zoom, every other week, at 15:00 CET. ([See that in your local time zone](https://time.is/compare/1500_in_CET).
The Kubescape project follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
@@ -109,7 +122,7 @@ Kubescape changes are tracked on the [release](https://github.com/kubescape/kube
## License
Copyright 2021-2023, the Kubescape Authors. All rights reserved. Kubescape is released under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details.
Copyright 2021-2024, the Kubescape Authors. All rights reserved. Kubescape is released under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details.
Kubescape is a [Cloud Native Computing Foundation (CNCF) sandbox project](https://www.cncf.io/sandbox-projects/) and was contributed by [ARMO](https://www.armosec.io/?utm_source=github&utm_medium=repository).

View File

@@ -203,7 +203,7 @@ func createPolicyBinding(bindingName string, policyName string, action string, p
policyBinding.Spec.MatchResources.NamespaceSelector = &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "name",
Key: "kubernetes.io/metadata.name",
Operator: metav1.LabelSelectorOpIn,
Values: namespaceArr,
},

View File

@@ -378,8 +378,8 @@ func (k8sHandler *K8sResourceHandler) pullSingleResource(resource *schema.GroupV
// list resources
if err := pager.New(func(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error) {
return clientResource.List(context.Background(), opts)
}).EachListItem(context.TODO(), listOptions, func(obj runtime.Object) error {
return clientResource.List(ctx, opts)
}).EachListItem(context.Background(), listOptions, func(obj runtime.Object) error {
uObject := obj.(*unstructured.Unstructured)
if k8sinterface.IsTypeWorkload(uObject.Object) && k8sinterface.WorkloadHasParent(workloadinterface.NewWorkloadObj(uObject.Object)) {
logger.L().Debug("Skipping resource with parent", helpers.String("kind", uObject.GetKind()), helpers.String("name", uObject.GetName()))

View File

@@ -6,7 +6,7 @@ The best way to get started with Kubescape is to download it to the machine you
## Install Kubescape
```sh
```bash
curl -s https://raw.githubusercontent.com/kubescape/kubescape/master/install.sh | /bin/bash
```
@@ -16,175 +16,255 @@ You can also check [other installation methods](installation.md)
## Run your first scan
```sh
kubescape scan --verbose
```bash
kubescape scan
```
You will see output like this:
<img src="img/summary.png">
```bash
Kubescape security posture overview for cluster: minikube
## Usage
In this overview, Kubescape shows you a summary of your cluster security posture, including the number of users who can perform administrative actions. For each result greater than 0, you should evaluate its need, and then define an exception to allow it. This baseline can be used to detect drift in future.
_Some documentation on using Kubescape is yet to move here from the [ARMO Platform docs](https://hub.armosec.io/docs?utm_source=github&utm_medium=repository)_.
Control plane
┌────┬─────────────────────────────────────┬────────────────────────────────────┐
│ │ Control Name │ Docs │
├────┼─────────────────────────────────────┼────────────────────────────────────┤
│ ✅ │ API server insecure port is enabled │ https://hub.armosec.io/docs/c-0005 │
│ ❌ │ Anonymous access enabled │ https://hub.armosec.io/docs/c-0262 │
│ ❌ │ Audit logs enabled │ https://hub.armosec.io/docs/c-0067 │
│ ✅ │ RBAC enabled │ https://hub.armosec.io/docs/c-0088 │
│ ❌ │ Secret/etcd encryption enabled │ https://hub.armosec.io/docs/c-0066 │
└────┴─────────────────────────────────────┴────────────────────────────────────┘
Access control
┌─────────────────────────────────────────────────┬───────────┬────────────────────────────────────┐
│ Control Name │ Resources │ View Details │
├─────────────────────────────────────────────────┼───────────┼────────────────────────────────────┤
│ Cluster-admin binding │ 1 │ $ kubescape scan control C-0035 -v │
│ Data Destruction │ 6 │ $ kubescape scan control C-0007 -v │
│ Exec into container │ 1 │ $ kubescape scan control C-0002 -v │
│ List Kubernetes secrets │ 6 │ $ kubescape scan control C-0015 -v │
│ Minimize access to create pods │ 2 │ $ kubescape scan control C-0188 -v │
│ Minimize wildcard use in Roles and ClusterRoles │ 1 │ $ kubescape scan control C-0187 -v │
│ Portforwarding privileges │ 1 │ $ kubescape scan control C-0063 -v │
│ Validate admission controller (mutating)0 │ $ kubescape scan control C-0039 -v │
│ Validate admission controller (validating)0 │ $ kubescape scan control C-0036 -v │
└─────────────────────────────────────────────────┴───────────┴────────────────────────────────────┘
Secrets
┌─────────────────────────────────────────────────┬───────────┬────────────────────────────────────┐
│ Control Name │ Resources │ View Details │
├─────────────────────────────────────────────────┼───────────┼────────────────────────────────────┤
│ Applications credentials in configuration files │ 1 │ $ kubescape scan control C-0012 -v │
└─────────────────────────────────────────────────┴───────────┴────────────────────────────────────┘
Network
┌────────────────────────┬───────────┬────────────────────────────────────┐
│ Control Name │ Resources │ View Details │
├────────────────────────┼───────────┼────────────────────────────────────┤
│ Missing network policy │ 13 │ $ kubescape scan control C-0260 -v │
└────────────────────────┴───────────┴────────────────────────────────────┘
Workload
┌─────────────────────────┬───────────┬────────────────────────────────────┐
│ Control Name │ Resources │ View Details │
├─────────────────────────┼───────────┼────────────────────────────────────┤
│ Host PID/IPC privileges │ 2 │ $ kubescape scan control C-0038 -v │
│ HostNetwork access │ 1 │ $ kubescape scan control C-0041 -v │
│ HostPath mount │ 1 │ $ kubescape scan control C-0048 -v │
│ Non-root containers │ 6 │ $ kubescape scan control C-0013 -v │
│ Privileged container │ 1 │ $ kubescape scan control C-0057 -v │
└─────────────────────────┴───────────┴────────────────────────────────────┘
Highest-stake workloads
────────────────────────
High-stakes workloads are defined as those which Kubescape estimates would have the highest impact if they were to be exploited.
1. namespace: gadget, name: gadget, kind: DaemonSet
'$ kubescape scan workload DaemonSet/gadget --namespace gadget'
2. namespace: kafka, name: my-cluster-kafka-0, kind: Pod
'$ kubescape scan workload Pod/my-cluster-kafka-0 --namespace kafka'
3. namespace: kafka, name: my-cluster-zookeeper-0, kind: Pod
'$ kubescape scan workload Pod/my-cluster-zookeeper-0 --namespace kafka'
Compliance Score
────────────────
The compliance score is calculated by multiplying control failures by the number of failures against supported compliance frameworks. Remediate controls, or configure your cluster baseline with exceptions, to improve this score.
* MITRE: 77.39%
* NSA: 69.97%
View a full compliance report by running '$ kubescape scan framework nsa' or '$ kubescape scan framework mitre'
What now?
─────────
* Run one of the suggested commands to learn more about a failed control failure
* Scan a workload with '$ kubescape scan workload' to see vulnerability information
* Install Kubescape in your cluster for continuous monitoring and a full vulnerability report: https://github.com/kubescape/helm-charts/tree/main/charts/kubescape-operator
```
# Usage
Capabilities
* Scan Kubernetes clusters for misconfigurations
* Scan Kubernetes YAML files/Helm charts for misconfigurations
* Scan container images for vulnerabilities
## Misconfigurations Scanning
Scan Kubernetes clusters, YAML files, Helm charts for misconfigurations.
Kubescape will highlight the misconfigurations and provide remediation steps.
The misconfigurations are based on multiple frameworks (including [NSA-CISA](https://www.armosec.io/blog/kubernetes-hardening-guidance-summary-by-armo/?utm_source=github&utm_medium=repository), [MITRE ATT&CK®](https://www.microsoft.com/security/blog/2021/03/23/secure-containerized-environments-with-updated-threat-matrix-for-kubernetes/) and the [CIS Benchmark](https://www.armosec.io/blog/cis-kubernetes-benchmark-framework-scanning-tools-comparison/?utm_source=github&utm_medium=repository)).
### Examples
* Scan a running Kubernetes cluster:
#### Scan a running Kubernetes cluster:
```sh
kubescape scan --verbose
```bash
kubescape scan
```
> **Note**
> [Read more about host scanning](https://hub.armosec.io/docs/host-sensor?utm_source=github&utm_medium=repository).
#### Scan NSA framework
Scan a running Kubernetes cluster with the [NSA framework](https://www.nsa.gov/Press-Room/News-Highlights/Article/Article/2716980/nsa-cisa-release-kubernetes-hardening-guidance/):
```bash
kubescape scan framework nsa
```
#### Scan MITRE framework
Scan a running Kubernetes cluster with the [MITRE ATT&CK® framework](https://www.microsoft.com/security/blog/2021/03/23/secure-containerized-environments-with-updated-threat-matrix-for-kubernetes/):
```bash
kubescape scan framework mitre
```
#### Scan a control
Scan for a specific control, using the control name or control ID. [See the list of controls](https://hub.armosec.io/docs/controls?utm_source=github&utm_medium=repository).
```bash
kubescape scan control c-0005 -v
```
#### Use an alternative kubeconfig file
```bash
kubescape scan --kubeconfig cluster.conf
```
#### Scan specific namespaces
```bash
kubescape scan --include-namespaces development,staging,production
```
#### Exclude certain namespaces
```bash
kubescape scan --exclude-namespaces kube-system,kube-public
```
#### Scan local YAML files
```sh
kubescape scan /path/to/directory-or-directory
```
Take a look at the [example](https://youtu.be/Ox6DaR7_4ZI).
#### Scan git repository
Scan Kubernetes manifest files from a Git repository:
```bash
kubescape scan https://github.com/kubescape/kubescape
```
#### Scan with exceptions
```bash
kubescape scan --exceptions examples/exceptions/exclude-kube-namespaces.json
```
Objects with exceptions will be presented as `exclude` and not `fail`.
[See more examples about exceptions.](/examples/exceptions/README.md)
#### Scan Helm charts
```bash
kubescape scan </path/to/directory>
```
> **Note**
> Kubescape will load the default VALUES file.
#### Scan a Kustomize directory
```bash
kubescape scan </path/to/directory>
```
> **Note**
> Kubescape will generate Kubernetes YAML objects using a `kustomize` file and scan them for security.
#### Trigger in cluster components for scanning your cluster
If the [kubescape-operator](https://github.com/kubescape/helm-charts/tree/main/charts/kubescape-operator#readme) is installed in your cluster, you can trigger scanning of the in cluster components from the kubescape CLI.
Trigger configuration scanning:
```bash
kubescape operator scan configurations
```
Trigger vulnerabilities scanning:
```bash
kubescape operator scan vulnerabilities
```
#### Compliance Score
We offer two important metrics to assess compliance:
- Control Compliance Score: This score measures the compliance of individual controls within a framework. It is calculated by evaluating the ratio of resources that passed to the total number of resources evaluated against that control.
```bash
kubescape scan --compliance-threshold <SCORE_VALUE[float32]>
```
> **Note**
> [Read more about host scanning](https://hub.armosec.io/docs/host-sensor?utm_source=github&utm_medium=repository).
* Scan a running Kubernetes cluster with the [NSA framework](https://www.nsa.gov/Press-Room/News-Highlights/Article/Article/2716980/nsa-cisa-release-kubernetes-hardening-guidance/):
```sh
kubescape scan framework nsa
- Framework Compliance Score: This score provides an overall assessment of your cluster's compliance with a specific framework. It is calculated by averaging the Control Compliance Scores of all controls within the framework.
```bash
kubescape scan framework <FRAMEWORK_NAME> --compliance-threshold <SCORE_VALUE[float32]>
```
* Scan a running Kubernetes cluster with the [MITRE ATT&CK® framework](https://www.microsoft.com/security/blog/2021/03/23/secure-containerized-environments-with-updated-threat-matrix-for-kubernetes/):
```sh
kubescape scan framework mitre
```
* Scan for a specific control, using the control name or control ID. [See the list of controls](https://hub.armosec.io/docs/controls?utm_source=github&utm_medium=repository).
```sh
kubescape scan control "Privileged container"
```
* Use an alternative kubeconfig file:
```sh
kubescape scan --kubeconfig cluster.conf
```
* Scan specific namespaces:
```sh
kubescape scan --include-namespaces development,staging,production
```
* Exclude certain namespaces:
```sh
kubescape scan --exclude-namespaces kube-system,kube-public
```
* Scan local YAML/JSON files before deploying:
```sh
kubescape scan *.yaml
```
[Take a look at the demonstration](https://youtu.be/Ox6DaR7_4ZI).
* Scan Kubernetes manifest files from a Git repository:
```sh
kubescape scan https://github.com/kubescape/kubescape
```
* Scan with exceptions
```sh
kubescape scan --exceptions examples/exceptions/exclude-kube-namespaces.json
```
Objects with exceptions will be presented as `exclude` and not `fail`.
[See more examples about exceptions.](/examples/exceptions/README.md)
* Scan Helm charts
```sh
kubescape scan </path/to/directory>
```
> **Note**
> Kubescape will load the default VALUES file.
* Scan a Kustomize directory
```sh
kubescape scan </path/to/directory>
```
> **Note**
> Kubescape will generate Kubernetes YAML objects using a `kustomize` file and scan them for security.
* Trigger in cluster components for scanning your cluster:
If kubescape helm chart is install in your cluster we can trigger scanning of the in cluster components from the kubescape CLI.
```sh
kubescape operator scan config
```
```sh
kubescape operator scan vulnerabilities
```
* Compliance Score
We offer two important metrics to assess compliance:
- Control Compliance Score: This score measures the compliance of individual controls within a framework. It is calculated by evaluating the ratio of resources that passed to the total number of resources evaluated against that control.
```sh
kubescape scan --compliance-threshold <SCORE_VALUE[float32]>
```
- Framework Compliance Score: This score provides an overall assessment of your cluster's compliance with a specific framework. It is calculated by averaging the Control Compliance Scores of all controls within the framework.
```sh
kubescape scan framework <FRAMEWORK_NAME> --compliance-threshold <SCORE_VALUE[float32]>
```
Kubescape scan with compliance score
<img src="img/ks-scan-with-compliance.gif">
### Output formats
* JSON:
#### JSON:
```sh
kubescape scan --format json --format-version v2 --output results.json
```
```bash
kubescape scan --format json --output results.json
```
> **Note**
> Add the `--format-version v2` flag for maximum compatibility.
#### junit XML:
* junit XML:
```bash
kubescape scan --format junit --output results.xml
```
#### SARIF:
```sh
kubescape scan --format junit --output results.xml
```
SARIF is a standard format for the output of static analysis tools. It is supported by many tools, including GitHub Code Scanning and Azure DevOps. [Read more about SARIF](https://docs.github.com/en/code-security/secure-coding/sarif-support-for-code-scanning/about-sarif-support-for-code-scanning).
* PDF:
```bash
kubescape scan --format sarif --output results.sarif
```
> **Note**
> SARIF format is supported only when scanning local files or git repositories, but not when scanning a running cluster.
```sh
kubescape scan --format pdf --output results.pdf
```
#### HTML
_Contributed by [@alegrey91](https://github.com/alegrey91)_
* Prometheus metrics:
```
kubescape scan --format prometheus
```
_Contributed by [@Joibel](https://github.com/Joibel)_
* HTML
```
kubescape scan --format html --output results.html
```
* Display all scanned resources (including the resources which passed):
```sh
kubescape scan --verbose
```
```bash
kubescape scan --format html --output results.html
```
## Offline/air-gapped environment support
@@ -194,7 +274,7 @@ It is possible to run Kubescape offline! Check out our [video tutorial](https:/
1. Download the controls and save them in the local directory. If no path is specified, they will be saved in `~/.kubescape`.
```sh
```bash
kubescape download artifacts --output path/to/local/dir
```
@@ -202,7 +282,7 @@ It is possible to run Kubescape offline! Check out our [video tutorial](https:/
3. Scan using the downloaded artifacts:
```sh
```bash
kubescape scan --use-artifacts-from path/to/local/dir
```
@@ -212,7 +292,7 @@ You can also download a single artifact, and scan with the `--use-from` flag:
1. Download and save in a file. If no file name is specified, the artifact will be saved as `~/.kubescape/<framework name>.json`.
```sh
```bash
kubescape download framework nsa --output /path/nsa.json
```
@@ -220,9 +300,32 @@ You can also download a single artifact, and scan with the `--use-from` flag:
3. Scan using the downloaded framework:
```sh
```bash
kubescape scan framework nsa --use-from /path/nsa.json
```
## Image scanning
Kubescape can scan container images for vulnerabilities. It uses [Grype]() to scan the images.
### Examples
#### Scan image
```bash
kubescape scan image nginx:1.19.6
```
#### Scan image from a private registry
```bash
kubescape scan image --username myuser --password mypassword myregistry/nginx:1.19.6
```
#### Scan image and see full report
```bash
kubescape scan image nginx:1.19.6 -v
```
## Other ways to use Kubescape

View File

@@ -13,6 +13,7 @@ import (
"github.com/kubescape/kubescape/v3/core/cautils/getter"
apisv1 "github.com/kubescape/opa-utils/httpserver/apis/v1"
utilsapisv1 "github.com/kubescape/opa-utils/httpserver/apis/v1"
utilsmetav1 "github.com/kubescape/opa-utils/httpserver/meta/v1"
"go.opentelemetry.io/otel/trace"
"github.com/google/uuid"
@@ -35,18 +36,16 @@ func (handler *HTTPHandler) Metrics(w http.ResponseWriter, r *http.Request) {
},
scanInfo: scanInfo,
scanID: scanID,
ctx: trace.ContextWithSpanContext(context.Background(), trace.SpanContextFromContext(r.Context())),
resp: make(chan *utilsmetav1.Response, 1),
}
scanParams.ctx = trace.ContextWithSpanContext(context.Background(), trace.SpanContextFromContext(r.Context()))
handler.scanResponseChan.set(scanID) // add scan to channel
defer handler.scanResponseChan.delete(scanID)
// send to scan queue
logger.L().Info("requesting scan", helpers.String("scanID", scanID), helpers.String("api", "v1/metrics"))
handler.scanRequestChan <- scanParams
// wait for scan to complete
results := <-handler.scanResponseChan.get(scanID)
results := <-scanParams.resp
defer removeResultsFile(scanID) // remove json format results file
defer os.Remove(resultsFile) // remove prometheus format results file

View File

@@ -6,7 +6,6 @@ import (
"fmt"
"io"
"net/http"
"sync"
"github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
@@ -16,47 +15,6 @@ import (
"github.com/gorilla/schema"
)
type scanResponseChan struct {
scanResponseChan map[string]chan *utilsmetav1.Response
mtx sync.RWMutex
}
// get response object chan
func (resChan *scanResponseChan) get(key string) chan *utilsmetav1.Response {
resChan.mtx.RLock()
defer resChan.mtx.RUnlock()
return resChan.scanResponseChan[key]
}
// set chan for response object
func (resChan *scanResponseChan) set(key string) {
resChan.mtx.Lock()
defer resChan.mtx.Unlock()
resChan.scanResponseChan[key] = make(chan *utilsmetav1.Response)
}
// push response object to chan
func (resChan *scanResponseChan) push(key string, resp *utilsmetav1.Response) {
resChan.mtx.Lock()
defer resChan.mtx.Unlock()
if _, ok := resChan.scanResponseChan[key]; ok {
resChan.scanResponseChan[key] <- resp
}
}
// delete channel
func (resChan *scanResponseChan) delete(key string) {
resChan.mtx.Lock()
defer resChan.mtx.Unlock()
delete(resChan.scanResponseChan, key)
}
func newScanResponseChan() *scanResponseChan {
return &scanResponseChan{
scanResponseChan: make(map[string]chan *utilsmetav1.Response),
mtx: sync.RWMutex{},
}
}
type ScanQueryParams struct {
// Wait for scanning to complete (synchronous request)
// default: false
@@ -106,6 +64,7 @@ type scanRequestParams struct {
scanQueryParams *ScanQueryParams // request as received from api
scanID string // generated scan ID
ctx context.Context
resp chan *utilsmetav1.Response // Respose chan; nil if not interested.
}
// swagger:parameters triggerScan
@@ -119,31 +78,30 @@ type ScanRequest struct {
func getScanParamsFromRequest(r *http.Request, scanID string) (*scanRequestParams, error) {
defer r.Body.Close()
scanRequestParams := &scanRequestParams{}
scanQueryParams := &ScanQueryParams{}
if err := schema.NewDecoder().Decode(scanQueryParams, r.URL.Query()); err != nil {
return scanRequestParams, fmt.Errorf("failed to parse query params, reason: %s", err.Error())
}
readBuffer, err := io.ReadAll(r.Body)
if err != nil {
// handler.writeError(w, fmt.Errorf("failed to read request body, reason: %s", err.Error()), scanID)
return scanRequestParams, fmt.Errorf("failed to read request body, reason: %s", err.Error())
}
logger.L().Info("REST API received scan request", helpers.String("body", string(readBuffer)))
scanRequest := &utilsmetav1.PostScanRequest{}
if err := json.Unmarshal(readBuffer, &scanRequest); err != nil {
return scanRequestParams, fmt.Errorf("failed to parse request payload, reason: %s", err.Error())
{
readBuffer, err := io.ReadAll(r.Body)
if err != nil {
// handler.writeError(w, fmt.Errorf("failed to read request body, reason: %s", err.Error()), scanID)
return nil, fmt.Errorf("failed to read request body, reason: %s", err.Error())
}
logger.L().Info("REST API received scan request", helpers.String("body", string(readBuffer)))
if err := json.Unmarshal(readBuffer, &scanRequest); err != nil {
return nil, fmt.Errorf("failed to parse request payload, reason: %s", err.Error())
}
}
scanInfo := getScanCommand(scanRequest, scanID)
p := &scanRequestParams{
scanID: scanID,
scanQueryParams: &ScanQueryParams{},
scanInfo: getScanCommand(scanRequest, scanID),
}
if err := schema.NewDecoder().Decode(p.scanQueryParams, r.URL.Query()); err != nil {
return p, fmt.Errorf("failed to parse query params, reason: %s", err.Error())
}
if p.scanQueryParams.ReturnResults {
p.resp = make(chan *utilsmetav1.Response, 1)
}
scanRequestParams.scanID = scanID
scanRequestParams.scanQueryParams = scanQueryParams
scanRequestParams.scanInfo = scanInfo
return scanRequestParams, nil
return p, nil
}

View File

@@ -30,19 +30,16 @@ type ScanResponse struct {
}
type HTTPHandler struct {
state *serverState
scanResponseChan *scanResponseChan
scanRequestChan chan *scanRequestParams
state *serverState
scanRequestChan chan *scanRequestParams
}
func NewHTTPHandler() *HTTPHandler {
handler := &HTTPHandler{
state: newServerState(),
scanRequestChan: make(chan *scanRequestParams),
scanResponseChan: newScanResponseChan(),
state: newServerState(),
scanRequestChan: make(chan *scanRequestParams),
}
go handler.watchForScan()
return handler
}
@@ -90,7 +87,6 @@ func (handler *HTTPHandler) Status(w http.ResponseWriter, r *http.Request) {
// ============================================== SCAN ========================================================
// Scan API
func (handler *HTTPHandler) Scan(w http.ResponseWriter, r *http.Request) {
// generate id
scanID := uuid.NewString()
@@ -101,7 +97,6 @@ func (handler *HTTPHandler) Scan(w http.ResponseWriter, r *http.Request) {
return
}
w.Header().Set("Content-Type", "application/json")
scanRequestParams, err := getScanParamsFromRequest(r, scanID)
if err != nil {
handler.writeError(w, err, "")
@@ -111,14 +106,6 @@ func (handler *HTTPHandler) Scan(w http.ResponseWriter, r *http.Request) {
handler.state.setBusy(scanID)
response := &utilsmetav1.Response{}
response.ID = scanID
response.Type = utilsapisv1.BusyScanResponseType
response.Response = fmt.Sprintf("scanning '%s' is in progress", scanID)
handler.scanResponseChan.set(scanID) // add channel
defer handler.scanResponseChan.delete(scanID)
// you must use a goroutine since the executeScan function is not always listening to the channel
go func() {
// send to scanning handler
@@ -126,9 +113,14 @@ func (handler *HTTPHandler) Scan(w http.ResponseWriter, r *http.Request) {
handler.scanRequestChan <- scanRequestParams
}()
if scanRequestParams.scanQueryParams.ReturnResults {
response := &utilsmetav1.Response{
ID: scanID,
Type: utilsapisv1.BusyScanResponseType,
Response: fmt.Sprintf("scanning '%s' is in progress", scanID),
}
if scanRequestParams.resp != nil {
// wait for scan to complete
response = <-handler.scanResponseChan.get(scanID)
response = <-scanRequestParams.resp
if scanRequestParams.scanQueryParams.KeepResults {
// delete results after returning

View File

@@ -1,5 +1,61 @@
package v1
import (
"bytes"
"context"
"encoding/json"
"io"
"net/http/httptest"
"testing"
"github.com/kubescape/kubescape/v3/core/cautils"
utilsmetav1 "github.com/kubescape/opa-utils/httpserver/meta/v1"
reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2"
)
func testBody(t *testing.T) io.Reader {
t.Helper()
b, err := json.Marshal(utilsmetav1.PostScanRequest{Account: "fakeFoobar"})
if err != nil {
t.Fatal("Can not marshal")
}
return bytes.NewReader(b)
}
type scanner func(_ context.Context, _ *cautils.ScanInfo, _ string) (*reporthandlingv2.PostureReport, error)
// TestScan tests that the scan handler passes the scan requests correctly to the underlying scan engine.
func TestScan(t *testing.T) {
// Our scanner is not setting up the k8s connection; the test is covering the rest of the wiring
// that the signaling from the http handler goes all the way to the scanner implementation.
defer func(o scanner) { scanImpl = o }(scanImpl)
scanImpl = func(context.Context, *cautils.ScanInfo, string) (*reporthandlingv2.PostureReport, error) {
return nil, nil
}
var (
h = NewHTTPHandler()
rq = httptest.NewRequest("POST", "/scan?wait=true", testBody(t))
w = httptest.NewRecorder()
)
h.Scan(w, rq)
rs := w.Result()
body, _ := io.ReadAll(rs.Body)
type out struct {
code int
ctype string
body string
}
want := out{200, "application/json", `{"id":"","type":"v1results"}`}
got := out{rs.StatusCode, rs.Header.Get("Content-type"), string(body)}
if got != want {
t.Errorf("Scan result: %v, want %v", got, want)
}
}
// ============================================== STATUS ========================================================
// Status API
// func TestStatus(t *testing.T) {

View File

@@ -25,11 +25,12 @@ import (
"go.opentelemetry.io/otel/trace"
)
var scanImpl = scan // Override for testing
func (handler *HTTPHandler) executeScan(scanReq *scanRequestParams) {
response := &utilsmetav1.Response{}
logger.L().Info("scan triggered", helpers.String("ID", scanReq.scanID))
_, err := scan(scanReq.ctx, scanReq.scanInfo, scanReq.scanID)
_, err := scanImpl(scanReq.ctx, scanReq.scanInfo, scanReq.scanID)
if err != nil {
logger.L().Ctx(scanReq.ctx).Error("scanning failed", helpers.String("ID", scanReq.scanID), helpers.Error(err))
if scanReq.scanQueryParams.ReturnResults {
@@ -39,14 +40,18 @@ func (handler *HTTPHandler) executeScan(scanReq *scanRequestParams) {
} else {
logger.L().Ctx(scanReq.ctx).Success("done scanning", helpers.String("ID", scanReq.scanID))
if scanReq.scanQueryParams.ReturnResults {
//TODO(ttimonen) should we actually pass the PostureReport here somehow?
response.Type = utilsapisv1.ResultsV1ScanResponseType
}
}
handler.state.setNotBusy(scanReq.scanID)
// return results
handler.scanResponseChan.push(scanReq.scanID, response)
// return results, if someone's waiting for them; never block.
select {
case scanReq.resp <- response:
default:
}
}
// executeScan execute the scan request passed in the channel