KubeLinter を使ってみる


# はじめに

`KubeLinter` は、`StackRox`社 (`Red Hat` が買収) が公開している `Open Source` の `Linter` ツールです。


**GitHub**

https://github.com/stackrox/kube-linter

**ドキュメント**

https://docs.kubelinter.io/#/

# セットアップ

いろいろ方法がありますが、バイナリ一つなので、[Release](https://github.com/stackrox/kube-linter/releases) からダウンロードする方法でインストールします。

ダウンロード→解凍→適当なディレクトリに移動。と最もシンプルなパターンでインストールできます。

```
# ダウンロード  
$ curl -OL https://github.com/stackrox/kube-linter/releases/download/0.2.5/kube-linter-linux.tar.gz　

# 解凍　
$ tar -xzf kube-linter-linux.tar.gz   

# コマンド を /usr/local/bin に移動  
$ mv kube-linter /usr/local/bin/       
```

# 使い方

[ドキュメントサイト](https://docs.kubelinter.io/#/?id=usage) のチュートリアルの方法をとりあえず試して見ます。

1)ドキュメントサイトに掲載されている以下の[テスト用のマニフェスト](https://docs.kubelinter.io/#/?id=usage) を用意します。

```pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
  volumes:
  - name: sec-ctx-vol
    emptyDir: {}
  containers:
  - name: sec-ctx-demo
    image: busybox
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
    command: [ "sh", "-c", "sleep 1h" ]
    volumeMounts:
    - name: sec-ctx-vol
      mountPath: /data/demo
    securityContext:
      allowPrivilegeEscalation: false
```

2) この `pod.yaml` を `KubeLinter` コマンドにかけてみます。

コマンド名は、ハイホンが入って `kube-linter`で以下のフォーマットになります。

```
kube-linter lint <Lintしたいファイル>
```

 `pod.yaml` に対して実行してみます。

```
$ kube-linter lint pod.yaml
KubeLinter 0.2.5

pod.yaml: (object: <no namespace>/security-context-demo /v1, Kind=Pod) container "sec-ctx-demo" does not have a read-only root file system (check: no-read-only-root-fs, remediation: Set readOnlyRootFilesystem to true in the container securityContext.)

pod.yaml: (object: <no namespace>/security-context-demo /v1, Kind=Pod) container "sec-ctx-demo" has cpu limit 0 (check: unset-cpu-requirements, remediation: Set CPU requests and limits for your container based on its requirements. Refer to https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits for details.)

pod.yaml: (object: <no namespace>/security-context-demo /v1, Kind=Pod) container "sec-ctx-demo" has memory limit 0 (check: unset-memory-requirements, remediation: Set memory requests and limits for your container based on its requirements. Refer to https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits for details.)

Error: found 3 lint errors
$
```

エラーが3つでています。

3) エラーを読んでみる。

一つ目のエラーは…

`.... Set readOnlyRootFilesystem to true in the container securityContext.`

ホストOSのファイルシステムにアクセスできる状態になっているので `securityContext` に `readOnlyRootFilesystem : true` を設定してください。と具体的に指定すべき`Field`名まで言及してくれています。 

2つめと3つめのエラーは…

```
container "sec-ctx-demo" has cpu limit 0 
container "sec-ctx-demo" has memory limit 0 
```

これはコンテナが使用する cpu と memory limit 値が指定されてないよ。というものでした。
テスト環境だと面倒で設定を書かない事が多い設定です。

4) 修整した pod.yaml を作成する

エラーの結果を踏まえて `pod.yaml` を修整した `pod.fix.yaml` を作成しました。

```pod.fix.yaml
apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
  volumes:
  - name: sec-ctx-vol
    emptyDir: {}
  containers:
  - name: sec-ctx-demo
    image: busybox
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:                 # cpu と memory の limit を追加
        memory: "64Mi"
        cpu: "250m"
    command: [ "sh", "-c", "sleep 1h" ]
    volumeMounts:
    - name: sec-ctx-vol
      mountPath: /data/demo
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true　　　   # readOnlyRootFileSystem : true を設定
```

5) もう一度トライ

修整した`pod.fix.yaml`を、`kube-linter`にかけてみます。

```
$ kube-linter lint pod.fix.yaml
KubeLinter 0.2.5

No lint errors found!
$
```

今度は、無事 No Error でした。

# その他のコマンド

この記事では、簡単な yaml チェックしかしませんでしたが、幾つか引数のパターンがあるようです。

