Skip to main content

Documentation Index

Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt

Use this file to discover all available pages before exploring further.

In this lesson, we’ll walk through scanning Kubernetes resource definitions using Kubesec. Kubesec helps you enforce cluster security best practices with a simple CLI, Docker image, or HTTP API.

Table of Contents

  1. Sample Pod Specification
  2. Scanning with Kubesec
    • CLI
    • Docker Image
    • HTTP API
  3. Bash Wrapper for HTTP API
  4. Jenkins Pipeline Integration
  5. Improving Your Security Score
  6. References

Sample Pod Specification

Here’s a minimal Pod manifest that enables a read-only root filesystem:
apiVersion: v1
kind: Pod
metadata:
  name: kubesec-demo
spec:
  containers:
    - name: kubesec-demo
      image: gcr.io/google-samples/node-hello:1.0
      securityContext:
        readOnlyRootFilesystem: true

Scanning with Kubesec

You can scan your YAML definitions in three ways:
MethodCommand Example
CLIkubesec scan pod.yaml
Docker imagedocker run --rm -i kubesec/kubesec:latest scan /dev/stdin < pod.yaml
HTTP APIcurl -sSX POST --data-binary @"pod.yaml" https://v2.kubesec.io/scan

1. CLI

Install the kubesec binary, then run:
$ kubesec scan pod.yaml
Sample JSON output:
[
  {
    "object": "Pod/kubesec-demo.default",
    "valid": true,
    "message": "Passed with a score of 1 points",
    "score": 1,
    "scoring": [
      {
        "id": "ReadOnlyRootFilesystem",
        "selector": "containers[].securityContext.readOnlyRootFilesystem == true",
        "reason": "Immutable root filesystems increase attack cost",
        "points": 1
      }
    ],
    "advice": [
      {
        "id": "ServiceAccountName",
        "selector": ".spec.serviceAccountName",
        "reason": "Use least-privilege service accounts",
        "points": 1
      },
      {
        "id": "AppArmorAny",
        "selector": "metadata.annotations.\"container.apparmor.security.beta.kubernetes.io/nginx\"",
        "reason": "Define AppArmor policies for stronger isolation",
        "points": 1
      },
      {
        "id": "SeccompAny",
        "selector": "metadata.annotations.\"container.seccomp.security.alpha.kubernetes.io/pod\"",
        "reason": "Apply Seccomp profiles to limit syscalls",
        "points": 1
      },
      {
        "id": "LimitsCPU",
        "selector": "containers[].resources.limits.cpu",
        "reason": "Prevent DoS by enforcing CPU limits",
        "points": 1
      },
      {
        "id": "LimitsMemory",
        "selector": "containers[].resources.limits.memory",
        "reason": "Prevent DoS by enforcing memory limits",
        "points": 1
      }
    ]
  }
]

Bash Wrapper for HTTP API

Create a shell function to simplify HTTP scans:
#!/usr/bin/env bash
kubesec_scan() {
  local FILE="${1:?Usage: kubesec_scan <file.yaml>}"
  [[ ! -f "$FILE" ]] && { echo "Error: $FILE not found"; return 1; }

  curl -sSX POST \
    --data-binary @"$FILE" \
    https://v2.kubesec.io/scan
}
Call it with:
$ kubesec_scan pod.yaml

Jenkins Pipeline Integration

Here’s a sample Jenkinsfile that builds a Docker image, pushes it, then runs parallel scans with Conftest and Kubesec:
pipeline {
  agent any

  stages {
    stage('Docker Build & Push') {
      steps {
        withDockerRegistry([credentialsId: 'docker-hub', url: '']) {
          sh 'docker build -t youruser/app:$GIT_COMMIT .'
          sh 'docker push youruser/app:$GIT_COMMIT'
        }
      }
    }

    stage('Vulnerability Scan') {
      steps {
        parallel(
          'OPA Scan': {
            sh '''
              docker run --rm -v $(pwd):/project \
                openpolicyagent/conftest test \
                --policy opa-k8s-security.rego \
                k8s_deployment_service.yaml
            '''
          },
          'Kubesec Scan': {
            sh 'bash kubesec-scan.sh'
          }
        )
      }
    }
  }
}

kubesec-scan.sh

#!/usr/bin/env bash
set -euo pipefail

scan_result=$(curl -sSX POST --data-binary @"k8s_deployment_service.yaml" https://v2.kubesec.io/scan)
scan_score=$(jq -r '.[0].score' <<<"$scan_result")
scan_message=$(jq -r '.[0].message' <<<"$scan_result")

echo "Scan Score: $scan_score"
if [[ "$scan_score" -ge 5 ]]; then
  echo "✅ Kubesec Scan Passed: $scan_message"
else
  echo "❌ Kubesec Scan Failed: $scan_message (score $scan_score < 5)"
  exit 1
fi
Adjust the threshold (5 points) to match your team’s security policy.

Improving Your Security Score

Based on the advice from Kubesec, let’s update our Deployment to include:
  • A dedicated service account
  • AppArmor & Seccomp annotations
  • CPU & memory limits
  • Immutable root filesystem
  • Non-root user execution
apiVersion: apps/v1
kind: Deployment
metadata:
  name: devsecops
  labels:
    app: devsecops
spec:
  replicas: 2
  selector:
    matchLabels:
      app: devsecops
  template:
    metadata:
      labels:
        app: devsecops
      annotations:
        container.apparmor.security.beta.kubernetes.io/devsecops-container: runtime/default
        container.seccomp.security.alpha.kubernetes.io/devsecops-container: runtime/default
    spec:
      serviceAccountName: default
      containers:
        - name: devsecops-container
          image: youruser/app:latest
          securityContext:
            runAsNonRoot: true
            runAsUser: 100
            readOnlyRootFilesystem: true
          resources:
            limits:
              cpu: "500m"
              memory: "256Mi"
---
apiVersion: v1
kind: Service
metadata:
  name: devsecops-svc
  labels:
    app: devsecops
spec:
  type: NodePort
  selector:
    app: devsecops
  ports:
    - port: 8080
      targetPort: 8080
      protocol: TCP
Re-running the scan:
+ bash kubesec-scan.sh
Scan Score: 5
 Kubesec Scan Passed: Passed with a score of 5 points

References

Watch Video