Este documento ha sido traducido utilizando tecnología de traducción automática. Si bien nos esforzamos por proporcionar traducciones precisas, no ofrecemos garantías sobre la integridad, precisión o confiabilidad del contenido traducido. En caso de discrepancia, la versión original en inglés prevalecerá y constituirá el texto autorizado.

Guía de endurecimiento CIS

Este documento proporciona orientación prescriptiva para endurecer una instalación de producción de K3s. Describe las configuraciones y controles necesarios para abordar los controles de referencia de Kubernetes del Centro para la Seguridad de Internet (CIS).

K3s tiene una serie de mitigaciones de seguridad aplicadas y activadas por defecto y pasará un número de los controles CIS de Kubernetes sin modificación. Hay algunas excepciones notables a esto que requieren intervención manual para cumplir completamente con el Benchmark del CIS:

  1. K3s no modificará el sistema operativo del host. Cualquier modificación a nivel de host deberá hacerse manualmente.

  2. Ciertos controles de políticas del CIS para NetworkPolicies y PodSecurityStandards (PodSecurityPolicies en v1.24 y versiones anteriores) restringirán la funcionalidad del clúster. Debes optar por que K3s configure estos añadiendo las opciones apropiadas (activación de plugins de admisión) a tus banderas de línea de comandos o archivo de configuración, así como aplicar manualmente las políticas adecuadas. Se presentan más detalles en las secciones a continuación.

La primera sección (1.1) del Benchmark del CIS se ocupa principalmente de los permisos y la propiedad de los manifiestos de pod. K3s no utiliza estos para los componentes centrales ya que todo está empaquetado en un único binario.

Requisitos a nivel de host

Hay dos áreas de requisitos a nivel de host: parámetros del kernel y configuración del proceso/directorio etcd. Estos se describen en esta sección.

Asegúrate de que protect-kernel-defaults esté configurado

Esta es una bandera de kubelet que hará que el kubelet salga si los parámetros del kernel requeridos no están configurados o están establecidos en valores diferentes de los predeterminados del kubelet.

protect-kernel-defaults se expone como una bandera de nivel superior para K3s.

Establecer parámetros del kernel

Crea un archivo llamado /etc/sysctl.d/90-kubelet.conf y añade el fragmento de código a continuación. Luego ejecuta sysctl -p /etc/sysctl.d/90-kubelet.conf.

vm.panic_on_oom=0
vm.overcommit_memory=1
kernel.panic=10
kernel.panic_on_oops=1

Configuración para Componentes de Kubernetes

La configuración a continuación debe ser colocada en el archivo de configuración, y contiene todas las remediaciones necesarias para proteger los componentes de Kubernetes.

  • v1.29 y versiones más recientes

  • v1.25 - v1.28

  • v1.24 y versiones anteriores

protect-kernel-defaults: true
secrets-encryption: true
kube-apiserver-arg:
  - "enable-admission-plugins=NodeRestriction,EventRateLimit"
  - 'admission-control-config-file=/var/lib/rancher/k3s/server/psa.yaml'
  - 'audit-log-path=/var/lib/rancher/k3s/server/logs/audit.log'
  - 'audit-policy-file=/var/lib/rancher/k3s/server/audit.yaml'
  - 'audit-log-maxage=30'
  - 'audit-log-maxbackup=10'
  - 'audit-log-maxsize=100'
  - 'service-account-extend-token-expiration=false'
kube-controller-manager-arg:
  - 'terminated-pod-gc-threshold=100'
kubelet-arg:
  - 'streaming-connection-idle-timeout=5m'
  - "tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"
protect-kernel-defaults: true
secrets-encryption: true
kube-apiserver-arg:
  - "enable-admission-plugins=NodeRestriction,EventRateLimit"
  - 'admission-control-config-file=/var/lib/rancher/k3s/server/psa.yaml'
  - 'audit-log-path=/var/lib/rancher/k3s/server/logs/audit.log'
  - 'audit-policy-file=/var/lib/rancher/k3s/server/audit.yaml'
  - 'audit-log-maxage=30'
  - 'audit-log-maxbackup=10'
  - 'audit-log-maxsize=100'
