Skip to content

Security Posture Management with Kubescape ​

Last Updated: September 13, 2026 Validation baseline: CLI 4.0.14 and Operator chart 1.40.4. The chart's scanner image is 4.0.13, separate from the CLI. Policy hashes are recorded in the example directory.

Kubescape evaluates Kubernetes configuration and selected image/runtime data. Passing a scan is not a security guarantee or compliance certification; unavailable coverage must be identified separately. This guide was checked with local YAML, policy bundles, the actual CLI, and chart rendering. No live cluster scan, node-agent installation, registry image/DB scan, or SaaS submission was performed.

Overview ​

Kubescape joined CNCF on December 13, 2022 and became Incubating on January 13, 2025. The former Sandbox description and stale tool-maturity comparison table are not current guidance.

The CLI performs explicit file or cluster scans; the Operator provides continuous/scheduled behavior according to enabled capabilities. Configuration controls, RBAC analysis, image CVEs, and runtime detection have different scopes. Compare kube-bench's node/CIS checks, Polaris workload policies, and Trivy image/configuration scans against versioned requirements rather than broad superiority claims.

Kubescape inputs, controls, separate results and optional outputs

Kubescape inputs, controls, separate results and optional outputsOpen full screen ↗

Installation ​

CLI Installation ​

Download the matching OS/CPU asset from the official 4.0.14 release and verify its checksum. This Linux AMD64 example pins the reviewed archive hash; ARM64 needs a different archive/hash.

bash
curl --fail --location \
  https://github.com/kubescape/kubescape/releases/download/v4.0.14/kubescape_4.0.14_linux_amd64.tar.gz \
  --output kubescape.tgz
printf '%s  %s\n' '1d253b70f88e80b74f68af73ccd422f897381468300be7cc486fdd656d907a40' kubescape.tgz | sha256sum --check
tar -xzf kubescape.tgz kubescape
./kubescape version
./kubescape scan --help

Check the actual package version when using Homebrew/Krew or other installers. Limit installer execution and kubeconfig exposure to the intended scope. Omitting a file target from kubescape scan can scan the current cluster.

Helm Operator Installation ​

Download the example directory and run these commands from examples/security/kubescape. The profile focuses on posture checks and metrics, explicitly disabling node/image/runtime/remediation capabilities.

bash
helm repo add kubescape https://kubescape.github.io/helm-charts
helm repo update kubescape
helm upgrade --install kubescape kubescape/kubescape-operator \
  --version 1.40.4 --namespace kubescape --create-namespace \
  --values operator-values.yaml
yaml
clusterName: documentation-cluster
defaultFrameworks:
- nsa
- mitre
capabilities:
  continuousScan: enable
  configurationScan: enable
  nodeScan: disable
  nodeSbomGeneration: disable
  vulnerabilityScan: disable
  relevancy: disable
  runtimeObservability: disable
  networkPolicyService: disable
  networkEventsStreaming: disable
  runtimeDetection: disable
  nodeProfileService: disable
  admissionController: disable
  httpDetection: disable
  seccompProfileService: disable
  prometheusExporter: enable
  riskAcceptance: disable
  remediation: disable
  manageWorkloads: disable
global:
  enableClusterWideSecretAccess: false
persistence:
  storageClass: gp3
kubescapeScheduler:
  scanSchedule: 0 8 * * *

Prepare the gp3 StorageClass/CSI driver and verify namespaces, RBAC, CRDs, and aggregated API availability. EKS Auto Mode and ordinary EBS CSI StorageClasses can use different provisioners. Helm rendering does not establish installation, persistence, or scanning success.

credentials.cloudSecret is an existing Secret name, not an account ID. Configure and authorize the backend/account/accessKey/data scope explicitly when SaaS is needed. CLI --submit requests submission; local examples use --keep-local and an isolated cache. Enable node/runtime features separately after checking host privileges, kernels/BTF, and supported node types.

Security Frameworks ​

Frameworks and Controls ​

Framework names and control counts depend on the policy bundle. The reviewed download contained NSA, MITRE, SOC2, ArmoBest, DevOpsBest, AllControls, and versioned CIS frameworks. NSA contained 26 controls, not all applicable to a local Pod.

bash
kubescape list frameworks
kubescape list controls --framework NSA
kubescape list controls --framework NSA --search container

