Introduction to KubeLinter
KubeLinter is an open-source static analysis tool designed specifically for Kubernetes configurations. Developed by StackRox (now part of Red Hat), it scans YAML files, Helm charts, and live Kubernetes resources to identify misconfigurations, security vulnerabilities, and deviations from best practices before they reach production. The tool ships with over 50 built-in checks that cover a wide spectrum of concerns — from security contexts and privilege escalation to resource limits and deprecated API versions.
At its core, KubeLinter operates as a command-line tool that lints Kubernetes manifests against a configurable rule set. What sets it apart from generic YAML validators is its deep understanding of Kubernetes semantics: it knows how deployments relate to pods, how services map to selectors, and how RBAC bindings cascade permissions. This semantic awareness allows it to catch issues that simple schema validators would miss entirely.
Configuration in KubeLinter is handled through a YAML-based configuration file, typically named kubelinter.yaml or .kubelinter.yaml. This file controls every aspect of the linting process — which checks run, which checks are disabled, which objects are exempted from scrutiny, and how certain checks should be tuned for your specific environment. Understanding this configuration system thoroughly is essential for integrating KubeLinter into CI/CD pipelines, pre-commit hooks, and developer workflows effectively.
Why KubeLinter Matters
🚀 Deploy your AI agent in 10 minutes
Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.
Try it free →Kubernetes misconfigurations are among the leading causes of production incidents, security breaches, and costly outages. Consider a deployment that runs as root, lacks read-only root filesystem, and has no resource limits — each of these individually represents a significant risk, and together they form a dangerous combination that could lead to container escape or resource exhaustion. KubeLinter catches these issues automatically.
The tool matters for three primary reasons:
- Shift-left security: By catching misconfigurations during development rather than after deployment, teams reduce the cost and effort of remediation dramatically. A fix made in a pull request costs far less than a fix applied to a running cluster under incident pressure.
- Policy as code: The configuration file serves as executable policy documentation. Instead of wiki pages describing what a secure deployment should look like, teams encode those rules directly into KubeLinter's configuration, making compliance verifiable and automated.
- Consistency across teams: When multiple development teams build Kubernetes manifests independently, consistency suffers. A shared KubeLinter configuration ensures every team adheres to the same baseline, reducing the cognitive load on platform engineering and SRE teams.
KubeLinter also integrates naturally into existing workflows. It can run as a standalone binary on a developer's laptop, as a CI step in a pipeline, or even as an admission controller with the right orchestration. The configuration file is the bridge that makes these different contexts behave consistently.
Installation and Getting Started
KubeLinter can be installed via multiple methods. The simplest approach for local development is downloading the binary directly from the GitHub releases page. For CI environments, the official Docker image is often more convenient.
Binary Installation
# Download the latest release for Linux (adjust URL for your OS and architecture)
curl -Lo kube-linter.tar.gz https://github.com/stackrox/kube-linter/releases/download/v0.6.8/kube-linter-linux.tar.gz
tar -xzf kube-linter.tar.gz
sudo mv kube-linter /usr/local/bin/
kube-linter version
Docker Usage
# Run KubeLinter against a directory of manifests using the official image
docker run --rm -v $(pwd)/manifests:/manifests \
ghcr.io/stackrox/kube-linter:latest \
lint /manifests
First Lint Run
Before diving into configuration, it's useful to see KubeLinter in action with its default rule set. Create a simple deployment manifest and run the linter against it:
# Create a sample deployment
cat > sample-deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
EOF
# Run KubeLinter with default checks
kube-linter lint sample-deployment.yaml
The output will likely flag several issues — missing security context, absent resource limits, and potentially a warning about using the latest image tag if you had used it. Each finding includes the check name, the object it applies to, and a description of the problem along with a suggested remediation.
Configuration File Structure
The KubeLinter configuration file is a YAML document that follows a specific schema. The top-level key is always customChecks, followed by optional sections for checks configuration, exclusions, and include / exclude patterns. Here is the complete structural reference:
# kubelinter.yaml - Complete configuration structure
customChecks:
# Custom check definitions go here (covered in depth below)
checks:
# Built-in check configuration
# Controls which built-in checks run and with what parameters
exclusions:
# Objects or namespaces to exclude from linting
include:
# Patterns for files to include (glob patterns)
exclude:
# Patterns for files to exclude (glob patterns)
severity:
# Severity overrides for specific checks
Configuration File Discovery
KubeLinter looks for configuration files in a specific order of precedence:
- A file explicitly specified via the
--configflag - A file named
.kubelinter.yamlin the current working directory - A file named
.kubelinter.yamlin the user's home directory - A file named
kubelinter.yamlin the current working directory
If no configuration file is found, KubeLinter runs all built-in checks with their default parameters. This fallback behavior is sensible for initial exploration but insufficient for production use — teams should always maintain an explicit configuration file checked into version control.
Configuring Built-in Checks
The checks section of the configuration file is where most teams spend the bulk of their configuration effort. This section controls which of the 50+ built-in checks are enabled, disabled, or tuned with custom parameters. The syntax for configuring a check follows a consistent pattern:
# kubelinter.yaml
checks:
# Disable a check entirely
runAsNonRoot:
doNotRun: true
# Configure a check with parameters
requiredLabel:
parameters:
key: "app.kubernetes.io/name"
# Use a check's default behavior (simply omit it)
Commonly Configured Checks
Below is a comprehensive reference of the most frequently configured built-in checks, their parameters, and practical configuration examples.
Security Context Checks
checks:
# Ensure containers do not run as root
# Default: enabled
runAsNonRoot:
doNotRun: false # Explicitly keep enabled
# Prevent containers from requesting privilege escalation
# Default: enabled
allowPrivilegeEscalation:
doNotRun: false
# Require a read-only root filesystem
# Default: enabled
readOnlyRootFilesystem:
doNotRun: false
# Ensure capabilities are explicitly dropped
# Parameters: specify additional capabilities to check
dropCapabilities:
parameters:
capabilities:
- "NET_RAW"
- "SYS_ADMIN"
Resource Constraint Checks
checks:
# Require CPU and memory limits on all containers
# Default: enabled
setCPUandMemoryLimits:
doNotRun: false
# Require CPU and memory requests on all containers
# Default: enabled
setCPUandMemoryRequests:
doNotRun: false
# Check for the presence of resource limits in general
# Parameters: specify which resource types to check
requiredLimits:
parameters:
resources:
- "cpu"
- "memory"
- "ephemeral-storage"
Label and Annotation Checks
checks:
# Require a specific label on all objects
# Parameters: key is the required label key
requiredLabel:
parameters:
key: "app.kubernetes.io/name"
# Optionally validate the value with a regex
valueRegex: "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$"
# Require a specific annotation
requiredAnnotation:
parameters:
key: "owner"
valueRegex: ".*@company\\.com"
Image and Container Checks
checks:
# Disallow the 'latest' image tag
# Default: enabled
latestTag:
doNotRun: false
# Require images to come from approved registries
# Parameters: list of allowed registries
requiredImageRegistry:
parameters:
registries:
- "registry.company.com"
- "registry.company.com/production"
- "docker.io/library"
# Disallow specific image patterns
disallowedImageTags:
parameters:
disallowedTags:
- "dev"
- "staging"
- "debug"
Port and Networking Checks
checks:
# Warn when hostPort is configured
# Default: enabled
hostPort:
doNotRun: false
# Check for hostNetwork usage
hostNetwork:
doNotRun: false
# Check for hostPID usage
hostPID:
doNotRun: false
# Ensure services target at least one pod
# Default: enabled
serviceTargetsPods:
doNotRun: false
Deprecated API Checks
checks:
# Warn on deprecated Kubernetes API versions
# Default: enabled
deprecatedAPIVersion:
doNotRun: false
parameters:
# Customize the minimum Kubernetes version for deprecation checks
minKubernetesVersion: "1.24"
Comprehensive Check Configuration Example
Here is a complete, production-ready checks section that balances security, reliability, and practical flexibility:
checks:
# Security baseline
runAsNonRoot:
doNotRun: false
allowPrivilegeEscalation:
doNotRun: false
readOnlyRootFilesystem:
doNotRun: false
dropCapabilities:
doNotRun: false
parameters:
capabilities:
- "NET_RAW"
- "SYS_ADMIN"
- "SYS_TIME"
# Resource management
setCPUandMemoryLimits:
doNotRun: false
setCPUandMemoryRequests:
doNotRun: false
# Image governance
latestTag:
doNotRun: false
requiredImageRegistry:
doNotRun: false
parameters:
registries:
- "registry.company.com"
- "registry.company.com/production"
- "docker.io/library"
# Networking restrictions
hostPort:
doNotRun: false
hostNetwork:
doNotRun: false
hostPID:
doNotRun: false
# Label requirements for operational visibility
requiredLabel:
parameters:
key: "app.kubernetes.io/name"
valueRegex: "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$"
# API version hygiene
deprecatedAPIVersion:
doNotRun: false
parameters:
minKubernetesVersion: "1.26"
Managing Exclusions
Not every violation warrants a manifest change. System components, third-party charts, and legacy workloads often need to bypass certain checks. KubeLinter provides a robust exclusion mechanism that allows teams to suppress findings for specific objects, namespaces, or entire files without disabling the check globally.
Exclusion Syntax
exclusions:
# Exclude by object name
- name: "kube-proxy"
reason: "System component managed by cluster operators"
checks:
- "runAsNonRoot"
- "readOnlyRootFilesystem"
# Exclude by namespace
- namespace: "kube-system"
reason: "System namespace with platform-managed workloads"
checks:
- "all" # 'all' excludes every check for objects in this namespace
# Exclude by object type and label selector
- type: "Deployment"
labels:
app.kubernetes.io/managed-by: "helm"
reason: "Helm-managed deployments reviewed separately"
# Exclude by a specific check and object name pattern
- name-regex: ".*-debug"
reason: "Debug pods are ephemeral and run with elevated privileges intentionally"
checks:
- "runAsNonRoot"
- "allowPrivilegeEscalation"
Practical Exclusion Strategy
A well-maintained exclusion list should include a reason for every entry. This documentation practice prevents the exclusion list from becoming a dumping ground for ignored warnings. Here is a realistic exclusion section that accounts for common enterprise scenarios:
exclusions:
- namespace: "kube-system"
reason: "Core Kubernetes components managed by platform team"
checks:
- "all"
- namespace: "istio-system"
reason: "Service mesh components managed by infrastructure team"
checks:
- "all"
- namespace: "cert-manager"
reason: "Certificate management infrastructure"
checks:
- "all"
- name-regex: ".*-job$"
reason: "Batch jobs complete and terminate; resource limits enforced at queue level"
checks:
- "setCPUandMemoryLimits"
- "setCPUandMemoryRequests"
- name: "fluentd-daemonset"
reason: "Logging agent requires host-level access for log collection"
checks:
- "hostNetwork"
- "runAsNonRoot"
- "readOnlyRootFilesystem"
- labels:
app.kubernetes.io/component: "monitoring"
reason: "Monitoring components require elevated access for metrics collection"
checks:
- "dropCapabilities"
File Inclusion and Exclusion Patterns
KubeLinter supports glob-based patterns for controlling which files are scanned. This is particularly valuable in monorepo setups where Kubernetes manifests coexist with application code, documentation, and configuration files for other tools.
# Include only specific patterns
include:
- "**/deploy/**/*.yaml"
- "**/manifests/**/*.yaml"
- "**/helm-charts/**/templates/**/*.yaml"
# Exclude patterns that match non-Kubernetes YAML files
exclude:
- "**/node_modules/**"
- "**/.gitlab-ci.yml"
- "**/.github/**"
- "**/docker-compose*.yml"
- "**/Makefile.yaml"
- "**/values.yaml" # Helm values files, not templates
- "**/Chart.yaml" # Helm chart metadata, not Kubernetes objects
When both include and exclude patterns are specified, KubeLinter first filters files by the include patterns (if any are defined), then removes files matching exclude patterns. If no include patterns are specified, all files discovered in the lint path are considered, subject to exclude patterns.
Severity Configuration
KubeLinter assigns a default severity to each built-in check — typically error or warning. The severity section allows teams to override these defaults, promoting warnings to errors (which cause non-zero exit codes) or demoting errors to warnings for gradual rollout scenarios.
severity:
# Promote warnings to errors for stricter enforcement
- check: "latestTag"
severity: "error"
# Demote errors to warnings during a transition period
- check: "requiredLabel"
severity: "warning"
reason: "Gradually rolling out label requirements; will promote to error in Q2"
The severity override takes effect globally unless paired with an exclusion that scopes it to specific objects. This mechanism is particularly useful for phased policy rollouts — start with a warning, communicate expectations to teams, then promote to error once compliance is achieved.
Custom Checks Deep Dive
While built-in checks cover a broad range of concerns, organizations often have unique requirements that demand custom logic. KubeLinter's custom checks system allows defining entirely new checks using YAML-based templates. Custom checks are defined under the customChecks key at the root of the configuration file.
Custom Check Anatomy
A custom check consists of a name, a description, a template (written in Go template syntax), and a set of match targets. The template is evaluated against Kubernetes objects and should produce a non-empty string when a violation is detected.
customChecks:
- name: "require-team-label"
description: "Every workload must have a team label for ownership tracking"
template: |
{{- $labels := .spec.template.metadata.labels -}}
{{- if or (not (hasKey $labels "team")) (eq (index $labels "team") "") -}}
"Missing 'team' label. Add 'team: your-team-name' to the pod template labels."
{{- end -}}
match:
- type: "Deployment"
- type: "StatefulSet"
- type: "DaemonSet"
- type: "Job"
- type: "CronJob"
- name: "require-probes"
description: "Production workloads must have liveness and readiness probes configured"
template: |
{{- $containers := .spec.template.spec.containers -}}
{{- range $container := $containers -}}
{{- if not (hasKey $container "livenessProbe") -}}
"Container '{{ $container.name }}' missing liveness probe."
{{- end -}}
{{- if not (hasKey $container "readinessProbe") -}}
"Container '{{ $container.name }}' missing readiness probe."
{{- end -}}
{{- end -}}
match:
- type: "Deployment"
- type: "StatefulSet"
- name: "require-pod-disruption-budget"
description: "Ensure critical deployments have a corresponding PodDisruptionBudget"
template: |
"Deployment '{{ .metadata.name }}' should have a corresponding PodDisruptionBudget."
match:
- type: "Deployment"
labels:
critical: "true"
Custom Check Template Context
The template in a custom check has access to the full Kubernetes object being evaluated. The root context is the object itself, so you access fields using standard Go template syntax with dot notation. Here are the available context variables and common patterns:
customChecks:
- name: "validate-ingress-tls"
description: "Ensure all ingress rules use TLS"
template: |
{{- range .spec.rules }}
{{- if not (hasKey . "http") }}
{{- continue }}
{{- end }}
{{- range .http.paths }}
{{- if not (hasKey . "backend") }}
"Ingress rule missing backend configuration."
{{- end }}
{{- end }}
{{- end }}
{{- if not .spec.tls }}
"Ingress '{{ $.metadata.name }}' does not configure TLS."
{{- end }}
match:
- type: "Ingress"
- name: "validate-service-port-names"
description: "Service ports should follow the IANA naming convention"
template: |
{{- $validProtocols := list "TCP" "UDP" "SCTP" }}
{{- range .spec.ports }}
{{- $port := . }}
{{- if and $port.name (not (hasPrefix (upper $port.name) $validProtocols)) }}
"Port name '{{ $port.name }}' should be prefixed with protocol (e.g., 'http-tcp', 'grpc-tcp')."
{{- end }}
{{- end }}
match:
- type: "Service"
Custom Check Match Targets
The match field determines which Kubernetes objects the custom check applies to. You can match by type (the Kind of object) and optionally by labels for more granular targeting:
customChecks:
- name: "production-readiness-gates"
description: "Production deployments must define readiness gates"
template: |
{{- if not .spec.template.spec.readinessGates }}
"Production deployment '{{ .metadata.name }}' missing readiness gates."
{{- end }}
match:
- type: "Deployment"
labels:
environment: "production"
- type: "StatefulSet"
labels:
environment: "production"
Complete Production Configuration Example
Below is a complete, battle-tested KubeLinter configuration file that you can use as a starting point for your organization. It balances security enforcement with practical flexibility, includes well-documented exclusions, and defines several custom checks that go beyond the built-in rule set:
# .kubelinter.yaml - Production-grade configuration
# Place this file in the root of your repository
customChecks:
- name: "require-team-label"
description: "Every workload must have a team label for ownership tracking"
template: |
{{- $labels := .spec.template.metadata.labels -}}
{{- if or (not (hasKey $labels "team")) (eq (index $labels "team") "") -}}
"Missing 'team' label. Add 'team: your-team-name' to the pod template labels."
{{- end -}}
match:
- type: "Deployment"
- type: "StatefulSet"
- type: "DaemonSet"
- type: "Job"
- type: "CronJob"
- name: "require-probes"
description: "Production workloads must have liveness and readiness probes"
template: |
{{- $containers := .spec.template.spec.containers -}}
{{- range $container := $containers -}}
{{- if not (hasKey $container "livenessProbe") -}}
"Container '{{ $container.name }}' missing liveness probe."
{{- end -}}
{{- if not (hasKey $container "readinessProbe") -}}
"Container '{{ $container.name }}' missing readiness probe."
{{- end -}}
{{- end -}}
match:
- type: "Deployment"
- type: "StatefulSet"
- name: "validate-ingress-tls"
description: "All ingress rules must configure TLS"
template: |
{{- if not .spec.tls }}
"Ingress '{{ .metadata.name }}' does not configure TLS."
{{- end }}
match:
- type: "Ingress"
checks:
# Security baseline
runAsNonRoot:
doNotRun: false
allowPrivilegeEscalation:
doNotRun: false
readOnlyRootFilesystem:
doNotRun: false
dropCapabilities:
doNotRun: false
parameters:
capabilities:
- "NET_RAW"
- "SYS_ADMIN"
- "SYS_TIME"
- "SYS_PTRACE"
# Resource management
setCPUandMemoryLimits:
doNotRun: false
setCPUandMemoryRequests:
doNotRun: false
# Image governance
latestTag:
doNotRun: false
requiredImageRegistry:
doNotRun: false
parameters:
registries:
- "registry.company.com"
- "registry.company.com/production"
- "docker.io/library"
# Networking restrictions
hostPort:
doNotRun: false
hostNetwork:
doNotRun: false
hostPID:
doNotRun: false
# Label requirements
requiredLabel:
parameters:
key: "app.kubernetes.io/name"
# API hygiene
deprecatedAPIVersion:
doNotRun: false
parameters:
minKubernetesVersion: "1.26"
exclusions:
- namespace: "kube-system"
reason: "Core Kubernetes components managed by platform team"
checks:
- "all"
- namespace: "istio-system"
reason: "Service mesh infrastructure"
checks:
- "all"
- namespace: "cert-manager"
reason: "Certificate management infrastructure"
checks:
- "all"
- namespace: "external-secrets"
reason: "Secrets management infrastructure"
checks:
- "all"
- name-regex: ".*-job$"
reason: "Batch jobs are ephemeral and managed separately"
checks:
- "setCPUandMemoryLimits"
- "setCPUandMemoryRequests"
- "require-probes"
- name: "fluentd-daemonset"
reason: "Logging agent requires host-level access"
checks:
- "hostNetwork"
- "runAsNonRoot"
- "readOnlyRootFilesystem"
- labels:
app.kubernetes.io/component: "monitoring"
reason: "Monitoring components need elevated access for metrics collection"
checks:
- "dropCapabilities"
exclude:
- "**/node_modules/**"
- "**/.gitlab-ci.yml"
- "**/.github/**"
- "**/docker-compose*.yml"
- "**/values.yaml"
- "**/Chart.yaml"
severity:
- check: "latestTag"
severity: "error"
- check: "requiredLabel"
severity: "error"
Integrating KubeLinter into CI/CD Pipelines
The configuration file shines brightest when integrated into automated pipelines. Below are examples for popular CI systems, all using the same .kubelinter.yaml configuration file committed to the repository.
GitHub Actions Integration
# .github/workflows/kubelinter.yml
name: KubeLinter Scan
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run KubeLinter
uses: stackrox/kube-linter-action@v1
with:
config: .kubelinter.yaml
directory: .
# Fail the pipeline on errors (warnings pass)
fail-on-error: true
GitLab CI Integration
# .gitlab-ci.yml
kubelinter:
stage: test
image: ghcr.io/stackrox/kube-linter:latest
script:
- kube-linter lint --config .kubelinter.yaml .
artifacts:
reports:
codequality: kubelinter-report.json
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
Jenkins Pipeline Integration
// Jenkinsfile
pipeline {
agent any
stages {
stage('KubeLinter') {
steps {
sh '''
docker run --rm \
-v "$WORKSPACE:/workspace" \
-w /workspace \
ghcr.io/stackrox/kube-linter:latest \
lint --config .kubelinter.yaml /workspace
'''
}
}
}
}
Pre-commit Hook Integration
For the fastest feedback loop, integrate KubeLinter as a pre-commit hook that runs only on changed YAML files:
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: kubelinter
name: KubeLinter
entry: kube-linter lint --config .kubelinter.yaml
language: system
files: \.(yaml|yml)$
pass_filenames: false
args: ['.']
Best Practices for KubeLinter Configuration
Through real-world usage across organizations of varying sizes, several best practices have emerged that maximize the value of KubeLinter while minimizing friction:
Start with the Default Rule Set, Then Tighten
Begin by running KubeLinter with its default configuration. Observe which checks produce the most findings in your codebase, then prioritize addressing those. Once the baseline is clean, progressively enable stricter checks and custom rules. This incremental approach prevents the overwhelming flood of findings that can cause teams to ignore the tool entirely.
# Phase 1: Default checks only
# No configuration file needed — just run:
kube-linter lint ./manifests
# Phase 2: Add custom checks incrementally
# .kubelinter.yaml
customChecks:
- name: "require-team-label"
...
Version Control Your Configuration
The .kubelinter.yaml file must be committed to the same repository as the Kubernetes manifests it governs. This ensures configuration changes are reviewed through the same pull request process as code changes, creating an audit trail and preventing unilateral policy modifications. Use branch protection rules to require KubeLinter passing checks before merging.
Document Every Exclusion with a Reason
Every exclusion entry should include a reason field that explains the business or technical justification. Exclusions without reasons become technical debt — six months later, no one remembers why a particular check was suppressed, and the exclusion persists indefinitely. Require reasons in your code review process for configuration changes.
Use Severity Overrides for Gradual Rollouts
When introducing a new check or custom rule, set its severity to warning initially. This allows the CI pipeline to pass while still surfacing findings to developers. After a defined transition period (typically two to four weeks), promote the severity to error. Communicate the timeline clearly to affected teams.
severity:
- check: "require-team-label"
severity: "warning"
reason: "Rolling out team label requirement; will promote to error on 2025-03-01"
Test Configuration Changes Against a Representative Sample
Before pushing a configuration change to all repositories, test it against a curated set of manifests that represent your organization's typical deployment patterns. This prevents configuration changes that inadvertently break CI for teams whose manifests have legitimate variations.
# Test a new configuration against a sample directory
kube-linter lint --config proposed-kubelinter.yaml ./sample-manifests/
Keep Custom Checks Simple and Focused
Custom check templates should enforce a single, well-defined requirement. Complex templates that check multiple unrelated conditions are harder to debug, harder to maintain, and produce confusing error messages. If you find yourself writing a template longer than 15 lines, consider splitting it into multiple focused checks.
Regularly Review and Prune Exclusions
Schedule a quarterly review of the exclusion list. Exclusions that were necessary six months ago may no longer apply — the system component may have been updated to comply with security policies, or the legacy workload may have been decommissioned. Pruning stale exclusions keeps the configuration lean and maintains its effectiveness as a security enforcement tool.
Combine KubeLinter with Complementary Tools
KubeLinter excels at static analysis of Kubernetes manifests, but it is not a complete security solution on its own. Pair it with tools that address adjacent concerns: container image scanning (Trivy, Grype), runtime security (Falco), and admission control (OPA/Gatekeeper, Kyverno). Each tool occupies a distinct layer of the defense-in-depth strategy.
Conclusion
KubeLinter's configuration system is both powerful and approachable. The built-in checks cover the most common Kubernetes security and reliability concerns out of the box, while the custom checks framework, exclusion mechanism, and severity overrides provide the flexibility needed for real-world enterprise environments. A well-crafted .kubelinter.yaml file — committed to version control, reviewed with the same rigor as application code, and regularly maintained — serves as executable policy that shifts security left, reduces production incidents, and creates a consistent deployment standard across every team in the organization. Start with the defaults, build incrementally, document every decision, and let the configuration evolve alongside your Kubernetes maturity. The result is a linting pipeline that catches problems before they become incidents, without becoming a bottleneck in the development workflow.