En esta página, se proporcionan prácticas recomendadas para planificar las políticas de control de acceso basado en roles (RBAC). Para aprender a implementar el RBAC en Google Kubernetes Engine (GKE), consulta Configura el control de acceso basado en roles.
RBAC es una función de seguridad principal en Kubernetes que te permite crear permisos detallados para administrar qué acciones pueden realizar los usuarios y las cargas de trabajo en los recursos de los clústeres. Como administrador de la plataforma, creas roles de RBAC y vinculas esos roles a los sujetos, que son usuarios autenticados, como cuentas de servicio o Grupos de Google.
Antes de comenzar
Asegúrate de conocer los siguientes conceptos:
Para obtener una lista de tareas de esta guía, consulta Lista de tareas resumida.
Cómo funciona RBAC
RBAC admite los siguientes tipos de roles y vinculaciones:
- ClusterRole: un conjunto de permisos que se puede aplicar a cualquier espacio de nombres o a todo el clúster.
- Role: Un conjunto de permisos que se limita a un solo espacio de nombres.
- ClusterRoleBinding: Asigna un objeto
ClusterRole
a un usuario o grupo para todos los espacios de nombres del clúster. - RoleBinding: Asigna un objeto
Role
oClusterRole
a un usuario o grupo en un espacio de nombres específico.
Los permisos se definen como rules
en un Role
o un ClusterRole
. Cada campo rules
en un rol consta de un grupo de API, los recursos de API dentro de ese grupo y los verbos (acciones) permitidos en esos recursos. De forma opcional, puedes definir el alcance de los verbos a las instancias con nombre de recursos de API mediante el campo resourceNames
. Para ver un ejemplo, consulta Restringe el acceso a instancias de recursos específicas.
Después de definir un rol, debes usar RoleBinding
o ClusterRoleBinding
para vincular el rol a un sujeto. Elige el tipo de vinculación según si deseas otorgar permisos en un solo espacio de nombres o en varios.
Diseño del rol de RBAC
Usa el principio de privilegio mínimo
Cuando asignes permisos en un rol de RBAC, usa el principio de privilegio mínimo y otorga los permisos mínimos necesarios para realizar una tarea. Con el uso del principio de privilegio mínimo, se reduce el potencial de elevación de privilegios si tu clúster se ve comprometido y reduce la probabilidad de que un acceso desmedido provoque un incidente de seguridad.
Cuando diseñes tus roles, considera con cuidado los riesgos de elevación de privilegios comunes, como los verbos escalate
o bind
, el acceso create
para PersistentVolumes o el acceso create
para solicitudes de firma de certificados. Para obtener una lista de riesgos, consulta RBAC de Kubernetes: Riesgos de elevación de privilegios.
Evita los roles y los grupos predeterminados
Kubernetes crea un conjunto de ClusterRoles y ClusterRoleBindings predeterminados que puedes usar para el descubrimiento de API y habilitar la funcionalidad de componentes administrados. Los permisos otorgados por estos roles predeterminados pueden ser extensos según el rol. Kubernetes también tiene un conjunto de usuarios y grupos de usuarios predeterminados, que se identifican con el prefijo system:
.
De forma predeterminada, Kubernetes y GKE vinculan automáticamente estos roles a los grupos predeterminados y a varios sujetos. Para obtener una lista completa de las vinculaciones y los roles predeterminados que crea Kubernetes, consulta Vinculaciones de roles y roles predeterminados.
En la siguiente tabla, se describen algunos roles, usuarios y grupos predeterminados. Te recomendamos que evites interactuar con estos roles, usuarios y grupos, a menos que las hayas evaluado con cuidado, ya que interactuar con estos recursos puede tener consecuencias no deseadas para la postura de seguridad de tu clúster.
Nombre | Tipo | Descripción |
---|---|---|
cluster-admin |
ClusterRole | Otorga permiso a un sujeto para que realice cualquier acción en cualquier recurso del clúster. |
system:anonymous |
Usuario | Kubernetes asigna este usuario a las solicitudes del servidor de la API que no proporcionan información de autenticación. Vincular un rol a este usuario le otorga a cualquier usuario no autenticado los permisos que otorga ese rol. |
system:unauthenticated |
Grupo | Kubernetes asigna este grupo a las solicitudes del servidor de la API que no proporcionan información de autenticación. Cuando se vincula un rol a este grupo, se otorga a cualquier usuario no autenticado los permisos que otorga ese rol. |
system:authenticated |
Grupo | GKE asigna este grupo a las solicitudes del servidor de la API realizadas por cualquier usuario que haya accedido con una Cuenta de Google, incluidas todas las cuentas de Gmail. En la práctica, esto no es muy diferente de Cuando se vincula un rol a este grupo, se otorga a cualquier usuario con una Cuenta de Google, incluidas todas las cuentas de Gmail, los permisos otorgados por ese rol. |
system:masters |
Grupo | Kubernetes asigna el ClusterRole Agregar tus propios sujetos a este grupo les da acceso a ellos para que realicen cualquier acción en cualquier recurso del clúster. |
Si es posible, evita crear vinculaciones que involucren a los usuarios, roles y grupos predeterminados. Esto puede tener consecuencias no deseadas para la postura de seguridad de tu clúster. Por ejemplo:
- Vincular el ClusterRole
cluster-admin
predeterminado al gruposystem:unauthenticated
otorga a los usuarios no autenticados acceso a todos los recursos del clúster (incluidos los Secrets). Estas vinculaciones con muchos privilegios se orientan activamente a ataques como campañas de software malicioso masivas. - Vincular un rol personalizado al grupo
system:unauthenticated
brinda a los usuarios no autenticados los permisos que otorga ese rol.
Cuando sea posible, usa los siguientes lineamientos:
- No agregues tus propios sujetos al grupo
system:masters
. - No vincules el grupo
system:unauthenticated
a ningún rol de RBAC. - No vincules el grupo
system:authenticated
a ningún rol de RBAC. - No vincules el grupo
system:anonymous
a ningún rol de RBAC. - No vincules el ClusterRole
cluster-admin
a tus propios sujetos ni a ninguno de los usuarios y grupos predeterminados. Si tu aplicación requiere muchos permisos, determina los permisos exactos necesarios y crea un rol específico para ese propósito. - Evalúa los permisos otorgados por otros roles predeterminados antes de vincular sujetos.
- Evalúa los roles vinculadas a los grupos predeterminados antes de modificar los miembros de esos grupos.
Evita el uso de grupos predeterminados
Puedes usar gcloud CLI para inhabilitar las vinculaciones de RBAC no predeterminadas en un clúster que haga referencia a los grupos system:unauthenticated
y system:authenticated
o al usuario system:anonymous
. Usa una o ambas de las siguientes marcas cuando crees un clúster de GKE nuevo o actualices uno existente.
El uso de estas marcas no inhabilita las vinculaciones predeterminadas de Kubernetes que hacen referencia a estos grupos. Estas marcas requieren la versión 1.30.1-gke.1283000 de GKE o una posterior.
--no-enable-insecure-binding-system-authenticated
: Inhabilita las vinculaciones que no son predeterminadas que hacen referencia asystem:authenticated
.--no-enable-insecure-binding-system-unauthenticated
: Inhabilita las vinculaciones que no son predeterminadas que hacen referencia asystem:unauthenticated
ysystem:anonymous
.
Detecta y quita el uso de roles y grupos predeterminados
Debes evaluar tus clústeres para identificar si vinculaste al usuario system:anonymous
o a los grupos system:unauthenticated
o system:authenticated
mediante ClusterRoleBindings y RoleBindings.
ClusterRoleBindings
Muestra una lista de los nombres de cualquier ClusterRoleBindings con el asunto
system:anonymous
,system:unauthenticated
osystem:authenticated
:kubectl get clusterrolebindings -o json \ | jq -r '["Name"], ["-----"], (.items[] | select((.subjects | length) > 0) | select(any(.subjects[]; .name == "system:anonymous" or .name == "system:unauthenticated" or .name == "system:authenticated")) | [.metadata.namespace, .metadata.name]) | @tsv'
El resultado debe incluir solo los siguientes ClusterRoleBindings:
Name ---- "system:basic-user" "system:discovery" "system:public-info-viewer"
Si el resultado contiene vinculaciones no predeterminadas adicionales, realiza lo siguiente para cada vinculación adicional. Si tu resultado no contiene vinculaciones no predeterminadas, omite los siguientes pasos.
Enumera los permisos de la función asociada con la vinculación:
kubectl get clusterrolebinding CLUSTER_ROLE_BINDING_NAME -o json \ | jq ' .roleRef.name +" " + .roleRef.kind' \ | sed -e 's/"//g' \ | xargs -l bash -c 'kubectl get $1 $0 -o yaml'
Reemplaza
CLUSTER_ROLE_BINDING_NAME
por el nombre del objeto ClusterRoleBinding no predeterminado.El resultado es similar al siguiente:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: ... rules: - apiGroups: - "" resources: - secrets verbs: - get - watch - list
Si determinas que los permisos en el resultado son seguros para otorgar a los usuarios o grupos predeterminados, no es necesario que realices ninguna otra acción. Si determinas que los permisos otorgados por la vinculación no son seguros, continúa con el siguiente paso.
Borra una vinculación no segura de tu clúster:
kubectl delete clusterrolebinding CLUSTER_ROLE_BINDING_NAME
Reemplaza
CLUSTER_ROLE_BINDING_NAME
por el nombre de la ClusterRoleBinding que deseas borrar.
RoleBindings
Enumera el espacio de nombres y el nombre de cualquier RoleBinding con el asunto
system:anonymous
,system:unauthenticated
osystem:authenticated
:kubectl get rolebindings -A -o json \ | jq -r '["Namespace", "Name"], ["---------", "-----"], (.items[] | select((.subjects | length) > 0) | select(any(.subjects[]; .name == "system:anonymous" or .name == "system:unauthenticated" or .name == "system:authenticated")) | [.metadata.namespace, .metadata.name]) | @tsv'
Si tu clúster está configurado de forma correcta, el resultado debe estar en blanco. Si el resultado contiene vinculaciones no predeterminadas, realiza los siguientes pasos para cada vinculación adicional. Si el resultado está en blanco, omite los siguientes pasos.
Si solo conoces el nombre del RoleBinding, puedes usar el siguiente comando para encontrar RoleBindings coincidentes en todos los espacios de nombres:
kubectl get rolebindings -A -o json \ | jq -r '["Namespace", "Name"], ["---------", "-----"], (.items[] | select((.subjects | length) > 0) | select(.metadata.name == "ROLE_BINDING_NAME") | [.metadata.namespace, .metadata.name]) | @tsv'
Reemplaza
ROLE_BINDING_NAME
por el nombre de la RoleBinding no predeterminada.Enumera los permisos del rol asociado con la vinculación:
kubectl get rolebinding ROLE_BINDING_NAME --namespace ROLE_BINDING_NAMESPACE -o json \ | jq ' .roleRef.name +" " + .roleRef.kind' \ | sed -e 's/"//g' \ | xargs -l bash -c 'kubectl get $1 $0 -o yaml --namespace ROLE_BINDING_NAMESPACE'
Reemplaza lo siguiente:
ROLE_BINDING_NAME
: El nombre del RoleBinding no predeterminado.ROLE_BINDING_NAMESPACE
: El espacio de nombres del RoleBinding no predeterminado.
El resultado es similar al siguiente:
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: ... rules: - apiGroups: - "" resources: - secrets verbs: - get - watch - list
Si determinas que los permisos en el resultado son seguros para otorgar a los usuarios o grupos predeterminados, no es necesario que realices ninguna otra acción. Si determinas que los permisos otorgados por la vinculación no son seguros, continúa con el siguiente paso.
Borra una vinculación no segura de tu clúster:
kubectl delete rolebinding ROLE_BINDING_NAME --namespace ROLE_BINDING_NAMESPACE
Reemplaza lo siguiente:
ROLE_BINDING_NAME
: El nombre del RoleBinding que se borrará.ROLE_BINDING_NAMESPACE
: Es el espacio de nombres del RoleBinding que se borrará.
Permisos de alcance al nivel del espacio de nombres
Usa las vinculaciones y los roles de la siguiente manera, según las necesidades de la carga de trabajo o el usuario:
- Para otorgar acceso a los recursos en un espacio de nombres, usa un
Role
con unaRoleBinding
. - Para otorgar acceso a los recursos en más de un espacio de nombres, usa un
ClusterRole
con unaRoleBinding
para cada espacio de nombres. - Para otorgar acceso a los recursos en todos los espacios de nombres, usa un
ClusterRole
con unaClusterRoleBinding
.
Otorga permisos en la menor cantidad de espacios de nombres posible.
No uses comodines
El carácter *
es un comodín que se aplica a todo. Evita usar comodines en tus reglas. Especifica de forma explícita grupos de API, recursos y verbos en las reglas de RBAC. Por ejemplo, si especificas *
en el campo verbs
, se otorgarían los permisos get
, list
, watch
, patch
, update
, deletecollection
y delete
en los recursos. En la siguiente tabla, se muestran ejemplos para evitar comodines en tus reglas:
Recomendado | No recomendado |
---|---|
- rules: apiGroups: ["apps","extensions"] resources: ["deployments"] verbs: ["get","list","watch"] Otorga los verbos |
- rules: apiGroups: ["*"] resources: ["deployments"] verbs: ["get","list","watch"] Otorga los verbos a |
- rules: apiGroups: ["apps", "extensions"] resources: ["deployments"] verbs: ["get", "list", "watch"] Otorga solo los verbos |
- rules: apiGroups: ["apps", "extensions"] resources: ["deployments"] verbs: ["*"] Otorga todos los verbos, incluidos |
Usa reglas independientes para otorgar acceso de privilegios mínimos a recursos específicos
Cuando planifiques tus reglas, prueba los siguientes pasos de alto nivel para lograr un diseño de reglas con menos privilegios más eficiente en cada rol:
- Crea reglas de RBAC separadas para cada verbo en cada recurso al que un sujeto necesite acceder.
- Después de redactar las reglas, analiza las reglas para verificar si varias reglas tienen la misma lista
verbs
. Combina esas reglas en una sola. - Mantén todas las reglas restantes separadas entre sí.
Este enfoque da como resultado un diseño de reglas más organizado, en el que las reglas que otorgan los mismos verbos a varios recursos se combinan y las reglas que otorgan verbos diferentes a los recursos se separan.
Por ejemplo, si tu carga de trabajo necesita obtener permisos para el recurso deployments
, pero necesita list
y watch
en los recursos daemonsets
, debes usar reglas independientes cuando crees un rol. Cuando vincules el rol de RBAC a tu carga de trabajo, no podrá usar watch
en deployments
.
Otro ejemplo, si tu carga de trabajo necesita get
y watch
en el recurso pods
y en el recurso daemonsets
, puedes combinarlos en una sola regla, ya que la carga de trabajo necesita los mismos verbos en ambos recursos.
En la siguiente tabla, ambos diseños de reglas funcionan, pero las reglas de división restringen de manera más detallada el acceso a los recursos según tus necesidades:
Recomendado | No recomendado |
---|---|
- rules: apiGroups: ["apps"] resources: ["deployments"] verbs: ["get"] - rules: apiGroups: ["apps"] resources: ["daemonsets"] verbs: ["list", "watch"] Otorga acceso |
- rules: apiGroups: ["apps"] resources: ["deployments", "daemonsets"] verbs: ["get","list","watch"] Otorga los verbos a Deployments y DaemonSets. Un sujeto que podría no necesitar acceso |
- rules: apiGroups: ["apps"] resources: ["daemonsets", "deployments"] verbs: ["list", "watch"] Combina dos reglas porque el sujeto necesita los mismos verbos para los recursos |
- rules: apiGroups: ["apps"] resources: ["daemonsets"] verbs: ["list", "watch"] - rules: apiGroups: ["apps"] resources: ["deployments"] verbs: ["list", "watch"] Estas reglas de división tendrían el mismo resultado que la regla combinada, pero crearían un desorden innecesario en el manifiesto de tu rol |
Restringe el acceso a instancias de recursos específicas
El RBAC te permite usar el campo resourceNames
en tus reglas para restringir el acceso a una instancia con nombre específica de un recurso. Por ejemplo, si escribes un rol de RBAC que necesita update
el ConfigMap seccomp-high
y nada más, puedes usar resourceNames
para especificar solo ese ConfigMap. Usa resourceNames
siempre que sea posible.
Recomendado | No recomendado |
---|---|
- rules: apiGroups: [""] resources: ["configmaps"] resourceNames: ["seccomp-high"] verbs: ["update"] Restringe el sujeto para actualizar solo el ConfigMap |
- rules: apiGroups: [""] resources: ["configmaps"] verbs: ["update"] El sujeto puede actualizar el ConfigMap |
- rules: apiGroups: [""] resources: ["configmaps"] verbs: ["list"] - rules: apiGroups: [""] resources: ["configmaps"] resourceNames: ["seccomp-high"] verbs: ["update"] Otorga a |
- rules: apiGroups: [""] resources: ["configmaps"] verbs: ["update", "list"] Otorga acceso |
No permitas que las cuentas de servicio modifiquen los recursos de RBAC
No vincules recursos Role
o ClusterRole
que tengan permisos bind
, escalate
, create
, update
o patch
en el grupo de API rbac.authorization.k8s.io
a cuentas de servicio en cualquier espacio de nombres. escalate
y bind
, en particular, pueden permitir que un atacante omita los mecanismos de prevención de derivación integrados en el RBAC.
Cuentas de servicio de Kubernetes
Crea una cuenta de servicio de Kubernetes para cada carga de trabajo.
Crea una cuenta de servicio de Kubernetes independiente para cada carga de trabajo. Vincula un Role
o un ClusterRole
con los privilegios mínimos a esa cuenta de servicio.
No uses la cuenta de servicio predeterminada
Kubernetes crea una cuenta de servicio llamada default
en cada espacio de nombres. La cuenta de servicio default
se asigna de forma automática a los Pods que no especifican una cuenta de servicio de forma explícita en el manifiesto. Evita vincular un Role
o un ClusterRole
a la cuenta de servicio default
. Kubernetes puede asignar la cuenta de servicio default
a un Pod que no necesita el acceso otorgado en esos roles.
No actives automáticamente los tokens de la cuenta de servicio
El campo automountServiceAccountToken
en la especificación del pod le indica a Kubernetes que inserte un token de credencial para una cuenta de servicio de Kubernetes en el Pod. El Pod puede usar este token para realizar solicitudes autenticadas al servidor de la API de Kubernetes. El valor predeterminado de este campo es true
En todas las versiones de GKE, configura automountServiceAccountToken=false
en la especificación del Pod si tus Pods no necesitan comunicarse con el servidor de la API.
Da preferencia a los tokens efímeros por los tokens basados en Secrets
De forma predeterminada, el proceso de kubelet en el nodo recupera un token de cuenta de servicio de corta duración de forma automática para cada Pod. Kubelet activa este token en el Pod como un volumen proyectado, a menos que establezcas el campo automountServiceAccountToken
en false
en la especificación del Pod. Todas las llamadas a la API de Kubernetes desde el Pod usan este token para autenticarse en el servidor de la API.
Si recuperas los tokens de una cuenta de servicio de forma manual, evita usar Secrets de Kubernetes para almacenar el token. Los tokens de cuentas de servicio basados en Secrets son credenciales heredadas que no vencen y no se rotan de forma automática. Si necesitas credenciales para cuentas de servicio, usa la API de TokenRequest
para obtener tokens de corta duración que se roten de forma automática.
Revisa de forma continua los permisos de RBAC
Revisa tus roles de RBAC y accede con regularidad para identificar posibles rutas de elevación y reglas redundantes. Por ejemplo, imagina una situación en la que no borras una RoleBinding
que vincula un Role
con privilegios especiales a un usuario borrado. Si un atacante crea una cuenta de usuario en ese espacio de nombres con el mismo nombre que el usuario borrado, estaría vinculado a ese Role
y heredaría el mismo acceso. Las revisiones periódicas minimizan este riesgo.
Resumen de la lista de tareas
¿Qué sigue?
- Lee los consejos de endurecimiento de GKE.
- Lee las prácticas recomendadas de RBAC de Kubernetes.
- Explora nuestras otras prácticas recomendadas.
- Visualiza los manifiestos de muestra de los roles comunes del clúster