```
$ kube-linter -h
Usage:
  kube-linter [command]

Available Commands:
  checks      View more information on lint checks
  completion  generate the autocompletion script for the specified shell
  help        Help about any command
  lint        Lint Kubernetes YAML files and Helm charts
  templates   View more information on check templates
  version     Print version and exit

Flags:
  -h, --help   help for kube-linter

Use "kube-linter [command] --help" for more information about a command.
$
```

`kube-linster checks list` というコマンドで、どんなチェックをしているのか一覧が取れるようなので、実行してみました。

<details><summary>`kube-linster checks list`実行結果</summary><div>

```
$ kube-linter checks list
Name: access-to-create-pods
Description: Indicates when a subject (Group/User/ServiceAccount) has create access to Pods. 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.
Remediation: Where possible, remove create access to pod objects in the cluster.
Template: access-to-resources
Parameters: map[resources:[^pods$ ^deployments$ ^statefulsets$ ^replicasets$ ^cronjob$ ^jobs$ ^daemonsets$] verbs:[^create$]]
Enabled by default: false

------------------------------

Name: access-to-secrets
Description: Indicates when a subject (Group/User/ServiceAccount) has access to Secrets. 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.
Remediation: Where possible, remove get, list and watch access to secret objects in the cluster.
Template: access-to-resources
Parameters: map[resources:[^secrets$] verbs:[^get$ ^list$ ^delete$ ^create$ ^watch$ ^*$]]
Enabled by default: false

------------------------------

Name: cluster-admin-role-binding
Description: CIS Benchmark 5.1.1 Ensure that the cluster-admin role is only used where required
Remediation: Create and assign a separate role that has access to specific resources/actions needed for the service account.
Template: cluster-admin-role-binding
Parameters: map[]
Enabled by default: false

------------------------------

Name: dangling-service
Description: Indicates when services do not have any associated deployments.
Remediation: Confirm that your service's selector correctly matches the labels on one of your deployments.
Template: dangling-service
Parameters: map[]
Enabled by default: true

------------------------------

Name: default-service-account
Description: Indicates when pods use the default service account.
Remediation: Create a dedicated service account for your pod. Refer to https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ for details.
Template: service-account
Parameters: map[serviceAccount:^(|default)$]
Enabled by default: false

------------------------------

Name: deprecated-service-account-field
Description: Indicates when deployments use the deprecated serviceAccount field.
Remediation: Use the serviceAccountName field instead. If you must specify serviceAccount, ensure values for serviceAccount and serviceAccountName match.
Template: deprecated-service-account-field
Parameters: map[]
Enabled by default: true

------------------------------

Name: docker-sock
Description: Alert on deployments with docker.sock mounted in containers.
Remediation: Ensure the Docker socket is not mounted inside any containers by removing the associated  Volume and VolumeMount in deployment yaml specification. If the Docker socket is mounted inside a container it could allow processes running within  the container to execute Docker commands which would effectively allow for full control of the host.
Template: host-mounts
Parameters: map[dirs:[docker.sock$]]
Enabled by default: true

------------------------------

Name: drop-net-raw-capability
Description: Indicates when containers do not drop NET_RAW capability
Remediation: NET_RAW makes it so that an application within the container is able to craft raw packets, use raw sockets, and bind to any address. Remove this capability in the containers under containers security contexts.
Template: verify-container-capabilities
Parameters: map[forbiddenCapabilities:[NET_RAW]]
Enabled by default: true

------------------------------

Name: env-var-secret
Description: Indicates when objects use a secret in an environment variable.
Remediation: Do not use raw secrets in environment variables. Instead, either mount the secret as a file or use a secretKeyRef. Refer to https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets for details.
Template: env-var
Parameters: map[name:(?i).*secret.* value:.+]
Enabled by default: true

------------------------------

Name: exposed-services
Description: Alert on services for forbidden types
Remediation: Ensure containers are not exposed through a forbidden service type such as NodePort or LoadBalancer.
Template: forbidden-service-types
Parameters: map[forbiddenServiceTypes:[NodePort LoadBalancer]]
Enabled by default: false

------------------------------

Name: host-ipc
Description: Alert on pods/deployment-likes with sharing host's IPC namespace
Remediation: Ensure the host's IPC namespace is not shared.
Template: host-ipc
Parameters: map[]
Enabled by default: true

------------------------------

Name: host-network
Description: Alert on pods/deployment-likes with sharing host's network namespace
Remediation: Ensure the host's network namespace is not shared.
Template: host-network
Parameters: map[]
Enabled by default: true

------------------------------

Name: host-pid
Description: Alert on pods/deployment-likes with sharing host's process namespace
Remediation: Ensure the host's process namespace is not shared.
Template: host-pid
Parameters: map[]
Enabled by default: true

------------------------------

Name: latest-tag
Description: Indicates when a deployment-like object is running a container with an invalid container image
Remediation: Use a container image with a proper image tag satisfying either the "AllowList" & "BlockList" regex patterns.
Template: latest-tag
Parameters: map[BlockList:[.*:(latest)$]]
Enabled by default: true

------------------------------

Name: minimum-three-replicas
Description: Indicates when a deployment uses less than three replicas
Remediation: Increase be number of replicas in the deployment to at least three to increase the fault tolerancy of the deployment.
Template: minimum-replicas
Parameters: map[minReplicas:3]
Enabled by default: false

------------------------------

Name: mismatching-selector
Description: Indicates when deployment selectors fail to match the pod template labels.
Remediation: Confirm that your deployment selector correctly matches the labels in its pod template.
Template: mismatching-selector
Parameters: map[]
Enabled by default: true

------------------------------

Name: no-anti-affinity
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.
Remediation: Specify anti-affinity in your pod specification to ensure that the orchestrator attempts to schedule replicas on different nodes. Using podAntiAffinity, specify a labelSelector that matches pods for the deployment, and set the topologyKey to kubernetes.io/hostname. Refer to https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity for details.
Template: anti-affinity
Parameters: map[minReplicas:2]
Enabled by default: true

------------------------------

Name: no-extensions-v1beta
Description: Indicates when objects use deprecated API versions under extensions/v1beta.
Remediation: Migrate using the apps/v1 API versions for the objects. Refer to https://kubernetes.io/blog/2019/07/18/api-deprecations-in-1-16/ for details.
Template: disallowed-api-obj
Parameters: map[group:extensions version:v1beta.+]
Enabled by default: true

------------------------------

Name: no-liveness-probe
Description: Indicates when containers fail to specify a liveness probe.
Remediation: Specify a liveness probe in your container. Refer to https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ for details.
Template: liveness-probe
Parameters: map[]
Enabled by default: false

------------------------------

Name: no-read-only-root-fs
Description: Indicates when containers are running without a read-only root filesystem.
Remediation: Set readOnlyRootFilesystem to true in the container securityContext.
Template: read-only-root-fs
Parameters: map[]
Enabled by default: true

------------------------------

Name: no-readiness-probe
Description: Indicates when containers fail to specify a readiness probe.
Remediation: Specify a readiness probe in your container. Refer to https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ for details.
Template: readiness-probe
Parameters: map[]
Enabled by default: false

------------------------------

Name: no-rolling-update-strategy
Description: Indicates when a deployment doesn't use a rolling update strategy
Remediation: Use a rolling update strategy to avoid service disruption during an update. A rolling update strategy allows for pods to be systematicaly replaced in a controlled fashion to ensure no service disruption.
Template: update-configuration
Parameters: map[strategyTypeRegex:^(RollingUpdate|Rolling)$]
Enabled by default: false

------------------------------

Name: non-existent-service-account
Description: Indicates when pods reference a service account that is not found.
Remediation: Create the missing service account, or refer to an existing service account.
Template: non-existent-service-account
Parameters: map[]
Enabled by default: true

------------------------------

Name: non-isolated-pod
Description: Alert on deployment-like objects that are not selected by any NetworkPolicy.
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.
Template: non-isolated-pod
Parameters: map[]
Enabled by default: false

------------------------------

Name: privilege-escalation-container
Description: Alert on containers of allowing privilege escalation that could gain more privileges than its parent process.
Remediation: Ensure containers do not allow privilege escalation by setting allowPrivilegeEscalation=false." See https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ for more details.
Template: privilege-escalation-container
Parameters: map[]
Enabled by default: true

------------------------------

Name: privileged-container
Description: Indicates when deployments have containers running in privileged mode.
Remediation: Do not run your container as privileged unless it is required.
Template: privileged
Parameters: map[]
Enabled by default: true

------------------------------

Name: privileged-ports
Description: Alert on deployments with privileged ports mapped in containers
Remediation: Ensure privileged ports [0, 1024] are not mapped within containers.
Template: privileged-ports
Parameters: map[]
Enabled by default: false

------------------------------

Name: read-secret-from-env-var
Description: Indicates when a deployment reads secret from environment variables. CIS Benchmark 5.4.1: "Prefer using secrets as files over secrets as environment variables. "
Remediation: If possible, rewrite application code to read secrets from mounted secret files, rather than from environment variables. Refer to https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets for details.
Template: read-secret-from-env-var
Parameters: map[]
Enabled by default: false

------------------------------

Name: required-annotation-email
Description: Indicates when objects do not have an email annotation with a valid email address.
Remediation: Add an email annotation to your object with the email address of the object's owner.
Template: required-annotation
Parameters: map[key:email value:[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+]
Enabled by default: false

------------------------------

Name: required-label-owner
Description: Indicates when objects do not have an email annotation with an owner label.
Remediation: Add an email annotation to your object with the name of the object's owner.
Template: required-label
Parameters: map[key:owner]
Enabled by default: false

------------------------------

Name: run-as-non-root
Description: Indicates when containers are not set to runAsNonRoot.
Remediation: Set runAsUser to a non-zero number and runAsNonRoot to true in your pod or container securityContext. Refer to https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ for details.
Template: run-as-non-root
Parameters: map[]
Enabled by default: true

------------------------------

Name: sensitive-host-mounts
Description: Alert on deployments with sensitive host system directories mounted in containers
Remediation: Ensure sensitive host system directories are not mounted in containers by removing those Volumes and VolumeMounts.
Template: host-mounts
Parameters: map[dirs:[^/$ ^/boot$ ^/dev$ ^/etc$ ^/lib$ ^/proc$ ^/sys$ ^/usr$]]
Enabled by default: true

------------------------------

Name: ssh-port
Description: Indicates when deployments expose port 22, which is commonly reserved for SSH access.
Remediation: Ensure that non-SSH services are not using port 22. Confirm that any actual SSH servers have been vetted.
Template: ports
Parameters: map[port:22 protocol:TCP]
Enabled by default: true

------------------------------

Name: unsafe-proc-mount
Description: Alert on deployments with unsafe /proc mount (procMount=Unmasked) that will bypass the default masking behavior of the container runtime
Remediation: Ensure container does not unsafely exposes parts of /proc by setting procMount=Default.  Unmasked ProcMount bypasses the default masking behavior of the container runtime. See https://kubernetes.io/docs/concepts/security/pod-security-standards/ for more details.
Template: unsafe-proc-mount
Parameters: map[]
Enabled by default: false

------------------------------

Name: unsafe-sysctls
Description: Alert on deployments specifying unsafe sysctls that may lead to severe problems like wrong behavior of containers
Remediation: Ensure container does not allow unsafe allocation of system resources by removing unsafe sysctls configurations. For more details see https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/ https://docs.docker.com/engine/reference/commandline/run/#configure-namespaced-kernel-parameters-sysctls-at-runtime.
Template: unsafe-sysctls
Parameters: map[unsafeSysCtls:[kernel.msg kernel.sem kernel.shm fs.mqueue. net.]]
Enabled by default: true

------------------------------

Name: unset-cpu-requirements
Description: Indicates when containers do not have CPU requests and limits set.
Remediation: Set CPU requests and limits for your container based on its requirements. Refer to https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits for details.
Template: cpu-requirements
Parameters: map[lowerBoundMillis:0 requirementsType:any upperBoundMillis:0]
Enabled by default: true

------------------------------

Name: unset-memory-requirements
Description: Indicates when containers do not have memory requests and limits set.
Remediation: Set memory requests and limits for your container based on its requirements. Refer to https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits for details.
Template: memory-requirements
Parameters: map[lowerBoundMB:0 requirementsType:any upperBoundMB:0]
Enabled by default: true

------------------------------

Name: use-namespace
Description: Indicates when a resource is deployed to the default namespace.   CIS Benchmark 5.7.1: Create administrative boundaries between resources using namespaces. CIS Benchmark 5.7.4: The default namespace should not be used.
Remediation: Create namespaces for objects in your deployment.
Template: use-namespace
Parameters: map[]
Enabled by default: false

------------------------------

Name: wildcard-in-rules
Description: Indicate when a wildcard is used in Role or ClusterRole rules. 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.
Remediation: Where possible replace any use of wildcards in clusterroles and roles with specific objects or actions.
Template: wildcard-in-rules
Parameters: map[]
Enabled by default: false

------------------------------

Name: writable-host-mount
Description: Indicates when containers mount a host path as writable.
Remediation: Set containers to mount host paths as readOnly, if you need to access files on the host.
Template: writable-host-mount
Parameters: map[]
Enabled by default: false
$
```

</div></details>

`kube-linter` のエラーの出力時に `(check: no-read-only-root-fs, ...`や、`(check: unset-cpu-requirements,... `、`(check: unset-memory-requirements,... ` と「`check:`<文字列>」のフォーマットで書かれていたのは、上記の出力の `Name:`の部分であった事がわかります。