kube-controller-manager-arg:
  - 'terminated-pod-gc-threshold=10'
kubelet-arg:
  - 'streaming-connection-idle-timeout=5m'
  - "tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"
protect-kernel-defaults: true
secrets-encryption: true
kube-apiserver-arg:
  - 'enable-admission-plugins=NodeRestriction,PodSecurityPolicy,NamespaceLifecycle,ServiceAccount'
  - 'audit-log-path=/var/lib/rancher/k3s/server/logs/audit.log'
  - 'audit-policy-file=/var/lib/rancher/k3s/server/audit.yaml'
  - 'audit-log-maxage=30'
  - 'audit-log-maxbackup=10'
  - 'audit-log-maxsize=100'
kube-controller-manager-arg:
  - 'terminated-pod-gc-threshold=10'
kubelet-arg:
  - 'streaming-connection-idle-timeout=5m'
  - 'make-iptables-util-chains=true'
  - "tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"

Requisitos de Ejecución de Kubernetes

Los requisitos de ejecución para cumplir con el CIS Benchmark se centran en la seguridad de los pods (a través de PSP o PSA), políticas de red y registros de auditoría del servidor API. Estos se describen en esta sección.

Por defecto, K3s no incluye ninguna política de seguridad de pods ni políticas de red. Sin embargo, K3s incluye un controlador que hará cumplir las políticas de red, si se crean. K3s no habilita la auditoría por defecto, por lo que la configuración de registros de auditoría y la política de auditoría deben ser creadas manualmente. Por defecto, K3s se ejecuta con ambos controladores de admisión PodSecurity y NodeRestriction habilitados, entre otros.

Seguridad de Pods

  • v1.25 y versiones más recientes

  • v1.24 y versiones anteriores

K3s v1.25 y versiones más recientes soportan Admisiones de Seguridad de Pods (PSAs) para controlar la seguridad de los pods. Las PSAs se habilitan pasando la siguiente bandera al servidor K3s:

--kube-apiserver-arg="admission-control-config-file=/var/lib/rancher/k3s/server/psa.yaml"

La política debe escribirse en un archivo llamado psa.yaml en el directorio /var/lib/rancher/k3s/server.

Aquí hay un ejemplo de una PSA conforme:

apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: PodSecurity
  configuration:
    apiVersion: pod-security.admission.config.k8s.io/v1beta1
    kind: PodSecurityConfiguration
    defaults:
      enforce: "restricted"
      enforce-version: "latest"
      audit: "restricted"
      audit-version: "latest"
      warn: "restricted"
      warn-version: "latest"
    exemptions:
      usernames: []
      runtimeClasses: []
      namespaces: [kube-system, cis-operator-system]

K3s v1.24 y versiones anteriores soportan Políticas de Seguridad de Pods (PSPs) para controlar la seguridad de los pods. Las PSPs se habilitan pasando la siguiente bandera al servidor K3s:

--kube-apiserver-arg="enable-admission-plugins=NodeRestriction,PodSecurityPolicy"

Esto tendrá el efecto de mantener el NodeRestriction plugin así como habilitar el PodSecurityPolicy.

Cuando las PSPs están habilitadas, se puede aplicar una política para satisfacer los controles necesarios descritos en la sección 5.2 del CIS Benchmark.

Aquí hay un ejemplo de una PSP conforme:

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: restricted-psp
spec:
  privileged: false                # CIS - 5.2.1
  allowPrivilegeEscalation: false  # CIS - 5.2.5
  requiredDropCapabilities:        # CIS - 5.2.7/8/9
    - ALL
  volumes:
    - 'configMap'
    - 'emptyDir'
    - 'projected'
    - 'secret'
    - 'downwardAPI'
    - 'csi'
    - 'persistentVolumeClaim'
    - 'ephemeral'
  hostNetwork: false               # CIS - 5.2.4
  hostIPC: false                   # CIS - 5.2.3
  hostPID: false                   # CIS - 5.2.2
  runAsUser:
    rule: 'MustRunAsNonRoot'       # CIS - 5.2.6
  seLinux:
    rule: 'RunAsAny'
  supplementalGroups:
    rule: 'MustRunAs'
    ranges:
      - min: 1
        max: 65535
  fsGroup:
    rule: 'MustRunAs'
    ranges:
      - min: 1
        max: 65535
  readOnlyRootFilesystem: false