Example names in the reviewed bundle include cis-v1.12.0 and cis-eks-t1.8.0. Do not assume cis-v1.23 or cis is a universal alias. Policy updates change coverage/scores; record binary versions and policy hashes together.

Control IDReviewed bundle name
C-0004Resources memory limit and request
C-0009Resource limits
C-0013Non-root containers
C-0016Allow privilege escalation
C-0034Automatic mapping of service account
C-0035Administrative Roles
C-0036Validate admission controller (validating)
C-0039Validate admission controller (mutating)
C-0057Privileged container

C-0036/0039 are not wildcard-RBAC/risky-ServiceAccount controls. Severity also depends on the bundle: the reviewed C-0057 was High, not universally Critical.

Custom Frameworks ​

--use-from loads a local policy object. A YAML name and unresolved list of control IDs is not necessarily an executable framework. The example policies/nsa.json is the tested bundle with license, provenance, and SHA records. Author/test new Rego controls with current CLI features such as kubescape policy init and kubescape policy test, then review organizational requirements.

CLI Scanning ​

Kubescape input, evaluation, score fields and report formats

Kubescape input, evaluation, score fields and report formatsOpen full screen ↗

Cluster versus Local Input ​

bash
# This accesses the current cluster; check authorization and scope first.
kubescape scan framework nsa --include-namespaces production
# Explicit local-file scan:
kubescape scan framework nsa secure-pod.yaml \
  --use-from policies/nsa.json --controls-config policies/controls-inputs.json \
  --exceptions no-exceptions.json --keep-local \
  --format json --output report.json

--format/-f selects the format; --output/-o names the file. -o json > report.json does not select JSON output. Version 4.0.14 supports JSON/SARIF/HTML/PDF/JUnit/gitlab-sast and other formats; choose the one the receiving tool expects.

Render Helm/Kustomize locally before scanning to make effective values explicit. Local checks do not reproduce API defaulting, admission, IAM authorization, or network behavior. --include-api-audit, --custom-framework, and --sort-by were unknown in the reviewed CLI. Do not present scan rbac as a separate current subcommand.

Actual Local Results ​

insecure-pod.yaml is a synthetic scan fixture, not a deployment recipe. It uses real privileged/runAsUser fields rather than nonexistent runAsRoot. secure-pod.yaml also demonstrates configuration only; replace its application image before any real deployment.

Local inputCompliancescoreResult
Insecure Pod5562.5High failures
Secure Pod956.818182High gate passes; not every control passes

These values apply to the attached policy snapshot and one local Pod. They do not measure cluster security or exploitability.

Image and RBAC Analysis ​

Request image scanning explicitly with kubescape scan image IMAGE. CLI 4.0.14 uses Grype 0.104.1 and Syft 1.42.3 in its source dependencies; the Operator kubevuln component is separately versioned. Verify registry credentials, platform, database freshness, and scan errors. Host scanning differs from image scanning and can require additional host access/resource creation.

RBAC controls evaluate collected Roles/Bindings within authorized API scope. A RoleBinding grants access within its namespace, not every namespace. Static analysis does not by itself establish unused permissions, external IAM authorization, or every effective access path.

Operator Mode (In-Cluster) ​

Kubescape operator coordination and aggregated storage API

Kubescape operator coordination and aggregated storage APIOpen full screen ↗

Use the chart's kubescapeScheduler.scanSchedule and requestBody.commands[].args.scanV1 fields. defaultFrameworks supplies defaults for requests without targets; explicit targetNames wins. An arbitrary ConfigMap with scanSchedule does not establish that a controller consumes it.

spdx.softwarecomposition.kubescape.io/v1beta1 results are served by the storage component's aggregated API, not all ordinary CRDs. Separate CRDs include SecurityException, ClusterSecurityException, and OperatorCommand. Discover actual names/scopes before querying results.

bash
kubectl get apiservices v1beta1.spdx.softwarecomposition.kubescape.io
kubectl api-resources --api-group=spdx.softwarecomposition.kubescape.io
kubectl get pods,pvc -n kubescape

Do not present the old ScanSchedule, VulnerabilityScanConfig, ThreatDetectionConfig, AcceptedRisk, and ScanConfiguration examples as APIs installed by this chart. Node-agent profiles/detection must use actual APIs/capabilities for the chosen image. Enabled configuration is not proof of healthy collection or detection on all nodes.

