Sign inSign up

derekahn/klint

By derekahn

•Updated over 4 years ago

A consolidated suite of kubernetes tools in a single container.

Image
0

3.3K

derekahn/klint repository overview

⁠klint 🧹

MIT license

A consolidated suite of kubernetes tools in a single container.

This is a portable solution to validate ☸️ manifests anywhere with a container runtime; local machine, CI, etc.

⁠Reminders 🎗

  • The container is set with the permissions nobody:nobody
  • The container's workspace is set to /src
  • The container doesn't have curl, but it has wget
  • Any vulnerabilities are not my own; see tools 🔧

⁠Tools 🔧

This swiss army knife stands on the shoulders of giants:

NameVersionLicenseDescription
helm⁠v3.7Apache 2.0⁠The Kubernetes Package Manager
kubectl⁠v1.23.3Apache 2.0⁠The designated kubernetes CLI client
kubesec⁠v2.11.4Apache 2.0⁠Security risk analysis for Kubernetes resources
kubeval⁠v0.15.0Apache 2.0⁠Validate your Kubernetes configuration files, supports multiple Kubernetes versions
kube-score⁠v1.13.0Apache 2.0⁠Kubernetes object analysis with recommendations for improved reliability and security
kustomize⁠v4.4.1Apache 2.0⁠Customization of kubernetes YAML configurations

⁠Usage 🐳

For local usage... first spin up the container

$ docker run --rm -it -v `pwd`:/src derekahn/klint
⁠Kubescore
⁠Example Usage
/src $ kube-score score *.yaml
⁠Example Output
apps/v1/Deployment my-app in awesome                                    💥
  [CRITICAL] Pod Probes
    · Container has the same readiness and liveness probe
        Using the same probe for liveness and readiness is very likely dangerous. Generally it's better to avoid
        the livenessProbe than re-using the readinessProbe.
        More information: https://github.com/zegl/kube-score/blob/master/README_PROBES.md
  [CRITICAL] Container Resources
    · scala-sample -> CPU limit is not set
        Resource limits are recommended to avoid resource DDOS. Set resources.limits.cpu
    · scala-sample -> Memory limit is not set
        Resource limits are recommended to avoid resource DDOS. Set resources.limits.memory
    · scala-sample -> CPU request is not set
        Resource requests are recommended to make sure that the application can start and run without crashing.
        Set resources.requests.cpu
    · scala-sample -> Memory request is not set
        Resource requests are recommended to make sure that the application can start and run without crashing.
        Set resources.requests.memory
  [CRITICAL] Container Image Tag
    · scala-sample -> Image with latest tag
        Using a fixed tag is recommended to avoid accidental upgrades
  [CRITICAL] Pod NetworkPolicy
    · The pod does not have a matching NetworkPolicy
        Create a NetworkPolicy that targets this pod to control who/what can communicate with this pod. Note, this
        feature needs to be supported by the CNI implementation used in the Kubernetes cluster to have an effect.
  [CRITICAL] Deployment has PodDisruptionBudget
    · No matching PodDisruptionBudget was found
        It's recommended to define a PodDisruptionBudget to avoid unexpected downtime during Kubernetes
        maintenance operations, such as when draining a node.
  [WARNING] Deployment has host PodAntiAffinity
    · Deployment does not have a host podAntiAffinity set
        It's recommended to set a podAntiAffinity that stops multiple pods from a deployment from being scheduled
        on the same node. This increases availability in case the node becomes unavailable.