Para que la PSP anterior sea efectiva, necesitamos crear un ClusterRole y un ClusterRoleBinding. También necesitamos incluir una "política de sistema sin restricciones" que es necesaria para los pods a nivel de sistema que requieren privilegios adicionales, y una política adicional que permita los sysctls necesarios para que servicelb funcione correctamente.

Combinando la configuración anterior con la Política de Red descrita en la siguiente sección, se puede colocar un único archivo en el directorio /var/lib/rancher/k3s/server/manifests. Aquí hay un ejemplo de un archivo policy.yaml:

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: restricted-psp
spec:
  privileged: false
  allowPrivilegeEscalation: false
  requiredDropCapabilities:
    - ALL
  volumes:
    - 'configMap'
    - 'emptyDir'
    - 'projected'
    - 'secret'
    - 'downwardAPI'
    - 'csi'
    - 'persistentVolumeClaim'
    - 'ephemeral'
  hostNetwork: false
  hostIPC: false
  hostPID: false
  runAsUser:
    rule: 'MustRunAsNonRoot'
  seLinux:
    rule: 'RunAsAny'
  supplementalGroups:
    rule: 'MustRunAs'
    ranges:
      - min: 1
        max: 65535
  fsGroup:
    rule: 'MustRunAs'
    ranges:
      - min: 1
        max: 65535
  readOnlyRootFilesystem: false
---
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: system-unrestricted-psp
  annotations:
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
spec:
  allowPrivilegeEscalation: true
  allowedCapabilities:
  - '*'
  fsGroup:
    rule: RunAsAny
  hostIPC: true
  hostNetwork: true
  hostPID: true
  hostPorts:
  - max: 65535
    min: 0
  privileged: true
  runAsUser:
    rule: RunAsAny
  seLinux:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  volumes:
  - '*'
---
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: svclb-psp
  annotations:
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
spec:
  allowPrivilegeEscalation: false
  allowedCapabilities:
  - NET_ADMIN
  allowedUnsafeSysctls:
  - net.ipv4.ip_forward
  - net.ipv6.conf.all.forwarding
  fsGroup:
    rule: RunAsAny
  hostPorts:
  - max: 65535
    min: 0
  runAsUser:
    rule: RunAsAny
  seLinux:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: psp:restricted-psp
rules:
- apiGroups:
  - policy
  resources:
  - podsecuritypolicies
  verbs:
  - use
  resourceNames:
  - restricted-psp
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: psp:system-unrestricted-psp
rules:
- apiGroups:
  - policy
  resources:
  - podsecuritypolicies
  resourceNames:
  - system-unrestricted-psp
  verbs:
  - use
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: psp:svclb-psp
rules:
- apiGroups:
  - policy
  resources:
  - podsecuritypolicies
  resourceNames:
  - svclb-psp
  verbs:
  - use
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: default:restricted-psp
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: psp:restricted-psp
subjects:
- kind: Group
  name: system:authenticated
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: system-unrestricted-node-psp-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: psp:system-unrestricted-psp
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:nodes
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: system-unrestricted-svc-acct-psp-rolebinding
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: psp:system-unrestricted-psp
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:serviceaccounts
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: svclb-psp-rolebinding
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: psp:svclb-psp
subjects:
- kind: ServiceAccount
  name: svclb
---
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: intra-namespace
  namespace: kube-system
spec:
  podSelector: {}
  ingress:
    - from:
      - namespaceSelector:
          matchLabels:
            name: kube-system
---
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: intra-namespace
  namespace: default