Risk Scoring ​

summaryDetails.complianceScore and summaryDetails.score are different aggregates. Higher compliance indicates more checks passing; risk score is neither the same value nor simply 100-compliance. Do not present invented severity weights or response SLAs as a universal Kubescape formula.

bash
jq '{compliance: .summaryDetails.complianceScore, risk: .summaryDetails.score,
     failed: [.summaryDetails.controls[] | select(.status == "failed") | {controlID, name, severity}]}' report.json

Use --compliance-threshold as a minimum compliance score, and --severity-threshold for failed-control severity. A local score of 55 returned exit 0 at threshold 55 and exit 1 at 56. --min-severity filters output; it does not replace current gate calculations.

Version 4.0.14 accepts --fail-threshold as a deprecated compatibility flag but ignores its value. The test returned exit 0 with failed findings when only --fail-threshold 0 was supplied. Distinguish that inert flag from still-processed options such as --scan-images/--skip-controls and genuinely unknown flags.

CI/CD Integration ​

CI gates based on minimum compliance, severity and command exit

CI gates based on minimum compliance, severity and command exitOpen full screen ↗

Shared Security Gate ​

bash
#!/usr/bin/env bash
# Scan explicit local manifests with an isolated Kubernetes/client configuration.
set -euo pipefail
if [[ $# -ne 2 ]]; then
  printf 'Usage: %s LOCAL_MANIFEST OUTPUT_JSON\n' "$0" >&2
  exit 2
fi
manifest_path=$1
report_path=$2
if [[ ! -f $manifest_path ]]; then
  printf 'Expected an existing local manifest file: %s\n' "$manifest_path" >&2
  exit 2
fi
# An absolute operand cannot be parsed as a flag such as --help.
manifest_path="$(cd -- "$(dirname -- "$manifest_path")" && pwd)/$(basename -- "$manifest_path")"
script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
: "${KUBESCAPE_BIN:=kubescape}"
: "${COMPLIANCE_MINIMUM:=90}"
: "${SEVERITY_LIMIT:=high}"
umask 077
scan_temp_dir=$(mktemp -d "${TMPDIR:-/tmp}/kubescape-local.XXXXXX")
trap 'rm -rf -- "$scan_temp_dir"' EXIT
mkdir -- "$scan_temp_dir/cache"
cat > "$scan_temp_dir/kubeconfig" <<'YAML'
apiVersion: v1
kind: Config
clusters: []
contexts: []
users: []
current-context: ''
YAML
# Block inherited in-cluster discovery as well as kubeconfig and cached backend state.
env -u KUBERNETES_SERVICE_HOST -u KUBERNETES_SERVICE_PORT -u KUBERNETES_PORT -u KUBERNETES_MASTER \
  KUBECONFIG="$scan_temp_dir/kubeconfig" KS_CACHE_DIR="$scan_temp_dir/cache" \
  "$KUBESCAPE_BIN" --cache-dir "$scan_temp_dir/cache" scan framework nsa "$manifest_path" \
  --kubeconfig "$scan_temp_dir/kubeconfig" --host-scan=false \
  --use-from "$script_dir/policies/nsa.json" \
  --controls-config "$script_dir/policies/controls-inputs.json" \
  --exceptions "$script_dir/no-exceptions.json" \
  --honor-inline-exceptions=false \
  --keep-local \
  --compliance-threshold "$COMPLIANCE_MINIMUM" \
  --severity-threshold "$SEVERITY_LIMIT" \
  --format json --output "$report_path"

The CI gate ignores skip-control annotations, uses an empty kubeconfig and fresh cache, and clears inherited in-cluster discovery. --keep-local alone does not prevent Kubernetes API access. Five native tests with a hostile loopback API context produced zero requests and the expected failure/success codes.

Missing input, scan errors, and failed thresholds return nonzero. Do not hide them with continue-on-error or || true. Report upload can run after failure but does not determine success. Excluding a control changes the evaluated denominator and must be recorded.

GitHub Actions ​

The validated workflow pins the binary/checksum and scans only k8s/rendered.yaml using the local policy snapshot. The project must produce that file first; absence fails the job. Permissions are contents:read, with no PR comments or SaaS submission.

GitLab and Jenkins ​

Both systems can preserve the same scan-manifests.sh exit code and archive reports. Generic Kubescape JSON is not GitLab SAST or Code Quality schema. For integrated SAST reporting, validate current --format gitlab-sast output against the receiving version. Jenkins readJSON/publishHTML require plugins; do not publish an HTML file the pipeline never generated.

EKS-Specific Guide ​

Kubernetes manifest scans do not fully validate EKS control-plane configuration, IAM, access entries, Pod Identity/IRSA, or node policies. aws-auth is a legacy authentication path; inspect the current authentication mode and access entries. system:masters or an emergency IAM user is not a least-privilege example.

C-0034 checks service account token automounting, not complete IRSA trust/aud/sub/IAM policy. Distinguish the projected STS token from automatic Kubernetes API token mounting. Validate actual workload identity and allowed AWS operations separately.

Review host-scanning and remediation permissions/mutations before enabling them. The example disables cluster-wide Secret access and remediation, while operators must still inspect the scanner/operator/storage RBAC needed for their installation.

Control Exception Handling ​

CLI Exceptions ​

json
[
  {
    "name": "documentation-privileged-exception",
    "policyType": "postureExceptionPolicy",
    "actions": [
      "alertOnly"
    ],
    "resources": [
      {
        "designatorType": "Attributes",
        "attributes": {
          "namespace": "demo-app",
          "kind": "Pod",
          "name": "insecure-example"
        }
      }
    ],
    "posturePolicies": [
      {
        "controlID": "C-0057"
      }
    ]
  }
]

This is a JSON array consumed by the CLI, not a ConfigMap wrapper. The tested alertOnly exception marked C-0057 acknowledged while preserving failure and compliance 55. --exclude-controls C-0057 removed the control from evaluation, changing the denominator and score. An exception is not a remediation.

In-Cluster Exceptions ​

yaml
apiVersion: kubescape.io/v1beta1
kind: SecurityException
metadata:
  name: documentation-privileged-exception
  namespace: demo-app
spec:
  author: documentation-security-team
  reason: Synthetic scan example; replace with an approved owner and justification.
  expiresAt: '2026-09-30T00:00:00Z'
  match:
    resources:
      - apiGroup: ''
        kind: Pod
        name: insecure-example
  posture:
    - controlID: C-0057
      action: alert_only

The current APIs are kubescape.io/v1beta1 SecurityException/ClusterSecurityException. Set namespace scope, match, posture action, expiry, and ownership according to approved policy. Schema success does not establish controller enforcement, RBAC, or CEL behavior. CLI alertOnly differs from CRD alert_only. Do not rely on invented ignore annotations for exception processing.

Best Practices ​

Remediation verification and separately tracked risk acceptance

Remediation verification and separately tracked risk acceptanceOpen full screen ↗

Record scope, passed/failed/unavailable checks, policy hashes, tool images, exception owners, and expiry dates. Compare scores only across equivalent inputs/policies. Node scanning, image scanning, and runtime detection are separate sources of evidence.

Prometheus Integration ​

yaml
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: kubescape-posture
  namespace: monitoring
spec:
  namespaceSelector:
    matchNames: [kubescape]
  selector:
    matchLabels:
      app.kubernetes.io/name: kubescape-operator
      app.kubernetes.io/instance: kubescape
      app.kubernetes.io/component: prometheus-exporter
  podMetricsEndpoints:
    - port: metrics
      path: /metrics
      interval: 60s

The reviewed exporter Pod names container port 8080 metrics, while its Service port is unnamed. This example therefore uses a PodMonitor matching the actual Pod labels and named port. Prometheus Operator and Prometheus PodMonitor selection are separate prerequisites.

Actual exporter 0.2.23 gauge examples are kubescape_controls_total_cluster_high and kubescape_controls_total_workload_high. A _total suffix does not make them counters. The old kubescape_compliance_score/critical_findings/last_scan_timestamp names are not established common metrics. Monitor missing scrapes and stale data separately.

Summary and References ​

Local validation covered binary/checksum, policy snapshot, threshold boundaries/severity/deprecated gate, exception/exclusion behavior, the published shell gate, Helm rendering, SecurityException schema, PodMonitor targeting, GitHub Actions syntax, and thirty diagram browser cases. No real AWS/Kubernetes/registry/notification/SaaS operations were performed.