v1/Service my-app in awesome                                        ✅
⁠Kubeval
⁠Example Usage
/src $ kube-score score *.yaml
⁠Example Output
PASS - my-app-deply.yaml contains a valid Deployment (awesome.my-app)
PASS - my-app-svc.yaml contains a valid Service (awesome.my-app-svc)
⁠Kubesec
⁠Example Usage
/src $ kubesec scan my-app-deploy.yaml
⁠Example Output
[
  {
    "object": "Deployment/my-app.awesome",
    "valid": true,
    "fileName": "my-app-deploy.yaml",
    "message": "Passed with a score of 5 points",
    "score": 5,
    "scoring": {
      "passed": [
        {
          "id": "CapDropAny",
          "selector": "containers[] .securityContext .capabilities .drop",
          "reason": "Reducing kernel capabilities available to a container limits its attack surface",
          "points": 1
        },
        {
          "id": "CapDropAll",
          "selector": "containers[] .securityContext .capabilities .drop | index(\"ALL\")",
          "reason": "Drop all capabilities and add only those required to reduce syscall attack surface",
          "points": 1
        },
        {
          "id": "ReadOnlyRootFilesystem",
          "selector": "containers[] .securityContext .readOnlyRootFilesystem == true",
          "reason": "An immutable root filesystem can prevent malicious binaries being added to PATH and increase attack cost",
          "points": 1
        },
        {
          "id": "RunAsNonRoot",
          "selector": "containers[] .securityContext .runAsNonRoot == true",
          "reason": "Force the running image to run as a non-root user to ensure least privilege",
          "points": 1
        },
        {
          "id": "RunAsUser",
          "selector": "containers[] .securityContext .runAsUser -gt 10000",
          "reason": "Run as a high-UID user to avoid conflicts with the host's user table",
          "points": 1
        }
      ],
      "advise": [
        {
          "id": "ApparmorAny",
          "selector": ".metadata .annotations .\"container.apparmor.security.beta.kubernetes.io/nginx\"",
          "reason": "Well defined AppArmor policies may provide greater protection from unknown threats. WARNING: NOT PRODUCTION READY",
          "points": 3
        },
        {
          "id": "ServiceAccountName",
          "selector": ".spec .serviceAccountName",
          "reason": "Service accounts restrict Kubernetes API access and should be configured with least privilege",
          "points": 3
        },
        {
          "id": "SeccompAny",
          "selector": ".metadata .annotations .\"container.seccomp.security.alpha.kubernetes.io/pod\"",
          "reason": "Seccomp profiles set minimum privilege and secure against unknown threats",
          "points": 1
        },
      ]
    }
  }
]
⁠Kustomize
/src $ kustomize build overlays/development/
apiVersion: v1
kind: Namespace
metadata:
  annotations:
    kube-score/ignore: pod-networkpolicy,deployment-has-host-podantiaffinity,container-security-context,deployment-has-poddisruptionbudget
  name: awesome
---
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    kube-score/ignore: pod-networkpolicy,deployment-has-host-podantiaffinity,container-security-context,deployment-has-poddisruptionbudget
  labels:
    app: my-app
  name: my-app
  namespace: awesome
spec:
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      annotations:
        kube-score/ignore: pod-networkpolicy,deployment-has-host-podantiaffinity,container-security-context,deployment-has-poddisruptionbudget
      labels:
        app: my-app
    spec:
      containers:
      - image: k8s:5000/my-app
        imagePullPolicy: Always
        name: my-app
        ports:
        - containerPort: 5000
        resources:
          limits:
            cpu: 1
            memory: 2048Mi
          requests:
            cpu: 1
            memory: 512Mi

⁠Continuous Integration

These are just simple examples of plugging this into your CI

⁠Github Actions
jobs:
  container:
    runs-on: ubuntu-latest
    container: derekahn/klint:latest
    steps:
      - run: |
          kubeval *.yaml
        name: Run in container
⁠Jenkins example using Docker agents

Jenkinsfile

pipeline {
  agent {
    docker { image 'derekahn/klint:latest' }
  }

  stages {
    stage('lint') {
      steps {
        sh 'kubeval *.yaml'
      }
    }
    stage('validate') {
      steps {
        sh 'kube-score score *.yaml'
      }
    }
    stage('security scan') {
      steps {
        sh 'kubeval *.yaml'
      }
    }
  }
}
⁠Drone

.drone.yml

kind: pipeline
name: k8s validations

steps:
  - name: lint
    image: derekahn/klint:latest
    commands:
      - kubeval score *.yaml
  - name: validate
    image: derekahn/klint:latest
    commands:
      - kube-score score *.yaml
  - name: scan
    image: derekahn/klint:latest
    commands:
      - kubesec scan *.yaml
⁠Circle-CI

.circleci/config.yml

version: 2.0
jobs:
  build:
    docker:
      - image: derekahn/klint:latest

Tag summary

Content type

Image

Digest

Size

60.6 MB

Last updated

over 4 years ago

docker pull derekahn/klint