spec:
  podSelector: {}
  ingress:
    - from:
      - namespaceSelector:
          matchLabels:
            name: default
---
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: intra-namespace
  namespace: kube-public
spec:
  podSelector: {}
  ingress:
    - from:
      - namespaceSelector:
          matchLabels:
            name: kube-public
Las adiciones críticas de Kubernetes como CNI, DNS e Ingress se ejecutan como pods en el espacio de nombres kube-system. Por lo tanto, este espacio de nombres tendrá una directiva que es menos restrictiva para que estos componentes puedan funcionar correctamente.

NetworkPolicies

CIS requiere que todos los espacios de nombres tengan una política de red aplicada que limite razonablemente el tráfico hacia los espacios de nombres y pods.

Las políticas de red deben colocarse en el directorio /var/lib/rancher/k3s/server/manifests, donde se desplegarán automáticamente al iniciar.

Aquí hay un ejemplo de una política de red conforme.

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: intra-namespace
  namespace: kube-system
spec:
  podSelector: {}
  ingress:
    - from:
      - namespaceSelector:
          matchLabels:
            kubernetes.io/metadata.name: kube-system

Con las restricciones aplicadas, DNS será bloqueado a menos que se permita intencionadamente. A continuación se muestra una política de red que permitirá que exista tráfico para DNS.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-network-dns-policy
  namespace: <NAMESPACE>
spec:
  ingress:
  - ports:
    - port: 53
      protocol: TCP
    - port: 53
      protocol: UDP
  podSelector:
    matchLabels:
      k8s-app: kube-dns
  policyTypes:
  - Ingress

El metrics-server y el controlador de ingreso Traefik serán bloqueados por defecto si no se crean políticas de red para permitir el acceso. Asegúrate de utilizar el yaml de muestra a continuación:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-metrics-server
  namespace: kube-system
spec:
  podSelector:
    matchLabels:
      k8s-app: metrics-server
  ingress:
  - {}
  policyTypes:
  - Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-svclbtraefik-ingress
  namespace: kube-system
spec:
  podSelector:
    matchLabels:
      svccontroller.k3s.cattle.io/svcname: traefik
  ingress:
  - {}
  policyTypes:
  - Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-traefik-v121-ingress
  namespace: kube-system
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: traefik
  ingress:
  - {}
  policyTypes:
  - Ingress
---

Los operadores deben gestionar las políticas de red como es normal para los espacios de nombres adicionales que se creen.

Configuración de auditoría del servidor API

Los requisitos CIS 1.2.22 a 1.2.25 están relacionados con la configuración de los registros de auditoría para el servidor API. K3s no crea por defecto el directorio de registros y la política de auditoría, ya que los requisitos de auditoría son específicos para las políticas y el entorno de cada usuario.

El directorio de registros, idealmente, debe ser creado antes de iniciar K3s. Se recomienda un permiso de acceso restrictivo para evitar la filtración de información sensible potencial.

sudo mkdir -p -m 700 /var/lib/rancher/k3s/server/logs

A continuación se proporciona una política de auditoría inicial para registrar los metadatos de las solicitudes. La política debe escribirse en un archivo llamado audit.yaml en el directorio /var/lib/rancher/k3s/server. Se puede encontrar información detallada sobre la configuración de políticas para el servidor API en la documentación de Kubernetes.

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata

Ambas configuraciones de directivas deben ser pasadas como argumentos al servidor API de la siguiente manera:

  • config

  • cmdline

kube-apiserver-arg:
  - 'admission-control-config-file=/var/lib/rancher/k3s/server/psa.yaml'
  - 'audit-log-path=/var/lib/rancher/k3s/server/logs/audit.log'
  - 'audit-policy-file=/var/lib/rancher/k3s/server/audit.yaml'
  - 'audit-log-maxage=30'
  - 'audit-log-maxbackup=10'
  - 'audit-log-maxsize=100'
--kube-apiserver-arg='audit-log-path=/var/lib/rancher/k3s/server/logs/audit.log'
--kube-apiserver-arg='audit-policy-file=/var/lib/rancher/k3s/server/audit.yaml'

