├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── dependabot.yaml
├── release.yml
└── workflows
│ ├── auto-merge.yaml
│ ├── build.yaml
│ └── release.yaml
├── .gitignore
├── .golangci.yml
├── .goreleaser.yaml
├── .pre-commit-hooks.yaml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── RELEASE.md
├── SECURITY.md
├── cmd
└── kube-linter
│ └── kube-linter.go
├── config.yaml.example
├── docs
├── .nojekyll
├── CNAME
├── README.md
├── _coverpage.md
├── _navbar.md
├── _sidebar.md
├── configuring-kubelinter.md
├── custom_resource_template_test.go
├── generated
│ ├── checks.md
│ └── templates.md
├── index.html
├── style.css
└── using-kubelinter.md
├── e2etests
├── bats-support-clone.bash
├── bats-tests.sh
├── check-bats-tests.sh
├── empty.go
├── sanity_test.go
└── testdata
│ ├── all-built-in-config.yaml
│ └── forbidden-annotation-config.yaml
├── go.mod
├── go.sum
├── image
├── Dockerfile
├── Dockerfile_alpine
└── bin
│ └── .gitignore
├── images
└── logo
│ ├── KubeLinter-horizontal.svg
│ ├── KubeLinter-vertical.svg
│ └── favicon.ico
├── internal
├── consts
│ └── consts.go
├── defaultchecks
│ ├── default_checks.go
│ └── default_test.go
├── errorhelpers
│ └── format.go
├── flagutil
│ └── enum.go
├── pointers
│ └── pointers.go
├── set
│ └── gen-string-generic.go
├── stringutils
│ ├── consume.go
│ ├── default.go
│ ├── repeat.go
│ ├── split.go
│ └── ternary.go
├── utils
│ ├── ignore_error.go
│ └── must.go
└── version
│ └── version.go
├── kubelinter-cosign.pub
├── pkg
├── builtinchecks
│ ├── built_in_checks.go
│ ├── built_in_checks_test.go
│ └── yamls
│ │ ├── access-to-create-pods.yaml
│ │ ├── access-to-secrets.yaml
│ │ ├── cluster-admin-role-binding.yaml
│ │ ├── dangling-horizontalpodautoscaler.yaml
│ │ ├── dangling-ingress.yaml
│ │ ├── dangling-networkpolicy.yaml
│ │ ├── dangling-networkpolicypeer-podselector.yaml
│ │ ├── dangling-service.yaml
│ │ ├── dangling-servicemonitor.yaml
│ │ ├── default-service-account.yaml
│ │ ├── deprecated-service-account.yaml
│ │ ├── dnsconfig-options.yaml
│ │ ├── docker-sock.yaml
│ │ ├── drop-net-raw-capability.yaml
│ │ ├── duplicate-env-var.yaml
│ │ ├── env-var-secret.yaml
│ │ ├── host-mounts.yaml
│ │ ├── hostipc.yaml
│ │ ├── hostnetwork.yaml
│ │ ├── hostpid.yaml
│ │ ├── hpa-minimum-replicas.yaml
│ │ ├── invalid-target-ports.yaml
│ │ ├── latest-tag.yaml
│ │ ├── liveness-port.yaml
│ │ ├── minimum-replicas.yaml
│ │ ├── mismatching-selector.yaml
│ │ ├── no-anti-affinity.yaml
│ │ ├── no-extensions-v1beta.yaml
│ │ ├── no-liveness-probe.yaml
│ │ ├── no-node-affinity.yaml
│ │ ├── no-readiness-probe.yaml
│ │ ├── no-rolling-update-strategy.yaml
│ │ ├── non-existent-service-account.yaml
│ │ ├── non-isolated-pod.yaml
│ │ ├── pdb-unhealthy-pod-eviction-policy.yaml
│ │ ├── pdbs-max-unavailable.yaml
│ │ ├── pdbs-min-available.yaml
│ │ ├── privilege-escalation.yaml
│ │ ├── privileged.yaml
│ │ ├── privilegedports.yaml
│ │ ├── read-only-root-fs.yaml
│ │ ├── read-secret-from-env-var.yaml
│ │ ├── readiness-port.yaml
│ │ ├── required-annotation-email.yaml
│ │ ├── required-label-owner.yaml
│ │ ├── restart-policy.yaml
│ │ ├── run-as-non-root.yaml
│ │ ├── scc-deny-privileged-container.yaml
│ │ ├── servicetype.yaml
│ │ ├── ssh-port.yaml
│ │ ├── startup-port.yaml
│ │ ├── sysctls.yaml
│ │ ├── unsafe-proc-mount.yaml
│ │ ├── unset-cpu-requirements.yaml
│ │ ├── unset-memory-requirements.yaml
│ │ ├── usenamespace.yaml
│ │ ├── wildcard-use-in-rules.yaml
│ │ └── writable-host-mount.yaml
├── check
│ ├── parameter_desc.go
│ └── template.go
├── checkregistry
│ └── check_registry.go
├── command
│ ├── checks
│ │ └── command.go
│ ├── common
│ │ ├── format_wrapper.go
│ │ ├── template.go
│ │ └── template_test.go
│ ├── lint
│ │ ├── command.go
│ │ ├── command_test.go
│ │ ├── sarif_format.go
│ │ └── testdata
│ │ │ ├── invalid-pod-resources.yaml
│ │ │ ├── invalid-pvc-resources.yaml
│ │ │ └── valid-pod.yaml
│ ├── root
│ │ ├── command.go
│ │ └── command_test.go
│ ├── templates
│ │ └── command.go
│ └── version
│ │ └── command.go
├── config
│ ├── check.go
│ ├── codegen
│ │ └── parse.go
│ ├── config.go
│ ├── flags.go
│ └── gen.go
├── configresolver
│ ├── config_resolver.go
│ └── config_resolver_test.go
├── diagnostic
│ └── diagnostic.go
├── extract
│ ├── customtypes
│ │ └── pod_spec.go
│ ├── gvk.go
│ ├── hpa_spec.go
│ ├── metadata.go
│ ├── pod_spec.go
│ ├── scc_spec.go
│ └── update_strategy.go
├── ignore
│ ├── ignore.go
│ └── ignore_test.go
├── instantiatedcheck
│ └── instantiated_check.go
├── k8sutil
│ └── object.go
├── lintcontext
│ ├── context.go
│ ├── create_contexts.go
│ ├── create_contexts_test.go
│ ├── mocks
│ │ ├── clusterrole.go
│ │ ├── clusterrolebinding.go
│ │ ├── container.go
│ │ ├── context.go
│ │ ├── horizontalpodautoscaler.go
│ │ ├── ingress.go
│ │ ├── networkpolicy.go
│ │ ├── pod.go
│ │ ├── role.go
│ │ ├── rolebinding.go
│ │ ├── scaledobject.go
│ │ ├── scc.go
│ │ ├── service.go
│ │ └── servicemonitor.go
│ └── parse_yaml.go
├── matcher
│ └── string.go
├── objectkinds
│ ├── any.go
│ ├── clusterrole.go
│ ├── clusterrolebinding.go
│ ├── deployment_like.go
│ ├── horizontalpodautoscaler.go
│ ├── ingress.go
│ ├── networkpolicy.go
│ ├── poddisruptionbudget.go
│ ├── registry.go
│ ├── role.go
│ ├── rolebinding.go
│ ├── scaledobject.go
│ ├── securitycontext.go
│ ├── service.go
│ ├── serviceMonitor.go
│ ├── serviceaccount.go
│ └── types.go
├── pathutil
│ └── path.go
├── run
│ └── run.go
└── templates
│ ├── accesstoresources
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── all
│ ├── all.go
│ └── all_test.go
│ ├── antiaffinity
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── clusteradminrolebinding
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── codegen
│ └── main.go
│ ├── containercapabilities
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── cpurequirements
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── danglinghpa
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── danglingingress
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── danglingnetworkpolicy
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── danglingnetworkpolicypeer
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── danglingservice
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── danglingservicemonitor
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── deprecatedserviceaccount
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── disallowedgvk
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── dnsconfigoptions
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── duplicatenvvar
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── envvar
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── forbiddenannotation
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── gen.go
│ ├── hostipc
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── hostmounts
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── hostnetwork
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── hostpid
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── hpareplicas
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── imagepullpolicy
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── latesttag
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── livenessport
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── livenessprobe
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── memoryrequirements
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── mismatchingselector
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── namespace
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── nodeaffinity
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── nonexistentserviceaccount
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── nonisolatedpod
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── pdbmaxunavailable
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── pdbminavailable
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── pdbunhealthypodevictionpolicy
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── ports
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── privileged
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── privilegedports
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── privilegeescalation
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── readinessport
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── readinessprobe
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── readonlyrootfs
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── readsecret
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── registry.go
│ ├── replicas
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── requiredannotation
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── requiredlabel
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── restartpolicy
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── runasnonroot
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── sccdenypriv
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── serviceaccount
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── servicetype
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── startupport
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── sysctl
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── targetport
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── templates_testutils.go
│ ├── unsafeprocmount
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ ├── updateconfig
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ ├── template.go
│ └── template_test.go
│ ├── util
│ ├── check_probe_port.go
│ ├── forbidden_matcher.go
│ ├── forbiden_matcher_test.go
│ ├── json.go
│ ├── map_structure.go
│ ├── per_container_check.go
│ ├── required_matcher.go
│ ├── required_matcher_test.go
│ ├── value_in_range.go
│ └── value_in_range_test.go
│ ├── wildcardinrules
│ ├── internal
│ │ └── params
│ │ │ ├── gen-params.go
│ │ │ └── params.go
│ └── template.go
│ └── writablehostmount
│ ├── internal
│ └── params
│ │ ├── gen-params.go
│ │ └── params.go
│ └── template.go
├── scripts
└── sarif
│ └── sarif-schema-2.1.0.json
├── tests
├── checks
│ ├── access-to-create-pods.yml
│ ├── access-to-secrets.yml
│ ├── cluster-admin-role-binding.yml
│ ├── dangling-hpa.yml
│ ├── dangling-ingress.yml
│ ├── dangling-networkpolicy.yml
│ ├── dangling-networkpolicypeer-podselector.yml
│ ├── dangling-service.yml
│ ├── dangling-servicemonitor.yml
│ ├── default-service-account.yml
│ ├── deprecated-service-account-field.yml
│ ├── dnsconfig-options-ndots.yml
│ ├── docker-sock.yml
│ ├── drop-net-raw-capability.yml
│ ├── duplicate-env-var.yaml
│ ├── env-var-secret.yml
│ ├── exposed-services.yml
│ ├── forbidden-annotation.yml
│ ├── host-ipc.yml
│ ├── host-network.yml
│ ├── host-pid.yml
│ ├── hpa-minimum-three-replicas.yml
│ ├── invalid-target-ports.yaml
│ ├── latest-tag.yml
│ ├── liveness-port.yml
│ ├── minimum-three-replicas.yml
│ ├── mismatching-selector.yml
│ ├── no-anti-affinity.yml
│ ├── no-extensions-v1beta.yml
│ ├── no-liveness-probe.yml
│ ├── no-node-affinity.yml
│ ├── no-read-only-root-fs.yml
│ ├── no-readiness-probe.yml
│ ├── no-rolling-update-strategy.yml
│ ├── non-existent-service-account.yml
│ ├── non-isolated-pod.yml
│ ├── pdb-max-unavailable.yaml
│ ├── pdb-min-available.yaml
│ ├── pdb-unhealthy-pod-eviction-policy.yaml
│ ├── privilege-escalation-container.yml
│ ├── privileged-container.yml
│ ├── privileged-ports.yml
│ ├── read-secret-from-env-var.yml
│ ├── readiness-port.yml
│ ├── required-annotation-email.yml
│ ├── required-label-owner.yml
│ ├── restart-policy.yaml
│ ├── run-as-non-root.yml
│ ├── scc-deny-privileged-container.yml
│ ├── sensitive-host-mounts.yml
│ ├── ssh-port.yml
│ ├── startup-port.yml
│ ├── unsafe-proc-mount.yml
│ ├── unsafe-sysctls.yml
│ ├── unset-cpu-requirements.yml
│ ├── unset-memory-requirements.yml
│ ├── use-namespace.yml
│ ├── wildcard-in-rules.yml
│ └── writable-host-mount.yml
└── testdata
│ ├── mychart-0.1.0.tgz
│ ├── mychart
│ ├── .helmignore
│ ├── Chart.lock
│ ├── Chart.yaml
│ ├── charts
│ │ └── subchart-0.1.0.tgz
│ ├── templates
│ │ ├── NOTES.txt
│ │ ├── _helpers.tpl
│ │ ├── deployment.yaml
│ │ ├── hpa.yaml
│ │ ├── ingress.yaml
│ │ ├── service.yaml
│ │ ├── serviceaccount.yaml
│ │ └── tests
│ │ │ └── test-connection.yaml
│ └── values.yaml
│ ├── splunk.yaml
│ └── subchart
│ ├── .helmignore
│ ├── Chart.yaml
│ ├── templates
│ └── deployment.yaml
│ └── values.yaml
└── tool-imports
├── empty.go
├── go.mod
├── go.sum
└── tools.go
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @janisz
2 | * @rhybrillou
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: "[BUG]"
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **System info:**
11 | - OS: [e.g. Linux? MaxOS? Windows?]
12 |
13 | **Describe the bug**
14 | A clear and concise description of the bug.
15 |
16 | **To Reproduce**
17 | Steps to reproduce the behavior:
18 |
19 | **Sample YAML input**
20 | If applicable, sample YAML input which reproduces the issue.
21 |
22 | **Expected behavior**
23 | A clear and concise description of what you expected to happen.
24 |
25 | **Screenshots**
26 | If applicable, add screenshots to help explain your problem.
27 |
28 | **Additional context**
29 | Add any other context about the problem here.
30 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: "[FEATURE_REQUEST]"
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Description of the problem/feature request**
11 | A clear and concise description of the problem, or the proposed new feature.
12 |
13 | **Description of the existing behavior vs. expected behavior**
14 | If applicable, please paste in the existing KubeLinter output along with the input used, and point out which part should be modified (expected output).
15 |
16 | **Additional context**
17 | Add any other context or screenshots about the feature request here.
18 |
--------------------------------------------------------------------------------
/.github/dependabot.yaml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions"
4 | directory: "/"
5 | open-pull-requests-limit: 3
6 | reviewers:
7 | - "janisz"
8 | schedule:
9 | interval: 'weekly'
10 | day: 'wednesday'
11 | - package-ecosystem: 'gomod'
12 | directory: '/'
13 | schedule:
14 | interval: 'weekly'
15 | day: 'wednesday'
16 | open-pull-requests-limit: 3
17 | reviewers:
18 | - "janisz"
19 | groups:
20 | k8s.io:
21 | patterns:
22 | - "k8s.io/*"
23 | - package-ecosystem: 'gomod'
24 | directory: 'tool-imports'
25 | schedule:
26 | interval: 'weekly'
27 | day: 'wednesday'
28 | open-pull-requests-limit: 3
29 | reviewers:
30 | - "janisz"
31 |
--------------------------------------------------------------------------------
/.github/release.yml:
--------------------------------------------------------------------------------
1 | changelog:
2 | categories:
3 | - title: "✔️ New checks"
4 | labels:
5 | - "new-check"
6 | - title: "🚀 Features"
7 | labels:
8 | - "feature"
9 | - "enhancement"
10 | - title: "🐛 Bug Fixes"
11 | labels:
12 | - "fix"
13 | - "bugfix"
14 | - "bug"
15 | - title: "🧰 Maintenance"
16 | labels:
17 | - "chore"
18 | - title: Other Changes
19 | labels:
20 | - '*'
21 | - title: '⬆️ Dependencies'
22 | labels:
23 | - 'dependencies'
24 |
--------------------------------------------------------------------------------
/.github/workflows/auto-merge.yaml:
--------------------------------------------------------------------------------
1 | name: auto-merge
2 |
3 | on:
4 | pull_request_target:
5 |
6 | jobs:
7 | auto-merge:
8 | runs-on: ubuntu-latest
9 | if: github.actor == 'dependabot[bot]'
10 | steps:
11 | - uses: ahmadnassri/action-dependabot-auto-merge@v2.6
12 | with:
13 | github-token: '${{ secrets.RHACS_BOT_GITHUB_TOKEN }}'
14 | command: "squash and merge"
15 | approve: true
16 | target: minor
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Settings files for JetBrains IDEs
2 | /.idea
3 |
4 | # Vim swap files
5 | *.swp
6 |
7 | # Project-specific $GOBIN
8 | /.gobin
9 |
10 | # Empty file touched by `make deps`
11 | /deps
12 |
13 | e2etests/test_helper
14 | dist/
15 | coverage.out
16 |
--------------------------------------------------------------------------------
/.pre-commit-hooks.yaml:
--------------------------------------------------------------------------------
1 | - id: kube-linter
2 | name: KubeLinter
3 | description: This hook installs (using Go) and runs the KubeLinter utility to lint Helm charts and Kubernetes YAML files.
4 | entry: kube-linter lint
5 | language: golang
6 | types: [yaml]
7 |
8 | - id: kube-linter-system
9 | name: KubeLinter System
10 | description: This hook runs the KubeLinter utility that exists already on the system to lint Helm charts and Kubernetes YAML files.
11 | entry: kube-linter lint
12 | language: system
13 | types: [yaml]
14 |
15 | - id: kube-linter-docker
16 | name: KubeLinter Docker
17 | description: This hook runs kube-linter using the project's official docker image
18 | language: docker_image
19 | types: [yaml]
20 | entry: stackrox/kube-linter:v0.6.4 lint
21 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing to KubeLinter
2 |
3 | Thank you for your interest in contributing to KubeLinter!
4 |
5 | ### Code Contributions
6 |
7 | We welcome code contributions from the community. Anyone is welcome to create a pull request,
8 | and request a review from any of the project maintainers.
9 |
10 | By default, your pull requests should be linked to an [issue](https://github.com/stackrox/kube-linter/issues).
11 | If you're addressing an existing issue, great! If your change is unrelated to an existing issue,
12 | please file an issue first, and make sure you get buy-in from the maintainers.
13 |
14 | However, if your change is relatively trivial (say, a documentation update, or a simple bugfix),
15 | feel free to directly create a pull request, and explain your changes in the pull request.
16 |
17 | ### Feature Requests and Bug Reports
18 |
19 | If you find a bug, or have a request for a feature,
20 | please [create a GitHub issue](https://github.com/stackrox/kube-linter/issues/new/choose).
21 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Reporting a vulnerability
2 |
3 | If you've found a security issue that you'd like to disclose confidentially please contact [Red Hat's Product Security team](https://access.redhat.com/security/team/contact).
4 |
--------------------------------------------------------------------------------
/cmd/kube-linter/kube-linter.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "os"
6 |
7 | "golang.stackrox.io/kube-linter/pkg/command/root"
8 | // Register templates
9 | _ "golang.stackrox.io/kube-linter/pkg/templates/all"
10 | )
11 |
12 | func main() {
13 | c := root.Command()
14 | if err := c.Execute(); err != nil {
15 | fmt.Fprintf(os.Stderr, "Error: %v\n", err)
16 | os.Exit(1)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/config.yaml.example:
--------------------------------------------------------------------------------
1 | # customChecks defines custom checks.
2 | customChecks:
3 | - name: "required-label-app"
4 | template: "required-label"
5 | params:
6 | key: "app"
7 | checks:
8 | # if doNotAutoAddDefaults is true, default checks are not automatically added.
9 | doNotAutoAddDefaults: false
10 |
11 | # addAllBuiltIn, if set, adds all built-in checks. This allows users to
12 | # explicitly opt-out of checks that are not relevant using Exclude.
13 | # Takes precedence over doNotAutoAddDefaults, if both are set.
14 | addAllBuiltIn: false
15 |
16 | # include explicitly adds checks, by name. You can reference any of the built-in checks.
17 | # Note that customChecks defined above are included automatically.
18 | include:
19 | - "required-label-owner"
20 | # exclude explicitly excludes checks, by name. exclude has the highest priority: if a check is
21 | # in exclude, then it is not considered, even if it is in include as well.
22 | exclude:
23 | - "privileged"
24 |
--------------------------------------------------------------------------------
/docs/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stackrox/kube-linter/e3a413f1435f6c1b4debd181c794ca0706e42660/docs/.nojekyll
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | docs.kubelinter.io
--------------------------------------------------------------------------------
/docs/_coverpage.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | > Static analysis for Kubernetes YAML files and Helm charts.
4 |
5 |
6 |
7 | [GitHub](https://github.com/stackrox/kube-linter)
8 | [Get Started](README)
--------------------------------------------------------------------------------
/docs/_navbar.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/stackrox/kube-linter)
--------------------------------------------------------------------------------
/docs/_sidebar.md:
--------------------------------------------------------------------------------
1 | * [Introduction](/)
2 | * [Using KubeLinter](/using-kubelinter.md)
3 | * [Configuring KubeLinter](/configuring-kubelinter.md)
4 | * [KubeLinter checks](/generated/checks.md)
5 | * [KubeLinter templates](/generated/templates.md)
--------------------------------------------------------------------------------
/e2etests/bats-support-clone.bash:
--------------------------------------------------------------------------------
1 | if [[ ! -d "e2etests/test_helper/bats-support" ]]; then
2 | # Download bats-support dynamically so it doesnt need to be added into source
3 | git clone https://github.com/ztombol/bats-support e2etests/test_helper/bats-support --depth 1
4 | fi
5 |
6 | if [[ ! -d "e2etests/test_helper/redhatcop-bats-library" ]]; then
7 | # Download redhat-cop/bats-library dynamically so it doesnt need to be added into source
8 | git clone https://github.com/redhat-cop/bats-library e2etests/test_helper/redhatcop-bats-library --depth 1
9 | fi
--------------------------------------------------------------------------------
/e2etests/check-bats-tests.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | run() {
4 | local tmp_write_dir=/tmp/kubelinter/$(date +'%d-%m-%Y-%H-%M')
5 | mkdir -p "${tmp_write_dir}"
6 |
7 | grep "@test" e2etests/bats-tests.sh | grep -v 'flag-' | grep -v 'template-' | cut -d'"' -f2 > ${tmp_write_dir}/batstests.log
8 | ${KUBE_LINTER_BIN:-kube-linter} checks list --format json | jq -r '.[].name' > ${tmp_write_dir}/kubelinterchecks.log
9 | diff -c ${tmp_write_dir}/kubelinterchecks.log ${tmp_write_dir}/batstests.log || { echo >&2 "ERROR: The output of '${KUBE_LINTER_BIN} checks list' differs from the tests in 'e2etests/bats-tests.sh'. See above diff."; exit 1; }
10 | }
11 |
12 | run
13 |
--------------------------------------------------------------------------------
/e2etests/empty.go:
--------------------------------------------------------------------------------
1 | package e2etests
2 |
3 | // Empty file with no build tag to keep the Go compiler happy.
4 |
--------------------------------------------------------------------------------
/e2etests/testdata/all-built-in-config.yaml:
--------------------------------------------------------------------------------
1 | checks:
2 | addAllBuiltIn: true
3 |
--------------------------------------------------------------------------------
/e2etests/testdata/forbidden-annotation-config.yaml:
--------------------------------------------------------------------------------
1 | checks:
2 | addAllBuiltIn: false
3 | customChecks:
4 | - name: "forbid-annotation-reloader-stakater-auto"
5 | description: ""
6 | remediation: "Remove reloader.stakater.com/auto annotation"
7 | scope:
8 | objectKinds:
9 | - DeploymentLike
10 | template: "forbidden-annotation"
11 | params:
12 | key: "reloader.stakater.com/auto"
13 | value: 'true'
14 | - name: invalid-irsa-role
15 | description: "IRSA annotations must have a valid IAM Role ARN value"
16 | remediation: "Validate the format of the annotation's value to ensure it is a valid IAM Role ARN"
17 | scope:
18 | objectKinds:
19 | - ServiceAccount
20 | template: "forbidden-annotation"
21 | params:
22 | key: "eks.amazonaws.com/role-arn"
23 | value: |
24 | !arn:aws:iam::\d{12}:role\/[\w+=,.@-]{1,64}$
--------------------------------------------------------------------------------
/image/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM scratch
2 |
3 | COPY kube-linter /
4 |
5 | ENTRYPOINT ["/kube-linter"]
6 |
--------------------------------------------------------------------------------
/image/Dockerfile_alpine:
--------------------------------------------------------------------------------
1 | FROM alpine:latest
2 |
3 | COPY kube-linter /
4 |
5 | ENTRYPOINT ["/kube-linter"]
6 |
--------------------------------------------------------------------------------
/image/bin/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/images/logo/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stackrox/kube-linter/e3a413f1435f6c1b4debd181c794ca0706e42660/images/logo/favicon.ico
--------------------------------------------------------------------------------
/internal/consts/consts.go:
--------------------------------------------------------------------------------
1 | package consts
2 |
3 | const (
4 | // ProgramName is for displaying help, etc.
5 | ProgramName = "kube-linter"
6 | // MainURL is where the project info can be found.
7 | MainURL = "https://github.com/stackrox/kube-linter"
8 | // TemplateURLFormat when formatted with template id, provides help link for the given template.
9 | TemplateURLFormat = "https://docs.kubelinter.io/#/generated/templates?id=%s"
10 | )
11 |
--------------------------------------------------------------------------------
/internal/defaultchecks/default_checks.go:
--------------------------------------------------------------------------------
1 | package defaultchecks
2 |
3 | import (
4 | "golang.stackrox.io/kube-linter/internal/set"
5 | )
6 |
7 | var (
8 | // List is the list of built-in checks that are enabled by default.
9 | List = set.NewFrozenStringSet(
10 | "dangling-service",
11 | "deprecated-service-account-field",
12 | "docker-sock",
13 | "drop-net-raw-capability",
14 | "duplicate-env-var",
15 | "env-var-secret",
16 | "host-ipc",
17 | "host-network",
18 | "host-pid",
19 | "invalid-target-ports",
20 | "latest-tag",
21 | "liveness-port",
22 | "mismatching-selector",
23 | "no-anti-affinity",
24 | "no-extensions-v1beta",
25 | "no-read-only-root-fs",
26 | "non-existent-service-account",
27 | "pdb-max-unavailable",
28 | "pdb-min-available",
29 | "privilege-escalation-container",
30 | "privileged-container",
31 | "readiness-port",
32 | "run-as-non-root",
33 | "sensitive-host-mounts",
34 | "ssh-port",
35 | "startup-port",
36 | "unsafe-sysctls",
37 | "unset-cpu-requirements",
38 | "unset-memory-requirements",
39 | "pdb-unhealthy-pod-eviction-policy",
40 | )
41 | )
42 |
--------------------------------------------------------------------------------
/internal/defaultchecks/default_test.go:
--------------------------------------------------------------------------------
1 | package defaultchecks
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/assert"
7 | "github.com/stretchr/testify/require"
8 | "golang.stackrox.io/kube-linter/internal/set"
9 | "golang.stackrox.io/kube-linter/pkg/builtinchecks"
10 | )
11 |
12 | func TestListReferencesOnlyValidChecks(t *testing.T) {
13 | allChecks, err := builtinchecks.List()
14 | require.NoError(t, err)
15 | allCheckNames := set.NewStringSet()
16 | for _, check := range allChecks {
17 | allCheckNames.Add(check.Name)
18 | }
19 | for _, defaultCheck := range List.AsSlice() {
20 | assert.True(t, allCheckNames.Contains(defaultCheck), "default check %s invalid", defaultCheck)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/internal/pointers/pointers.go:
--------------------------------------------------------------------------------
1 | package pointers
2 |
3 | // Bool returns a pointer to a bool.
4 | func Bool(b bool) *bool {
5 | return &b
6 | }
7 |
8 | // Int32 returns a pointer to an int32.
9 | func Int32(i int32) *int32 {
10 | return &i
11 | }
12 |
13 | // Int64 returns a pointer to an int64.
14 | func Int64(i int64) *int64 {
15 | return &i
16 | }
17 |
18 | // Int returns a pointer to an int.
19 | func Int(i int) *int {
20 | return &i
21 | }
22 |
--------------------------------------------------------------------------------
/internal/stringutils/consume.go:
--------------------------------------------------------------------------------
1 | package stringutils
2 |
3 | import "strings"
4 |
5 | // ConsumePrefix checks if *s has the given prefix, and if yes, modifies it
6 | // to remove the prefix. The return value indicates whether the original string
7 | // had the given prefix.
8 | func ConsumePrefix(s *string, prefix string) bool {
9 | orig := *s
10 | if !strings.HasPrefix(orig, prefix) {
11 | return false
12 | }
13 | *s = orig[len(prefix):]
14 | return true
15 | }
16 |
17 | // ConsumeSuffix checks if *s has the given suffix, and if yes, modifies it
18 | // to remove the suffix. The return value indicates whether the original string
19 | // had the given suffix.
20 | func ConsumeSuffix(s *string, suffix string) bool {
21 | orig := *s
22 | if !strings.HasSuffix(orig, suffix) {
23 | return false
24 | }
25 | *s = orig[:len(orig)-len(suffix)]
26 | return true
27 | }
28 |
--------------------------------------------------------------------------------
/internal/stringutils/default.go:
--------------------------------------------------------------------------------
1 | package stringutils
2 |
3 | // OrDefault returns the string if it's not empty, or the default.
4 | func OrDefault(s, defaultValue string) string {
5 | if s != "" {
6 | return s
7 | }
8 | return defaultValue
9 | }
10 |
11 | // PointerOrDefault returns the string if it's not nil nor empty, or the default.
12 | func PointerOrDefault(s *string, defaultValue string) string {
13 | if s == nil {
14 | return defaultValue
15 | }
16 |
17 | return OrDefault(*s, defaultValue)
18 | }
19 |
--------------------------------------------------------------------------------
/internal/stringutils/repeat.go:
--------------------------------------------------------------------------------
1 | package stringutils
2 |
3 | import (
4 | "strings"
5 | )
6 |
7 | // Repeat repeats the given string `n` times efficiently.
8 | func Repeat(s string, n int) string {
9 | var sb strings.Builder
10 | sb.Grow(len([]byte(s)) * n)
11 | for i := 0; i < n; i++ {
12 | sb.WriteString(s)
13 | }
14 | return sb.String()
15 | }
16 |
--------------------------------------------------------------------------------
/internal/stringutils/split.go:
--------------------------------------------------------------------------------
1 | package stringutils
2 |
3 | import (
4 | "strings"
5 | )
6 |
7 | // Split2 splits the given string at the given separator, returning the part before and after the separator as two
8 | // separate return values.
9 | // If the string does not contain `sep`, the entire string is returned as the first return value.
10 | func Split2(str, sep string) (string, string) {
11 | splitIdx := strings.Index(str, sep)
12 | if splitIdx == -1 {
13 | return str, ""
14 | }
15 | return str[:splitIdx], str[splitIdx+len(sep):]
16 | }
17 |
--------------------------------------------------------------------------------
/internal/stringutils/ternary.go:
--------------------------------------------------------------------------------
1 | package stringutils
2 |
3 | // Ternary does a ternary based on the condition.
4 | func Ternary(condition bool, ifTrue, ifFalse string) string {
5 | if condition {
6 | return ifTrue
7 | }
8 | return ifFalse
9 | }
10 |
--------------------------------------------------------------------------------
/internal/utils/ignore_error.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | // IgnoreError is useful when you want to defer a func that returns an error,
4 | // but ignore the error without having the linter complain.
5 | func IgnoreError(f func() error) {
6 | _ = f()
7 | }
8 |
--------------------------------------------------------------------------------
/internal/utils/must.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | // Must panics if any of the errors are not nil.
4 | // It is intended for use in cases where an error returned would
5 | // mean a programming error.
6 | func Must(errs ...error) {
7 | for _, err := range errs {
8 | if err != nil {
9 | panic(err)
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/internal/version/version.go:
--------------------------------------------------------------------------------
1 | package version
2 |
3 | import (
4 | "golang.stackrox.io/kube-linter/internal/stringutils"
5 | )
6 |
7 | var (
8 | version string //XDef:VERSION
9 | )
10 |
11 | // Get returns the version.
12 | func Get() string {
13 | return stringutils.OrDefault(version, "development")
14 | }
15 |
--------------------------------------------------------------------------------
/kubelinter-cosign.pub:
--------------------------------------------------------------------------------
1 | -----BEGIN PUBLIC KEY-----
2 | MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEl0HCkCRzYv0qH5QiazoXeXe2qwFX
3 | DmAszeH26g1s3OSsG/focPWkN88wEKQ5eiE95v+Z2snUQPl/mjPdvqpyjA==
4 | -----END PUBLIC KEY-----
--------------------------------------------------------------------------------
/pkg/builtinchecks/built_in_checks_test.go:
--------------------------------------------------------------------------------
1 | package builtinchecks
2 |
3 | import (
4 | "strings"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/assert"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func TestBuiltInChecksWellFormed(t *testing.T) {
12 | checks, err := List()
13 | require.NoError(t, err)
14 | for _, check := range checks {
15 | t.Run(check.Name, func(t *testing.T) {
16 | assert.NotEmpty(t, check.Remediation, "Please add remediation")
17 | assert.True(t, strings.HasSuffix(check.Remediation, "."), "Please end your remediation texts with a period (got %q)", check.Remediation)
18 | })
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/access-to-create-pods.yaml:
--------------------------------------------------------------------------------
1 | name: "access-to-create-pods"
2 | description: >-
3 | Indicates when a subject (Group/User/ServiceAccount) has create access to Pods.
4 | CIS Benchmark 5.1.4: The ability to create pods in a cluster opens up possibilities for privilege escalation and should be restricted, where possible.
5 | remediation: "Where possible, remove create access to pod objects in the cluster."
6 | scope:
7 | objectKinds:
8 | - ClusterRoleBinding
9 | - RoleBinding
10 | template: "access-to-resources"
11 | params:
12 | resources: ["^pods$", "^deployments$", "^statefulsets$", "^replicasets$", "^cronjob$", "^jobs$","^daemonsets$"]
13 | verbs: ["^create$"]
14 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/access-to-secrets.yaml:
--------------------------------------------------------------------------------
1 | name: "access-to-secrets"
2 | description: >-
3 | Indicates when a subject (Group/User/ServiceAccount) has access to Secrets.
4 | CIS Benchmark 5.1.2: Access to secrets should be restricted to the smallest possible group of users to reduce the risk of privilege escalation.
5 | remediation: "Where possible, remove get, list and watch access to secret objects in the cluster."
6 | scope:
7 | objectKinds:
8 | - ClusterRoleBinding
9 | - RoleBinding
10 | template: "access-to-resources"
11 | params:
12 | resources: ["^secrets$"]
13 | verbs: ["^get$", "^list$", "^delete$", "^create$", "^watch$", "^*$"]
14 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/cluster-admin-role-binding.yaml:
--------------------------------------------------------------------------------
1 | name: "cluster-admin-role-binding"
2 | description: "CIS Benchmark 5.1.1 Ensure that the cluster-admin role is only used where required"
3 | remediation: "Create and assign a separate role that has access to specific resources/actions needed for the service account."
4 | scope:
5 | objectKinds:
6 | - ClusterRoleBinding
7 | template: "cluster-admin-role-binding"
8 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/dangling-horizontalpodautoscaler.yaml:
--------------------------------------------------------------------------------
1 | name: "dangling-horizontalpodautoscaler"
2 | description: "Indicates when HorizontalPodAutoscalers target a missing resource."
3 | remediation: "Confirm that your HorizontalPodAutoscaler's scaleTargetRef correctly matches one of your deployments."
4 | scope:
5 | objectKinds:
6 | - HorizontalPodAutoscaler
7 | template: "dangling-horizontalpodautoscaler"
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/dangling-ingress.yaml:
--------------------------------------------------------------------------------
1 | name: "dangling-ingress"
2 | description: "Indicates when ingress do not have any associated services."
3 | remediation: "Confirm that your ingress's backend correctly matches the name and port on one of your services."
4 | scope:
5 | objectKinds:
6 | - Ingress
7 | template: "dangling-ingress"
8 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/dangling-networkpolicy.yaml:
--------------------------------------------------------------------------------
1 | name: "dangling-networkpolicy"
2 | description: "Indicates when networkpolicies do not have any associated deployments."
3 | remediation: "Confirm that your networkPolicy's podselector correctly matches the labels on one of your deployments."
4 | scope:
5 | objectKinds:
6 | - NetworkPolicy
7 | template: "dangling-networkpolicy"
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/dangling-networkpolicypeer-podselector.yaml:
--------------------------------------------------------------------------------
1 | name: "dangling-networkpolicypeer-podselector"
2 | description: "Indicates when NetworkPolicyPeer in Egress/Ingress rules -in the Spec of NetworkPolicy- do not have any associated deployments. Applied on peer specified with podSelectors only."
3 | remediation: "Confirm that your NetworkPolicy's Ingress/Egress peer's podselector correctly matches the labels on one of your deployments."
4 | scope:
5 | objectKinds:
6 | - NetworkPolicy
7 | template: "dangling-networkpolicypeer-podselector"
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/dangling-service.yaml:
--------------------------------------------------------------------------------
1 | name: "dangling-service"
2 | description: "Indicates when services do not have any associated deployments."
3 | remediation: "Confirm that your service's selector correctly matches the labels on one of your deployments."
4 | scope:
5 | objectKinds:
6 | - Service
7 | template: "dangling-service"
8 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/dangling-servicemonitor.yaml:
--------------------------------------------------------------------------------
1 | name: "dangling-servicemonitor"
2 | description: "Indicates when a service monitor's selectors don't match any service. ServiceMonitors are a custom resource only used by the Prometheus operator (https://prometheus-operator.dev/docs/operator/design/#servicemonitor)."
3 | remediation: "Check selectors and your services."
4 | scope:
5 | objectKinds:
6 | - ServiceMonitor
7 | template: "dangling-servicemonitor"
8 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/default-service-account.yaml:
--------------------------------------------------------------------------------
1 | name: "default-service-account"
2 | description: "Indicates when pods use the default service account."
3 | remediation: >-
4 | Create a dedicated service account for your pod.
5 | Refer to https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ for details.
6 | scope:
7 | objectKinds:
8 | - DeploymentLike
9 | template: "service-account"
10 | params:
11 | serviceAccount: "^(|default)$"
12 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/deprecated-service-account.yaml:
--------------------------------------------------------------------------------
1 | name: "deprecated-service-account-field"
2 | description: "Indicates when deployments use the deprecated serviceAccount field."
3 | remediation: "Use the serviceAccountName field instead. If you must specify serviceAccount, ensure values for serviceAccount and serviceAccountName match."
4 | scope:
5 | objectKinds:
6 | - DeploymentLike
7 | template: "deprecated-service-account-field"
8 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/dnsconfig-options.yaml:
--------------------------------------------------------------------------------
1 | name: "dnsconfig-options"
2 | description: "Alert on deployments that have no specified dnsConfig options"
3 | remediation: >-
4 | Specify dnsconfig options in your Pod specification to ensure the expected DNS setting on the Pod.
5 | Refer to https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config for details.
6 | scope:
7 | objectKinds:
8 | - DeploymentLike
9 | template: "dnsconfig-options"
10 | params:
11 | Key: ndots
12 | Value: "2"
13 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/docker-sock.yaml:
--------------------------------------------------------------------------------
1 | name: "docker-sock"
2 | description: "Alert on deployments with docker.sock mounted in containers. "
3 | remediation: >-
4 | Ensure the Docker socket is not mounted inside any containers by removing the associated
5 | Volume and VolumeMount in deployment yaml specification.
6 | If the Docker socket is mounted inside a container it could allow processes running within
7 | the container to execute Docker commands which would effectively allow for full control of the host.
8 |
9 | scope:
10 | objectKinds:
11 | - DeploymentLike
12 | template: "host-mounts"
13 | params:
14 | dirs: ["docker.sock$"]
15 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/drop-net-raw-capability.yaml:
--------------------------------------------------------------------------------
1 | name: "drop-net-raw-capability"
2 | description: "Indicates when containers do not drop NET_RAW capability"
3 | remediation: >-
4 | NET_RAW makes it so that an application within the container is able to craft raw packets,
5 | use raw sockets, and bind to any address. Remove this capability in the containers under
6 | containers security contexts.
7 | scope:
8 | objectKinds:
9 | - DeploymentLike
10 | template: "verify-container-capabilities"
11 | params:
12 | forbiddenCapabilities: ["NET_RAW"]
13 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/duplicate-env-var.yaml:
--------------------------------------------------------------------------------
1 | name: "duplicate-env-var"
2 | description: "Check that duplicate named env vars aren't passed to a deployment like."
3 | remediation: "Confirm that your DeploymentLike doesn't have duplicate env vars names."
4 | scope:
5 | objectKinds:
6 | - DeploymentLike
7 | template: "duplicate-env-var"
8 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/env-var-secret.yaml:
--------------------------------------------------------------------------------
1 | name: "env-var-secret"
2 | description: "Indicates when objects use a secret in an environment variable."
3 | remediation: >-
4 | Do not use raw secrets in environment variables. Instead, either mount the secret as a file or use a secretKeyRef.
5 | Refer to https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets for details.
6 | scope:
7 | objectKinds:
8 | - DeploymentLike
9 | template: "env-var"
10 | params:
11 | name: "(?i).*secret.*"
12 | value: ".+"
13 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/host-mounts.yaml:
--------------------------------------------------------------------------------
1 | name: "sensitive-host-mounts"
2 | description: "Alert on deployments with sensitive host system directories mounted in containers"
3 | remediation: "Ensure sensitive host system directories are not mounted in containers by removing those Volumes and VolumeMounts."
4 | scope:
5 | objectKinds:
6 | - DeploymentLike
7 | template: "host-mounts"
8 | params:
9 | dirs: ["^/$", "^/boot$", "^/dev$", "^/etc$", "^/lib$", "^/proc$", "^/sys$", "^/usr$"]
10 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/hostipc.yaml:
--------------------------------------------------------------------------------
1 | name: "host-ipc"
2 | description: "Alert on pods/deployment-likes with sharing host's IPC namespace"
3 | remediation: "Ensure the host's IPC namespace is not shared."
4 | scope:
5 | objectKinds:
6 | - DeploymentLike
7 | template: "host-ipc"
8 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/hostnetwork.yaml:
--------------------------------------------------------------------------------
1 | name: "host-network"
2 | description: "Alert on pods/deployment-likes with sharing host's network namespace"
3 | remediation: "Ensure the host's network namespace is not shared."
4 | scope:
5 | objectKinds:
6 | - DeploymentLike
7 | template: "host-network"
8 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/hostpid.yaml:
--------------------------------------------------------------------------------
1 | name: "host-pid"
2 | description: "Alert on pods/deployment-likes with sharing host's process namespace"
3 | remediation: "Ensure the host's process namespace is not shared."
4 | scope:
5 | objectKinds:
6 | - DeploymentLike
7 | template: "host-pid"
8 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/hpa-minimum-replicas.yaml:
--------------------------------------------------------------------------------
1 | name: "hpa-minimum-three-replicas"
2 | description: "Indicates when a HorizontalPodAutoscaler specifies less than three minReplicas"
3 | remediation: >-
4 | Increase the number of replicas in the HorizontalPodAutoscaler to at least three to increase fault tolerance.
5 | scope:
6 | objectKinds:
7 | - HorizontalPodAutoscaler
8 | template: "hpa-minimum-replicas"
9 | params:
10 | minReplicas: 3
11 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/invalid-target-ports.yaml:
--------------------------------------------------------------------------------
1 | name: "invalid-target-ports"
2 | description: "Indicates when deployments or services are using port names that are violating specifications."
3 | remediation: >-
4 | Ensure that port naming is in conjunction with the specification. For more information,
5 | please look at the Kubernetes Service specification on this page:
6 | https://kubernetes.io/docs/reference/_print/#ServiceSpec. And additional information
7 | about IANA Service naming can be found on the following page:
8 | https://www.rfc-editor.org/rfc/rfc6335.html#section-5.1.
9 | scope:
10 | objectKinds:
11 | - DeploymentLike
12 | - Service
13 | template: "target-port"
14 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/latest-tag.yaml:
--------------------------------------------------------------------------------
1 | name: "latest-tag"
2 | description: "Indicates when a deployment-like object is running a container with an invalid container image"
3 | remediation: "Use a container image with a specific tag other than latest."
4 | scope:
5 | objectKinds:
6 | - DeploymentLike
7 | template: "latest-tag"
8 | params:
9 | BlockList: [".*:(latest)$", "^[^:]*$", "(.*/[^:]+)$"]
10 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/liveness-port.yaml:
--------------------------------------------------------------------------------
1 | name: "liveness-port"
2 | description: "Indicates when containers have a liveness probe to a not exposed port."
3 | remediation: >-
4 | Check which ports you've exposed and ensure they match what you have specified
5 | in the liveness probe.
6 | scope:
7 | objectKinds:
8 | - DeploymentLike
9 | template: "liveness-port"
10 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/minimum-replicas.yaml:
--------------------------------------------------------------------------------
1 | name: "minimum-three-replicas"
2 | description: "Indicates when a deployment uses less than three replicas"
3 | remediation: >-
4 | Increase the number of replicas in the deployment to at least three to increase the fault tolerance of the deployment.
5 | scope:
6 | objectKinds:
7 | - DeploymentLike
8 | template: "minimum-replicas"
9 | params:
10 | minReplicas: 3
11 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/mismatching-selector.yaml:
--------------------------------------------------------------------------------
1 | name: "mismatching-selector"
2 | description: "Indicates when deployment selectors fail to match the pod template labels."
3 | remediation: "Confirm that your deployment selector correctly matches the labels in its pod template."
4 | scope:
5 | objectKinds:
6 | - DeploymentLike
7 | template: "mismatching-selector"
8 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/no-anti-affinity.yaml:
--------------------------------------------------------------------------------
1 | name: "no-anti-affinity"
2 | description: "Indicates when deployments with multiple replicas fail to specify inter-pod anti-affinity, to ensure that the orchestrator attempts to schedule replicas on different nodes."
3 | remediation: >-
4 | Specify anti-affinity in your pod specification to ensure that the orchestrator attempts to schedule replicas on different nodes.
5 | Using podAntiAffinity, specify a labelSelector that matches pods for the deployment,
6 | and set the topologyKey to kubernetes.io/hostname.
7 | Refer to https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity for details.
8 | scope:
9 | objectKinds:
10 | - DeploymentLike
11 | template: "anti-affinity"
12 | params:
13 | minReplicas: 2
14 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/no-extensions-v1beta.yaml:
--------------------------------------------------------------------------------
1 | name: "no-extensions-v1beta"
2 | description: "Indicates when objects use deprecated API versions under extensions/v1beta."
3 | remediation: >-
4 | Migrate using the apps/v1 API versions for the objects.
5 | Refer to https://kubernetes.io/blog/2019/07/18/api-deprecations-in-1-16/ for details.
6 | scope:
7 | objectKinds:
8 | - Any
9 | template: "disallowed-api-obj"
10 | params:
11 | group: "extensions"
12 | version: "v1beta.+"
13 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/no-liveness-probe.yaml:
--------------------------------------------------------------------------------
1 | name: "no-liveness-probe"
2 | description: "Indicates when containers fail to specify a liveness probe."
3 | remediation: >-
4 | Specify a liveness probe in your container.
5 | Refer to https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ for details.
6 | scope:
7 | objectKinds:
8 | - DeploymentLike
9 | template: "liveness-probe"
10 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/no-node-affinity.yaml:
--------------------------------------------------------------------------------
1 | name: "no-node-affinity"
2 | description: "Alert on deployments that have no node affinity defined"
3 | remediation: >-
4 | Specify node-affinity in your pod specification to ensure that the orchestrator attempts to schedule replicas on specified nodes.
5 | Refer to https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity for details.
6 | scope:
7 | objectKinds:
8 | - DeploymentLike
9 | template: "no-node-affinity"
10 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/no-readiness-probe.yaml:
--------------------------------------------------------------------------------
1 | name: "no-readiness-probe"
2 | description: "Indicates when containers fail to specify a readiness probe."
3 | remediation: >-
4 | Specify a readiness probe in your container.
5 | Refer to https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ for details.
6 | scope:
7 | objectKinds:
8 | - DeploymentLike
9 | template: "readiness-probe"
10 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/no-rolling-update-strategy.yaml:
--------------------------------------------------------------------------------
1 | name: "no-rolling-update-strategy"
2 | description: "Indicates when a deployment doesn't use a rolling update strategy"
3 | remediation: >-
4 | Use a rolling update strategy to avoid service disruption during an update.
5 | A rolling update strategy allows for pods to be systematicaly replaced in a
6 | controlled fashion to ensure no service disruption.
7 | scope:
8 | objectKinds:
9 | - DeploymentLike
10 | template: "update-configuration"
11 | params:
12 | strategyTypeRegex: "^(RollingUpdate|Rolling)$"
13 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/non-existent-service-account.yaml:
--------------------------------------------------------------------------------
1 | name: "non-existent-service-account"
2 | description: "Indicates when pods reference a service account that is not found."
3 | remediation: "Create the missing service account, or refer to an existing service account."
4 | scope:
5 | objectKinds:
6 | - DeploymentLike
7 | template: "non-existent-service-account"
8 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/non-isolated-pod.yaml:
--------------------------------------------------------------------------------
1 | name: "non-isolated-pod"
2 | description: "Alert on deployment-like objects that are not selected by any NetworkPolicy."
3 | remediation: "Ensure pod does not accept unsafe traffic by isolating it with a NetworkPolicy. See https://cloud.redhat.com/blog/guide-to-kubernetes-ingress-network-policies for more details."
4 | scope:
5 | objectKinds:
6 | - DeploymentLike
7 | template: "non-isolated-pod"
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/pdb-unhealthy-pod-eviction-policy.yaml:
--------------------------------------------------------------------------------
1 | name: "pdb-unhealthy-pod-eviction-policy"
2 | description: "Indicates when a PodDisruptionBudget does not explicitly set the unhealthyPodEvictionPolicy field."
3 | remediation: "Set unhealthyPodEvictionPolicy to AlwaysAllow. Refer to https://kubernetes.io/docs/tasks/run-application/configure-pdb/#unhealthy-pod-eviction-policy for more information."
4 | scope:
5 | objectKinds:
6 | - PodDisruptionBudget
7 | template: "pdb-unhealthy-pod-eviction-policy"
8 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/pdbs-max-unavailable.yaml:
--------------------------------------------------------------------------------
1 | name: "pdb-max-unavailable"
2 | description: "Indicates when a PodDisruptionBudget has a maxUnavailable value that will always prevent disruptions of pods created by related deployment-like objects."
3 | remediation: "Change the PodDisruptionBudget to have maxUnavailable set to a value greater than 0. Refer to https://kubernetes.io/docs/tasks/run-application/configure-pdb/ for more information."
4 | scope:
5 | objectKinds:
6 | - PodDisruptionBudget
7 | template: "pdb-max-unavailable"
8 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/pdbs-min-available.yaml:
--------------------------------------------------------------------------------
1 | name: "pdb-min-available"
2 | description: "Indicates when a PodDisruptionBudget sets a minAvailable value that will always prevent disruptions of pods created by related deployment-like objects."
3 | remediation: "Change the PodDisruptionBudget to have minAvailable set to a number lower than the number of replicas in the related deployment-like objects. Refer to https://kubernetes.io/docs/tasks/run-application/configure-pdb/ for more information."
4 | scope:
5 | objectKinds:
6 | - PodDisruptionBudget
7 | template: "pdb-min-available"
8 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/privilege-escalation.yaml:
--------------------------------------------------------------------------------
1 | name: "privilege-escalation-container"
2 | description: "Alert on containers of allowing privilege escalation that could gain more privileges than its parent process."
3 | remediation: >-
4 | Ensure containers do not allow privilege escalation by setting
5 | allowPrivilegeEscalation=false, privileged=false and removing CAP_SYS_ADMIN capability.
6 | See https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ for more details.
7 | scope:
8 | objectKinds:
9 | - DeploymentLike
10 | template: "privilege-escalation-container"
11 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/privileged.yaml:
--------------------------------------------------------------------------------
1 | name: "privileged-container"
2 | description: "Indicates when deployments have containers running in privileged mode."
3 | remediation: "Do not run your container as privileged unless it is required."
4 | scope:
5 | objectKinds:
6 | - DeploymentLike
7 | template: "privileged"
8 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/privilegedports.yaml:
--------------------------------------------------------------------------------
1 | name: "privileged-ports"
2 | description: "Alert on deployments with privileged ports mapped in containers"
3 | remediation: "Ensure privileged ports [0, 1024] are not mapped within containers."
4 | scope:
5 | objectKinds:
6 | - DeploymentLike
7 | template: "privileged-ports"
8 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/read-only-root-fs.yaml:
--------------------------------------------------------------------------------
1 | name: "no-read-only-root-fs"
2 | description: "Indicates when containers are running without a read-only root filesystem."
3 | remediation: "Set readOnlyRootFilesystem to true in the container securityContext."
4 | scope:
5 | objectKinds:
6 | - DeploymentLike
7 | template: "read-only-root-fs"
8 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/read-secret-from-env-var.yaml:
--------------------------------------------------------------------------------
1 | name: "read-secret-from-env-var"
2 | description: >-
3 | Indicates when a deployment reads secret from environment variables.
4 | CIS Benchmark 5.4.1: "Prefer using secrets as files over secrets as environment variables. "
5 | remediation: >-
6 | If possible, rewrite application code to read secrets from mounted secret files, rather than from environment variables.
7 | Refer to https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets for details.
8 | scope:
9 | objectKinds:
10 | - DeploymentLike
11 | template: "read-secret-from-env-var"
12 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/readiness-port.yaml:
--------------------------------------------------------------------------------
1 | name: "readiness-port"
2 | description: "Indicates when containers have a readiness probe to a not exposed port."
3 | remediation: >-
4 | Check which ports you've exposed and ensure they match what you have specified
5 | in the readiness probe.
6 | scope:
7 | objectKinds:
8 | - DeploymentLike
9 | template: "readiness-port"
10 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/required-annotation-email.yaml:
--------------------------------------------------------------------------------
1 | name: "required-annotation-email"
2 | description: "Indicates when objects do not have an email annotation with a valid email address."
3 | remediation: "Add an email annotation to your object with the email address of the object's owner."
4 | scope:
5 | objectKinds:
6 | - DeploymentLike
7 | template: "required-annotation"
8 | params:
9 | key: "email"
10 | value: '[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+'
11 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/required-label-owner.yaml:
--------------------------------------------------------------------------------
1 | name: "required-label-owner"
2 | description: "Indicates when objects do not have an email annotation with an owner label."
3 | remediation: "Add an email annotation to your object with the name of the object's owner."
4 | scope:
5 | objectKinds:
6 | - DeploymentLike
7 | template: "required-label"
8 | params:
9 | key: "owner"
10 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/restart-policy.yaml:
--------------------------------------------------------------------------------
1 | name: "restart-policy"
2 | description: "Indicates when a deployment-like object does not use a restart policy"
3 | remediation: >-
4 | Set up the restart policy for your object to 'Always' or 'OnFailure' to increase the fault tolerance.
5 | scope:
6 | objectKinds:
7 | - DeploymentLike
8 | template: "restart-policy"
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/run-as-non-root.yaml:
--------------------------------------------------------------------------------
1 | name: "run-as-non-root"
2 | description: "Indicates when containers are not set to runAsNonRoot."
3 | remediation: >-
4 | Set runAsUser to a non-zero number and runAsNonRoot to true in your pod or container securityContext.
5 | Refer to https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ for details.
6 | scope:
7 | objectKinds:
8 | - DeploymentLike
9 | template: "run-as-non-root"
10 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/scc-deny-privileged-container.yaml:
--------------------------------------------------------------------------------
1 | name: "scc-deny-privileged-container"
2 | description: "Indicates when allowPrivilegedContainer SecurityContextConstraints set to true"
3 | remediation: >-
4 | SecurityContextConstraints has AllowPrivilegedContainer set to "true". Using this option is dangerous, please consider using allowedCapabilities instead. Refer to https://docs.openshift.com/container-platform/4.12/authentication/managing-security-context-constraints.html#scc-settings_configuring-internal-oauth for details.
5 | scope:
6 | objectKinds:
7 | - SecurityContextConstraints
8 | template: "scc-deny-privileged-container"
9 | params:
10 | AllowPrivilegedContainer: true
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/servicetype.yaml:
--------------------------------------------------------------------------------
1 | name: "exposed-services"
2 | description: "Alert on services for forbidden types"
3 | remediation: "Ensure containers are not exposed through a forbidden service type such as NodePort or LoadBalancer."
4 | scope:
5 | objectKinds:
6 | - Service
7 | template: "forbidden-service-types"
8 | params:
9 | forbiddenServiceTypes: ["NodePort", "LoadBalancer"]
10 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/ssh-port.yaml:
--------------------------------------------------------------------------------
1 | name: "ssh-port"
2 | description: "Indicates when deployments expose port 22, which is commonly reserved for SSH access."
3 | remediation: "Ensure that non-SSH services are not using port 22. Confirm that any actual SSH servers have been vetted."
4 | scope:
5 | objectKinds:
6 | - DeploymentLike
7 | template: "ports"
8 | params:
9 | port: 22
10 | protocol: "TCP"
11 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/startup-port.yaml:
--------------------------------------------------------------------------------
1 | name: "startup-port"
2 | description: "Indicates when containers have a startup probe to a not exposed port."
3 | remediation: >-
4 | Check which ports you've exposed and ensure they match what you have specified
5 | in the startup probe.
6 | scope:
7 | objectKinds:
8 | - DeploymentLike
9 | template: "startup-port"
10 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/sysctls.yaml:
--------------------------------------------------------------------------------
1 | name: "unsafe-sysctls"
2 | description: "Alert on deployments specifying unsafe sysctls that may lead to severe problems like wrong behavior of containers"
3 | remediation: >-
4 | Ensure container does not allow unsafe allocation of system resources by removing unsafe sysctls configurations.
5 | For more details see https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/
6 | https://docs.docker.com/engine/reference/commandline/run/#configure-namespaced-kernel-parameters-sysctls-at-runtime.
7 | scope:
8 | objectKinds:
9 | - DeploymentLike
10 | template: "unsafe-sysctls"
11 | params:
12 | unsafeSysCtls: ["kernel.msg", "kernel.sem", "kernel.shm", "fs.mqueue.", "net."]
13 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/unsafe-proc-mount.yaml:
--------------------------------------------------------------------------------
1 | name: "unsafe-proc-mount"
2 | description: "Alert on deployments with unsafe /proc mount (procMount=Unmasked) that will bypass the default masking behavior of the container runtime"
3 | remediation: >-
4 | Ensure container does not unsafely exposes parts of /proc by setting procMount=Default.
5 | Unmasked ProcMount bypasses the default masking behavior of the container runtime.
6 | See https://kubernetes.io/docs/concepts/security/pod-security-standards/ for more details.
7 | scope:
8 | objectKinds:
9 | - DeploymentLike
10 | template: "unsafe-proc-mount"
11 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/unset-cpu-requirements.yaml:
--------------------------------------------------------------------------------
1 | name: "unset-cpu-requirements"
2 | description: "Indicates when containers do not have CPU requests and limits set."
3 | scope:
4 | objectKinds:
5 | - DeploymentLike
6 | remediation: >-
7 | Set CPU requests for your container based on its requirements.
8 | Refer to https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits for details.
9 | template: "cpu-requirements"
10 | params:
11 | requirementsType: "request"
12 | lowerBoundMillis: 0
13 | upperBoundMillis: 0
14 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/unset-memory-requirements.yaml:
--------------------------------------------------------------------------------
1 | name: "unset-memory-requirements"
2 | description: "Indicates when containers do not have memory requests and limits set."
3 | remediation: >-
4 | Set memory limits for your container based on its requirements.
5 | Refer to https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits for details.
6 | scope:
7 | objectKinds:
8 | - DeploymentLike
9 | template: "memory-requirements"
10 | params:
11 | requirementsType: "limit"
12 | lowerBoundMB: 0
13 | upperBoundMB: 0
14 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/usenamespace.yaml:
--------------------------------------------------------------------------------
1 | name: "use-namespace"
2 | description: >-
3 | Indicates when a resource is deployed to the default namespace.
4 | CIS Benchmark 5.7.1: Create administrative boundaries between resources using namespaces.
5 | CIS Benchmark 5.7.4: The default namespace should not be used.
6 | remediation: "Create namespaces for objects in your deployment."
7 | scope:
8 | objectKinds:
9 | - DeploymentLike
10 | - Service
11 | template: "use-namespace"
12 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/wildcard-use-in-rules.yaml:
--------------------------------------------------------------------------------
1 | name: "wildcard-in-rules"
2 | description: >-
3 | Indicate when a wildcard is used in Role or ClusterRole rules.
4 | CIS Benchmark 5.1.3 Use of wildcards is not optimal from a security perspective as it may allow for inadvertent access to be granted when new resources are added to the Kubernetes API either as CRDs or in later versions of the product.
5 | remediation: "Where possible replace any use of wildcards in clusterroles and roles with specific objects or actions."
6 | scope:
7 | objectKinds:
8 | - ClusterRole
9 | - Role
10 | template: "wildcard-in-rules"
11 |
--------------------------------------------------------------------------------
/pkg/builtinchecks/yamls/writable-host-mount.yaml:
--------------------------------------------------------------------------------
1 | name: "writable-host-mount"
2 | description: "Indicates when containers mount a host path as writable."
3 | remediation: "Set containers to mount host paths as readOnly, if you need to access files on the host."
4 | scope:
5 | objectKinds:
6 | - DeploymentLike
7 | template: "writable-host-mount"
8 |
--------------------------------------------------------------------------------
/pkg/checkregistry/check_registry.go:
--------------------------------------------------------------------------------
1 | package checkregistry
2 |
3 | import (
4 | "github.com/pkg/errors"
5 | "golang.stackrox.io/kube-linter/pkg/config"
6 | "golang.stackrox.io/kube-linter/pkg/instantiatedcheck"
7 | )
8 |
9 | // A CheckRegistry is a registry of checks.
10 | // It is not thread-safe. It is anticipated that checks will all be registered ahead of time
11 | // before calls to Load.
12 | type CheckRegistry interface {
13 | Register(checks ...*config.Check) error
14 | Load(name string) *instantiatedcheck.InstantiatedCheck
15 | }
16 |
17 | type checkRegistry map[string]*instantiatedcheck.InstantiatedCheck
18 |
19 | func (cr checkRegistry) Register(checks ...*config.Check) error {
20 | for _, c := range checks {
21 | instantiated, err := instantiatedcheck.ValidateAndInstantiate(c)
22 | if err != nil {
23 | return errors.Wrapf(err, "invalid check %s", c.Name)
24 | }
25 | if _, ok := cr[instantiated.Spec.Name]; ok {
26 | return errors.Errorf("duplicate check name: %s", instantiated.Spec.Name)
27 | }
28 | cr[instantiated.Spec.Name] = instantiated
29 | }
30 | return nil
31 | }
32 |
33 | func (cr checkRegistry) Load(name string) *instantiatedcheck.InstantiatedCheck {
34 | return cr[name]
35 | }
36 |
37 | // New returns a ready-to-use, empty CheckRegistry.
38 | func New() CheckRegistry {
39 | return make(checkRegistry)
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/command/lint/command_test.go:
--------------------------------------------------------------------------------
1 | package lint
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/spf13/cobra"
7 |
8 | // Register templates
9 | _ "golang.stackrox.io/kube-linter/pkg/templates/all"
10 | )
11 |
12 | func TestCommand_InvalidResources(t *testing.T) {
13 | tests := []struct {
14 | name string
15 | cmd *cobra.Command
16 | failure bool
17 | output string
18 | }{
19 | {name: "InvalidPodResource", cmd: createLintCommand("./testdata/invalid-pod-resources.yaml", "--fail-on-invalid-resource"), failure: true},
20 | {name: "InvalidPVCResource", cmd: createLintCommand("./testdata/invalid-pvc-resources.yaml", "--fail-on-invalid-resource"), failure: true},
21 | {name: "NonexistentFile", cmd: createLintCommand("./testdata/foo-bar.yaml", "--fail-on-invalid-resource"), failure: true},
22 | {name: "ValidPod", cmd: createLintCommand("./testdata/valid-pod.yaml", "--fail-on-invalid-resource"), failure: false},
23 | }
24 | for _, tt := range tests {
25 | t.Run(tt.name, func(t *testing.T) {
26 | err := tt.cmd.Execute()
27 | if err == nil && tt.failure || err != nil && !tt.failure {
28 | t.Fail()
29 | }
30 | })
31 | }
32 | }
33 |
34 | func createLintCommand(args ...string) *cobra.Command {
35 | c := Command()
36 | c.SilenceUsage = true
37 | c.SetArgs(args)
38 | return c
39 | }
40 |
--------------------------------------------------------------------------------
/pkg/command/lint/testdata/invalid-pod-resources.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | creationTimestamp: null
5 | name: foo-pod
6 | namespace: foo
7 | spec:
8 | containers:
9 | - image: busybox
10 | name: invalid
11 | command:
12 | - "sleep"
13 | args:
14 | - "infinity"
15 | resources:
16 | limits:
17 | cpu: 25m
18 | memory: 1GB
19 | requests:
20 | cpu: 25m
21 | memory: 1GB
22 | dnsPolicy: ClusterFirst
23 | restartPolicy: Always
24 | status: {}
--------------------------------------------------------------------------------
/pkg/command/lint/testdata/invalid-pvc-resources.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: PersistentVolumeClaim
3 | metadata:
4 | name: foo-pvc
5 | namespace: foo
6 | spec:
7 | accessModes:
8 | - ReadWriteOnce
9 | resources:
10 | requests:
11 | storage: 250GB
12 | storageClassName: thin-disk
--------------------------------------------------------------------------------
/pkg/command/lint/testdata/valid-pod.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: homebrew-demo
5 | spec:
6 | securityContext:
7 | runAsUser: 1000
8 | runAsGroup: 3000
9 | fsGroup: 2000
10 | containers:
11 | - name: homebrew-test
12 | image: busybox:stable
13 | resources:
14 | limits:
15 | memory: "128Mi"
16 | cpu: "500m"
17 | requests:
18 | memory: "64Mi"
19 | cpu: "250m"
20 | securityContext:
21 | readOnlyRootFilesystem: true
--------------------------------------------------------------------------------
/pkg/command/root/command.go:
--------------------------------------------------------------------------------
1 | package root
2 |
3 | import (
4 | "os"
5 | "path/filepath"
6 |
7 | "github.com/fatih/color"
8 | "github.com/spf13/cobra"
9 | "golang.stackrox.io/kube-linter/pkg/command/checks"
10 | "golang.stackrox.io/kube-linter/pkg/command/lint"
11 | "golang.stackrox.io/kube-linter/pkg/command/templates"
12 | "golang.stackrox.io/kube-linter/pkg/command/version"
13 | )
14 |
15 | const (
16 | colorFlag = "with-color"
17 | )
18 |
19 | // Command is the root command.
20 | func Command() *cobra.Command {
21 | c := &cobra.Command{
22 | Use: filepath.Base(os.Args[0]),
23 | SilenceUsage: true,
24 | SilenceErrors: true,
25 | PersistentPreRun: func(cmd *cobra.Command, _ []string) {
26 | // Only forcefully set colorful output if the flag has been set.
27 | if cmd.Flags().Changed(colorFlag) {
28 | color.NoColor = false
29 | }
30 | },
31 | }
32 | c.AddCommand(
33 | checks.Command(),
34 | lint.Command(),
35 | templates.Command(),
36 | version.Command(),
37 | )
38 | c.PersistentFlags().Bool(colorFlag, true, "Force color output")
39 | return c
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/command/root/command_test.go:
--------------------------------------------------------------------------------
1 | package root
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "testing"
7 |
8 | "github.com/fatih/color"
9 | "github.com/stretchr/testify/assert"
10 | "github.com/stretchr/testify/require"
11 | )
12 |
13 | func TestCommand(t *testing.T) {
14 | c := Command()
15 | c.SetOut(io.Discard)
16 | c.SetArgs([]string{
17 | "version",
18 | fmt.Sprintf("--%s", colorFlag),
19 | })
20 | err := c.Execute()
21 | require.NoError(t, err)
22 | assert.False(t, color.NoColor)
23 | }
24 |
--------------------------------------------------------------------------------
/pkg/command/version/command.go:
--------------------------------------------------------------------------------
1 | package version
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/spf13/cobra"
7 | "golang.stackrox.io/kube-linter/internal/version"
8 | )
9 |
10 | // Command defines the version command
11 | func Command() *cobra.Command {
12 | c := &cobra.Command{
13 | Use: "version",
14 | Short: "Print version and exit",
15 | Args: cobra.NoArgs,
16 | Run: func(cmd *cobra.Command, _ []string) {
17 | fmt.Println(version.Get())
18 | },
19 | }
20 | return c
21 | }
22 |
--------------------------------------------------------------------------------
/pkg/config/check.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | // A Check represents a single check. It is serializable.
4 | type Check struct {
5 | Name string `json:"name"`
6 | Description string `json:"description"`
7 | Remediation string `json:"remediation"`
8 | Scope *ObjectKindsDesc `json:"scope"`
9 | Template string `json:"template"`
10 | Params map[string]interface{} `json:"params,omitempty"`
11 | }
12 |
13 | // ObjectKindsDesc describes a list of supported object kinds for a check template.
14 | type ObjectKindsDesc struct {
15 | ObjectKinds []string `json:"objectKinds"`
16 | }
17 |
--------------------------------------------------------------------------------
/pkg/config/gen.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | //go:generate go run ./codegen flags.go
4 |
--------------------------------------------------------------------------------
/pkg/configresolver/config_resolver_test.go:
--------------------------------------------------------------------------------
1 | package configresolver
2 |
3 | import (
4 | "os"
5 | "path/filepath"
6 | "testing"
7 |
8 | "github.com/mitchellh/go-homedir"
9 | "github.com/stretchr/testify/assert"
10 | "golang.stackrox.io/kube-linter/pkg/config"
11 | )
12 |
13 | func TestIgnorePaths(t *testing.T) {
14 | home, homeErr := homedir.Dir()
15 | if homeErr != nil {
16 | t.Fatal(homeErr)
17 | }
18 | wd, wdErr := os.Getwd()
19 | if wdErr != nil {
20 | t.Fatal(wdErr)
21 | }
22 |
23 | parent := filepath.Dir(wd)
24 | c := new(config.Config)
25 |
26 | var tests = []struct {
27 | Paths []string
28 | Expected string
29 | ErrorExpeted bool
30 | }{
31 | {[]string{"~/test"}, home + "/test", false},
32 | {[]string{"~/*.yaml"}, home + "/*.yaml", false},
33 | {[]string{"~~/test"}, "", true},
34 | {[]string{"../test"}, parent + "/test", false},
35 | {[]string{"../*.yaml"}, parent + "/*.yaml", false},
36 | {[]string{"~/test", "~/test"}, home + "/test", false},
37 | }
38 |
39 | for _, e := range tests {
40 | c.Checks.IgnorePaths = e.Paths
41 | paths, err := GetIgnorePaths(c)
42 |
43 | if e.ErrorExpeted {
44 | assert.Error(t, err)
45 | } else {
46 | for _, path := range paths {
47 | assert.NoError(t, err)
48 | assert.Equal(t, e.Expected, path)
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/diagnostic/diagnostic.go:
--------------------------------------------------------------------------------
1 | package diagnostic
2 |
3 | import (
4 | "golang.stackrox.io/kube-linter/pkg/lintcontext"
5 | )
6 |
7 | // A Diagnostic represents one specific problem diagnosed by a check.
8 | type Diagnostic struct {
9 | Message string
10 |
11 | // TODO: add line number/col number
12 | }
13 |
14 | // WithContext puts a diagnostic in the context of which check emitted it,
15 | // and which object it applied to.
16 | type WithContext struct {
17 | Diagnostic Diagnostic
18 | Check string
19 | Remediation string
20 | Object lintcontext.Object
21 | }
22 |
--------------------------------------------------------------------------------
/pkg/extract/gvk.go:
--------------------------------------------------------------------------------
1 | package extract
2 |
3 | import (
4 | "golang.stackrox.io/kube-linter/pkg/k8sutil"
5 | "k8s.io/apimachinery/pkg/runtime/schema"
6 | )
7 |
8 | // GVK extracts the GroupVersionKind of an object.
9 | func GVK(object k8sutil.Object) schema.GroupVersionKind {
10 | return object.GetObjectKind().GroupVersionKind()
11 | }
12 |
--------------------------------------------------------------------------------
/pkg/extract/metadata.go:
--------------------------------------------------------------------------------
1 | package extract
2 |
3 | import (
4 | "golang.stackrox.io/kube-linter/pkg/k8sutil"
5 | )
6 |
7 | // Labels extracts labels from the given object.
8 | func Labels(object k8sutil.Object) map[string]string {
9 | return object.GetLabels()
10 | }
11 |
12 | // Annotations extracts annotations from the given object.
13 | func Annotations(object k8sutil.Object) map[string]string {
14 | return object.GetAnnotations()
15 | }
16 |
--------------------------------------------------------------------------------
/pkg/extract/scc_spec.go:
--------------------------------------------------------------------------------
1 | package extract
2 |
3 | import (
4 | ocpSecV1 "github.com/openshift/api/security/v1"
5 | "golang.stackrox.io/kube-linter/pkg/k8sutil"
6 | )
7 |
8 | // SCCallowPrivilegedContainer extracts allowPrivilegedContainer from the given object, if available.
9 | func SCCallowPrivilegedContainer(obj k8sutil.Object) (bool, bool) {
10 | if scc, ok := obj.(*ocpSecV1.SecurityContextConstraints); ok {
11 | return scc.AllowPrivilegedContainer, true
12 | }
13 | return false, false
14 | }
15 |
--------------------------------------------------------------------------------
/pkg/ignore/ignore.go:
--------------------------------------------------------------------------------
1 | package ignore
2 |
3 | import (
4 | "golang.stackrox.io/kube-linter/internal/stringutils"
5 | )
6 |
7 | const (
8 | // AnnotationKeyPrefix is the prefix for annotations for kube-linter check ignores.
9 | AnnotationKeyPrefix = "ignore-check.kube-linter.io/"
10 |
11 | // AllAnnotationKey is used to ignore all checks for a given object.
12 | AllAnnotationKey = "kube-linter.io/ignore-all"
13 | )
14 |
15 | // ObjectForCheck returns whether to ignore the given object for the passed check name.
16 | func ObjectForCheck(annotations map[string]string, checkName string) bool {
17 | for k := range annotations {
18 | if k == AllAnnotationKey {
19 | return true
20 | }
21 | key := k
22 | if stringutils.ConsumePrefix(&key, AnnotationKeyPrefix) && key == checkName {
23 | return true
24 | }
25 | }
26 | return false
27 | }
28 |
--------------------------------------------------------------------------------
/pkg/k8sutil/object.go:
--------------------------------------------------------------------------------
1 | package k8sutil
2 |
3 | import (
4 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5 | "k8s.io/apimachinery/pkg/runtime"
6 | )
7 |
8 | // Object is a combination of `runtime.Object` and `metav1.Object`.
9 | type Object interface {
10 | runtime.Object
11 | metaV1.Object
12 | }
13 |
--------------------------------------------------------------------------------
/pkg/lintcontext/mocks/clusterrole.go:
--------------------------------------------------------------------------------
1 | package mocks
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
8 | rbacV1 "k8s.io/api/rbac/v1"
9 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10 | )
11 |
12 | // AddMockClusterRole adds a mock ClusterRole to LintContext
13 | func (l *MockLintContext) AddMockClusterRole(t *testing.T, name string) {
14 | require.NotEmpty(t, name)
15 | l.objects[name] = &rbacV1.ClusterRole{
16 | TypeMeta: metaV1.TypeMeta{
17 | Kind: objectkinds.ClusterRole,
18 | APIVersion: objectkinds.GetClusterRoleAPIVersion(),
19 | },
20 | ObjectMeta: metaV1.ObjectMeta{Name: name},
21 | Rules: []rbacV1.PolicyRule{},
22 | AggregationRule: &rbacV1.AggregationRule{},
23 | }
24 | }
25 |
26 | // ModifyClusterRole modifies a given clusterrole in the context via the passed function.
27 | func (l *MockLintContext) ModifyClusterRole(t *testing.T, name string, f func(clusterrole *rbacV1.ClusterRole)) {
28 | r, ok := l.objects[name].(*rbacV1.ClusterRole)
29 | require.True(t, ok)
30 | f(r)
31 | }
32 |
--------------------------------------------------------------------------------
/pkg/lintcontext/mocks/clusterrolebinding.go:
--------------------------------------------------------------------------------
1 | package mocks
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
8 | rbacV1 "k8s.io/api/rbac/v1"
9 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10 | )
11 |
12 | // AddMockClusterRoleBinding adds a mock ClusterRoleBinding to LintContext
13 | func (l *MockLintContext) AddMockClusterRoleBinding(t *testing.T, name string) {
14 | require.NotEmpty(t, name)
15 | l.objects[name] = &rbacV1.ClusterRoleBinding{
16 | TypeMeta: metaV1.TypeMeta{
17 | Kind: objectkinds.ClusterRoleBinding,
18 | APIVersion: objectkinds.GetClusterRoleBindingAPIVersion(),
19 | },
20 | ObjectMeta: metaV1.ObjectMeta{Name: name},
21 | Subjects: []rbacV1.Subject{},
22 | RoleRef: rbacV1.RoleRef{},
23 | }
24 | }
25 |
26 | // ModifyClusterRoleBinding modifies a given ClusterRoleBinding in the context via the passed function.
27 | func (l *MockLintContext) ModifyClusterRoleBinding(t *testing.T, name string, f func(clusterrolebinding *rbacV1.ClusterRoleBinding)) {
28 | crb, ok := l.objects[name].(*rbacV1.ClusterRoleBinding)
29 | require.True(t, ok)
30 | f(crb)
31 | }
32 |
--------------------------------------------------------------------------------
/pkg/lintcontext/mocks/container.go:
--------------------------------------------------------------------------------
1 | package mocks
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | appsV1 "k8s.io/api/apps/v1"
8 | v1 "k8s.io/api/core/v1"
9 | )
10 |
11 | // AddContainerToDeployment adds a mock container to the specified pod under context
12 | func (l *MockLintContext) AddContainerToDeployment(t *testing.T, deploymentName string, container v1.Container) {
13 | deployment, ok := l.objects[deploymentName].(*appsV1.Deployment)
14 | require.True(t, ok, "deployment with name %s not found", deploymentName)
15 | // TODO: keep supporting other fields
16 | deployment.Spec.Template.Spec.Containers = append(deployment.Spec.Template.Spec.Containers, container)
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/lintcontext/mocks/context.go:
--------------------------------------------------------------------------------
1 | package mocks
2 |
3 | import (
4 | "golang.stackrox.io/kube-linter/pkg/k8sutil"
5 | "golang.stackrox.io/kube-linter/pkg/lintcontext"
6 | )
7 |
8 | // MockLintContext is mock implementation of the LintContext used in unit tests
9 | type MockLintContext struct {
10 | objects map[string]k8sutil.Object
11 | }
12 |
13 | // Objects returns all the objects under this MockLintContext
14 | func (l *MockLintContext) Objects() []lintcontext.Object {
15 | result := make([]lintcontext.Object, 0, len(l.objects))
16 | for _, p := range l.objects {
17 | result = append(result, lintcontext.Object{Metadata: lintcontext.ObjectMetadata{}, K8sObject: p})
18 | }
19 | return result
20 | }
21 |
22 | // InvalidObjects is not implemented. For now we don't care about invalid objects for mock context.
23 | func (l *MockLintContext) InvalidObjects() []lintcontext.InvalidObject {
24 | return nil
25 | }
26 |
27 | // NewMockContext returns an empty mockLintContext
28 | func NewMockContext() *MockLintContext {
29 | return &MockLintContext{objects: make(map[string]k8sutil.Object)}
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/lintcontext/mocks/ingress.go:
--------------------------------------------------------------------------------
1 | package mocks
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
8 | networkingV1 "k8s.io/api/networking/v1"
9 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10 | )
11 |
12 | func (l *MockLintContext) AddMockIngress(t *testing.T, name string) {
13 | require.NotEmpty(t, name)
14 | l.objects[name] = &networkingV1.Ingress{
15 | TypeMeta: metaV1.TypeMeta{
16 | Kind: objectkinds.Ingress,
17 | APIVersion: objectkinds.GetIngressAPIVersion(),
18 | },
19 | ObjectMeta: metaV1.ObjectMeta{Name: name},
20 | Spec: networkingV1.IngressSpec{},
21 | }
22 | }
23 |
24 | // ModifyIngress modifies a given networkpolicy in the context via the passed function.
25 | func (l *MockLintContext) ModifyIngress(t *testing.T, name string, f func(ingress *networkingV1.Ingress)) {
26 | r, ok := l.objects[name].(*networkingV1.Ingress)
27 | require.True(t, ok)
28 | f(r)
29 | }
30 |
--------------------------------------------------------------------------------
/pkg/lintcontext/mocks/networkpolicy.go:
--------------------------------------------------------------------------------
1 | package mocks
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
8 | networkingV1 "k8s.io/api/networking/v1"
9 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10 | )
11 |
12 | // AddMockNetworkPolicy adds a mock NetworkPolicy to LintContext
13 | func (l *MockLintContext) AddMockNetworkPolicy(t *testing.T, name string) {
14 | require.NotEmpty(t, name)
15 | l.objects[name] = &networkingV1.NetworkPolicy{
16 | TypeMeta: metaV1.TypeMeta{
17 | Kind: objectkinds.NetworkPolicy,
18 | APIVersion: objectkinds.GetNetworkPolicyAPIVersion(),
19 | },
20 | ObjectMeta: metaV1.ObjectMeta{Name: name},
21 | Spec: networkingV1.NetworkPolicySpec{},
22 | }
23 | }
24 |
25 | // ModifyNetworkPolicy modifies a given networkpolicy in the context via the passed function.
26 | func (l *MockLintContext) ModifyNetworkPolicy(t *testing.T, name string, f func(networkpolicy *networkingV1.NetworkPolicy)) {
27 | r, ok := l.objects[name].(*networkingV1.NetworkPolicy)
28 | require.True(t, ok)
29 | f(r)
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/lintcontext/mocks/role.go:
--------------------------------------------------------------------------------
1 | package mocks
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
8 | rbacV1 "k8s.io/api/rbac/v1"
9 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10 | )
11 |
12 | // AddMockRole adds a mock Role to LintContext
13 | func (l *MockLintContext) AddMockRole(t *testing.T, name, namespace string) {
14 | require.NotEmpty(t, name)
15 | l.objects[name] = &rbacV1.Role{
16 | TypeMeta: metaV1.TypeMeta{
17 | Kind: objectkinds.Role,
18 | APIVersion: objectkinds.GetRoleAPIVersion(),
19 | },
20 | ObjectMeta: metaV1.ObjectMeta{Name: name, Namespace: namespace},
21 | Rules: []rbacV1.PolicyRule{},
22 | }
23 | }
24 |
25 | // ModifyRole modifies a given Role in the context via the passed function.
26 | func (l *MockLintContext) ModifyRole(t *testing.T, name string, f func(role *rbacV1.Role)) {
27 | r, ok := l.objects[name].(*rbacV1.Role)
28 | require.True(t, ok)
29 | f(r)
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/lintcontext/mocks/rolebinding.go:
--------------------------------------------------------------------------------
1 | package mocks
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
8 | rbacV1 "k8s.io/api/rbac/v1"
9 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10 | )
11 |
12 | // AddMockRoleBinding adds a mock RoleBinding to LintContext
13 | func (l *MockLintContext) AddMockRoleBinding(t *testing.T, name, namespace string) {
14 | require.NotEmpty(t, name)
15 | l.objects[name] = &rbacV1.RoleBinding{
16 | TypeMeta: metaV1.TypeMeta{
17 | Kind: objectkinds.RoleBinding,
18 | APIVersion: objectkinds.GetRoleBindingAPIVersion(),
19 | },
20 | ObjectMeta: metaV1.ObjectMeta{Name: name, Namespace: namespace},
21 | Subjects: []rbacV1.Subject{},
22 | RoleRef: rbacV1.RoleRef{},
23 | }
24 | }
25 |
26 | // ModifyRoleBinding modifies a given RoleBinding in the context via the passed function.
27 | func (l *MockLintContext) ModifyRoleBinding(t *testing.T, name string, f func(rolebinding *rbacV1.RoleBinding)) {
28 | rb, ok := l.objects[name].(*rbacV1.RoleBinding)
29 | require.True(t, ok)
30 | f(rb)
31 | }
32 |
--------------------------------------------------------------------------------
/pkg/lintcontext/mocks/scaledobject.go:
--------------------------------------------------------------------------------
1 | package mocks
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | kedaV1Alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1"
8 | "github.com/stretchr/testify/require"
9 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
10 |
11 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12 | )
13 |
14 | // AddMockScaledObject adds a mock ScaledObject to LintContext
15 | func (l *MockLintContext) AddMockScaledObject(t *testing.T, name, version string) {
16 | require.NotEmpty(t, name)
17 | switch version {
18 | case "v1alpha1":
19 | l.objects[name] = &kedaV1Alpha1.ScaledObject{
20 | TypeMeta: metaV1.TypeMeta{
21 | Kind: objectkinds.ScaledObject,
22 | APIVersion: objectkinds.GetScaledObjectAPIVersion(version),
23 | },
24 | ObjectMeta: metaV1.ObjectMeta{Name: name},
25 | Spec: kedaV1Alpha1.ScaledObjectSpec{},
26 | }
27 | default:
28 | require.FailNow(t, fmt.Sprintf("Unknown scaled object version %s", version))
29 | }
30 | }
31 |
32 | // ModifyScaledObjectV1Alpha1 modifies a given ScaledObject in the context via the passed function.
33 | func (l *MockLintContext) ModifyScaledObjectV1Alpha1(t *testing.T, name string, f func(hpa *kedaV1Alpha1.ScaledObject)) {
34 | r, ok := l.objects[name].(*kedaV1Alpha1.ScaledObject)
35 | require.True(t, ok)
36 | f(r)
37 | }
38 |
--------------------------------------------------------------------------------
/pkg/lintcontext/mocks/scc.go:
--------------------------------------------------------------------------------
1 | package mocks
2 |
3 | import (
4 | "testing"
5 |
6 | ocpSecV1 "github.com/openshift/api/security/v1"
7 | "github.com/stretchr/testify/require"
8 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
9 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10 | )
11 |
12 | // AddMockSecurityContextConstraints adds a mock SecurityContextConstraints to LintContext
13 | func (l *MockLintContext) AddMockSecurityContextConstraints(t *testing.T, name string, allowFlag bool) {
14 | require.NotEmpty(t, name)
15 | l.objects[name] = &ocpSecV1.SecurityContextConstraints{
16 | TypeMeta: metaV1.TypeMeta{
17 | Kind: objectkinds.SecurityContextConstraints,
18 | APIVersion: objectkinds.GetSCCAPIVersion(),
19 | },
20 | ObjectMeta: metaV1.ObjectMeta{Name: name},
21 | AllowPrivilegedContainer: allowFlag,
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/pkg/lintcontext/mocks/service.go:
--------------------------------------------------------------------------------
1 | package mocks
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | coreV1 "k8s.io/api/core/v1"
8 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9 | )
10 |
11 | // AddMockService adds a mock Service to LintContext
12 | func (l *MockLintContext) AddMockService(t *testing.T, name string) {
13 | require.NotEmpty(t, name)
14 | l.objects[name] = &coreV1.Service{
15 | ObjectMeta: metaV1.ObjectMeta{Name: name},
16 | }
17 | }
18 |
19 | // ModifyService modifies a given service in the context via the passed function
20 | func (l *MockLintContext) ModifyService(t *testing.T, name string, f func(service *coreV1.Service)) {
21 | dep, ok := l.objects[name].(*coreV1.Service)
22 | require.True(t, ok)
23 | f(dep)
24 | }
25 |
--------------------------------------------------------------------------------
/pkg/lintcontext/mocks/servicemonitor.go:
--------------------------------------------------------------------------------
1 | package mocks
2 |
3 | import (
4 | "testing"
5 |
6 | k8sMonitoring "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
7 | "github.com/stretchr/testify/require"
8 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
9 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10 | )
11 |
12 | // AddMockServiceMonitor adds a mock ServiceMonitor to LintContext
13 | func (l *MockLintContext) AddMockServiceMonitor(t *testing.T, name string) {
14 | require.NotEmpty(t, name)
15 | l.objects[name] = &k8sMonitoring.ServiceMonitor{
16 | TypeMeta: metaV1.TypeMeta{
17 | Kind: objectkinds.ServiceMonitor,
18 | APIVersion: objectkinds.GetServiceMonitorAPIVersion(),
19 | },
20 | ObjectMeta: metaV1.ObjectMeta{Name: name},
21 | Spec: k8sMonitoring.ServiceMonitorSpec{},
22 | }
23 | }
24 |
25 | // ModifyServiceMonitor modifies a given servicemonitor in the context via the passed function
26 | func (l *MockLintContext) ModifyServiceMonitor(t *testing.T, name string, f func(servicemonitor *k8sMonitoring.ServiceMonitor)) {
27 | r, ok := l.objects[name].(*k8sMonitoring.ServiceMonitor)
28 | require.True(t, ok)
29 | f(r)
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/matcher/string.go:
--------------------------------------------------------------------------------
1 | package matcher
2 |
3 | import (
4 | "regexp"
5 |
6 | "golang.stackrox.io/kube-linter/internal/stringutils"
7 | )
8 |
9 | const (
10 | // NegationPrefix is the prefix used for negations.
11 | NegationPrefix = "!"
12 | )
13 |
14 | func matchAny(_ string) bool {
15 | return true
16 | }
17 |
18 | // ForString constructs a string matcher for the given value.
19 | func ForString(value string) (func(string) bool, error) {
20 | if value == "" {
21 | return matchAny, nil
22 | }
23 | var negate bool
24 | if stringutils.ConsumePrefix(&value, NegationPrefix) {
25 | negate = true
26 | }
27 | re, err := regexp.Compile(value)
28 | if err != nil {
29 | return nil, err
30 | }
31 | return func(s string) bool {
32 | matched := re.MatchString(s)
33 | return matched != negate
34 | }, nil
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/objectkinds/any.go:
--------------------------------------------------------------------------------
1 | package objectkinds
2 |
3 | import (
4 | "k8s.io/apimachinery/pkg/runtime/schema"
5 | )
6 |
7 | const (
8 | // Any represents the ObjectKind that matches any object.
9 | Any = "Any"
10 | )
11 |
12 | func init() {
13 | RegisterObjectKind(Any, MatcherFunc(func(gvk schema.GroupVersionKind) bool {
14 | return true
15 | }))
16 | }
17 |
--------------------------------------------------------------------------------
/pkg/objectkinds/clusterrole.go:
--------------------------------------------------------------------------------
1 | package objectkinds
2 |
3 | import (
4 | "fmt"
5 |
6 | rbacV1 "k8s.io/api/rbac/v1"
7 | "k8s.io/apimachinery/pkg/runtime/schema"
8 | )
9 |
10 | const (
11 | // ClusterRole represents Kubernetes ClusterRole objects. Case sensitive.
12 | ClusterRole = "ClusterRole"
13 | )
14 |
15 | var (
16 | clusterRoleGVK = rbacV1.SchemeGroupVersion.WithKind("ClusterRole")
17 | )
18 |
19 | func init() {
20 | RegisterObjectKind(ClusterRole, MatcherFunc(func(gvk schema.GroupVersionKind) bool {
21 | return gvk == clusterRoleGVK
22 | }))
23 | }
24 |
25 | // GetClusterRoleAPIVersion returns ClusterRole's APIVersion
26 | func GetClusterRoleAPIVersion() string {
27 | return fmt.Sprintf("%s/%s", clusterRoleGVK.Group, clusterRoleGVK.Version)
28 | }
29 |
--------------------------------------------------------------------------------
/pkg/objectkinds/clusterrolebinding.go:
--------------------------------------------------------------------------------
1 | package objectkinds
2 |
3 | import (
4 | rbacV1 "k8s.io/api/rbac/v1"
5 | "k8s.io/apimachinery/pkg/runtime/schema"
6 | )
7 |
8 | const (
9 | // ClusterRoleBinding represents Kubernetes ClusterRoleBinding objects. Case sensitive.
10 | ClusterRoleBinding = "ClusterRoleBinding"
11 | )
12 |
13 | var (
14 | clusterRoleBindingGVK = rbacV1.SchemeGroupVersion.WithKind("ClusterRoleBinding")
15 | )
16 |
17 | func init() {
18 | RegisterObjectKind(ClusterRoleBinding, MatcherFunc(func(gvk schema.GroupVersionKind) bool {
19 | return gvk == clusterRoleBindingGVK
20 | }))
21 | }
22 |
23 | // GetClusterRoleBindingAPIVersion returns ClusterRoleBinding's APIVersion
24 | func GetClusterRoleBindingAPIVersion() string {
25 | return clusterRoleBindingGVK.GroupVersion().String()
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/objectkinds/deployment_like.go:
--------------------------------------------------------------------------------
1 | package objectkinds
2 |
3 | import (
4 | "fmt"
5 |
6 | ocsAppsV1 "github.com/openshift/api/apps/v1"
7 | appsV1 "k8s.io/api/apps/v1"
8 | batchV1 "k8s.io/api/batch/v1"
9 | coreV1 "k8s.io/api/core/v1"
10 | "k8s.io/apimachinery/pkg/runtime/schema"
11 | )
12 |
13 | var (
14 | deploymentLikeGroupKinds = func() map[schema.GroupKind]struct{} {
15 | m := make(map[schema.GroupKind]struct{})
16 | for _, gk := range []schema.GroupKind{
17 | {Group: appsV1.GroupName, Kind: "Deployment"},
18 | {Group: appsV1.GroupName, Kind: "DaemonSet"},
19 | {Group: ocsAppsV1.GroupName, Kind: "DeploymentConfig"},
20 | {Group: appsV1.GroupName, Kind: "StatefulSet"},
21 | {Group: appsV1.GroupName, Kind: "ReplicaSet"},
22 | {Group: coreV1.GroupName, Kind: "Pod"},
23 | {Group: coreV1.GroupName, Kind: "ReplicationController"},
24 | {Group: batchV1.GroupName, Kind: "Job"},
25 | {Group: batchV1.GroupName, Kind: "CronJob"},
26 | } {
27 | if _, ok := m[gk]; ok {
28 | panic(fmt.Sprintf("group kind double-registered: %v", gk))
29 | }
30 | m[gk] = struct{}{}
31 | }
32 | return m
33 | }()
34 | )
35 |
36 | func IsDeploymentLike(gvk schema.GroupVersionKind) bool {
37 | _, ok := deploymentLikeGroupKinds[gvk.GroupKind()]
38 | return ok
39 | }
40 |
41 | const (
42 | // DeploymentLike is the name of the DeploymentLike ObjectKind.
43 | DeploymentLike = "DeploymentLike"
44 | )
45 |
46 | func init() {
47 | RegisterObjectKind(DeploymentLike, MatcherFunc(IsDeploymentLike))
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/objectkinds/horizontalpodautoscaler.go:
--------------------------------------------------------------------------------
1 | package objectkinds
2 |
3 | import (
4 | "fmt"
5 |
6 | autoscalingV1 "k8s.io/api/autoscaling/v1"
7 | autoscalingV2 "k8s.io/api/autoscaling/v2"
8 | autoscalingV2Beta1 "k8s.io/api/autoscaling/v2beta1"
9 | autoscalingV2Beta2 "k8s.io/api/autoscaling/v2beta2"
10 | "k8s.io/apimachinery/pkg/runtime/schema"
11 | )
12 |
13 | const (
14 | // HorizontalPodAutoscaler represents Kubernetes HorizontalPodAutoscaler objects. Case sensitive.
15 | HorizontalPodAutoscaler = "HorizontalPodAutoscaler"
16 | )
17 |
18 | var (
19 | horizontalPodAutoscalerV2Beta1GVK = autoscalingV2Beta1.SchemeGroupVersion.WithKind(HorizontalPodAutoscaler)
20 | horizontalPodAutoscalerV2Beta2GVK = autoscalingV2Beta2.SchemeGroupVersion.WithKind(HorizontalPodAutoscaler)
21 | horizontalPodAutoscalerV2GVK = autoscalingV2.SchemeGroupVersion.WithKind(HorizontalPodAutoscaler)
22 | horizontalPodAutoscalerV1GVK = autoscalingV1.SchemeGroupVersion.WithKind(HorizontalPodAutoscaler)
23 | )
24 |
25 | func isHorizontalPodAutoscaler(gvk schema.GroupVersionKind) bool {
26 | return gvk == horizontalPodAutoscalerV1GVK ||
27 | gvk == horizontalPodAutoscalerV2GVK ||
28 | gvk == horizontalPodAutoscalerV2Beta1GVK ||
29 | gvk == horizontalPodAutoscalerV2Beta2GVK
30 | }
31 |
32 | func init() {
33 | RegisterObjectKind(HorizontalPodAutoscaler, MatcherFunc(isHorizontalPodAutoscaler))
34 | }
35 |
36 | // GetHorizontalPodAutoscalerAPIVersion returns HorizontalPodAutoscaler's APIVersion
37 | func GetHorizontalPodAutoscalerAPIVersion(version string) string {
38 | return fmt.Sprintf("%s/%s", horizontalPodAutoscalerV2Beta1GVK.Group, version)
39 | }
40 |
--------------------------------------------------------------------------------
/pkg/objectkinds/ingress.go:
--------------------------------------------------------------------------------
1 | package objectkinds
2 |
3 | import (
4 | v1 "k8s.io/api/networking/v1"
5 | "k8s.io/apimachinery/pkg/runtime/schema"
6 | )
7 |
8 | const (
9 | // Ingress represents Kubernetes Ingress objects.
10 | Ingress = "Ingress"
11 | )
12 |
13 | var (
14 | ingressGVK = v1.SchemeGroupVersion.WithKind(Ingress)
15 | )
16 |
17 | func init() {
18 | RegisterObjectKind(Ingress, MatcherFunc(func(gvk schema.GroupVersionKind) bool {
19 | return gvk == ingressGVK
20 | }))
21 | }
22 |
23 | // GetIngressAPIVersion returns Ingress's apiversion
24 | func GetIngressAPIVersion() string {
25 | return ingressGVK.GroupVersion().String()
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/objectkinds/networkpolicy.go:
--------------------------------------------------------------------------------
1 | package objectkinds
2 |
3 | import (
4 | v1 "k8s.io/api/networking/v1"
5 | "k8s.io/apimachinery/pkg/runtime/schema"
6 | )
7 |
8 | const (
9 | // NetworkPolicy represents Kubernetes NetworkPolicy objects.
10 | NetworkPolicy = "NetworkPolicy"
11 | )
12 |
13 | var (
14 | networkpolicyGVK = v1.SchemeGroupVersion.WithKind("NetworkPolicy")
15 | )
16 |
17 | func init() {
18 | RegisterObjectKind(NetworkPolicy, MatcherFunc(func(gvk schema.GroupVersionKind) bool {
19 | return gvk == networkpolicyGVK
20 | }))
21 | }
22 |
23 | // GetNetworkPolicyAPIVersion returns networkpolicy's apiversion
24 | func GetNetworkPolicyAPIVersion() string {
25 | return networkpolicyGVK.GroupVersion().String()
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/objectkinds/poddisruptionbudget.go:
--------------------------------------------------------------------------------
1 | package objectkinds
2 |
3 | import (
4 | policyv1 "k8s.io/api/policy/v1"
5 | "k8s.io/apimachinery/pkg/runtime/schema"
6 | )
7 |
8 | const (
9 | // PodDisruptionBudget represents Kubernetes PodDisruptionBudget objects.
10 | PodDisruptionBudget = "PodDisruptionBudget"
11 | )
12 |
13 | var (
14 | pdbGVK = policyv1.SchemeGroupVersion.WithKind("PodDisruptionBudget")
15 | )
16 |
17 | func init() {
18 | RegisterObjectKind(PodDisruptionBudget, MatcherFunc(func(gvk schema.GroupVersionKind) bool {
19 | return gvk == pdbGVK
20 | }))
21 | }
22 |
23 | // GetPodDisruptionBudgetAPIVersion returns pdb's apiversion
24 | func GetPodDisruptionBudgetAPIVersion() string {
25 | return pdbGVK.GroupVersion().String()
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/objectkinds/registry.go:
--------------------------------------------------------------------------------
1 | package objectkinds
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/pkg/errors"
7 | "k8s.io/apimachinery/pkg/runtime/schema"
8 | )
9 |
10 | var (
11 | allObjectKinds = make(map[string]Matcher)
12 | )
13 |
14 | // RegisterObjectKind allows a matcher function to be registered for a given object kind
15 | func RegisterObjectKind(name string, objectKind Matcher) {
16 | if _, ok := allObjectKinds[name]; ok {
17 | panic(fmt.Sprintf("duplicate object kind: %v", name))
18 | }
19 | allObjectKinds[name] = objectKind
20 | }
21 |
22 | // AllObjectKinds will return all the object kind names that are registered
23 | func AllObjectKinds() []string {
24 | kinds := make([]string, 0, len(allObjectKinds))
25 |
26 | for k := range allObjectKinds {
27 | kinds = append(kinds, k)
28 | }
29 | return kinds
30 | }
31 |
32 | type orMatcher []Matcher
33 |
34 | func (o orMatcher) Matches(gvk schema.GroupVersionKind) bool {
35 | for _, m := range o {
36 | if m.Matches(gvk) {
37 | return true
38 | }
39 | }
40 | return false
41 | }
42 |
43 | // ConstructMatcher constructs a matcher that matches objects that fall
44 | // into one of the given object kinds.
45 | func ConstructMatcher(objectKinds ...string) (Matcher, error) {
46 | var matchers []Matcher
47 | for _, obj := range objectKinds {
48 | matcher := allObjectKinds[obj]
49 | if matcher == nil {
50 | return nil, errors.Errorf("unknown object kind: %v", obj)
51 | }
52 | matchers = append(matchers, matcher)
53 | }
54 | return orMatcher(matchers), nil
55 | }
56 |
--------------------------------------------------------------------------------
/pkg/objectkinds/role.go:
--------------------------------------------------------------------------------
1 | package objectkinds
2 |
3 | import (
4 | rbacV1 "k8s.io/api/rbac/v1"
5 | "k8s.io/apimachinery/pkg/runtime/schema"
6 | )
7 |
8 | const (
9 | // Role represents Kubernetes Role objects. Case sensitive.
10 | Role = "Role"
11 | )
12 |
13 | var (
14 | // roleGVK represents Kubernetes Role objects. Case sensitive.
15 | roleGVK = rbacV1.SchemeGroupVersion.WithKind("Role")
16 | )
17 |
18 | func init() {
19 | RegisterObjectKind(Role, MatcherFunc(func(gvk schema.GroupVersionKind) bool {
20 | return gvk == roleGVK
21 | }))
22 | }
23 |
24 | // GetRoleAPIVersion returns Role's APIVersion
25 | func GetRoleAPIVersion() string {
26 | return roleGVK.GroupVersion().String()
27 | }
28 |
--------------------------------------------------------------------------------
/pkg/objectkinds/rolebinding.go:
--------------------------------------------------------------------------------
1 | package objectkinds
2 |
3 | import (
4 | rbacV1 "k8s.io/api/rbac/v1"
5 | "k8s.io/apimachinery/pkg/runtime/schema"
6 | )
7 |
8 | const (
9 | // RoleBinding represents Kubernetes RoleBinding objects. Case sensitive.
10 | RoleBinding = "RoleBinding"
11 | )
12 |
13 | var (
14 | roleBindingGVK = rbacV1.SchemeGroupVersion.WithKind("RoleBinding")
15 | )
16 |
17 | func init() {
18 | RegisterObjectKind(RoleBinding, MatcherFunc(func(gvk schema.GroupVersionKind) bool {
19 | return gvk == roleBindingGVK
20 | }))
21 | }
22 |
23 | // GetRoleBindingAPIVersion returns RoleBinding's APIVersion
24 | func GetRoleBindingAPIVersion() string {
25 | return roleBindingGVK.GroupVersion().String()
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/objectkinds/scaledobject.go:
--------------------------------------------------------------------------------
1 | package objectkinds
2 |
3 | import (
4 | "fmt"
5 |
6 | kedaV1Alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1"
7 | "k8s.io/apimachinery/pkg/runtime/schema"
8 | )
9 |
10 | const (
11 | // ScaledObject represents Kubernetes ScaledObject objects. Case sensitive.
12 | ScaledObject = "ScaledObject"
13 | )
14 |
15 | var (
16 | ScaledObjectV1Alpha1 = kedaV1Alpha1.SchemeGroupVersion.WithKind(ScaledObject)
17 | )
18 |
19 | func isScaledObject(gvk schema.GroupVersionKind) bool {
20 | return gvk == ScaledObjectV1Alpha1
21 | }
22 |
23 | func init() {
24 | RegisterObjectKind(ScaledObject, MatcherFunc(isScaledObject))
25 | }
26 |
27 | // GetScaledObjectAPIVersion returns ScaledObject's APIVersion
28 | func GetScaledObjectAPIVersion(version string) string {
29 | return fmt.Sprintf("%s/%s", ScaledObjectV1Alpha1.Group, version)
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/objectkinds/securitycontext.go:
--------------------------------------------------------------------------------
1 | package objectkinds
2 |
3 | import (
4 | ocpSecV1 "github.com/openshift/api/security/v1"
5 | "k8s.io/apimachinery/pkg/runtime/schema"
6 | )
7 |
8 | const (
9 | // Service represents Kubernetes Service objects.
10 | SecurityContextConstraints = "SecurityContextConstraints"
11 | )
12 |
13 | var (
14 | sccGVK = ocpSecV1.SchemeGroupVersion.WithKind("SecurityContextConstraints")
15 | )
16 |
17 | func init() {
18 | RegisterObjectKind(SecurityContextConstraints, MatcherFunc(func(gvk schema.GroupVersionKind) bool {
19 | return gvk == sccGVK
20 | }))
21 | }
22 |
23 | // GetSCCAPIVersion returns SCC's apiversion
24 | func GetSCCAPIVersion() string {
25 | return sccGVK.GroupVersion().String()
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/objectkinds/service.go:
--------------------------------------------------------------------------------
1 | package objectkinds
2 |
3 | import (
4 | v1 "k8s.io/api/core/v1"
5 | "k8s.io/apimachinery/pkg/runtime/schema"
6 | )
7 |
8 | const (
9 | // Service represents Kubernetes Service objects.
10 | Service = "Service"
11 | )
12 |
13 | var (
14 | serviceGVK = v1.SchemeGroupVersion.WithKind("Service")
15 | )
16 |
17 | func init() {
18 | RegisterObjectKind(Service, MatcherFunc(func(gvk schema.GroupVersionKind) bool {
19 | return gvk == serviceGVK
20 | }))
21 | }
22 |
--------------------------------------------------------------------------------
/pkg/objectkinds/serviceMonitor.go:
--------------------------------------------------------------------------------
1 | package objectkinds
2 |
3 | import (
4 | k8sMonitoring "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
5 | "k8s.io/apimachinery/pkg/runtime/schema"
6 | )
7 |
8 | const (
9 | // ServiceMonitor represents Prometheus Service Monitor objects.
10 | ServiceMonitor = k8sMonitoring.ServiceMonitorsKind
11 | )
12 |
13 | var (
14 | serviceMonitorGVK = k8sMonitoring.SchemeGroupVersion.WithKind(ServiceMonitor)
15 | )
16 |
17 | func init() {
18 | RegisterObjectKind(ServiceMonitor, MatcherFunc(func(gvk schema.GroupVersionKind) bool {
19 | return gvk == serviceMonitorGVK
20 | }))
21 | }
22 |
23 | // GetServiceMonitorAPIVersion returns servicemonitor's apiversion
24 | func GetServiceMonitorAPIVersion() string {
25 | return serviceMonitorGVK.GroupVersion().String()
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/objectkinds/serviceaccount.go:
--------------------------------------------------------------------------------
1 | package objectkinds
2 |
3 | import (
4 | v1 "k8s.io/api/core/v1"
5 | "k8s.io/apimachinery/pkg/runtime/schema"
6 | )
7 |
8 | const (
9 | // ServiceAccount represents Kubernetes ServiceAccount objects.
10 | ServiceAccount = "ServiceAccount"
11 | )
12 |
13 | var (
14 | serviceAccountGVK = v1.SchemeGroupVersion.WithKind("ServiceAccount")
15 | )
16 |
17 | func init() {
18 | RegisterObjectKind(ServiceAccount, MatcherFunc(func(gvk schema.GroupVersionKind) bool {
19 | return gvk == serviceAccountGVK
20 | }))
21 | }
22 |
--------------------------------------------------------------------------------
/pkg/objectkinds/types.go:
--------------------------------------------------------------------------------
1 | package objectkinds
2 |
3 | import (
4 | "k8s.io/apimachinery/pkg/runtime/schema"
5 | )
6 |
7 | // A Matcher selects a certain subset of GVKs.
8 | type Matcher interface {
9 | Matches(gvk schema.GroupVersionKind) bool
10 | }
11 |
12 | // MatcherFunc takes in a GVK and decides if it matches an object kind
13 | type MatcherFunc func(gvk schema.GroupVersionKind) bool
14 |
15 | func (f MatcherFunc) Matches(gvk schema.GroupVersionKind) bool {
16 | return f(gvk)
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/pathutil/path.go:
--------------------------------------------------------------------------------
1 | package pathutil
2 |
3 | import (
4 | "path/filepath"
5 |
6 | "github.com/mitchellh/go-homedir"
7 | "github.com/pkg/errors"
8 | )
9 |
10 | // GetAbsolutPath returns the absolute representation of given path.
11 | func GetAbsolutPath(path string) (string, error) {
12 | switch {
13 | case path[0] == '~':
14 | expandedPath, err := homedir.Expand(path)
15 | if err != nil {
16 | return "", errors.Wrapf(err, "could not expand path: %q", expandedPath)
17 | }
18 | return expandedPath, nil
19 | case !filepath.IsAbs(path):
20 | absPath, err := filepath.Abs(path)
21 | if err != nil {
22 | return "", errors.Wrapf(err, "could not expand non-absolute path: %q", absPath)
23 | }
24 | return absPath, nil
25 | default:
26 | return path, nil
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/pkg/templates/accesstoresources/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | // Set to true to flag the roles that are referenced in bindings but not found in the context
6 | FlagRolesNotFound bool `json:"flagRolesNotFound"`
7 | // An array of regular expressions specifying resources. e.g. ^secrets$ for secrets and ^*$ for any resources
8 | // +notnegatable
9 | Resources []string `json:"resources"`
10 | // An array of regular expressions specifying verbs. e.g. ^create$ for create and ^*$ for any k8s verbs
11 | // +notnegatable
12 | Verbs []string `json:"verbs"`
13 | }
14 |
--------------------------------------------------------------------------------
/pkg/templates/all/all_test.go:
--------------------------------------------------------------------------------
1 | package all
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/assert"
7 | "golang.stackrox.io/kube-linter/pkg/templates"
8 | )
9 |
10 | func TestTemplatesAreValid(t *testing.T) {
11 | for _, template := range templates.List() {
12 | t.Run(template.HumanName, func(t *testing.T) {
13 | assert.NotEmpty(t, template.HumanName, "human name")
14 | assert.NotEmpty(t, template.Key, "name")
15 | assert.NotEmpty(t, template.Description, "description")
16 | assert.NotNil(t, template.ParseAndValidateParams, "parse and validate params")
17 | assert.NotNil(t, template.Parameters, "params") // We want people to use the generated code and explicitly set it to an empty list.
18 | assert.NotNil(t, template.Instantiate, "instantiate")
19 | })
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/pkg/templates/antiaffinity/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 |
6 | // The minimum number of replicas a deployment must have before anti-affinity is enforced on it
7 | MinReplicas int
8 |
9 | // The topology key that the anti-affinity term should use.
10 | // If not specified, it defaults to "kubernetes.io/hostname".
11 | TopologyKey string
12 | }
13 |
--------------------------------------------------------------------------------
/pkg/templates/clusteradminrolebinding/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/containercapabilities/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 |
6 | // List of capabilities that needs to be removed from containers.
7 | // +noregex
8 | // +notnegatable
9 | ForbiddenCapabilities []string `json:"forbiddenCapabilities"`
10 |
11 | // List of capabilities that are exceptions to the above list. This should only be filled
12 | // when the above contains "all", and is used to forgive capabilities in ADD list.
13 | // +noregex
14 | // +notnegatable
15 | Exceptions []string `json:"exceptions"`
16 | }
17 |
--------------------------------------------------------------------------------
/pkg/templates/cpurequirements/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 |
6 | // The type of requirement. Use any to apply to both requests and limits.
7 | // +enum=request
8 | // +enum=limit
9 | // +enum=any
10 | // +required
11 | RequirementsType string
12 |
13 | // The lower bound of the requirement (inclusive), specified as
14 | // a number of milli-cores.
15 | // If not specified, it is treated as a lower bound of zero.
16 | LowerBoundMillis int `json:"lowerBoundMillis"`
17 |
18 | // The upper bound of the requirement (inclusive), specified as
19 | // a number of milli-cores.
20 | // If not specified, it is treated as "no upper bound".
21 | UpperBoundMillis *int `json:"upperBoundMillis"`
22 | }
23 |
--------------------------------------------------------------------------------
/pkg/templates/danglinghpa/internal/params/gen-params.go:
--------------------------------------------------------------------------------
1 | // Code generated by kube-linter template codegen. DO NOT EDIT.
2 | // +build !templatecodegen
3 |
4 | package params
5 |
6 | import (
7 | "fmt"
8 | "strings"
9 |
10 | "github.com/pkg/errors"
11 | "golang.stackrox.io/kube-linter/pkg/check"
12 | "golang.stackrox.io/kube-linter/pkg/templates/util"
13 | )
14 |
15 | var (
16 | // Use some imports in case they don't get used otherwise.
17 | _ = util.MustParseParameterDesc
18 | _ = fmt.Sprintf
19 |
20 | ParamDescs = []check.ParameterDesc{
21 | }
22 | )
23 |
24 | func (p *Params) Validate() error {
25 | var validationErrors []string
26 | if len(validationErrors) > 0 {
27 | return errors.Errorf("invalid parameters: %s", strings.Join(validationErrors, ", "))
28 | }
29 | return nil
30 | }
31 |
32 | // ParseAndValidate instantiates a Params object out of the passed map[string]interface{},
33 | // validates it, and returns it.
34 | // The return type is interface{} to satisfy the type in the Template struct.
35 | func ParseAndValidate(m map[string]interface{}) (interface{}, error) {
36 | var p Params
37 | if err := util.DecodeMapStructure(m, &p); err != nil {
38 | return nil, err
39 | }
40 | if err := p.Validate(); err != nil {
41 | return nil, err
42 | }
43 | return p, nil
44 | }
45 |
46 | // WrapInstantiateFunc is a convenience wrapper that wraps an untyped instantiate function
47 | // into a typed one.
48 | func WrapInstantiateFunc(f func(p Params) (check.Func, error)) func (interface{}) (check.Func, error) {
49 | return func(paramsInt interface{}) (check.Func, error) {
50 | return f(paramsInt.(Params))
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/templates/danglinghpa/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/danglingingress/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/danglingnetworkpolicy/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/danglingnetworkpolicypeer/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/danglingservice/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | // A list of labels that will not cause the check to fail. For example, a label that is known to be populated at runtime by Kubernetes.
6 | IgnoredLabels []string `json:"ignoredLabels"`
7 | }
8 |
--------------------------------------------------------------------------------
/pkg/templates/danglingservicemonitor/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/deprecatedserviceaccount/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/disallowedgvk/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 |
6 | // The disallowed object group.
7 | // +example=apps
8 | Group string `json:"group"`
9 |
10 | // The disallowed object API version.
11 | // +example=v1
12 | // +example=v1beta1
13 | Version string
14 |
15 | // The disallowed kind.
16 | // +example=Deployment
17 | // +example=DaemonSet
18 | Kind string
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/templates/dnsconfigoptions/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 |
6 | // Key of the dnsConfig option.
7 | Key string
8 |
9 | // Value of the dnsConfig option.
10 | Value string
11 | }
12 |
--------------------------------------------------------------------------------
/pkg/templates/duplicatenvvar/internal/params/gen-params.go:
--------------------------------------------------------------------------------
1 | // Code generated by kube-linter template codegen. DO NOT EDIT.
2 | // +build !templatecodegen
3 |
4 | package params
5 |
6 | import (
7 | "fmt"
8 | "strings"
9 |
10 | "github.com/pkg/errors"
11 | "golang.stackrox.io/kube-linter/pkg/check"
12 | "golang.stackrox.io/kube-linter/pkg/templates/util"
13 | )
14 |
15 | var (
16 | // Use some imports in case they don't get used otherwise.
17 | _ = util.MustParseParameterDesc
18 | _ = fmt.Sprintf
19 |
20 | ParamDescs = []check.ParameterDesc{
21 | }
22 | )
23 |
24 | func (p *Params) Validate() error {
25 | var validationErrors []string
26 | if len(validationErrors) > 0 {
27 | return errors.Errorf("invalid parameters: %s", strings.Join(validationErrors, ", "))
28 | }
29 | return nil
30 | }
31 |
32 | // ParseAndValidate instantiates a Params object out of the passed map[string]interface{},
33 | // validates it, and returns it.
34 | // The return type is interface{} to satisfy the type in the Template struct.
35 | func ParseAndValidate(m map[string]interface{}) (interface{}, error) {
36 | var p Params
37 | if err := util.DecodeMapStructure(m, &p); err != nil {
38 | return nil, err
39 | }
40 | if err := p.Validate(); err != nil {
41 | return nil, err
42 | }
43 | return p, nil
44 | }
45 |
46 | // WrapInstantiateFunc is a convenience wrapper that wraps an untyped instantiate function
47 | // into a typed one.
48 | func WrapInstantiateFunc(f func(p Params) (check.Func, error)) func (interface{}) (check.Func, error) {
49 | return func(paramsInt interface{}) (check.Func, error) {
50 | return f(paramsInt.(Params))
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/templates/duplicatenvvar/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct{}
5 |
--------------------------------------------------------------------------------
/pkg/templates/envvar/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 |
6 | // The name of the environment variable.
7 | // +required
8 | Name string
9 |
10 | // The value of the environment variable.
11 | Value string
12 | }
13 |
--------------------------------------------------------------------------------
/pkg/templates/forbiddenannotation/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 |
6 | // Key of the forbidden annotation.
7 | // +required
8 | Key string
9 |
10 | // Value of the forbidden annotation.
11 | Value string
12 | }
13 |
--------------------------------------------------------------------------------
/pkg/templates/forbiddenannotation/template.go:
--------------------------------------------------------------------------------
1 | package forbiddenannotation
2 |
3 | import (
4 | "golang.stackrox.io/kube-linter/pkg/check"
5 | "golang.stackrox.io/kube-linter/pkg/config"
6 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
7 | "golang.stackrox.io/kube-linter/pkg/templates"
8 | "golang.stackrox.io/kube-linter/pkg/templates/forbiddenannotation/internal/params"
9 | "golang.stackrox.io/kube-linter/pkg/templates/util"
10 | )
11 |
12 | func init() {
13 | templates.Register(check.Template{
14 | HumanName: "Forbidden Annotation",
15 | Key: "forbidden-annotation",
16 | Description: "Flag objects carrying at least one annotation matching the provided patterns",
17 | SupportedObjectKinds: config.ObjectKindsDesc{
18 | ObjectKinds: []string{objectkinds.Any},
19 | },
20 | Parameters: params.ParamDescs,
21 | ParseAndValidateParams: params.ParseAndValidate,
22 | Instantiate: params.WrapInstantiateFunc(func(p params.Params) (check.Func, error) {
23 | return util.ConstructForbiddenMapMatcher(p.Key, p.Value, "annotation")
24 | }),
25 | })
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/templates/gen.go:
--------------------------------------------------------------------------------
1 | package templates
2 |
3 | //go:generate go run ./codegen
4 |
--------------------------------------------------------------------------------
/pkg/templates/hostipc/internal/params/gen-params.go:
--------------------------------------------------------------------------------
1 | // Code generated by kube-linter template codegen. DO NOT EDIT.
2 | // +build !templatecodegen
3 |
4 | package params
5 |
6 | import (
7 | "fmt"
8 | "strings"
9 |
10 | "github.com/pkg/errors"
11 | "golang.stackrox.io/kube-linter/pkg/check"
12 | "golang.stackrox.io/kube-linter/pkg/templates/util"
13 | )
14 |
15 | var (
16 | // Use some imports in case they don't get used otherwise.
17 | _ = util.MustParseParameterDesc
18 | _ = fmt.Sprintf
19 |
20 | ParamDescs = []check.ParameterDesc{
21 | }
22 | )
23 |
24 | func (p *Params) Validate() error {
25 | var validationErrors []string
26 | if len(validationErrors) > 0 {
27 | return errors.Errorf("invalid parameters: %s", strings.Join(validationErrors, ", "))
28 | }
29 | return nil
30 | }
31 |
32 | // ParseAndValidate instantiates a Params object out of the passed map[string]interface{},
33 | // validates it, and returns it.
34 | // The return type is interface{} to satisfy the type in the Template struct.
35 | func ParseAndValidate(m map[string]interface{}) (interface{}, error) {
36 | var p Params
37 | if err := util.DecodeMapStructure(m, &p); err != nil {
38 | return nil, err
39 | }
40 | if err := p.Validate(); err != nil {
41 | return nil, err
42 | }
43 | return p, nil
44 | }
45 |
46 | // WrapInstantiateFunc is a convenience wrapper that wraps an untyped instantiate function
47 | // into a typed one.
48 | func WrapInstantiateFunc(f func(p Params) (check.Func, error)) func (interface{}) (check.Func, error) {
49 | return func(paramsInt interface{}) (check.Func, error) {
50 | return f(paramsInt.(Params))
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/templates/hostipc/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/hostipc/template.go:
--------------------------------------------------------------------------------
1 | package hostipc
2 |
3 | import (
4 | "golang.stackrox.io/kube-linter/pkg/check"
5 | "golang.stackrox.io/kube-linter/pkg/config"
6 | "golang.stackrox.io/kube-linter/pkg/diagnostic"
7 | "golang.stackrox.io/kube-linter/pkg/extract"
8 | "golang.stackrox.io/kube-linter/pkg/lintcontext"
9 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
10 | "golang.stackrox.io/kube-linter/pkg/templates"
11 | "golang.stackrox.io/kube-linter/pkg/templates/hostipc/internal/params"
12 | )
13 |
14 | func init() {
15 | templates.Register(check.Template{
16 | HumanName: "Host IPC",
17 | Key: "host-ipc",
18 | Description: "Flag Pod sharing host's IPC namespace",
19 | SupportedObjectKinds: config.ObjectKindsDesc{
20 | ObjectKinds: []string{objectkinds.DeploymentLike},
21 | },
22 | Parameters: params.ParamDescs,
23 | ParseAndValidateParams: params.ParseAndValidate,
24 | Instantiate: params.WrapInstantiateFunc(func(_ params.Params) (check.Func, error) {
25 | return func(_ lintcontext.LintContext, object lintcontext.Object) []diagnostic.Diagnostic {
26 | podSpec, found := extract.PodSpec(object.K8sObject)
27 | if !found {
28 | return nil
29 | }
30 | if podSpec.HostIPC {
31 | return []diagnostic.Diagnostic{{Message: "resource shares host's IPC namespace (via hostIPC=true)."}}
32 | }
33 | return nil
34 | }, nil
35 | }),
36 | })
37 | }
38 |
--------------------------------------------------------------------------------
/pkg/templates/hostmounts/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | // An array of regular expressions specifying system directories to be mounted on containers. e.g. ^/usr$ for /usr
6 | // +notnegatable
7 | Dirs []string `json:"dirs"`
8 | }
9 |
--------------------------------------------------------------------------------
/pkg/templates/hostnetwork/internal/params/gen-params.go:
--------------------------------------------------------------------------------
1 | // Code generated by kube-linter template codegen. DO NOT EDIT.
2 | // +build !templatecodegen
3 |
4 | package params
5 |
6 | import (
7 | "fmt"
8 | "strings"
9 |
10 | "github.com/pkg/errors"
11 | "golang.stackrox.io/kube-linter/pkg/check"
12 | "golang.stackrox.io/kube-linter/pkg/templates/util"
13 | )
14 |
15 | var (
16 | // Use some imports in case they don't get used otherwise.
17 | _ = util.MustParseParameterDesc
18 | _ = fmt.Sprintf
19 |
20 | ParamDescs = []check.ParameterDesc{
21 | }
22 | )
23 |
24 | func (p *Params) Validate() error {
25 | var validationErrors []string
26 | if len(validationErrors) > 0 {
27 | return errors.Errorf("invalid parameters: %s", strings.Join(validationErrors, ", "))
28 | }
29 | return nil
30 | }
31 |
32 | // ParseAndValidate instantiates a Params object out of the passed map[string]interface{},
33 | // validates it, and returns it.
34 | // The return type is interface{} to satisfy the type in the Template struct.
35 | func ParseAndValidate(m map[string]interface{}) (interface{}, error) {
36 | var p Params
37 | if err := util.DecodeMapStructure(m, &p); err != nil {
38 | return nil, err
39 | }
40 | if err := p.Validate(); err != nil {
41 | return nil, err
42 | }
43 | return p, nil
44 | }
45 |
46 | // WrapInstantiateFunc is a convenience wrapper that wraps an untyped instantiate function
47 | // into a typed one.
48 | func WrapInstantiateFunc(f func(p Params) (check.Func, error)) func (interface{}) (check.Func, error) {
49 | return func(paramsInt interface{}) (check.Func, error) {
50 | return f(paramsInt.(Params))
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/templates/hostnetwork/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/hostnetwork/template.go:
--------------------------------------------------------------------------------
1 | package hostnetwork
2 |
3 | import (
4 | "golang.stackrox.io/kube-linter/pkg/check"
5 | "golang.stackrox.io/kube-linter/pkg/config"
6 | "golang.stackrox.io/kube-linter/pkg/diagnostic"
7 | "golang.stackrox.io/kube-linter/pkg/extract"
8 | "golang.stackrox.io/kube-linter/pkg/lintcontext"
9 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
10 | "golang.stackrox.io/kube-linter/pkg/templates"
11 | "golang.stackrox.io/kube-linter/pkg/templates/hostnetwork/internal/params"
12 | )
13 |
14 | func init() {
15 | templates.Register(check.Template{
16 | HumanName: "Host Network",
17 | Key: "host-network",
18 | Description: "Flag Pod sharing host's network namespace",
19 | SupportedObjectKinds: config.ObjectKindsDesc{
20 | ObjectKinds: []string{objectkinds.DeploymentLike},
21 | },
22 | Parameters: params.ParamDescs,
23 | ParseAndValidateParams: params.ParseAndValidate,
24 | Instantiate: params.WrapInstantiateFunc(func(_ params.Params) (check.Func, error) {
25 | return func(_ lintcontext.LintContext, object lintcontext.Object) []diagnostic.Diagnostic {
26 | podSpec, found := extract.PodSpec(object.K8sObject)
27 | if !found {
28 | return nil
29 | }
30 | if podSpec.HostNetwork {
31 | return []diagnostic.Diagnostic{{Message: "resource shares host's network namespace (via hostNetwork=true)."}}
32 | }
33 | return nil
34 | }, nil
35 | }),
36 | })
37 | }
38 |
--------------------------------------------------------------------------------
/pkg/templates/hostpid/internal/params/gen-params.go:
--------------------------------------------------------------------------------
1 | // Code generated by kube-linter template codegen. DO NOT EDIT.
2 | // +build !templatecodegen
3 |
4 | package params
5 |
6 | import (
7 | "fmt"
8 | "strings"
9 |
10 | "github.com/pkg/errors"
11 | "golang.stackrox.io/kube-linter/pkg/check"
12 | "golang.stackrox.io/kube-linter/pkg/templates/util"
13 | )
14 |
15 | var (
16 | // Use some imports in case they don't get used otherwise.
17 | _ = util.MustParseParameterDesc
18 | _ = fmt.Sprintf
19 |
20 | ParamDescs = []check.ParameterDesc{
21 | }
22 | )
23 |
24 | func (p *Params) Validate() error {
25 | var validationErrors []string
26 | if len(validationErrors) > 0 {
27 | return errors.Errorf("invalid parameters: %s", strings.Join(validationErrors, ", "))
28 | }
29 | return nil
30 | }
31 |
32 | // ParseAndValidate instantiates a Params object out of the passed map[string]interface{},
33 | // validates it, and returns it.
34 | // The return type is interface{} to satisfy the type in the Template struct.
35 | func ParseAndValidate(m map[string]interface{}) (interface{}, error) {
36 | var p Params
37 | if err := util.DecodeMapStructure(m, &p); err != nil {
38 | return nil, err
39 | }
40 | if err := p.Validate(); err != nil {
41 | return nil, err
42 | }
43 | return p, nil
44 | }
45 |
46 | // WrapInstantiateFunc is a convenience wrapper that wraps an untyped instantiate function
47 | // into a typed one.
48 | func WrapInstantiateFunc(f func(p Params) (check.Func, error)) func (interface{}) (check.Func, error) {
49 | return func(paramsInt interface{}) (check.Func, error) {
50 | return f(paramsInt.(Params))
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/templates/hostpid/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/hostpid/template.go:
--------------------------------------------------------------------------------
1 | package hostpid
2 |
3 | import (
4 | "golang.stackrox.io/kube-linter/pkg/check"
5 | "golang.stackrox.io/kube-linter/pkg/config"
6 | "golang.stackrox.io/kube-linter/pkg/diagnostic"
7 | "golang.stackrox.io/kube-linter/pkg/extract"
8 | "golang.stackrox.io/kube-linter/pkg/lintcontext"
9 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
10 | "golang.stackrox.io/kube-linter/pkg/templates"
11 | "golang.stackrox.io/kube-linter/pkg/templates/hostpid/internal/params"
12 | )
13 |
14 | func init() {
15 | templates.Register(check.Template{
16 | HumanName: "Host PID",
17 | Key: "host-pid",
18 | Description: "Flag Pod sharing host's process namespace",
19 | SupportedObjectKinds: config.ObjectKindsDesc{
20 | ObjectKinds: []string{objectkinds.DeploymentLike},
21 | },
22 | Parameters: params.ParamDescs,
23 | ParseAndValidateParams: params.ParseAndValidate,
24 | Instantiate: params.WrapInstantiateFunc(func(_ params.Params) (check.Func, error) {
25 | return func(_ lintcontext.LintContext, object lintcontext.Object) []diagnostic.Diagnostic {
26 | podSpec, found := extract.PodSpec(object.K8sObject)
27 | if !found {
28 | return nil
29 | }
30 | if podSpec.HostPID {
31 | return []diagnostic.Diagnostic{{Message: "object shares the host's process namespace (via hostPID=true)."}}
32 | }
33 | return nil
34 | }, nil
35 | }),
36 | })
37 | }
38 |
--------------------------------------------------------------------------------
/pkg/templates/hpareplicas/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 |
6 | // The minimum number of replicas a HorizontalPodAutoscaler should have
7 | MinReplicas int
8 | }
9 |
--------------------------------------------------------------------------------
/pkg/templates/imagepullpolicy/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | // list of forbidden image pull policy
6 | // +noregex
7 | // +notnegatable
8 | // +enum=Always
9 | // +enum=IfNotPresent
10 | // +enum=Never
11 | ForbiddenPolicies []string
12 | }
13 |
--------------------------------------------------------------------------------
/pkg/templates/imagepullpolicy/template.go:
--------------------------------------------------------------------------------
1 | package imagepullpolicy
2 |
3 | import (
4 | "fmt"
5 |
6 | "golang.stackrox.io/kube-linter/internal/set"
7 | "golang.stackrox.io/kube-linter/pkg/check"
8 | "golang.stackrox.io/kube-linter/pkg/config"
9 | "golang.stackrox.io/kube-linter/pkg/diagnostic"
10 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
11 | "golang.stackrox.io/kube-linter/pkg/templates"
12 | "golang.stackrox.io/kube-linter/pkg/templates/imagepullpolicy/internal/params"
13 | "golang.stackrox.io/kube-linter/pkg/templates/util"
14 | v1 "k8s.io/api/core/v1"
15 | )
16 |
17 | const (
18 | templateKey = "image-pull-policy"
19 | )
20 |
21 | func init() {
22 | templates.Register(check.Template{
23 | HumanName: "Image Pull Policy",
24 | Key: templateKey,
25 | Description: "Flag containers with forbidden image pull policy",
26 | SupportedObjectKinds: config.ObjectKindsDesc{
27 | ObjectKinds: []string{objectkinds.DeploymentLike},
28 | },
29 | Parameters: params.ParamDescs,
30 | ParseAndValidateParams: params.ParseAndValidate,
31 | Instantiate: params.WrapInstantiateFunc(func(p params.Params) (check.Func, error) {
32 | forbiddenPolicies := set.NewStringSet(p.ForbiddenPolicies...)
33 | return util.PerContainerCheck(func(container *v1.Container) []diagnostic.Diagnostic {
34 | if forbiddenPolicies.Contains(string(container.ImagePullPolicy)) {
35 | return []diagnostic.Diagnostic{{Message: fmt.Sprintf("container %q has imagePullPolicy set to %s", container.Name, container.ImagePullPolicy)}}
36 | }
37 | return nil
38 | }), nil
39 | }),
40 | })
41 | }
42 |
--------------------------------------------------------------------------------
/pkg/templates/latesttag/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 |
6 | // list of regular expressions specifying pattern(s) for container images that will be blocked. */
7 | BlockList []string
8 |
9 | // list of regular expressions specifying pattern(s) for container images that will be allowed.
10 | AllowList []string
11 | }
12 |
--------------------------------------------------------------------------------
/pkg/templates/livenessport/internal/params/gen-params.go:
--------------------------------------------------------------------------------
1 | // Code generated by kube-linter template codegen. DO NOT EDIT.
2 | // +build !templatecodegen
3 |
4 | package params
5 |
6 | import (
7 | "fmt"
8 | "strings"
9 |
10 | "github.com/pkg/errors"
11 | "golang.stackrox.io/kube-linter/pkg/check"
12 | "golang.stackrox.io/kube-linter/pkg/templates/util"
13 | )
14 |
15 | var (
16 | // Use some imports in case they don't get used otherwise.
17 | _ = util.MustParseParameterDesc
18 | _ = fmt.Sprintf
19 |
20 | ParamDescs = []check.ParameterDesc{
21 | }
22 | )
23 |
24 | func (p *Params) Validate() error {
25 | var validationErrors []string
26 | if len(validationErrors) > 0 {
27 | return errors.Errorf("invalid parameters: %s", strings.Join(validationErrors, ", "))
28 | }
29 | return nil
30 | }
31 |
32 | // ParseAndValidate instantiates a Params object out of the passed map[string]interface{},
33 | // validates it, and returns it.
34 | // The return type is interface{} to satisfy the type in the Template struct.
35 | func ParseAndValidate(m map[string]interface{}) (interface{}, error) {
36 | var p Params
37 | if err := util.DecodeMapStructure(m, &p); err != nil {
38 | return nil, err
39 | }
40 | if err := p.Validate(); err != nil {
41 | return nil, err
42 | }
43 | return p, nil
44 | }
45 |
46 | // WrapInstantiateFunc is a convenience wrapper that wraps an untyped instantiate function
47 | // into a typed one.
48 | func WrapInstantiateFunc(f func(p Params) (check.Func, error)) func (interface{}) (check.Func, error) {
49 | return func(paramsInt interface{}) (check.Func, error) {
50 | return f(paramsInt.(Params))
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/templates/livenessport/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct{}
5 |
--------------------------------------------------------------------------------
/pkg/templates/livenessport/template.go:
--------------------------------------------------------------------------------
1 | package livenessport
2 |
3 | import (
4 | "golang.stackrox.io/kube-linter/pkg/check"
5 | "golang.stackrox.io/kube-linter/pkg/config"
6 | "golang.stackrox.io/kube-linter/pkg/diagnostic"
7 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
8 | "golang.stackrox.io/kube-linter/pkg/templates"
9 | "golang.stackrox.io/kube-linter/pkg/templates/livenessport/internal/params"
10 | "golang.stackrox.io/kube-linter/pkg/templates/util"
11 | v1 "k8s.io/api/core/v1"
12 | )
13 |
14 | const templateKey = "liveness-port"
15 |
16 | func init() {
17 | templates.Register(check.Template{
18 | HumanName: "Liveness Port Exposed",
19 | Key: templateKey,
20 | Description: "Flag containers with an liveness probe to not exposed port.",
21 | SupportedObjectKinds: config.ObjectKindsDesc{
22 | ObjectKinds: []string{objectkinds.DeploymentLike},
23 | },
24 | Parameters: params.ParamDescs,
25 | ParseAndValidateParams: params.ParseAndValidate,
26 | Instantiate: params.WrapInstantiateFunc(func(_ params.Params) (check.Func, error) {
27 | return util.PerNonInitContainerCheck(func(container *v1.Container) []diagnostic.Diagnostic {
28 | return util.CheckProbePort(container, container.LivenessProbe)
29 | }), nil
30 | }),
31 | })
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/templates/livenessprobe/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/livenessprobe/template.go:
--------------------------------------------------------------------------------
1 | package livenessprobe
2 |
3 | import (
4 | "fmt"
5 |
6 | "golang.stackrox.io/kube-linter/pkg/check"
7 | "golang.stackrox.io/kube-linter/pkg/config"
8 | "golang.stackrox.io/kube-linter/pkg/diagnostic"
9 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
10 | "golang.stackrox.io/kube-linter/pkg/templates"
11 | "golang.stackrox.io/kube-linter/pkg/templates/livenessprobe/internal/params"
12 | "golang.stackrox.io/kube-linter/pkg/templates/util"
13 | v1 "k8s.io/api/core/v1"
14 | )
15 |
16 | func init() {
17 | templates.Register(check.Template{
18 | HumanName: "Liveness Probe Not Specified",
19 | Key: "liveness-probe",
20 | Description: "Flag containers that don't specify a liveness probe",
21 | SupportedObjectKinds: config.ObjectKindsDesc{
22 | ObjectKinds: []string{objectkinds.DeploymentLike},
23 | },
24 | Parameters: params.ParamDescs,
25 |
26 | ParseAndValidateParams: params.ParseAndValidate,
27 | Instantiate: params.WrapInstantiateFunc(func(_ params.Params) (check.Func, error) {
28 | return util.PerNonInitContainerCheck(func(container *v1.Container) []diagnostic.Diagnostic {
29 | if container.LivenessProbe == nil {
30 | return []diagnostic.Diagnostic{{Message: fmt.Sprintf("container %q does not specify a liveness probe", container.Name)}}
31 | }
32 | return nil
33 | }), nil
34 | }),
35 | })
36 | }
37 |
--------------------------------------------------------------------------------
/pkg/templates/memoryrequirements/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 |
6 | // The type of requirement. Use any to apply to both requests and limits.
7 | // +enum=request
8 | // +enum=limit
9 | // +enum=any
10 | // +required
11 | RequirementsType string
12 |
13 | // The lower bound of the requirement (inclusive), specified as
14 | // a number of MB.
15 | LowerBoundMB int `json:"lowerBoundMB"`
16 |
17 | // The upper bound of the requirement (inclusive), specified as
18 | // a number of MB.
19 | // If not specified, it is treated as "no upper bound".
20 | UpperBoundMB *int `json:"upperBoundMB"`
21 | }
22 |
--------------------------------------------------------------------------------
/pkg/templates/mismatchingselector/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/namespace/internal/params/gen-params.go:
--------------------------------------------------------------------------------
1 | // Code generated by kube-linter template codegen. DO NOT EDIT.
2 | // +build !templatecodegen
3 |
4 | package params
5 |
6 | import (
7 | "fmt"
8 | "strings"
9 |
10 | "github.com/pkg/errors"
11 | "golang.stackrox.io/kube-linter/pkg/check"
12 | "golang.stackrox.io/kube-linter/pkg/templates/util"
13 | )
14 |
15 | var (
16 | // Use some imports in case they don't get used otherwise.
17 | _ = util.MustParseParameterDesc
18 | _ = fmt.Sprintf
19 |
20 | ParamDescs = []check.ParameterDesc{
21 | }
22 | )
23 |
24 | func (p *Params) Validate() error {
25 | var validationErrors []string
26 | if len(validationErrors) > 0 {
27 | return errors.Errorf("invalid parameters: %s", strings.Join(validationErrors, ", "))
28 | }
29 | return nil
30 | }
31 |
32 | // ParseAndValidate instantiates a Params object out of the passed map[string]interface{},
33 | // validates it, and returns it.
34 | // The return type is interface{} to satisfy the type in the Template struct.
35 | func ParseAndValidate(m map[string]interface{}) (interface{}, error) {
36 | var p Params
37 | if err := util.DecodeMapStructure(m, &p); err != nil {
38 | return nil, err
39 | }
40 | if err := p.Validate(); err != nil {
41 | return nil, err
42 | }
43 | return p, nil
44 | }
45 |
46 | // WrapInstantiateFunc is a convenience wrapper that wraps an untyped instantiate function
47 | // into a typed one.
48 | func WrapInstantiateFunc(f func(p Params) (check.Func, error)) func (interface{}) (check.Func, error) {
49 | return func(paramsInt interface{}) (check.Func, error) {
50 | return f(paramsInt.(Params))
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/templates/namespace/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/namespace/template.go:
--------------------------------------------------------------------------------
1 | package namespace
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.stackrox.io/kube-linter/internal/stringutils"
7 | "golang.stackrox.io/kube-linter/pkg/check"
8 | "golang.stackrox.io/kube-linter/pkg/config"
9 | "golang.stackrox.io/kube-linter/pkg/diagnostic"
10 | "golang.stackrox.io/kube-linter/pkg/lintcontext"
11 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
12 | "golang.stackrox.io/kube-linter/pkg/templates"
13 | "golang.stackrox.io/kube-linter/pkg/templates/namespace/internal/params"
14 | )
15 |
16 | func init() {
17 | templates.Register(check.Template{
18 | HumanName: "Use Namespaces for Administrative Boundaries between Resources",
19 | Key: "use-namespace",
20 | Description: "Flag resources with no namespace specified or using default namespace",
21 | SupportedObjectKinds: config.ObjectKindsDesc{
22 | ObjectKinds: []string{objectkinds.DeploymentLike, objectkinds.Service},
23 | },
24 | Parameters: params.ParamDescs,
25 | ParseAndValidateParams: params.ParseAndValidate,
26 | Instantiate: params.WrapInstantiateFunc(func(_ params.Params) (check.Func, error) {
27 | return func(_ lintcontext.LintContext, object lintcontext.Object) []diagnostic.Diagnostic {
28 | namespace := object.K8sObject.GetNamespace()
29 | ns := stringutils.OrDefault(namespace, "default")
30 | if strings.EqualFold(ns, "default") {
31 | return []diagnostic.Diagnostic{{Message: "object in default namespace"}}
32 | }
33 | return nil
34 | }, nil
35 | }),
36 | })
37 | }
38 |
--------------------------------------------------------------------------------
/pkg/templates/nodeaffinity/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/nonexistentserviceaccount/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/nonisolatedpod/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/pdbmaxunavailable/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/pdbminavailable/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/pdbunhealthypodevictionpolicy/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/ports/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 |
6 | // The port
7 | Port int
8 |
9 | // The protocol
10 | Protocol string
11 | }
12 |
--------------------------------------------------------------------------------
/pkg/templates/privileged/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/privileged/template.go:
--------------------------------------------------------------------------------
1 | package privileged
2 |
3 | import (
4 | "fmt"
5 |
6 | "golang.stackrox.io/kube-linter/pkg/check"
7 | "golang.stackrox.io/kube-linter/pkg/config"
8 | "golang.stackrox.io/kube-linter/pkg/diagnostic"
9 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
10 | "golang.stackrox.io/kube-linter/pkg/templates"
11 | "golang.stackrox.io/kube-linter/pkg/templates/privileged/internal/params"
12 | "golang.stackrox.io/kube-linter/pkg/templates/util"
13 | v1 "k8s.io/api/core/v1"
14 | )
15 |
16 | func init() {
17 | templates.Register(check.Template{
18 | HumanName: "Privileged Containers",
19 | Key: "privileged",
20 | Description: "Flag privileged containers",
21 | SupportedObjectKinds: config.ObjectKindsDesc{
22 | ObjectKinds: []string{objectkinds.DeploymentLike},
23 | },
24 | Parameters: params.ParamDescs,
25 | ParseAndValidateParams: params.ParseAndValidate,
26 | Instantiate: params.WrapInstantiateFunc(func(_ params.Params) (check.Func, error) {
27 | return util.PerContainerCheck(func(container *v1.Container) []diagnostic.Diagnostic {
28 | if securityContext := container.SecurityContext; securityContext != nil {
29 | if securityContext.Privileged != nil && *securityContext.Privileged {
30 | return []diagnostic.Diagnostic{{Message: fmt.Sprintf("container %q is privileged", container.Name)}}
31 | }
32 | }
33 | return nil
34 | }), nil
35 | }),
36 | })
37 | }
38 |
--------------------------------------------------------------------------------
/pkg/templates/privilegedports/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/privilegedports/template.go:
--------------------------------------------------------------------------------
1 | package privilegedports
2 |
3 | import (
4 | "fmt"
5 |
6 | "golang.stackrox.io/kube-linter/pkg/check"
7 | "golang.stackrox.io/kube-linter/pkg/config"
8 | "golang.stackrox.io/kube-linter/pkg/diagnostic"
9 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
10 | "golang.stackrox.io/kube-linter/pkg/templates"
11 | "golang.stackrox.io/kube-linter/pkg/templates/privilegedports/internal/params"
12 | "golang.stackrox.io/kube-linter/pkg/templates/util"
13 | v1 "k8s.io/api/core/v1"
14 | )
15 |
16 | func init() {
17 | templates.Register(check.Template{
18 | HumanName: "Privileged Ports",
19 | Key: "privileged-ports",
20 | Description: "Flag privileged ports",
21 | SupportedObjectKinds: config.ObjectKindsDesc{
22 | ObjectKinds: []string{objectkinds.DeploymentLike},
23 | },
24 | Parameters: params.ParamDescs,
25 | ParseAndValidateParams: params.ParseAndValidate,
26 | Instantiate: params.WrapInstantiateFunc(func(_ params.Params) (check.Func, error) {
27 | return util.PerContainerCheck(func(container *v1.Container) []diagnostic.Diagnostic {
28 | var results []diagnostic.Diagnostic
29 | for _, port := range container.Ports {
30 | if int(port.ContainerPort) > 0 && int(port.ContainerPort) < 1024 {
31 | results = append(results, diagnostic.Diagnostic{
32 | Message: fmt.Sprintf("port %d is mapped in container %q.", port.ContainerPort, container.Name),
33 | })
34 | }
35 | }
36 | return results
37 | }), nil
38 | }),
39 | })
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/templates/privilegeescalation/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/readinessport/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct{}
5 |
--------------------------------------------------------------------------------
/pkg/templates/readinessport/template.go:
--------------------------------------------------------------------------------
1 | package readinessport
2 |
3 | import (
4 | "golang.stackrox.io/kube-linter/pkg/check"
5 | "golang.stackrox.io/kube-linter/pkg/config"
6 | "golang.stackrox.io/kube-linter/pkg/diagnostic"
7 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
8 | "golang.stackrox.io/kube-linter/pkg/templates"
9 | "golang.stackrox.io/kube-linter/pkg/templates/readinessport/internal/params"
10 | "golang.stackrox.io/kube-linter/pkg/templates/util"
11 | v1 "k8s.io/api/core/v1"
12 | )
13 |
14 | const templateKey = "readiness-port"
15 |
16 | func init() {
17 | templates.Register(check.Template{
18 | HumanName: "Readiness Port Not Exposed",
19 | Key: templateKey,
20 | Description: "Flag containers with an Readiness probe to not exposed port.",
21 | SupportedObjectKinds: config.ObjectKindsDesc{
22 | ObjectKinds: []string{objectkinds.DeploymentLike},
23 | },
24 | Parameters: params.ParamDescs,
25 | ParseAndValidateParams: params.ParseAndValidate,
26 | Instantiate: params.WrapInstantiateFunc(func(_ params.Params) (check.Func, error) {
27 | return util.PerNonInitContainerCheck(func(container *v1.Container) []diagnostic.Diagnostic {
28 | return util.CheckProbePort(container, container.ReadinessProbe)
29 | }), nil
30 | }),
31 | })
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/templates/readinessprobe/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/readinessprobe/template.go:
--------------------------------------------------------------------------------
1 | package readinessprobe
2 |
3 | import (
4 | "fmt"
5 |
6 | "golang.stackrox.io/kube-linter/pkg/check"
7 | "golang.stackrox.io/kube-linter/pkg/config"
8 | "golang.stackrox.io/kube-linter/pkg/diagnostic"
9 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
10 | "golang.stackrox.io/kube-linter/pkg/templates"
11 | "golang.stackrox.io/kube-linter/pkg/templates/readinessprobe/internal/params"
12 | "golang.stackrox.io/kube-linter/pkg/templates/util"
13 | v1 "k8s.io/api/core/v1"
14 | )
15 |
16 | func init() {
17 | templates.Register(check.Template{
18 | HumanName: "Readiness Probe Not Specified",
19 | Key: "readiness-probe",
20 | Description: "Flag containers that don't specify a readiness probe",
21 | SupportedObjectKinds: config.ObjectKindsDesc{
22 | ObjectKinds: []string{objectkinds.DeploymentLike},
23 | },
24 | Parameters: params.ParamDescs,
25 | ParseAndValidateParams: params.ParseAndValidate,
26 | Instantiate: params.WrapInstantiateFunc(func(_ params.Params) (check.Func, error) {
27 | return util.PerNonInitContainerCheck(func(container *v1.Container) []diagnostic.Diagnostic {
28 | if container.ReadinessProbe == nil {
29 | return []diagnostic.Diagnostic{{Message: fmt.Sprintf("container %q does not specify a readiness probe", container.Name)}}
30 | }
31 | return nil
32 | }), nil
33 | }),
34 | })
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/templates/readonlyrootfs/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/readonlyrootfs/template.go:
--------------------------------------------------------------------------------
1 | package readonlyrootfs
2 |
3 | import (
4 | "fmt"
5 |
6 | "golang.stackrox.io/kube-linter/pkg/check"
7 | "golang.stackrox.io/kube-linter/pkg/config"
8 | "golang.stackrox.io/kube-linter/pkg/diagnostic"
9 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
10 | "golang.stackrox.io/kube-linter/pkg/templates"
11 | "golang.stackrox.io/kube-linter/pkg/templates/readonlyrootfs/internal/params"
12 | "golang.stackrox.io/kube-linter/pkg/templates/util"
13 | v1 "k8s.io/api/core/v1"
14 | )
15 |
16 | func init() {
17 | templates.Register(check.Template{
18 | HumanName: "Read-only Root Filesystems",
19 | Key: "read-only-root-fs",
20 | Description: "Flag containers without read-only root file systems",
21 | SupportedObjectKinds: config.ObjectKindsDesc{
22 | ObjectKinds: []string{objectkinds.DeploymentLike},
23 | },
24 | Parameters: params.ParamDescs,
25 | ParseAndValidateParams: params.ParseAndValidate,
26 | Instantiate: params.WrapInstantiateFunc(func(p params.Params) (check.Func, error) {
27 | return util.PerContainerCheck(func(container *v1.Container) []diagnostic.Diagnostic {
28 | sc := container.SecurityContext
29 | if sc == nil || sc.ReadOnlyRootFilesystem == nil || !*sc.ReadOnlyRootFilesystem {
30 | return []diagnostic.Diagnostic{{Message: fmt.Sprintf("container %q does not have a read-only root file system", container.Name)}}
31 | }
32 | return nil
33 | }), nil
34 | }),
35 | })
36 | }
37 |
--------------------------------------------------------------------------------
/pkg/templates/readsecret/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/readsecret/template.go:
--------------------------------------------------------------------------------
1 | package readsecret
2 |
3 | import (
4 | "fmt"
5 |
6 | "golang.stackrox.io/kube-linter/pkg/check"
7 | "golang.stackrox.io/kube-linter/pkg/config"
8 | "golang.stackrox.io/kube-linter/pkg/diagnostic"
9 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
10 | "golang.stackrox.io/kube-linter/pkg/templates"
11 | "golang.stackrox.io/kube-linter/pkg/templates/readsecret/internal/params"
12 | "golang.stackrox.io/kube-linter/pkg/templates/util"
13 | v1 "k8s.io/api/core/v1"
14 | )
15 |
16 | func init() {
17 | templates.Register(check.Template{
18 | HumanName: "Read Secret From Environment Variables",
19 | Key: "read-secret-from-env-var",
20 | Description: "Flag environment variables that use SecretKeyRef",
21 | SupportedObjectKinds: config.ObjectKindsDesc{
22 | ObjectKinds: []string{objectkinds.DeploymentLike},
23 | },
24 | Parameters: params.ParamDescs,
25 | ParseAndValidateParams: params.ParseAndValidate,
26 | Instantiate: params.WrapInstantiateFunc(func(_ params.Params) (check.Func, error) {
27 | return util.PerContainerCheck(func(container *v1.Container) []diagnostic.Diagnostic {
28 | var results []diagnostic.Diagnostic
29 | for _, envVar := range container.Env {
30 | if envVar.ValueFrom != nil && envVar.ValueFrom.SecretKeyRef != nil {
31 | results = append(results, diagnostic.Diagnostic{
32 | Message: fmt.Sprintf("environment variable %q in container %q uses SecretKeyRef", envVar.Name, container.Name),
33 | })
34 | }
35 | }
36 | return results
37 | }), nil
38 | }),
39 | })
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/templates/registry.go:
--------------------------------------------------------------------------------
1 | package templates
2 |
3 | import (
4 | "fmt"
5 | "sort"
6 |
7 | "golang.stackrox.io/kube-linter/pkg/check"
8 | )
9 |
10 | var (
11 | allTemplates = make(map[string]check.Template)
12 | )
13 |
14 | // Register registers a template with the given name.
15 | // Intended to be called at program init time.
16 | func Register(t check.Template) {
17 | if _, ok := allTemplates[t.Key]; ok {
18 | panic(fmt.Sprintf("duplicate template: %v", t.Key))
19 | }
20 | allTemplates[t.Key] = t
21 | }
22 |
23 | // Get gets a template by name, returning a boolean indicating whether it was found.
24 | func Get(name string) (check.Template, bool) {
25 | t, ok := allTemplates[name]
26 | return t, ok
27 | }
28 |
29 | // List returns all known templates, sorted by name.
30 | func List() []check.Template {
31 | out := make([]check.Template, 0, len(allTemplates))
32 | for _, t := range allTemplates {
33 | out = append(out, t)
34 | }
35 | sort.Slice(out, func(i, j int) bool {
36 | return out[i].Key < out[j].Key
37 | })
38 | return out
39 | }
40 |
--------------------------------------------------------------------------------
/pkg/templates/replicas/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 |
6 | // The minimum number of replicas a deployment should have
7 | MinReplicas int
8 | }
9 |
--------------------------------------------------------------------------------
/pkg/templates/requiredannotation/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 |
6 | // Key of the required label.
7 | // +required
8 | Key string
9 |
10 | // Value of the required label.
11 | Value string
12 | }
13 |
--------------------------------------------------------------------------------
/pkg/templates/requiredannotation/template.go:
--------------------------------------------------------------------------------
1 | package requiredannotation
2 |
3 | import (
4 | "golang.stackrox.io/kube-linter/pkg/check"
5 | "golang.stackrox.io/kube-linter/pkg/config"
6 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
7 | "golang.stackrox.io/kube-linter/pkg/templates"
8 | "golang.stackrox.io/kube-linter/pkg/templates/requiredannotation/internal/params"
9 | "golang.stackrox.io/kube-linter/pkg/templates/util"
10 | )
11 |
12 | func init() {
13 | templates.Register(check.Template{
14 | HumanName: "Required Annotation",
15 | Key: "required-annotation",
16 | Description: "Flag objects not carrying at least one annotation matching the provided patterns",
17 | SupportedObjectKinds: config.ObjectKindsDesc{
18 | ObjectKinds: []string{objectkinds.Any},
19 | },
20 | Parameters: params.ParamDescs,
21 | ParseAndValidateParams: params.ParseAndValidate,
22 | Instantiate: params.WrapInstantiateFunc(func(p params.Params) (check.Func, error) {
23 | return util.ConstructRequiredMapMatcher(p.Key, p.Value, "annotation")
24 | }),
25 | })
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/templates/requiredlabel/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 |
6 | // Key of the required label.
7 | // +required
8 | Key string
9 |
10 | // Value of the required label.
11 | Value string
12 | }
13 |
--------------------------------------------------------------------------------
/pkg/templates/requiredlabel/template.go:
--------------------------------------------------------------------------------
1 | package requiredlabel
2 |
3 | import (
4 | "golang.stackrox.io/kube-linter/pkg/check"
5 | "golang.stackrox.io/kube-linter/pkg/config"
6 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
7 | "golang.stackrox.io/kube-linter/pkg/templates"
8 | "golang.stackrox.io/kube-linter/pkg/templates/requiredlabel/internal/params"
9 | "golang.stackrox.io/kube-linter/pkg/templates/util"
10 | )
11 |
12 | func init() {
13 | templates.Register(check.Template{
14 | HumanName: "Required Label",
15 | Key: "required-label",
16 | Description: "Flag objects not carrying at least one label matching the provided patterns",
17 | SupportedObjectKinds: config.ObjectKindsDesc{
18 | ObjectKinds: []string{objectkinds.Any},
19 | },
20 | Parameters: params.ParamDescs,
21 | ParseAndValidateParams: params.ParseAndValidate,
22 | Instantiate: params.WrapInstantiateFunc(func(p params.Params) (check.Func, error) {
23 | return util.ConstructRequiredMapMatcher(p.Key, p.Value, "label")
24 | }),
25 | })
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/templates/restartpolicy/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/runasnonroot/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/sccdenypriv/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 |
6 | // allowPrivilegedContainer value
7 | AllowPrivilegedContainer bool
8 | }
9 |
--------------------------------------------------------------------------------
/pkg/templates/sccdenypriv/template.go:
--------------------------------------------------------------------------------
1 | package sccdenypriv
2 |
3 | import (
4 | "fmt"
5 |
6 | "golang.stackrox.io/kube-linter/pkg/check"
7 | "golang.stackrox.io/kube-linter/pkg/config"
8 | "golang.stackrox.io/kube-linter/pkg/diagnostic"
9 | "golang.stackrox.io/kube-linter/pkg/extract"
10 | "golang.stackrox.io/kube-linter/pkg/lintcontext"
11 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
12 | "golang.stackrox.io/kube-linter/pkg/templates"
13 | "golang.stackrox.io/kube-linter/pkg/templates/sccdenypriv/internal/params"
14 | )
15 |
16 | const (
17 | templateKey = "scc-deny-privileged-container"
18 | )
19 |
20 | func init() {
21 | templates.Register(check.Template{
22 | HumanName: "SecurityContextConstraints allowPrivilegedContainer",
23 | Key: templateKey,
24 | Description: "Flag SCC with allowPrivilegedContainer set to true",
25 | SupportedObjectKinds: config.ObjectKindsDesc{
26 | ObjectKinds: []string{objectkinds.SecurityContextConstraints},
27 | },
28 | Parameters: params.ParamDescs,
29 | ParseAndValidateParams: params.ParseAndValidate,
30 | Instantiate: params.WrapInstantiateFunc(func(p params.Params) (check.Func, error) {
31 | return func(_ lintcontext.LintContext, object lintcontext.Object) []diagnostic.Diagnostic {
32 | state, found := extract.SCCallowPrivilegedContainer(object.K8sObject)
33 | if found && state == p.AllowPrivilegedContainer {
34 | return []diagnostic.Diagnostic{
35 | {Message: fmt.Sprintf("SCC has allowPrivilegedContainer set to %v", state)},
36 | }
37 | }
38 | return nil
39 | }, nil
40 | }),
41 | })
42 | }
43 |
--------------------------------------------------------------------------------
/pkg/templates/serviceaccount/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 |
6 | // A regex specifying the required service account to match.
7 | // +required
8 | ServiceAccount string
9 | }
10 |
--------------------------------------------------------------------------------
/pkg/templates/servicetype/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | // An array of service types that should not be used
6 | // +noregex
7 | // +notnegatable
8 | ForbiddenServiceTypes []string `json:"forbiddenServiceTypes"`
9 | }
10 |
--------------------------------------------------------------------------------
/pkg/templates/servicetype/template.go:
--------------------------------------------------------------------------------
1 | package servicetype
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 |
7 | "golang.stackrox.io/kube-linter/pkg/check"
8 | "golang.stackrox.io/kube-linter/pkg/config"
9 | "golang.stackrox.io/kube-linter/pkg/diagnostic"
10 | "golang.stackrox.io/kube-linter/pkg/lintcontext"
11 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
12 | "golang.stackrox.io/kube-linter/pkg/templates"
13 | "golang.stackrox.io/kube-linter/pkg/templates/servicetype/internal/params"
14 | v1 "k8s.io/api/core/v1"
15 | )
16 |
17 | func init() {
18 | templates.Register(check.Template{
19 | HumanName: "Forbidden Service Types",
20 | Key: "forbidden-service-types",
21 | Description: "Flag forbidden services",
22 | SupportedObjectKinds: config.ObjectKindsDesc{
23 | ObjectKinds: []string{objectkinds.Service},
24 | },
25 | Parameters: params.ParamDescs,
26 | ParseAndValidateParams: params.ParseAndValidate,
27 | Instantiate: params.WrapInstantiateFunc(func(p params.Params) (check.Func, error) {
28 | return func(lintCtx lintcontext.LintContext, object lintcontext.Object) []diagnostic.Diagnostic {
29 |
30 | service, ok := object.K8sObject.(*v1.Service)
31 | if !ok {
32 | return nil
33 | }
34 | var results []diagnostic.Diagnostic
35 | for _, servicetype := range p.ForbiddenServiceTypes {
36 | if strings.EqualFold(string(service.Spec.Type), servicetype) {
37 | results = append(results, diagnostic.Diagnostic{Message: fmt.Sprintf("%q service type is forbidden.", servicetype)})
38 | }
39 | }
40 | return results
41 | }, nil
42 | }),
43 | })
44 | }
45 |
--------------------------------------------------------------------------------
/pkg/templates/startupport/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct{}
5 |
--------------------------------------------------------------------------------
/pkg/templates/startupport/template.go:
--------------------------------------------------------------------------------
1 | package startupport
2 |
3 | import (
4 | "golang.stackrox.io/kube-linter/pkg/check"
5 | "golang.stackrox.io/kube-linter/pkg/config"
6 | "golang.stackrox.io/kube-linter/pkg/diagnostic"
7 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
8 | "golang.stackrox.io/kube-linter/pkg/templates"
9 | "golang.stackrox.io/kube-linter/pkg/templates/startupport/internal/params"
10 | "golang.stackrox.io/kube-linter/pkg/templates/util"
11 | v1 "k8s.io/api/core/v1"
12 | )
13 |
14 | const templateKey = "startup-port"
15 |
16 | func init() {
17 | templates.Register(check.Template{
18 | HumanName: "Startup Port Exposed",
19 | Key: templateKey,
20 | Description: "Flag containers with an Startup probe to not exposed port.",
21 | SupportedObjectKinds: config.ObjectKindsDesc{
22 | ObjectKinds: []string{objectkinds.DeploymentLike},
23 | },
24 | Parameters: params.ParamDescs,
25 | ParseAndValidateParams: params.ParseAndValidate,
26 | Instantiate: params.WrapInstantiateFunc(func(_ params.Params) (check.Func, error) {
27 | return util.PerNonInitContainerCheck(func(container *v1.Container) []diagnostic.Diagnostic {
28 | return util.CheckProbePort(container, container.StartupProbe)
29 | }), nil
30 | }),
31 | })
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/templates/sysctl/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | // An array of unsafe system controls
6 | // +noregex
7 | // +notnegatable
8 | UnsafeSysCtls []string `json:"unsafeSysCtls"`
9 | }
10 |
--------------------------------------------------------------------------------
/pkg/templates/targetport/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/unsafeprocmount/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/unsafeprocmount/template.go:
--------------------------------------------------------------------------------
1 | package unsafeprocmount
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 |
7 | "golang.stackrox.io/kube-linter/pkg/check"
8 | "golang.stackrox.io/kube-linter/pkg/config"
9 | "golang.stackrox.io/kube-linter/pkg/diagnostic"
10 | "golang.stackrox.io/kube-linter/pkg/objectkinds"
11 | "golang.stackrox.io/kube-linter/pkg/templates"
12 | "golang.stackrox.io/kube-linter/pkg/templates/unsafeprocmount/internal/params"
13 | "golang.stackrox.io/kube-linter/pkg/templates/util"
14 | v1 "k8s.io/api/core/v1"
15 | )
16 |
17 | func init() {
18 | templates.Register(check.Template{
19 | HumanName: "Unsafe Proc Mount",
20 | Key: "unsafe-proc-mount",
21 | Description: "Flag containers of unsafe proc mount",
22 | SupportedObjectKinds: config.ObjectKindsDesc{
23 | ObjectKinds: []string{objectkinds.DeploymentLike},
24 | },
25 | Parameters: params.ParamDescs,
26 | ParseAndValidateParams: params.ParseAndValidate,
27 | Instantiate: params.WrapInstantiateFunc(func(_ params.Params) (check.Func, error) {
28 | return util.PerContainerCheck(func(container *v1.Container) []diagnostic.Diagnostic {
29 | if container.SecurityContext != nil && container.SecurityContext.ProcMount != nil {
30 | if strings.EqualFold(string(*container.SecurityContext.ProcMount), "Unmasked") {
31 | return []diagnostic.Diagnostic{{Message: fmt.Sprintf("container %q exposes /proc unsafely (via procMount=Unmasked).", container.Name)}}
32 | }
33 | }
34 | return nil
35 | }), nil
36 | }),
37 | })
38 | }
39 |
--------------------------------------------------------------------------------
/pkg/templates/updateconfig/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | // A regular expression the defines the type of update
6 | // strategy allowed.
7 | // +required
8 | StrategyTypeRegex string
9 |
10 | // The maximum value that be set in a RollingUpdate
11 | // configuration for the MaxUnavailable. This can be
12 | // an integer or a percent.
13 | MaxPodsUnavailable string
14 |
15 | // The minimum value that be set in a RollingUpdate
16 | // configuration for the MaxUnavailable. This can be
17 | // an integer or a percent.
18 | MinPodsUnavailable string
19 |
20 | // The maximum value that be set in a RollingUpdate
21 | // configuration for the MaxSurge. This can be
22 | // an integer or a percent.
23 | MaxSurge string
24 |
25 | // The minimum value that be set in a RollingUpdate
26 | // configuration for the MaxSurge. This can be
27 | // an integer or a percent.
28 | MinSurge string
29 | }
30 |
--------------------------------------------------------------------------------
/pkg/templates/util/check_probe_port.go:
--------------------------------------------------------------------------------
1 | package util
2 |
3 | import (
4 | "fmt"
5 |
6 | "golang.stackrox.io/kube-linter/pkg/diagnostic"
7 | v1 "k8s.io/api/core/v1"
8 | "k8s.io/apimachinery/pkg/util/intstr"
9 | )
10 |
11 | var sentinel = struct{}{}
12 |
13 | func CheckProbePort(container *v1.Container, probe *v1.Probe) []diagnostic.Diagnostic {
14 | if probe == nil {
15 | return nil
16 | }
17 |
18 | ports := map[intstr.IntOrString]struct{}{}
19 | for _, port := range container.Ports {
20 | if port.Protocol != "" && port.Protocol != v1.ProtocolTCP {
21 | continue
22 | }
23 | ports[intstr.FromInt32(port.ContainerPort)] = sentinel
24 | ports[intstr.FromString(port.Name)] = sentinel
25 | }
26 |
27 | if httpProbe := probe.HTTPGet; httpProbe != nil {
28 | if _, ok := ports[httpProbe.Port]; !ok {
29 | return []diagnostic.Diagnostic{{
30 | Message: fmt.Sprintf("container %q does not expose port %s for the HTTPGet", container.Name, httpProbe.Port.String()),
31 | }}
32 | }
33 | }
34 |
35 | if tcpProbe := probe.TCPSocket; tcpProbe != nil {
36 | if _, ok := ports[tcpProbe.Port]; !ok {
37 | return []diagnostic.Diagnostic{{
38 | Message: fmt.Sprintf("container %q does not expose port %s for the TCPSocket", container.Name, tcpProbe.Port.String()),
39 | }}
40 | }
41 | }
42 |
43 | if grpcProbe := probe.GRPC; grpcProbe != nil {
44 | if _, ok := ports[intstr.FromInt32(grpcProbe.Port)]; !ok {
45 | return []diagnostic.Diagnostic{{
46 | Message: fmt.Sprintf("container %q does not expose port %d for the GRPC check", container.Name, grpcProbe.Port),
47 | }}
48 | }
49 | }
50 | return nil
51 | }
52 |
--------------------------------------------------------------------------------
/pkg/templates/util/json.go:
--------------------------------------------------------------------------------
1 | package util
2 |
3 | import (
4 | "encoding/json"
5 | "strings"
6 |
7 | "golang.stackrox.io/kube-linter/pkg/check"
8 | )
9 |
10 | // MustParseParameterDesc unmarshals the given JSON into a templates.ParameterDesc.
11 | func MustParseParameterDesc(asJSON string) check.ParameterDesc {
12 | var out check.ParameterDesc
13 |
14 | decoder := json.NewDecoder(strings.NewReader(asJSON))
15 | decoder.DisallowUnknownFields()
16 | if err := decoder.Decode(&out); err != nil {
17 | panic(err)
18 | }
19 | return out
20 | }
21 |
--------------------------------------------------------------------------------
/pkg/templates/util/map_structure.go:
--------------------------------------------------------------------------------
1 | package util
2 |
3 | import (
4 | "github.com/mitchellh/mapstructure"
5 | )
6 |
7 | // DecodeMapStructure decodes the given map[string]interface{} into the given out variable, typically
8 | // a pointer to a struct.
9 | func DecodeMapStructure(m map[string]interface{}, out interface{}) error {
10 | dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
11 | ErrorUnused: true,
12 | TagName: "json",
13 | Result: out,
14 | })
15 | if err != nil {
16 | return err
17 | }
18 | return dec.Decode(m)
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/templates/util/value_in_range.go:
--------------------------------------------------------------------------------
1 | package util
2 |
3 | // ValueInRange returns whether the given quantity is in the range between the lowerBound and the upperBound (inclusive).
4 | // A nil upper bound is interpreted as infinity.
5 | func ValueInRange(value, lowerBound int, upperBound *int) bool {
6 | if value < lowerBound {
7 | return false
8 | }
9 | if upperBound != nil && value > *upperBound {
10 | return false
11 | }
12 | return true
13 | }
14 |
--------------------------------------------------------------------------------
/pkg/templates/wildcardinrules/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/pkg/templates/writablehostmount/internal/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Params represents the params accepted by this template.
4 | type Params struct {
5 | }
6 |
--------------------------------------------------------------------------------
/tests/checks/access-to-create-pods.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: Role
4 | metadata:
5 | name: dont-fire
6 | namespace: namespace-dev
7 | rules:
8 | - apiGroups: [""]
9 | resources: ["pods"]
10 | verbs: ["get"]
11 | ---
12 | apiVersion: rbac.authorization.k8s.io/v1
13 | kind: Role
14 | metadata:
15 | name: role1
16 | namespace: namespace-dev
17 | rules:
18 | - apiGroups: [""]
19 | resources: ["pods"]
20 | verbs: ["create"]
21 | ---
22 | apiVersion: rbac.authorization.k8s.io/v1
23 | kind: RoleBinding
24 | metadata:
25 | name: role-binding1
26 | namespace: namespace-dev
27 | subjects:
28 | - kind: ServiceAccount
29 | name: account1
30 | namespace: namespace-dev
31 | roleRef:
32 | apiGroup: rbac.authorization.k8s.io
33 | kind: Role
34 | name: role1
35 |
--------------------------------------------------------------------------------
/tests/checks/access-to-secrets.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: Role
4 | metadata:
5 | name: dont-fire
6 | namespace: namespace-dev
7 | rules:
8 | - apiGroups: [""]
9 | resources: ["pods"]
10 | verbs: ["get"]
11 | ---
12 | apiVersion: rbac.authorization.k8s.io/v1
13 | kind: Role
14 | metadata:
15 | name: role1
16 | namespace: namespace-dev
17 | rules:
18 | - apiGroups: [""]
19 | resources: ["secrets"]
20 | verbs: ["get"]
21 | ---
22 | apiVersion: rbac.authorization.k8s.io/v1
23 | kind: RoleBinding
24 | metadata:
25 | name: role-binding1
26 | namespace: namespace-dev
27 | subjects:
28 | - kind: ServiceAccount
29 | name: account1
30 | namespace: namespace-dev
31 | roleRef:
32 | apiGroup: rbac.authorization.k8s.io
33 | kind: Role
34 | name: role1
35 |
--------------------------------------------------------------------------------
/tests/checks/cluster-admin-role-binding.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRoleBinding
4 | metadata:
5 | name: dont-fire
6 | namespace: namespace-dev
7 | subjects:
8 | - kind: ServiceAccount
9 | name: account1
10 | namespace: namespace-dev
11 | roleRef:
12 | apiGroup: rbac.authorization.k8s.io
13 | kind: ClusterRole
14 | name: admin
15 | ---
16 | apiVersion: rbac.authorization.k8s.io/v1
17 | kind: ClusterRoleBinding
18 | metadata:
19 | name: role-binding1
20 | namespace: namespace-dev
21 | subjects:
22 | - kind: ServiceAccount
23 | name: account1
24 | namespace: namespace-dev
25 | roleRef:
26 | apiGroup: rbac.authorization.k8s.io
27 | kind: ClusterRole
28 | name: cluster-admin
29 |
--------------------------------------------------------------------------------
/tests/checks/dangling-hpa.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | template:
8 | metadata:
9 | labels:
10 | app.kubernetes.io/name: dontfire
11 | ---
12 | apiVersion: autoscaling/v2beta1
13 | kind: HorizontalPodAutoscaler
14 | metadata:
15 | name: RELEASE-NAME-mychart
16 | spec:
17 | scaleTargetRef:
18 | apiVersion: apps/v1
19 | kind: Deployment
20 | name: dont-fire
21 | minReplicas: 1
22 | maxReplicas: 100
23 | metrics:
24 | - type: Resource
25 | resource:
26 | name: cpu
27 | targetAverageUtilization: 80
28 | ---
29 | apiVersion: apps/v1
30 | kind: Deployment
31 | metadata:
32 | name: app1
33 | spec:
34 | template:
35 | metadata:
36 | labels:
37 | app.kubernetes.io/name: app1
38 | ---
39 | apiVersion: autoscaling/v2beta1
40 | kind: HorizontalPodAutoscaler
41 | metadata:
42 | name: hpa1
43 | spec:
44 | scaleTargetRef:
45 | apiVersion: apps/v1
46 | kind: Deployment
47 | name: app2
48 | minReplicas: 1
49 | maxReplicas: 100
50 | metrics:
51 | - type: Resource
52 | resource:
53 | name: cpu
54 | targetAverageUtilization: 80
--------------------------------------------------------------------------------
/tests/checks/dangling-networkpolicy.yml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1
2 | kind: NetworkPolicy
3 | metadata:
4 | name: app
5 | spec:
6 | podSelector:
7 | matchLabels:
8 | app.kubernetes.io/name: app1
--------------------------------------------------------------------------------
/tests/checks/dangling-networkpolicypeer-podselector.yml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1
2 | kind: NetworkPolicy
3 | metadata:
4 | name: app
5 | spec:
6 | podSelector:
7 | matchLabels:
8 | app.kubernetes.io/name: app1
9 | ingress:
10 | - from:
11 | - podSelector:
12 | matchLabels:
13 | app.kubernetes.io/name: app2
14 | ports:
15 | - protocol: TCP
16 | port: 8080
--------------------------------------------------------------------------------
/tests/checks/dangling-service.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | template:
8 | metadata:
9 | labels:
10 | app.kubernetes.io/name: dontfire
11 | ---
12 | apiVersion: v1
13 | kind: Service
14 | metadata:
15 | name: dont-fire
16 | spec:
17 | ports:
18 | - name: 8080-tcp
19 | port: 8080
20 | selector:
21 | app.kubernetes.io/name: dontfire
22 | ---
23 | apiVersion: apps/v1
24 | kind: Deployment
25 | metadata:
26 | name: app1
27 | spec:
28 | template:
29 | metadata:
30 | labels:
31 | app.kubernetes.io/name: app1
32 | ---
33 | apiVersion: v1
34 | kind: Service
35 | metadata:
36 | name: app1
37 | spec:
38 | ports:
39 | - name: 8080-tcp
40 | port: 8080
41 | selector:
42 | app.kubernetes.io/name: app
43 | ---
44 | apiVersion: apps.openshift.io/v1
45 | kind: DeploymentConfig
46 | metadata:
47 | name: app2
48 | spec:
49 | template:
50 | metadata:
51 | labels:
52 | app.kubernetes.io/name: app2
53 | ---
54 | apiVersion: v1
55 | kind: Service
56 | metadata:
57 | name: app2
58 | spec:
59 | ports:
60 | - name: 8080-tcp
61 | port: 8080
62 | selector:
63 | app.kubernetes.io/name: app
--------------------------------------------------------------------------------
/tests/checks/default-service-account.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | template:
8 | spec:
9 | serviceAccountName: app
10 | ---
11 | apiVersion: apps.openshift.io/v1
12 | kind: DeploymentConfig
13 | metadata:
14 | name: dont-fire
15 | spec:
16 | template:
17 | spec:
18 | serviceAccountName: app
19 | ---
20 | apiVersion: apps/v1
21 | kind: Deployment
22 | metadata:
23 | name: app
24 | spec:
25 | template:
26 | spec:
27 | serviceAccountName: default
28 | ---
29 | apiVersion: apps.openshift.io/v1
30 | kind: DeploymentConfig
31 | metadata:
32 | name: app
33 | spec:
34 | template:
35 | spec:
36 | serviceAccountName: default
--------------------------------------------------------------------------------
/tests/checks/deprecated-service-account-field.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | template:
8 | spec:
9 | serviceAccountName: default
10 | ---
11 | apiVersion: apps.openshift.io/v1
12 | kind: DeploymentConfig
13 | metadata:
14 | name: dont-fire
15 | spec:
16 | template:
17 | spec:
18 | serviceAccountName: default
19 | ---
20 | apiVersion: apps/v1
21 | kind: Deployment
22 | metadata:
23 | name: app
24 | spec:
25 | template:
26 | spec:
27 | serviceAccount: default
28 | ---
29 | apiVersion: apps.openshift.io/v1
30 | kind: DeploymentConfig
31 | metadata:
32 | name: app
33 | spec:
34 | template:
35 | spec:
36 | serviceAccount: default
--------------------------------------------------------------------------------
/tests/checks/drop-net-raw-capability.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: app
11 | securityContext:
12 | capabilities:
13 | ---
14 | apiVersion: apps.openshift.io/v1
15 | kind: DeploymentConfig
16 | metadata:
17 | name: dont-fire
18 | spec:
19 | template:
20 | spec:
21 | containers:
22 | - name: app
23 | securityContext:
24 | capabilities:
25 | ---
26 | apiVersion: apps/v1
27 | kind: Deployment
28 | metadata:
29 | name: app
30 | spec:
31 | template:
32 | spec:
33 | containers:
34 | - name: app
35 | securityContext:
36 | capabilities:
37 | add:
38 | - NET_RAW
39 | ---
40 | apiVersion: apps.openshift.io/v1
41 | kind: DeploymentConfig
42 | metadata:
43 | name: app
44 | spec:
45 | template:
46 | spec:
47 | containers:
48 | - name: app
49 | securityContext:
50 | capabilities:
51 | add:
52 | - NET_RAW
--------------------------------------------------------------------------------
/tests/checks/duplicate-env-var.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | spec:
4 | template:
5 | spec:
6 | containers:
7 | - name: dont-fire-deployment
8 | env:
9 | - name: PORT
10 | value: "8080"
11 | - name: HOST
12 | value: "localhost"
13 | - name: fire-deployment
14 | env:
15 | - name: PORT
16 | value: "8080"
17 | - name: PORT
18 | value: "9090"
19 | ---
20 | apiVersion: apps/v1
21 | kind: StatefulSet
22 | spec:
23 | template:
24 | spec:
25 | containers:
26 | - name: dont-fire-stateful
27 | env:
28 | - name: PORT
29 | value: "8080"
30 | - name: HOST
31 | value: "localhost"
32 | - name: fire-stateful
33 | env:
34 | - name: PORT
35 | value: "8080"
36 | - name: PORT
37 | value: "9090"
38 |
--------------------------------------------------------------------------------
/tests/checks/env-var-secret.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: app
11 | env:
12 | - name: BLAH
13 | value: secretsquirrels
14 | ---
15 | apiVersion: apps.openshift.io/v1
16 | kind: DeploymentConfig
17 | metadata:
18 | name: dont-fire
19 | spec:
20 | template:
21 | spec:
22 | containers:
23 | - name: app
24 | env:
25 | - name: BLAH
26 | value: secretsquirrels
27 | ---
28 | apiVersion: apps/v1
29 | kind: Deployment
30 | metadata:
31 | name: app
32 | spec:
33 | template:
34 | spec:
35 | containers:
36 | - name: app
37 | env:
38 | - name: SECRET_BLAH
39 | value: secretsquirrels
40 | ---
41 | apiVersion: apps.openshift.io/v1
42 | kind: DeploymentConfig
43 | metadata:
44 | name: app
45 | spec:
46 | template:
47 | spec:
48 | containers:
49 | - name: app
50 | env:
51 | - name: SECRET_BLAH
52 | value: secretsquirrels
--------------------------------------------------------------------------------
/tests/checks/exposed-services.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Service
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | selector:
8 | app: app
9 | ports:
10 | - protocol: TCP
11 | port: 80
12 | targetPort: 8080
13 | ---
14 | apiVersion: v1
15 | kind: Service
16 | metadata:
17 | name: app
18 | spec:
19 | type: NodePort
--------------------------------------------------------------------------------
/tests/checks/forbidden-annotation.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: app1
6 | annotations:
7 | reloader.stakater.com/auto: "true"
8 | ---
9 | apiVersion: apps/v1
10 | kind: Deployment
11 | metadata:
12 | name: dont-fire
13 | annotations:
14 | reloader.stakater.com/auto: "false"
15 | ---
16 | apiVersion: apps/v1
17 | kind: Deployment
18 | metadata:
19 | name: dont-fire
20 | annotations:
21 | reloader.stakater.com/auto: T
22 | ---
23 | apiVersion: v1
24 | kind: ServiceAccount
25 | metadata:
26 | name: bad-irsa-role
27 | annotations:
28 | eks.amazonaws.com/role-arn: this-is-not-a-valid-iam-role-arn
29 | ---
30 | apiVersion: v1
31 | kind: ServiceAccount
32 | metadata:
33 | name: good-irsa-role
34 | annotations:
35 | eks.amazonaws.com/role-arn: arn:aws:iam::121212121212:role/role-name-goes-here
36 |
--------------------------------------------------------------------------------
/tests/checks/host-ipc.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | template:
8 | spec:
9 | hostIPC: false
10 | ---
11 | apiVersion: apps.openshift.io/v1
12 | kind: DeploymentConfig
13 | metadata:
14 | name: dont-fire
15 | spec:
16 | template:
17 | spec:
18 | hostIPC: false
19 | ---
20 | apiVersion: apps/v1
21 | kind: Deployment
22 | metadata:
23 | name: app
24 | spec:
25 | template:
26 | spec:
27 | hostIPC: true
28 | ---
29 | apiVersion: apps.openshift.io/v1
30 | kind: DeploymentConfig
31 | metadata:
32 | name: app
33 | spec:
34 | template:
35 | spec:
36 | hostIPC: true
--------------------------------------------------------------------------------
/tests/checks/host-network.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | template:
8 | spec:
9 | hostNetwork: false
10 | ---
11 | apiVersion: apps.openshift.io/v1
12 | kind: DeploymentConfig
13 | metadata:
14 | name: dont-fire
15 | spec:
16 | template:
17 | spec:
18 | hostNetwork: false
19 | ---
20 | apiVersion: apps/v1
21 | kind: Deployment
22 | metadata:
23 | name: app
24 | spec:
25 | template:
26 | spec:
27 | hostNetwork: true
28 | ---
29 | apiVersion: apps.openshift.io/v1
30 | kind: DeploymentConfig
31 | metadata:
32 | name: app
33 | spec:
34 | template:
35 | spec:
36 | hostNetwork: true
--------------------------------------------------------------------------------
/tests/checks/host-pid.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | template:
8 | spec:
9 | hostPID: false
10 | ---
11 | apiVersion: apps.openshift.io/v1
12 | kind: DeploymentConfig
13 | metadata:
14 | name: dont-fire
15 | spec:
16 | template:
17 | spec:
18 | hostPID: false
19 | ---
20 | apiVersion: apps/v1
21 | kind: Deployment
22 | metadata:
23 | name: app
24 | spec:
25 | template:
26 | spec:
27 | hostPID: true
28 | ---
29 | apiVersion: apps.openshift.io/v1
30 | kind: DeploymentConfig
31 | metadata:
32 | name: app
33 | spec:
34 | template:
35 | spec:
36 | hostPID: true
--------------------------------------------------------------------------------
/tests/checks/hpa-minimum-three-replicas.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: autoscaling/v2beta1
3 | kind: HorizontalPodAutoscaler
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | minReplicas: 3
8 | maxReplicas: 100
9 | scaleTargetRef:
10 | apiVersion: apps/v1
11 | kind: Deployment
12 | name: testing
13 | targetCPUUtilizationPercentage: 85
14 | ---
15 | apiVersion: autoscaling/v2beta1
16 | kind: HorizontalPodAutoscaler
17 | metadata:
18 | name: app
19 | spec:
20 | minReplicas: 2
21 | maxReplicas: 100
22 | scaleTargetRef:
23 | apiVersion: apps/v1
24 | kind: Deployment
25 | name: testing
26 | targetCPUUtilizationPercentage: 85
27 |
--------------------------------------------------------------------------------
/tests/checks/invalid-target-ports.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | namespace: test
5 | name: invalid-target-ports
6 | spec:
7 | ports:
8 | - targetPort: 1234
9 | - targetPort: 'n-3456789012345'
10 | - targetPort: 123456
11 | - targetPort: 'n234567890123456'
12 | ---
13 | apiVersion: apps/v1
14 | kind: Deployment
15 | metadata:
16 | namespace: test
17 | name: invalid-target-ports
18 | spec:
19 | template:
20 | spec:
21 | containers:
22 | - name: invalid-target-ports
23 | ports:
24 | - name: 'n23456789012345'
25 | containerPort: 1234
26 | - name: 'n234567890123456'
27 | containerPort: 1235
28 | - name: '123456'
29 | containerPort: 123456
30 | ---
31 | apiVersion: v1
32 | kind: Service
33 | metadata:
34 | namespace: test
35 | name: empty-ports
36 | ---
37 | apiVersion: apps/v1
38 | kind: Deployment
39 | metadata:
40 | namespace: test
41 | name: empty-ports
42 | spec:
43 | template:
44 | spec:
45 | containers:
46 | - name: empty-ports
47 | ---
48 | apiVersion: v1
49 | kind: Service
50 | metadata:
51 | namespace: test
52 | name: no-target-port
53 | spec:
54 | ports:
55 | - port: 8080
56 | name: test
57 | ---
58 | apiVersion: apps/v1
59 | kind: Deployment
60 | metadata:
61 | namespace: test
62 | name: no-target-port
63 | spec:
64 | template:
65 | spec:
66 | containers:
67 | - name: no-target-port
68 | ports:
69 | - containerPort: 1234
70 |
--------------------------------------------------------------------------------
/tests/checks/latest-tag.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: app
11 | image: app:v1
12 | ---
13 | apiVersion: apps.openshift.io/v1
14 | kind: DeploymentConfig
15 | metadata:
16 | name: dont-fire
17 | spec:
18 | template:
19 | spec:
20 | containers:
21 | - name: app
22 | image: app:v1
23 | ---
24 | apiVersion: apps/v1
25 | kind: Deployment
26 | metadata:
27 | name: app
28 | spec:
29 | template:
30 | spec:
31 | containers:
32 | - name: app
33 | image: app:latest
34 | ---
35 | apiVersion: apps.openshift.io/v1
36 | kind: DeploymentConfig
37 | metadata:
38 | name: app
39 | spec:
40 | template:
41 | spec:
42 | containers:
43 | - name: app
44 | image: app:latest
--------------------------------------------------------------------------------
/tests/checks/minimum-three-replicas.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | replicas: 3
8 | ---
9 | apiVersion: apps.openshift.io/v1
10 | kind: DeploymentConfig
11 | metadata:
12 | name: dont-fire
13 | spec:
14 | replicas: 3
15 | ---
16 | apiVersion: apps/v1
17 | kind: Deployment
18 | metadata:
19 | name: app
20 | spec:
21 | replicas: 2
22 | ---
23 | apiVersion: apps.openshift.io/v1
24 | kind: DeploymentConfig
25 | metadata:
26 | name: app
27 | spec:
28 | replicas: 2
--------------------------------------------------------------------------------
/tests/checks/mismatching-selector.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | selector:
8 | matchLabels:
9 | app.kubernetes.io/name: dont-fire
10 | template:
11 | metadata:
12 | labels:
13 | app.kubernetes.io/name: dont-fire
14 | spec:
15 | containers:
16 | - name: app
17 | ---
18 | apiVersion: apps.openshift.io/v1
19 | kind: DeploymentConfig
20 | metadata:
21 | name: dont-fire
22 | spec:
23 | selector:
24 | app.kubernetes.io/name: dont-fire
25 | template:
26 | metadata:
27 | labels:
28 | app.kubernetes.io/name: dont-fire
29 | spec:
30 | containers:
31 | - name: app2
32 | ---
33 | apiVersion: apps/v1
34 | kind: Deployment
35 | metadata:
36 | name: app1
37 | spec:
38 | selector:
39 | matchLabels:
40 | app.kubernetes.io/name: app1
41 | template:
42 | spec:
43 | containers:
44 | - name: app
45 | ---
46 | apiVersion: apps.openshift.io/v1
47 | kind: DeploymentConfig
48 | metadata:
49 | name: app2
50 | spec:
51 | selector:
52 | app.kubernetes.io/name: app2
53 | template:
54 | spec:
55 | containers:
56 | - name: app2
--------------------------------------------------------------------------------
/tests/checks/no-extensions-v1beta.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: networking.k8s.io/v1
3 | kind: NetworkPolicy
4 | metadata:
5 | name: app
6 | ---
7 | apiVersion: extensions/v1beta1
8 | kind: NetworkPolicy
9 | metadata:
10 | name: app
--------------------------------------------------------------------------------
/tests/checks/no-node-affinity.yml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: nginx-deployment
5 | spec:
6 | selector:
7 | matchLabels:
8 | app: nginx
9 | replicas: 1
10 | template:
11 | metadata:
12 | labels:
13 | app: nginx
14 | spec:
15 | containers:
16 | - name: nginx
17 | image: nginx:1.14.2
18 | ports:
19 | - containerPort: 80
--------------------------------------------------------------------------------
/tests/checks/no-read-only-root-fs.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | replicas: 3
8 | template:
9 | spec:
10 | containers:
11 | - name: app
12 | securityContext:
13 | readOnlyRootFilesystem: true
14 | ---
15 | apiVersion: apps.openshift.io/v1
16 | kind: DeploymentConfig
17 | metadata:
18 | name: dont-fire
19 | spec:
20 | replicas: 3
21 | template:
22 | spec:
23 | containers:
24 | - name: app
25 | securityContext:
26 | readOnlyRootFilesystem: true
27 | ---
28 | apiVersion: apps/v1
29 | kind: Deployment
30 | metadata:
31 | name: app1
32 | spec:
33 | replicas: 3
34 | template:
35 | spec:
36 | containers:
37 | - name: app
38 | securityContext:
39 | readOnlyRootFilesystem: false
40 | ---
41 | apiVersion: apps.openshift.io/v1
42 | kind: DeploymentConfig
43 | metadata:
44 | name: app2
45 | spec:
46 | replicas: 3
47 | template:
48 | spec:
49 | containers:
50 | - name: app
51 | securityContext:
52 | readOnlyRootFilesystem: false
--------------------------------------------------------------------------------
/tests/checks/no-rolling-update-strategy.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: app1
6 | spec:
7 | strategy:
8 | type: Other
9 | ---
10 | apiVersion: apps.openshift.io/v1
11 | kind: DeploymentConfig
12 | metadata:
13 | name: app2
14 | spec:
15 | strategy:
16 | type: Other
--------------------------------------------------------------------------------
/tests/checks/non-existent-service-account.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: dont-fire
6 | ---
7 | apiVersion: apps/v1
8 | kind: Deployment
9 | metadata:
10 | name: dont-fire
11 | spec:
12 | template:
13 | spec:
14 | serviceAccount: dont-fire
15 | ---
16 | apiVersion: apps/v1
17 | kind: Deployment
18 | metadata:
19 | name: app
20 | spec:
21 | template:
22 | spec:
23 | serviceAccount: missing
24 | ---
25 | apiVersion: apps.openshift.io/v1
26 | kind: DeploymentConfig
27 | metadata:
28 | name: app
29 | spec:
30 | template:
31 | spec:
32 | serviceAccount: missing
--------------------------------------------------------------------------------
/tests/checks/pdb-max-unavailable.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: policy/v1
3 | kind: PodDisruptionBudget
4 | metadata:
5 | name: baz
6 | namespace: bar
7 | spec:
8 | maxUnavailable: 1
9 | ---
10 | apiVersion: policy/v1
11 | kind: PodDisruptionBudget
12 | metadata:
13 | name: foo
14 | namespace: bar
15 | spec:
16 | maxUnavailable: 0
17 |
--------------------------------------------------------------------------------
/tests/checks/pdb-unhealthy-pod-eviction-policy.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: policy/v1
3 | kind: PodDisruptionBudget
4 | metadata:
5 | name: fire
6 | spec:
7 | selector:
8 | matchLabels:
9 | app: app1
10 | maxUnavailable: 1
11 | ---
12 | apiVersion: policy/v1
13 | kind: PodDisruptionBudget
14 | metadata:
15 | name: dont-fire-1
16 | spec:
17 | selector:
18 | matchLabels:
19 | app: app2
20 | maxUnavailable: 1
21 | unhealthyPodEvictionPolicy: AlwaysAllow
22 | ---
23 | apiVersion: policy/v1
24 | kind: PodDisruptionBudget
25 | metadata:
26 | name: dont-fire-2
27 | spec:
28 | selector:
29 | matchLabels:
30 | app: app2
31 | maxUnavailable: 1
32 | unhealthyPodEvictionPolicy: IfHealthyBudget
33 |
--------------------------------------------------------------------------------
/tests/checks/privilege-escalation-container.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | replicas: 3
8 | template:
9 | spec:
10 | containers:
11 | - name: app
12 | securityContext:
13 | allowPrivilegeEscalation: false
14 | ---
15 | apiVersion: apps.openshift.io/v1
16 | kind: DeploymentConfig
17 | metadata:
18 | name: dont-fire
19 | spec:
20 | replicas: 3
21 | template:
22 | spec:
23 | containers:
24 | - name: app
25 | securityContext:
26 | allowPrivilegeEscalation: false
27 | ---
28 | apiVersion: apps/v1
29 | kind: Deployment
30 | metadata:
31 | name: app1
32 | spec:
33 | replicas: 3
34 | template:
35 | spec:
36 | containers:
37 | - name: app
38 | securityContext:
39 | allowPrivilegeEscalation: true
40 | ---
41 | apiVersion: apps.openshift.io/v1
42 | kind: DeploymentConfig
43 | metadata:
44 | name: app2
45 | spec:
46 | replicas: 3
47 | template:
48 | spec:
49 | containers:
50 | - name: app
51 | securityContext:
52 | allowPrivilegeEscalation: true
--------------------------------------------------------------------------------
/tests/checks/privileged-container.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | replicas: 3
8 | template:
9 | spec:
10 | containers:
11 | - name: app
12 | securityContext:
13 | privileged: false
14 | ---
15 | apiVersion: apps.openshift.io/v1
16 | kind: DeploymentConfig
17 | metadata:
18 | name: dont-fire
19 | spec:
20 | replicas: 3
21 | template:
22 | spec:
23 | containers:
24 | - name: app
25 | securityContext:
26 | privileged: false
27 | ---
28 | apiVersion: apps/v1
29 | kind: Deployment
30 | metadata:
31 | name: app1
32 | spec:
33 | replicas: 3
34 | template:
35 | spec:
36 | containers:
37 | - name: app
38 | securityContext:
39 | privileged: true
40 | ---
41 | apiVersion: apps.openshift.io/v1
42 | kind: DeploymentConfig
43 | metadata:
44 | name: app2
45 | spec:
46 | replicas: 3
47 | template:
48 | spec:
49 | containers:
50 | - name: app
51 | securityContext:
52 | privileged: true
--------------------------------------------------------------------------------
/tests/checks/privileged-ports.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | replicas: 3
8 | template:
9 | spec:
10 | containers:
11 | - name: app
12 | ports:
13 | - containerPort: 8080
14 | ---
15 | apiVersion: apps.openshift.io/v1
16 | kind: DeploymentConfig
17 | metadata:
18 | name: dont-fire
19 | spec:
20 | replicas: 3
21 | template:
22 | spec:
23 | containers:
24 | - name: app
25 | ports:
26 | - containerPort: 8080
27 | ---
28 | apiVersion: apps/v1
29 | kind: Deployment
30 | metadata:
31 | name: app1
32 | spec:
33 | replicas: 3
34 | template:
35 | spec:
36 | containers:
37 | - name: app
38 | ports:
39 | - containerPort: 80
40 | ---
41 | apiVersion: apps.openshift.io/v1
42 | kind: DeploymentConfig
43 | metadata:
44 | name: app2
45 | spec:
46 | replicas: 3
47 | template:
48 | spec:
49 | containers:
50 | - name: app
51 | ports:
52 | - containerPort: 80
--------------------------------------------------------------------------------
/tests/checks/read-secret-from-env-var.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: app1
6 | spec:
7 | replicas: 3
8 | template:
9 | spec:
10 | containers:
11 | - name: app
12 | env:
13 | - name: TOKEN
14 | valueFrom:
15 | secretKeyRef:
16 | name: my-secret
17 | key: token
18 | ---
19 | apiVersion: apps.openshift.io/v1
20 | kind: DeploymentConfig
21 | metadata:
22 | name: app2
23 | spec:
24 | replicas: 3
25 | template:
26 | spec:
27 | containers:
28 | - name: app
29 | env:
30 | - name: TOKEN
31 | valueFrom:
32 | secretKeyRef:
33 | name: my-secret
34 | key: token
--------------------------------------------------------------------------------
/tests/checks/readiness-port.yml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | spec:
4 | template:
5 | spec:
6 | containers:
7 | - name: dont-fire-deployment-grpc
8 | ports:
9 | - containerPort: 8080
10 | name: http
11 | readinessProbe:
12 | grpc:
13 | port: 8080
14 | - name: dont-fire-deployment
15 | ports:
16 | - containerPort: 8080
17 | name: http
18 | protocol: TCP
19 | readinessProbe:
20 | httpGet:
21 | path: "/"
22 | port: 8080
23 | - name: fire-deployment-name
24 | readinessProbe:
25 | httpGet:
26 | path: "/"
27 | port: http
28 | - name: fire-deployment-int
29 | ports:
30 | - containerPort: 9999
31 | name: http
32 | protocol: TCP
33 | readinessProbe:
34 | httpGet:
35 | path: "/"
36 | port: 8080
37 | - name: fire-deployment-udp
38 | ports:
39 | - containerPort: 9999
40 | name: udp
41 | protocol: UDP
42 | readinessProbe:
43 | tcpSocket:
44 | port: udp
45 | - name: fire-deployment-grpc
46 | ports:
47 | - containerPort: 9999
48 | name: grpc
49 | protocol: TCP
50 | readinessProbe:
51 | grpc:
52 | port: 8080
53 | ---
54 |
--------------------------------------------------------------------------------
/tests/checks/required-annotation-email.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | annotations:
7 | email: kubelinter@stackrox.com
8 | ---
9 | apiVersion: apps.openshift.io/v1
10 | kind: DeploymentConfig
11 | metadata:
12 | name: dont-fire
13 | annotations:
14 | email: kubelinter@stackrox.com
15 | ---
16 | apiVersion: apps/v1
17 | kind: Deployment
18 | metadata:
19 | name: app1
20 | annotations:
21 | whois: kubelinter@stackrox.com
22 | ---
23 | apiVersion: apps.openshift.io/v1
24 | kind: DeploymentConfig
25 | metadata:
26 | name: app2
27 | annotations:
28 | whois: kubelinter@stackrox.com
--------------------------------------------------------------------------------
/tests/checks/required-label-owner.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | labels:
7 | owner: kubelinter@stackrox.com
8 | ---
9 | apiVersion: apps.openshift.io/v1
10 | kind: DeploymentConfig
11 | metadata:
12 | name: dont-fire
13 | labels:
14 | owner: kubelinter@stackrox.com
15 | ---
16 | apiVersion: apps/v1
17 | kind: Deployment
18 | metadata:
19 | name: app1
20 | labels:
21 | dev: kubelinter@stackrox.com
22 | ---
23 | apiVersion: apps.openshift.io/v1
24 | kind: DeploymentConfig
25 | metadata:
26 | name: app2
27 | labels:
28 | dev: kubelinter@stackrox.com
--------------------------------------------------------------------------------
/tests/checks/run-as-non-root.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | selector:
8 | matchLabels:
9 | app.kubernetes.io/name: app1
10 | template:
11 | spec:
12 | containers:
13 | - name: app
14 | runAsUser: 1001
15 | securityContext:
16 | runAsNonRoot: true
17 | ---
18 | apiVersion: apps.openshift.io/v1
19 | kind: DeploymentConfig
20 | metadata:
21 | name: dont-fire
22 | spec:
23 | selector:
24 | app.kubernetes.io/name: app2
25 | template:
26 | spec:
27 | containers:
28 | - name: app2
29 | runAsUser: 1001
30 | securityContext:
31 | runAsNonRoot: true
32 | ---
33 | apiVersion: apps/v1
34 | kind: Deployment
35 | metadata:
36 | name: app1
37 | spec:
38 | selector:
39 | matchLabels:
40 | app.kubernetes.io/name: app1
41 | template:
42 | spec:
43 | containers:
44 | - name: app
45 | runAsUser: 0
46 | ---
47 | apiVersion: apps.openshift.io/v1
48 | kind: DeploymentConfig
49 | metadata:
50 | name: app2
51 | spec:
52 | selector:
53 | app.kubernetes.io/name: app2
54 | template:
55 | spec:
56 | containers:
57 | - name: app2
58 | runAsUser: 0
--------------------------------------------------------------------------------
/tests/checks/sensitive-host-mounts.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: app1
6 | spec:
7 | selector:
8 | matchLabels:
9 | app.kubernetes.io/name: app1
10 | template:
11 | spec:
12 | containers:
13 | - name: app
14 | volumeMounts:
15 | - name: config
16 | mountPath: /etc
17 | volumes:
18 | - name: config
19 | hostPath:
20 | path: /etc
21 | ---
22 | apiVersion: apps.openshift.io/v1
23 | kind: DeploymentConfig
24 | metadata:
25 | name: app2
26 | spec:
27 | selector:
28 | app.kubernetes.io/name: app2
29 | template:
30 | spec:
31 | containers:
32 | - name: app2
33 | runAsUser: 0
34 | volumeMounts:
35 | - name: config
36 | mountPath: /etc
37 | volumes:
38 | - name: config
39 | hostPath:
40 | path: /etc
--------------------------------------------------------------------------------
/tests/checks/ssh-port.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | spec:
7 | replicas: 3
8 | template:
9 | spec:
10 | containers:
11 | - name: app
12 | ports:
13 | - containerPort: 2222
14 | protocol: TCP
15 | ---
16 | apiVersion: apps.openshift.io/v1
17 | kind: DeploymentConfig
18 | metadata:
19 | name: dont-fire
20 | spec:
21 | replicas: 3
22 | template:
23 | spec:
24 | containers:
25 | - name: app
26 | ports:
27 | - containerPort: 2222
28 | protocol: TCP
29 | ---
30 | apiVersion: apps/v1
31 | kind: Deployment
32 | metadata:
33 | name: app1
34 | spec:
35 | replicas: 3
36 | template:
37 | spec:
38 | containers:
39 | - name: app
40 | ports:
41 | - containerPort: 22
42 | protocol: TCP
43 | ---
44 | apiVersion: apps.openshift.io/v1
45 | kind: DeploymentConfig
46 | metadata:
47 | name: app2
48 | spec:
49 | replicas: 3
50 | template:
51 | spec:
52 | containers:
53 | - name: app
54 | ports:
55 | - containerPort: 22
56 | protocol: TCP
57 | ---
58 | apiVersion: apps.openshift.io/v1
59 | kind: DeploymentConfig
60 | metadata:
61 | name: app3
62 | spec:
63 | replicas: 3
64 | template:
65 | spec:
66 | containers:
67 | - name: app-no-protocol
68 | ports:
69 | - containerPort: 22
--------------------------------------------------------------------------------
/tests/checks/startup-port.yml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | spec:
4 | template:
5 | spec:
6 | containers:
7 | - name: dont-fire-deployment-grpc
8 | ports:
9 | - containerPort: 8080
10 | name: http
11 | startupProbe:
12 | grpc:
13 | port: 8080
14 | - name: dont-fire-deployment
15 | ports:
16 | - containerPort: 8080
17 | name: http
18 | protocol: TCP
19 | startupProbe:
20 | httpGet:
21 | path: "/"
22 | port: 8080
23 | - name: fire-deployment-name
24 | startupProbe:
25 | httpGet:
26 | path: "/"
27 | port: http
28 | - name: fire-deployment-int
29 | ports:
30 | - containerPort: 9999
31 | name: http
32 | protocol: TCP
33 | startupProbe:
34 | httpGet:
35 | path: "/"
36 | port: 8080
37 | - name: fire-deployment-udp
38 | ports:
39 | - containerPort: 9999
40 | name: udp
41 | protocol: UDP
42 | startupProbe:
43 | tcpSocket:
44 | port: udp
45 | - name: fire-deployment-grpc
46 | ports:
47 | - containerPort: 9999
48 | name: grpc
49 | protocol: TCP
50 | startupProbe:
51 | grpc:
52 | port: 8080
53 | ---
54 |
--------------------------------------------------------------------------------
/tests/checks/unsafe-proc-mount.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: app1
6 | spec:
7 | replicas: 3
8 | template:
9 | spec:
10 | containers:
11 | - name: app
12 | securityContext:
13 | procMount: Unmasked
14 | ---
15 | apiVersion: apps.openshift.io/v1
16 | kind: DeploymentConfig
17 | metadata:
18 | name: app2
19 | spec:
20 | replicas: 3
21 | template:
22 | spec:
23 | containers:
24 | - name: app
25 | securityContext:
26 | procMount: Unmasked
--------------------------------------------------------------------------------
/tests/checks/unsafe-sysctls.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: app1
6 | spec:
7 | replicas: 3
8 | template:
9 | spec:
10 | containers:
11 | - name: app
12 | securityContext:
13 | sysctls:
14 | - name: kernel.sem
15 | ---
16 | apiVersion: apps.openshift.io/v1
17 | kind: DeploymentConfig
18 | metadata:
19 | name: app2
20 | spec:
21 | replicas: 3
22 | template:
23 | spec:
24 | containers:
25 | - name: app
26 | securityContext:
27 | sysctls:
28 | - name: kernel.sem
--------------------------------------------------------------------------------
/tests/checks/unset-cpu-requirements.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: app1
6 | spec:
7 | replicas: 3
8 | template:
9 | spec:
10 | containers:
11 | - name: app
12 | requests:
13 | memory: 1Gi
14 |
15 | ---
16 | apiVersion: apps.openshift.io/v1
17 | kind: DeploymentConfig
18 | metadata:
19 | name: app2
20 | spec:
21 | replicas: 3
22 | template:
23 | spec:
24 | containers:
25 | - name: app
26 | requests:
27 | memory: 1Gi
--------------------------------------------------------------------------------
/tests/checks/unset-memory-requirements.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: app1
6 | spec:
7 | replicas: 3
8 | template:
9 | spec:
10 | containers:
11 | - name: app
12 | limit:
13 | cpu: 1
14 | ---
15 | apiVersion: apps.openshift.io/v1
16 | kind: DeploymentConfig
17 | metadata:
18 | name: app2
19 | spec:
20 | replicas: 3
21 | template:
22 | spec:
23 | containers:
24 | - name: app
25 | limit:
26 | cpu: 1
--------------------------------------------------------------------------------
/tests/checks/use-namespace.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: dont-fire
6 | namespace: namespace-dev
7 | ---
8 | apiVersion: apps/v1
9 | kind: Deployment
10 | metadata:
11 | name: app1
12 | namespace: default
--------------------------------------------------------------------------------
/tests/checks/wildcard-in-rules.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: Role
4 | metadata:
5 | name: role1
6 | namespace: namespace-dev
7 | rules:
8 | - apiGroups: [""]
9 | resources: ["pods"]
10 | verbs: ["get"]
11 | ---
12 | apiVersion: rbac.authorization.k8s.io/v1
13 | kind: Role
14 | metadata:
15 | name: role1
16 | namespace: namespace-dev
17 | rules:
18 | - apiGroups: [""]
19 | resources: ["secrets"]
20 | verbs: ["*"]
21 |
--------------------------------------------------------------------------------
/tests/checks/writable-host-mount.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: app1
6 | spec:
7 | selector:
8 | matchLabels:
9 | app.kubernetes.io/name: app1
10 | template:
11 | spec:
12 | containers:
13 | - name: app
14 | volumeMounts:
15 | - name: config
16 | mountPath: /config
17 | volumes:
18 | - name: config
19 | hostPath:
20 | path: /config
21 | ---
22 | apiVersion: apps.openshift.io/v1
23 | kind: DeploymentConfig
24 | metadata:
25 | name: app2
26 | spec:
27 | selector:
28 | app.kubernetes.io/name: app2
29 | template:
30 | spec:
31 | containers:
32 | - name: app2
33 | runAsUser: 0
34 | volumeMounts:
35 | - name: config
36 | mountPath: /config
37 | volumes:
38 | - name: config
39 | hostPath:
40 | path: /config
--------------------------------------------------------------------------------
/tests/testdata/mychart-0.1.0.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stackrox/kube-linter/e3a413f1435f6c1b4debd181c794ca0706e42660/tests/testdata/mychart-0.1.0.tgz
--------------------------------------------------------------------------------
/tests/testdata/mychart/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *.orig
18 | *~
19 | # Various IDEs
20 | .project
21 | .idea/
22 | *.tmproj
23 | .vscode/
24 |
--------------------------------------------------------------------------------
/tests/testdata/mychart/Chart.lock:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - name: subchart
3 | repository: file://../subchart
4 | version: 0.1.0
5 | digest: sha256:f8645a52640009a9d8905d929d3362e04720964c71e37af357b8b5e2852c365d
6 | generated: "2023-11-23T15:35:33.69184771+01:00"
7 |
--------------------------------------------------------------------------------
/tests/testdata/mychart/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | appVersion: 1.16.0
3 | description: A Helm chart for Kubernetes
4 | name: mychart
5 | type: application
6 | version: 0.1.0
7 | dependencies:
8 | - name: subchart
9 | version: 0.1.0
10 | repository: file://../subchart
11 |
--------------------------------------------------------------------------------
/tests/testdata/mychart/charts/subchart-0.1.0.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stackrox/kube-linter/e3a413f1435f6c1b4debd181c794ca0706e42660/tests/testdata/mychart/charts/subchart-0.1.0.tgz
--------------------------------------------------------------------------------
/tests/testdata/mychart/templates/hpa.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.autoscaling.enabled }}
2 | apiVersion: autoscaling/v2beta1
3 | kind: HorizontalPodAutoscaler
4 | metadata:
5 | name: {{ include "mychart.fullname" . }}
6 | labels:
7 | {{- include "mychart.labels" . | nindent 4 }}
8 | spec:
9 | scaleTargetRef:
10 | apiVersion: apps/v1
11 | kind: Deployment
12 | name: {{ include "mychart.fullname" . }}
13 | minReplicas: {{ .Values.autoscaling.minReplicas }}
14 | maxReplicas: {{ .Values.autoscaling.maxReplicas }}
15 | metrics:
16 | {{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
17 | - type: Resource
18 | resource:
19 | name: cpu
20 | targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
21 | {{- end }}
22 | {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
23 | - type: Resource
24 | resource:
25 | name: memory
26 | targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
27 | {{- end }}
28 | {{- end }}
29 |
--------------------------------------------------------------------------------
/tests/testdata/mychart/templates/ingress.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.ingress.enabled -}}
2 | {{- $fullName := include "mychart.fullname" . -}}
3 | {{- $svcPort := .Values.service.port -}}
4 | {{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
5 | apiVersion: networking.k8s.io/v1beta1
6 | {{- else -}}
7 | apiVersion: extensions/v1beta1
8 | {{- end }}
9 | kind: Ingress
10 | metadata:
11 | name: {{ $fullName }}
12 | labels:
13 | {{- include "mychart.labels" . | nindent 4 }}
14 | {{- with .Values.ingress.annotations }}
15 | annotations:
16 | {{- toYaml . | nindent 4 }}
17 | {{- end }}
18 | spec:
19 | {{- if .Values.ingress.tls }}
20 | tls:
21 | {{- range .Values.ingress.tls }}
22 | - hosts:
23 | {{- range .hosts }}
24 | - {{ . | quote }}
25 | {{- end }}
26 | secretName: {{ .secretName }}
27 | {{- end }}
28 | {{- end }}
29 | rules:
30 | {{- range .Values.ingress.hosts }}
31 | - host: {{ .host | quote }}
32 | http:
33 | paths:
34 | {{- range .paths }}
35 | - path: {{ . }}
36 | backend:
37 | serviceName: {{ $fullName }}
38 | servicePort: {{ $svcPort }}
39 | {{- end }}
40 | {{- end }}
41 | {{- end }}
42 |
--------------------------------------------------------------------------------
/tests/testdata/mychart/templates/service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: {{ include "mychart.fullname" . }}
5 | labels:
6 | {{- include "mychart.labels" . | nindent 4 }}
7 | spec:
8 | type: {{ .Values.service.type }}
9 | ports:
10 | - port: {{ .Values.service.port }}
11 | targetPort: http
12 | protocol: TCP
13 | name: http
14 | selector:
15 | {{- include "mychart.selectorLabels" . | nindent 4 }}
16 |
--------------------------------------------------------------------------------
/tests/testdata/mychart/templates/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.serviceAccount.create -}}
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: {{ include "mychart.serviceAccountName" . }}
6 | labels:
7 | {{- include "mychart.labels" . | nindent 4 }}
8 | {{- with .Values.serviceAccount.annotations }}
9 | annotations:
10 | {{- toYaml . | nindent 4 }}
11 | {{- end }}
12 | {{- end }}
13 |
--------------------------------------------------------------------------------
/tests/testdata/mychart/templates/tests/test-connection.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: "{{ include "mychart.fullname" . }}-test-connection"
5 | labels:
6 | {{- include "mychart.labels" . | nindent 4 }}
7 | annotations:
8 | "helm.sh/hook": test
9 | spec:
10 | containers:
11 | - name: wget
12 | image: busybox
13 | command: ['wget']
14 | args: ['{{ include "mychart.fullname" . }}:{{ .Values.service.port }}']
15 | restartPolicy: Never
16 |
--------------------------------------------------------------------------------
/tests/testdata/splunk.yaml:
--------------------------------------------------------------------------------
1 | kind: Service
2 | apiVersion: v1
3 | metadata:
4 | name: splunk
5 | namespace: splunk-ns
6 | spec:
7 | selector:
8 | app: splunk
9 | ports:
10 | - name: http
11 | protocol: TCP
12 | port: 8000
13 | targetPort: 8000
14 | - name: https
15 | protocol: TCP
16 | port: 8088
17 | targetPort: 8088
18 | ---
19 | apiVersion: apps/v1
20 | kind: Deployment
21 | metadata:
22 | name: splunk
23 | namespace: splunk-ns
24 | labels:
25 | apps: splunk
26 | spec:
27 | replicas: 1
28 | selector:
29 | matchLabels:
30 | app: splunk
31 | template:
32 | metadata:
33 | labels:
34 | app: splunk
35 | spec:
36 | containers:
37 | - name: splunk
38 | image: splunk/splunk:8.1.2
39 | securityContext:
40 | privileged: true
41 | ports:
42 | - containerPort: 8000
43 | - containerPort: 8088
44 | env:
45 | - name: SPLUNK_START_ARGS
46 | value: --accept-license
47 | - name: SPLUNK_USER
48 | value: root
49 | - name: SPLUNK_PASSWORD
50 | value: helloworld
51 |
--------------------------------------------------------------------------------
/tests/testdata/subchart/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *.orig
18 | *~
19 | # Various IDEs
20 | .project
21 | .idea/
22 | *.tmproj
23 | .vscode/
24 |
--------------------------------------------------------------------------------
/tests/testdata/subchart/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | appVersion: 1.16.0
3 | description: A Helm chart for Kubernetes
4 | name: subchart
5 | type: application
6 | version: 0.1.0
7 |
--------------------------------------------------------------------------------
/tool-imports/empty.go:
--------------------------------------------------------------------------------
1 | package toolimports
2 |
3 | // Empty file to ensure that this directory has at least one Go file even without build tags.
4 |
--------------------------------------------------------------------------------
/tool-imports/tools.go:
--------------------------------------------------------------------------------
1 | //go:build tools
2 | // +build tools
3 |
4 | package toolimports
5 |
6 | // This file declares dependencies on tool for `go mod` purposes.
7 | // See https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module
8 | // for an explanation of the approach.
9 |
10 | import (
11 | _ "github.com/golangci/golangci-lint/v2/cmd/golangci-lint"
12 | _ "github.com/goreleaser/goreleaser"
13 | )
14 |
--------------------------------------------------------------------------------