Kubernetes Basics
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
El autor original de esta página es Jorge (lee su publicación original aquí)
Permite ejecutar contenedor/es en un motor de contenedores.
La programación permite que las misiones de los contenedores sean eficientes.
Mantiene los contenedores vivos.
Permite la comunicación entre contenedores.
Permite técnicas de despliegue.
Maneja volúmenes de información.
Nodo: sistema operativo con pod o pods.
Pod: envoltura alrededor de un contenedor o múltiples contenedores. Un pod debe contener solo una aplicación (por lo general, un pod ejecuta solo 1 contenedor). El pod es la forma en que Kubernetes abstrae la tecnología de contenedores en ejecución.
Servicio: Cada pod tiene 1 dirección IP interna del rango interno del nodo. Sin embargo, también puede ser expuesto a través de un servicio. El servicio también tiene una dirección IP y su objetivo es mantener la comunicación entre pods, por lo que si uno muere, el nuevo reemplazo (con una IP interna diferente) será accesible expuesto en la misma IP del servicio. Puede configurarse como interno o externo. El servicio también actúa como un balanceador de carga cuando 2 pods están conectados al mismo servicio.
Cuando se crea un servicio, puedes encontrar los puntos finales de cada servicio ejecutando kubectl get endpoints
Kubelet: Agente principal del nodo. El componente que establece la comunicación entre el nodo y kubectl, y solo puede ejecutar pods (a través del servidor API). El kubelet no gestiona contenedores que no fueron creados por Kubernetes.
Kube-proxy: es el servicio encargado de las comunicaciones (servicios) entre el apiserver y el nodo. La base es un IPtables para nodos. Los usuarios más experimentados podrían instalar otros kube-proxies de otros proveedores.
Contenedor Sidecar: Los contenedores sidecar son los contenedores que deben ejecutarse junto con el contenedor principal en el pod. Este patrón sidecar extiende y mejora la funcionalidad de los contenedores actuales sin cambiarlos. Hoy en día, sabemos que usamos tecnología de contenedores para envolver todas las dependencias para que la aplicación se ejecute en cualquier lugar. Un contenedor hace solo una cosa y la hace muy bien.
Proceso maestro:
Api Server: Es la forma en que los usuarios y los pods se comunican con el proceso maestro. Solo se deben permitir solicitudes autenticadas.
Scheduler: La programación se refiere a asegurarse de que los Pods estén emparejados con los Nodos para que Kubelet pueda ejecutarlos. Tiene suficiente inteligencia para decidir qué nodo tiene más recursos disponibles y asignar el nuevo pod a él. Ten en cuenta que el scheduler no inicia nuevos pods, solo se comunica con el proceso Kubelet que se ejecuta dentro del nodo, que lanzará el nuevo pod.
Kube Controller manager: Verifica recursos como conjuntos de réplicas o despliegues para comprobar si, por ejemplo, el número correcto de pods o nodos está en ejecución. En caso de que falte un pod, se comunicará con el scheduler para iniciar uno nuevo. Controla la replicación, tokens y servicios de cuentas para la API.
etcd: Almacenamiento de datos, persistente, consistente y distribuido. Es la base de datos de Kubernetes y el almacenamiento clave-valor donde mantiene el estado completo de los clústeres (cada cambio se registra aquí). Componentes como el Scheduler o el Controller manager dependen de estos datos para saber qué cambios han ocurrido (recursos disponibles de los nodos, número de pods en ejecución...)
Cloud controller manager: Es el controlador específico para el control de flujo y aplicaciones, es decir: si tienes clústeres en AWS o OpenStack.
Ten en cuenta que como puede haber varios nodos (ejecutando varios pods), también puede haber varios procesos maestros cuyo acceso al Api server está balanceado y su etcd sincronizado.
Volúmenes:
Cuando un pod crea datos que no deberían perderse cuando el pod desaparece, deben almacenarse en un volumen físico. Kubernetes permite adjuntar un volumen a un pod para persistir los datos. El volumen puede estar en la máquina local o en un almacenamiento remoto. Si estás ejecutando pods en diferentes nodos físicos, deberías usar un almacenamiento remoto para que todos los pods puedan acceder a él.
Otras configuraciones:
ConfigMap: Puedes configurar URLs para acceder a servicios. El pod obtendrá datos de aquí para saber cómo comunicarse con el resto de los servicios (pods). Ten en cuenta que este no es el lugar recomendado para guardar credenciales.
Secret: Este es el lugar para almacenar datos secretos como contraseñas, claves API... codificados en B64. El pod podrá acceder a estos datos para usar las credenciales requeridas.
Deployments: Aquí es donde se indican los componentes que serán ejecutados por Kubernetes. Un usuario generalmente no trabajará directamente con pods, los pods están abstraídos en ReplicaSets (número de pods idénticos replicados), que se ejecutan a través de despliegues. Ten en cuenta que los despliegues son para aplicaciones sin estado. La configuración mínima para un despliegue es el nombre y la imagen a ejecutar.
StatefulSet: Este componente está destinado específicamente a aplicaciones como bases de datos que necesitan acceder al mismo almacenamiento.
Ingress: Esta es la configuración que se utiliza para exponer la aplicación públicamente con una URL. Ten en cuenta que esto también se puede hacer utilizando servicios externos, pero esta es la forma correcta de exponer la aplicación.
Si implementas un Ingress, necesitarás crear Ingress Controllers. El Ingress Controller es un pod que será el punto final que recibirá las solicitudes y las verificará y las balanceará a los servicios. El controlador de ingreso enviará la solicitud según las reglas de ingreso configuradas. Ten en cuenta que las reglas de ingreso pueden apuntar a diferentes rutas o incluso subdominios a diferentes servicios internos de Kubernetes.
Una mejor práctica de seguridad sería usar un balanceador de carga en la nube o un servidor proxy como punto de entrada para no tener ninguna parte del clúster de Kubernetes expuesta.
Cuando se recibe una solicitud que no coincide con ninguna regla de ingreso, el controlador de ingreso la dirigirá al "Backend predeterminado". Puedes describe
el controlador de ingreso para obtener la dirección de este parámetro.
minikube addons enable ingress
CA es la raíz de confianza para todos los certificados dentro del clúster.
Permite que los componentes se validen entre sí.
Todos los certificados del clúster son firmados por la CA.
etcd tiene su propio certificado.
tipos:
certificado apiserver.
certificado kubelet.
certificado scheduler.
Minikube se puede usar para realizar algunas pruebas rápidas en Kubernetes sin necesidad de desplegar un entorno completo de Kubernetes. Ejecutará los procesos maestro y nodo en una máquina. Minikube utilizará virtualbox para ejecutar el nodo. Consulta aquí cómo instalarlo.
Kubectl
es la herramienta de línea de comandos para clústeres de kubernetes. Se comunica con el servidor Api del proceso maestro para realizar acciones en kubernetes o para solicitar datos.
El panel de control te permite ver más fácilmente lo que está ejecutando minikube, puedes encontrar la URL para acceder a él en:
Cada archivo de configuración tiene 3 partes: metadata, specification (lo que necesita ser lanzado), status (estado deseado). Dentro de la especificación del archivo de configuración de despliegue, puedes encontrar la plantilla definida con una nueva estructura de configuración que define la imagen a ejecutar:
Ejemplo de Deployment + Service declarados en el mismo archivo de configuración (de aquí)
Como un servicio generalmente está relacionado con un despliegue, es posible declarar ambos en el mismo archivo de configuración (el servicio declarado en esta configuración solo es accesible internamente):
Ejemplo de configuración de servicio externo
Este servicio será accesible externamente (ver los atributos nodePort
y type: LoadBlancer
):
Esto es útil para pruebas, pero para producción solo deberías tener servicios internos y un Ingress para exponer la aplicación.
Ejemplo de archivo de configuración de Ingress
Esto expondrá la aplicación en http://dashboard.com
.
Ejemplo de archivo de configuración de secretos
Nota cómo las contraseñas están codificadas en B64 (¡lo cual no es seguro!)
Ejemplo de ConfigMap
Un ConfigMap es la configuración que se le da a los pods para que sepan cómo localizar y acceder a otros servicios. En este caso, cada pod sabrá que el nombre mongodb-service
es la dirección de un pod con el que pueden comunicarse (este pod estará ejecutando un mongodb):
Luego, dentro de una deployment config, esta dirección se puede especificar de la siguiente manera para que se cargue dentro del env del pod:
Ejemplo de configuración de volumen
Puedes encontrar diferentes ejemplos de archivos yaml de configuración de almacenamiento en https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes. Nota que los volúmenes no están dentro de los namespaces
Kubernetes soporta múltiples clústeres virtuales respaldados por el mismo clúster físico. Estos clústeres virtuales se llaman namespaces. Están destinados para su uso en entornos con muchos usuarios distribuidos en múltiples equipos o proyectos. Para clústeres con unos pocos a decenas de usuarios, no deberías necesitar crear o pensar en namespaces en absoluto. Solo deberías comenzar a usar namespaces para tener un mejor control y organización de cada parte de la aplicación desplegada en kubernetes.
Los namespaces proporcionan un ámbito para los nombres. Los nombres de los recursos deben ser únicos dentro de un namespace, pero no entre namespaces. Los namespaces no pueden estar anidados dentro de otros y cada recurso de Kubernetes solo puede estar en un namespace.
Hay 4 namespaces por defecto si estás usando minikube:
kube-system: No está destinado para el uso de los usuarios y no deberías tocarlo. Es para procesos de master y kubectl.
kube-public: Datos accesibles públicamente. Contiene un configmap que contiene información del clúster.
kube-node-lease: Determina la disponibilidad de un nodo.
default: El namespace que el usuario utilizará para crear recursos.
Tenga en cuenta que la mayoría de los recursos de Kubernetes (por ejemplo, pods, servicios, controladores de replicación y otros) están en algunos namespaces. Sin embargo, otros recursos como los recursos de namespace y recursos de bajo nivel, como nodos y persistenVolumes no están en un namespace. Para ver qué recursos de Kubernetes están y no están en un namespace:
Puedes guardar el namespace para todos los comandos kubectl subsiguientes en ese contexto.
Helm es el gestor de paquetes para Kubernetes. Permite empaquetar archivos YAML y distribuirlos en repositorios públicos y privados. Estos paquetes se llaman Helm Charts.
Helm también es un motor de plantillas que permite generar archivos de configuración con variables:
Un Secret es un objeto que contiene datos sensibles como una contraseña, un token o una clave. Tal información podría de otro modo ser colocada en una especificación de Pod o en una imagen. Los usuarios pueden crear Secrets y el sistema también crea Secrets. El nombre de un objeto Secret debe ser un nombre de subdominio DNS válido. Lea aquí la documentación oficial.
Los Secrets pueden ser cosas como:
Claves API, SSH.
Tokens de OAuth.
Credenciales, Contraseñas (texto plano o b64 + cifrado).
Información o comentarios.
Código de conexión a la base de datos, cadenas… .
Hay diferentes tipos de secretos en Kubernetes
Tipo incorporado | Uso |
---|---|
Opaque | datos arbitrarios definidos por el usuario (Predeterminado) |
kubernetes.io/service-account-token | token de cuenta de servicio |
kubernetes.io/dockercfg | archivo ~/.dockercfg serializado |
kubernetes.io/dockerconfigjson | archivo ~/.docker/config.json serializado |
kubernetes.io/basic-auth | credenciales para autenticación básica |
kubernetes.io/ssh-auth | credenciales para autenticación SSH |
kubernetes.io/tls | datos para un cliente o servidor TLS |
bootstrap.kubernetes.io/token | datos del token de arranque |
El tipo Opaque es el predeterminado, el par clave-valor típico definido por los usuarios.
Cómo funcionan los secretos:
El siguiente archivo de configuración define un secret llamado mysecret
con 2 pares clave-valor username: YWRtaW4=
y password: MWYyZDFlMmU2N2Rm
. También define un pod llamado secretpod
que tendrá el username
y password
definidos en mysecret
expuestos en las variables de entorno SECRET_USERNAME
__ y __ SECRET_PASSWOR
. También montará el secreto username
dentro de mysecret
en la ruta /etc/foo/my-group/my-username
con permisos 0640
.
etcd es un almacén de clave-valor consistente y altamente disponible utilizado como almacenamiento de respaldo de Kubernetes para todos los datos del clúster. Accedamos a los secretos almacenados en etcd:
Verás que los certs, claves y URL están ubicados en el FS. Una vez que los obtengas, podrás conectarte a etcd.
Una vez que logres establecer comunicación, podrás obtener los secretos:
Agregar cifrado al ETCD
Por defecto, todos los secretos están almacenados en texto plano dentro de etcd a menos que apliques una capa de cifrado. El siguiente ejemplo se basa en https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/
Después de eso, necesitas establecer la bandera --encryption-provider-config
en el kube-apiserver
para apuntar a la ubicación del archivo de configuración creado. Puedes modificar /etc/kubernetes/manifest/kube-apiserver.yaml
y agregar las siguientes líneas:
Desplázate hacia abajo en los volumeMounts:
Desplácese hacia abajo en los volumeMounts hasta hostPath:
Verificando que los datos están encriptados
Los datos están encriptados cuando se escriben en etcd. Después de reiniciar tu kube-apiserver
, cualquier secreto creado o actualizado debería estar encriptado al almacenarse. Para verificar, puedes usar el programa de línea de comandos etcdctl
para recuperar el contenido de tu secreto.
Crea un nuevo secreto llamado secret1
en el espacio de nombres default
:
Usando la línea de comandos etcdctl, lee ese secreto de etcd:
ETCDCTL_API=3 etcdctl get /registry/secrets/default/secret1 [...] | hexdump -C
donde [...]
debe ser los argumentos adicionales para conectarse al servidor etcd. 3. Verifica que el secreto almacenado esté precedido por k8s:enc:aescbc:v1:
lo que indica que el proveedor aescbc
ha encriptado los datos resultantes. 4. Verifica que el secreto se descifre correctamente al recuperarlo a través de la API:
debería coincidir con mykey: bXlkYXRh
, mydata está codificado, consulta decodificando un secreto para decodificar completamente el secreto.
Dado que los secretos están encriptados al escribir, realizar una actualización en un secreto encriptará ese contenido:
Consejos finales:
Intenta no mantener secretos en el FS, obténlos de otros lugares.
Consulta https://www.vaultproject.io/ para agregar más protección a tus secretos.
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE) Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)