K3s debe ser reiniciado para cargar la nueva configuración.

sudo systemctl daemon-reload
sudo systemctl restart k3s.service

Operaciones manuales

Los siguientes son controles que K3s actualmente no cumple con la configuración anterior aplicada. Estos controles requieren intervención manual para cumplir completamente con el CIS Benchmark.

Control 1.1.20

Asegúrese de que los permisos del archivo de certificado PKI de Kubernetes estén configurados en 600 o más restrictivos (Manual)

Solución

Los archivos de certificado PKI de K3s se almacenan en /var/lib/rancher/k3s/server/tls/ con permiso 644. Para remediar, ejecute el siguiente comando:

chmod -R 600 /var/lib/rancher/k3s/server/tls/*.crt

Control 1.2.9

Asegúrese de que el plugin de control de admisión EventRateLimit esté configurado

Solución

Siga la documentación de Kubernetes y establezca los límites deseados en un archivo de configuración. Para esta y otra configuración de psa, esta documentación utiliza /var/lib/rancher/k3s/server/psa.yaml. Luego, edita el archivo de configuración de K3s /etc/rancher/k3s/config.yaml y establece los parámetros a continuación.

kube-apiserver-arg:
  - "enable-admission-plugins=NodeRestriction,EventRateLimit"
  - "admission-control-config-file=/var/lib/rancher/k3s/server/psa.yaml"

Control 1.2.11

Asegúrate de que el plugin de control de admisión AlwaysPullImages esté configurado

Solución

Permisivo, según las directrices de CIS, "Esta configuración podría afectar a clústeres desconectados o aislados, que tienen imágenes pre-cargadas y no tienen acceso a un registro para obtener imágenes en uso." Esta configuración no es apropiada para clústeres que utilizan esta configuración." Edita el archivo de configuración de K3s /etc/rancher/k3s/config.yaml y establece el parámetro a continuación.

kube-apiserver-arg:
  - "enable-admission-plugins=...,AlwaysPullImages,..."

Control 1.2.21

Asegúrate de que el argumento --request-timeout esté configurado adecuadamente

Solución

Permisivo, según las directrices de CIS, "se recomienda establecer este límite de manera adecuada y cambiar el límite predeterminado de 60 segundos solo si es necesario". Edita el archivo de configuración de K3s /etc/rancher/k3s/config.yaml y establece el parámetro a continuación si es necesario. Por ejemplo,

kube-apiserver-arg:
  - "request-timeout=300s"

Control 4.2.13

Asegúrate de que se establezca un límite en los PIDs de los pods

Solución

Decide un nivel apropiado para este parámetro y configúralo. Si utilizas un archivo de configuración de K3s /etc/rancher/k3s/config.yaml, edita el archivo para establecer podPidsLimit en

kubelet-arg:
  - "pod-max-pids=<value>"

Control 5.X

Todos los controles 5.X están relacionados con la configuración de políticas de Kubernetes. Estos controles no son aplicados por K3s por defecto.

Consulta CIS 1.8 Sección 5 para más información sobre cómo crear y aplicar estas políticas.

Control 5.1.5

La remediación para lograr una puntuación aprobatoria solo es necesaria para cis-1.9.

Solución

Crea cuentas de servicio explícitas siempre que una carga de trabajo de Kubernetes requiera acceso específico al servidor API de Kubernetes. Como mínimo, aplica el siguiente parche:

kubectl patch serviceaccount --namespace default default --patch '{"automountServiceAccountToken": false}'
kubectl patch serviceaccount --namespace kube-node-lease default --patch '{"automountServiceAccountToken": false}'
kubectl patch serviceaccount --namespace kube-public default --patch '{"automountServiceAccountToken": false}'

Conclusión

Si has seguido esta guía, tu clúster K3s estará configurado para cumplir con el CIS Kubernetes Benchmark. Puedes revisar la Guía de Autoevaluación CIS 1.11 para entender las expectativas de cada uno de los controles del benchmark y cómo puedes hacer lo mismo en tu clúster.