Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.
Aislamiento de inquilinos
Cuando pensamos en la multitenencia, a menudo queremos aislar un usuario o una aplicación de otros usuarios o aplicaciones que se ejecutan en una infraestructura compartida.
Kubernetes es un orquestador de un solo inquilino, es decir, todos los inquilinos de un clúster comparten una única instancia del plano de control. Sin embargo, hay varios objetos de Kubernetes que puedes usar para crear una apariencia de tenencia múltiple. Por ejemplo, los espacios de nombres y los controles de acceso basados en roles (RBAC) se pueden implementar para aislar de forma lógica a los inquilinos unos de otros. Del mismo modo, las cuotas y los rangos de límites se pueden usar para controlar la cantidad de recursos del clúster que puede consumir cada inquilino. Sin embargo, el clúster es la única construcción que proporciona un límite de seguridad sólido. Esto se debe a que un atacante que consigue acceder a un host del clúster puede recuperar todos los secretos y volúmenes que estén instalados en ese host. ConfigMaps También podrían hacerse pasar por el Kubelet, lo que les permitiría manipular los atributos del nodo y and/or moverlos lateralmente dentro del clúster.
En las siguientes secciones, se explica cómo implementar el aislamiento de inquilinos y, al mismo tiempo, mitigar los riesgos de usar un único orquestador de inquilinos, como Kubernetes.
Multitenencia suave
Con la multitenencia flexible, se utilizan estructuras nativas de Kubernetes, por ejemplo, espacios de nombres, funciones y enlaces de funciones y políticas de red, para crear una separación lógica entre los inquilinos. El RBAC, por ejemplo, puede impedir que los inquilinos accedan o manipulen los recursos de los demás. Las cuotas y los rangos límite controlan la cantidad de recursos del clúster que puede consumir cada inquilino, mientras que las políticas de red pueden ayudar a evitar que las aplicaciones implementadas en diferentes espacios de nombres se comuniquen entre sí.
Sin embargo, ninguno de estos controles impide que los pods de distintos inquilinos compartan un nodo. Si se requiere un aislamiento más estricto, puedes usar un selector de nodos, reglas de antiafinidad, restricciones y tolerancias para obligar a and/or los pods de distintos arrendatarios a programarse en nodos separados, lo que suele denominarse nodos de arrendatario único. Esto podría resultar bastante complicado y tener un coste prohibitivo en un entorno con muchos inquilinos.
importante
La multitenencia flexible implementada con los espacios de nombres no permite proporcionar a los inquilinos una lista filtrada de espacios de nombres porque los espacios de nombres son un tipo de ámbito global. Si un inquilino puede ver un espacio de nombres concreto, puede ver todos los espacios de nombres del clúster.
aviso
Con soft-multi-tenancy, los inquilinos conservan la capacidad de consultar CoredNS para todos los servicios que se ejecutan en el clúster de forma predeterminada. Un atacante podría aprovecharlo ejecutando dig SRV
..svc.cluster.local
desde cualquier pod del clúster. Si necesita restringir el acceso a los registros DNS de los servicios que se ejecutan en sus clústeres, considere la posibilidad de utilizar los complementos Firewall o Policy para CoreDNS. Para obtener información adicional, consulte https://github.com/coredns/kubernetes-metadata-multi-tenancypolicy#
Kiosk
-
Cuentas y usuarios de cuentas para separar a los inquilinos en un clúster de Kubernetes compartido
-
Aprovisionamiento de espacios de nombres de autoservicio para usuarios de cuentas
-
Límites de cuentas para garantizar la calidad del servicio y la imparcialidad al compartir un clúster
-
Plantillas de espacios de nombres para el aislamiento seguro de los inquilinos y la inicialización de los espacios de nombres con autoservicio
Loft
-
Acceso a varios clústeres para permitir el acceso a los espacios de diferentes clústeres
-
El modo de suspensión reduce las implementaciones en un espacio durante los períodos de inactividad
-
Inicio de sesión único con proveedores de autenticación OIDC como GitHub
Hay tres casos de uso principales que se pueden abordar mediante la multitenencia flexible.
Entorno empresarial
La primera es en un entorno empresarial, en el que los «inquilinos» son casi confiables, ya que son empleados, contratistas o están autorizados por la organización. Por lo general, cada inquilino se alinea con una división administrativa, como un departamento o un equipo.
En este tipo de entorno, un administrador de clústeres suele ser responsable de crear los espacios de nombres y administrar las políticas. También pueden implementar un modelo de administración delegada en el que determinadas personas supervisen un espacio de nombres, lo que les permite realizar operaciones CRUD para objetos no relacionados con las políticas, como despliegues, servicios, módulos, trabajos, etc.
El aislamiento que proporciona el tiempo de ejecución de un contenedor puede ser aceptable dentro de esta configuración o puede que sea necesario aumentarlo con controles adicionales para garantizar la seguridad de los módulos. También puede ser necesario restringir la comunicación entre los servicios en diferentes espacios de nombres si se requiere un aislamiento más estricto.
Kubernetes como servicio
Por el contrario, la multitenencia flexible se puede utilizar en entornos en los que se quiera ofrecer Kubernetes como servicio (KaaS). Con KaaS, la aplicación se aloja en un clúster compartido junto con un conjunto de controladores CRDs que proporcionan un conjunto de servicios de PaaS. Los inquilinos interactúan directamente con el servidor API de Kubernetes y se les permite realizar operaciones CRUD en objetos ajenos a las políticas. También hay un elemento de autoservicio que permite a los inquilinos crear y administrar sus propios espacios de nombres. En este tipo de entorno, se supone que los inquilinos ejecutan código que no es de confianza.
Para aislar a los inquilinos en este tipo de entorno, es probable que tengas que implementar políticas de red estrictas, así como un entorno aislado. El sandboxing consiste en ejecutar los contenedores de un pod dentro de una micromáquina virtual, como Firecracker, o en un núcleo de espacio de usuario. Hoy en día, puede crear cápsulas con caja de arena con EKS Fargate.
Software como servicio (SaaS)
El caso de uso final de la multitenencia flexible es en un entorno ( Software-as-a-ServiceSaaS). En este entorno, cada inquilino está asociado a una instancia concreta de una aplicación que se ejecuta dentro del clúster. Cada instancia suele tener sus propios datos y utiliza controles de acceso independientes que suelen ser independientes del RBAC de Kubernetes.
A diferencia de otros casos de uso, el inquilino de un entorno de SaaS no interactúa directamente con la API de Kubernetes. En cambio, la aplicación SaaS es responsable de interactuar con la API de Kubernetes para crear los objetos necesarios para dar soporte a cada inquilino.
Construcciones de Kubernetes
En cada uno de estos casos, se utilizan las siguientes estructuras para aislar a los inquilinos unos de otros:
Espacios de nombres
Los espacios de nombres son fundamentales para implementar la multitenencia flexible. Permiten dividir el clúster en particiones lógicas. Las cuotas, las políticas de red, las cuentas de servicio y otros objetos necesarios para implementar la multitenencia dependen de un espacio de nombres.
Políticas de red
De forma predeterminada, todos los pods de un clúster de Kubernetes pueden comunicarse entre sí. Este comportamiento se puede modificar mediante políticas de red.
Las políticas de red restringen la comunicación entre los pods mediante etiquetas o rangos de direcciones IP. En un entorno multiusuario en el que se requiera un aislamiento estricto de la red entre los usuarios, recomendamos empezar con una regla predeterminada que deniegue la comunicación entre los pods y otra que permita a todos los pods consultar el servidor DNS para obtener la resolución de nombres. Una vez establecido esto, puedes empezar a añadir reglas más permisivas que permitan la comunicación dentro de un espacio de nombres. Esto se puede refinar aún más según sea necesario.
nota
Amazon VPC CNI ahora es compatible con las políticas de red de Kubernetes para crear políticas
importante
Las políticas de red son necesarias pero no suficientes. La aplicación de las políticas de red requiere un motor de políticas como Calico o Cilium.
Control de acceso basado en roles (RBAC)
Los roles y los enlaces de roles son los objetos de Kubernetes que se utilizan para aplicar el control de acceso basado en roles (RBAC) en Kubernetes. Los roles contienen listas de acciones que se pueden realizar contra los objetos del clúster. Los enlaces de roles especifican las personas o grupos a los que se aplican los roles. En los entornos empresarial y de KaaS, el RBAC se puede utilizar para permitir la administración de objetos por parte de grupos o individuos seleccionados.
Cuotas
Las cuotas se utilizan para definir los límites de las cargas de trabajo alojadas en el clúster. Con las cuotas, puedes especificar la cantidad máxima de CPU y memoria que puede consumir un pod, o puedes limitar la cantidad de recursos que se pueden asignar en un clúster o espacio de nombres. Los rangos de límites te permiten declarar los valores mínimos, máximos y predeterminados para cada límite.
La sobreasignación de recursos en un clúster compartido suele ser beneficiosa porque permite maximizar los recursos. Sin embargo, el acceso ilimitado a un clúster puede provocar una escasez de recursos, lo que puede provocar una degradación del rendimiento y una pérdida de disponibilidad de las aplicaciones. Si las solicitudes de un pod son demasiado bajas y la utilización real de los recursos supera la capacidad del nodo, el nodo empezará a sufrir una presión de CPU o memoria. Cuando esto sucede, los pods pueden reiniciarse y and/or expulsarse del nodo.
Para evitar que esto suceda, deberías planificar la imposición de cuotas a los espacios de nombres en un entorno con varios inquilinos para obligar a los inquilinos a especificar las solicitudes y los límites al programar sus pods en el clúster. También mitigará una posible denegación de servicio al limitar la cantidad de recursos que puede consumir un pod.
También puedes usar las cuotas para distribuir los recursos del clúster y adaptarlos a los gastos del inquilino. Esto es particularmente útil en el escenario de KaaS.
Prioridad y preferencia de los pods
La prioridad y la prioridad de los pods pueden resultar útiles si quieres dar más importancia a un pod que a otros pods. Por ejemplo, con la prioridad de los pods, puede configurar los pods del cliente A para que se ejecuten con una prioridad mayor que la del cliente B. Cuando no haya suficiente capacidad disponible, el programador desalojará los pods de menor prioridad del cliente B para dar cabida a los pods de mayor prioridad del cliente A. Esto puede resultar especialmente útil en un entorno SaaS en el que los clientes dispuestos a pagar una prima reciben una prioridad más alta.
importante
La prioridad de los pods puede tener un efecto no deseado en otros pods con menor prioridad. Por ejemplo, aunque los pods afectados se cierren correctamente, pero no PodDisruptionBudget está garantizado, lo que podría interrumpir una aplicación de menor prioridad que dependa de un quórum de pods (consulta Limitaciones
Controles atenuantes
Su principal preocupación como administrador de un entorno multiusuario es evitar que un atacante acceda al host subyacente. Se deben tener en cuenta los siguientes controles para mitigar este riesgo:
Entornos de ejecución aislados para contenedores
El sandboxing es una técnica mediante la cual cada contenedor se ejecuta en su propia máquina virtual aislada. Entre las tecnologías que utilizan el sandboxing en cápsulas se incluyen Firecracker
Open Policy Agent (OPA) y Gatekeeper
Gatekeeper
También hay un complemento OPA experimental para CoreDNS
Kyverno
Kyverno
Puedes usar Kyverno para aislar los espacios de nombres, reforzar la seguridad de los módulos y otras prácticas recomendadas, y generar configuraciones predeterminadas, como políticas de red. En el GitHub repositorio
Aislar las cargas de trabajo de los inquilinos en nodos específicos
Se puede restringir las cargas de trabajo arrendatarias para que se ejecuten en nodos específicos para aumentar el aislamiento en el modelo flexible de tenencia múltiple. Con este enfoque, las cargas de trabajo específicas de los inquilinos solo se ejecutan en los nodos aprovisionados para los inquilinos respectivos. Para lograr este aislamiento, se utilizan las propiedades nativas de Kubernetes (afinidad entre los nodos y limitaciones y tolerancias) para programar los pods en nodos específicos e impedir que los pods, procedentes de otros inquilinos, se programen en los nodos específicos de cada inquilino.
Parte 1: Afinidad de nodos
La afinidad de nodosrequiredDuringSchedulingIgnoredDuringExecution
nodos se aplica al pod respectivo. El resultado es que el pod se dirigirá a los nodos que estén etiquetados con la siguiente clave/valor:. node-restriction.kubernetes.io/tenant: tenants-x
... spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: node-restriction.kubernetes.io/tenant operator: In values: - tenants-x ...
Con esta afinidad de nodos, la etiqueta es obligatoria durante la programación, pero no durante la ejecución; si las etiquetas de los nodos subyacentes cambian, los pods no se desalojarán únicamente por ese cambio de etiqueta. Sin embargo, la programación futura podría verse afectada.
aviso
El prefijo de etiqueta de node-restriction.kubernetes.io/
tiene un significado especial en Kubernetes. NodeRestrictionkubelet
impide las adding/removing/updating etiquetas con este prefijo. Los atacantes no pueden usar el kubelet’s credentials to update the node object or modify the system setup to pass these labels into `kubelet
as y kubelet
no está permitido modificar estas etiquetas. Si se utiliza este prefijo para toda la programación de un pod a un nodo, se evitan situaciones en las que un atacante quiera atraer un conjunto diferente de cargas de trabajo a un nodo modificando las etiquetas de los nodos.
En lugar de la afinidad de nodos, podríamos haber utilizado el selector de nodos
Parte 2: Manchas y tolerancias
Atraer cápsulas a los nodos es solo la primera parte de este enfoque de tres partes. Para que este enfoque funcione, debemos evitar que los pods se programen en nodos para los que los pods no estén autorizados. Para repeler los pods no deseados o no autorizados, Kubernetes utiliza nodos contaminados.tenant: tenants-x
... taints: - key: tenant value: tenants-x effect: NoSchedule ...
Dado el nodo anteriortaint
, solo los grupos que toleren la contaminación podrán programarse en el nodo. Para poder programar la entrada de cápsulas autorizadas en el nodo, las especificaciones de las cápsulas correspondientes deben incluir una referencia toleration
a la contaminación, tal y como se muestra a continuación.
... tolerations: - effect: NoSchedule key: tenant operator: Equal value: tenants-x ...
No se toleration
impedirá que los pods con las características anteriores se programen en el nodo, al menos no debido a esa imperfección específica. Kubernetes también utiliza las manchas para detener temporalmente la programación de los pods en determinadas condiciones, como la presión de los recursos del nodo. Gracias a la afinidad entre nodos y a las contaminaciones y tolerancias, podemos atraer eficazmente los grupos deseados a nodos específicos y repeler los grupos no deseados.
importante
Se requieren algunos pods de Kubernetes para ejecutarse en todos los nodos. Algunos ejemplos de estos pods son los iniciados por la interfaz de red de contenedores (CNI)
Parte 3: Gestión basada en políticas para la selección de nodos
Hay varias herramientas que se pueden utilizar para ayudar a gestionar la afinidad de los nodos y las tolerancias de las especificaciones de los módulos, incluida la aplicación de las normas en los procesos de CICD. Sin embargo, la aplicación del aislamiento también debe hacerse a nivel de clúster de Kubernetes. Para ello, se pueden utilizar herramientas de gestión de políticas para modificar las solicitudes entrantes del servidor API de Kubernetes, en función de la carga útil de las solicitudes, a fin de aplicar las reglas y tolerancias de afinidad de nodos respectivas mencionadas anteriormente.
Por ejemplo, los pods destinados al espacio de nombres tenants-x se pueden marcar con la afinidad y tolerancia de nodos correctas para permitir la programación en los nodos tenants-x. Al utilizar herramientas de administración de políticas configuradas mediante el webhook de admisión mutante de Kubernetes, las políticas se pueden utilizar para modificar las especificaciones de los pods entrantes.
apiVersion: mutations.gatekeeper.sh/v1alpha1 kind: Assign metadata: name: mutator-add-nodeaffinity-pod annotations: aws-eks-best-practices/description: >- Adds Node affinity - https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity spec: applyTo: - groups: [""] kinds: ["Pod"] versions: ["v1"] match: namespaces: ["tenants-x"] location: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms" parameters: assign: value: - matchExpressions: - key: "tenant" operator: In values: - "tenants-x"
La política anterior se aplica a una solicitud de servidor de API de Kubernetes para aplicar un pod al espacio de nombres tenants-x. La política añade la regla de afinidad de requiredDuringSchedulingIgnoredDuringExecution
nodos para que los pods se sientan atraídos por los nodos con la etiqueta. tenant: tenants-x
Una segunda política, que se muestra a continuación, añade la tolerancia a la misma especificación de pod, utilizando los mismos criterios de coincidencia entre el espacio de nombres y los grupos, tipos y versiones de destino.
apiVersion: mutations.gatekeeper.sh/v1alpha1 kind: Assign metadata: name: mutator-add-toleration-pod annotations: aws-eks-best-practices/description: >- Adds toleration - https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ spec: applyTo: - groups: [""] kinds: ["Pod"] versions: ["v1"] match: namespaces: ["tenants-x"] location: "spec.tolerations" parameters: assign: value: - key: "tenant" operator: "Equal" value: "tenants-x" effect: "NoSchedule"
Las políticas anteriores son específicas de los grupos; esto se debe a las rutas hacia los elementos mutados en los elementos de las políticas. location
Se podrían escribir políticas adicionales para gestionar los recursos que crean pods, como los recursos de Deployment y Job. Las políticas enumeradas y otros ejemplos se pueden ver en el GitHubproyecto
El resultado de estas dos mutaciones es que las vainas son atraídas hacia el nódulo deseado y, al mismo tiempo, no son repelidas por el nudo específico. Para comprobarlo, podemos ver los fragmentos del resultado de dos kubectl
llamadas para obtener los nodos etiquetados con tenant=tenants-x
ellos y colocar los pods en el espacio de nombres. tenants-x
kubectl get nodes -l tenant=tenants-x NAME ip-10-0-11-255... ip-10-0-28-81... ip-10-0-43-107... kubectl -n tenants-x get pods -owide NAME READY STATUS RESTARTS AGE IP NODE tenant-test-deploy-58b895ff87-2q7xw 1/1 Running 0 13s 10.0.42.143 ip-10-0-43-107... tenant-test-deploy-58b895ff87-9b6hg 1/1 Running 0 13s 10.0.18.145 ip-10-0-28-81... tenant-test-deploy-58b895ff87-nxvw5 1/1 Running 0 13s 10.0.30.117 ip-10-0-28-81... tenant-test-deploy-58b895ff87-vw796 1/1 Running 0 13s 10.0.3.113 ip-10-0-11-255... tenant-test-pod 1/1 Running 0 13s 10.0.35.83 ip-10-0-43-107...
Como podemos ver en los resultados anteriores, todos los pods están programados en los nodos etiquetados con. tenant=tenants-x
En pocas palabras, los pods solo se ejecutarán en los nodos deseados y los otros pods (sin la afinidad y las tolerancias requeridas) no. Las cargas de trabajo de los inquilinos están aisladas de manera efectiva.
A continuación se muestra un ejemplo de especificación de un módulo mutado.
apiVersion: v1 kind: Pod metadata: name: tenant-test-pod namespace: tenants-x spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: tenant operator: In values: - tenants-x ... tolerations: - effect: NoSchedule key: tenant operator: Equal value: tenants-x ...
importante
Las herramientas de administración de políticas que se integran en el flujo de solicitudes del servidor de la API de Kubernetes, que utilizan webhooks de admisión que mutan y validan, están diseñadas para responder a la solicitud del servidor de la API en un plazo específico. Suele ser de 3 segundos o menos. Si la llamada al webhook no devuelve una respuesta dentro del tiempo configurado, la and/or validación de la mutación de la solicitud entrante del servidor de API puede producirse o no. Este comportamiento se basa en si las configuraciones del webhook de admisión están configuradas en Fail Open o Fail Close
En los ejemplos anteriores, utilizamos políticas escritas para OPA/Gatekeeper. Sin embargo, hay otras herramientas de administración de políticas que también se encargan de nuestro caso de uso de selección de nodos. Por ejemplo, esta política de Kyverno
nota
Si funciona correctamente, la modificación de las políticas efectuará los cambios deseados en las cargas útiles de las solicitudes entrantes del servidor API. Sin embargo, también se deben incluir políticas de validación para verificar que se produzcan los cambios deseados antes de permitir que los cambios persistan. Esto es especialmente importante cuando se utilizan estas políticas para el tenant-to-node aislamiento. También es una buena idea incluir políticas de auditoría para comprobar de forma rutinaria el clúster en busca de configuraciones no deseadas.
Referencias
-
k-rail
Diseñado para ayudarle a proteger un entorno multiusuario mediante la aplicación de determinadas políticas. -
Prácticas de seguridad para aplicaciones MultiTenant SaaS que utilizan Amazon EKS
Tenencia múltiple dura
La multitenencia estricta se puede implementar mediante el aprovisionamiento de clústeres separados para cada inquilino. Si bien esto proporciona un aislamiento muy fuerte entre los inquilinos, tiene varios inconvenientes.
En primer lugar, cuando tiene muchos inquilinos, este enfoque puede resultar caro rápidamente. No solo tendrá que pagar los costos del plano de control de cada clúster, sino que tampoco podrá compartir los recursos de cómputo entre los clústeres. Con el tiempo, esto provocará una fragmentación, en la que un subconjunto de los clústeres se subutilizará mientras que otros se sobreutilizarán.
En segundo lugar, es probable que necesite comprar o construir herramientas especiales para administrar todos estos clústeres. Con el tiempo, administrar cientos o miles de clústeres puede resultar simplemente demasiado engorroso.
Por último, la creación de un clúster por inquilino será lenta en comparación con la creación de un espacio de nombres. Sin embargo, puede ser necesario un enfoque de tenencia estricta en industrias altamente reguladas o en entornos de SaaS donde se requiere un fuerte aislamiento.
Orientaciones futuras
La comunidad de Kubernetes ha reconocido las deficiencias actuales de la multitenencia flexible y los desafíos que plantea la multitenencia dura. El Multi-Tenancy Special Interest Group (SIG)
La propuesta del HNC (KEP) describe una forma de crear relaciones padre-hijo entre los espacios de nombres mediante la herencia de objetos [normativos], además de la posibilidad de que los administradores arrendatarios creen subespacios de nombres.
La propuesta de clúster virtual describe un mecanismo para crear instancias independientes de los servicios del plano de control, que incluyen el servidor API, el administrador del controlador y el programador, para cada inquilino del clúster (también conocido como «Kubernetes en Kubernetes»).
La propuesta de puntos de referencia para varios arrendatarios