Mostrando las entradas para la consulta kubernetes ordenadas por relevancia. Ordenar por fecha Mostrar todas las entradas
Mostrando las entradas para la consulta kubernetes ordenadas por relevancia. Ordenar por fecha Mostrar todas las entradas

viernes, enero 31, 2020

Kubernetes: Cómo comprobar la salud de los pods con “probes”

Pues sí amigos y amigas, en este 2020 también vamos a seguir hablando de Docker y sobre todo, de Kubernetes. Cuanto más lo utilizamos, más vemos las grandes posibilidades que ofrece para todo tipo de entornos. Por este motivo es importante también centrarnos especialmente en su seguridad, integridad y disponibilidad.

Figura 1: Kubernetes: Cómo comprobar la salud de los pods con “probes”

De esto trata esta serie, no sólo de mostraros cómo funciona sino, además, de intentar aplicar buenas prácticas para minimizar al máximo todo tipo de riesgos asociados a esta arquitectura. No olvidéis que en nuestro libro Docker: SecDevOps podéis comenzar a adentraros en el mundo de Docker y los contenedores.

Figura 2: Libro Docker: SecDevOps

Kubernetes es una plataforma que nos permite definir el estado de nuestro clúster en profundidad. Por ejemplo, cuando desplegamos un servicio, especificamos cómo queremos correrlo, el número de réplicas o copias que queremos, entre otras muchas acciones.

En ese momento, Kubernetes se encargará de desplegar nuestro servicio e intentará cumplir con “nuestros deseos”. Es decir, levantará el número de copias que hayamos especificado, y si una de dichas copias se cae, levantará una nueva. En otras palabras, Kubernetes nos permite definir el estado de nuestro clúster de forma declarativa e intentará realizar todo lo posible por mantener dicho estado.

Pero ¿cómo sabe cuando un servicio está listo para recibir tráfico? ¿Y si un servicio tiene problemas y necesita ser reiniciado o reemplazado? Para responder a esas preguntas, Kubernetes nos ofrece tres tipos de puntos de comprobación o probes.

Readiness Probe

Esta es la forma en la que podemos decir a Kubernetes que nuestro pod está listo para recibir peticiones. Un ejemplo típico de uso de este tipo probe puede ser que por ejemplo tu pod necesite conectarse a un servicio externo, y éste por el motivo que sea no se encuentra disponible. Asumiendo que tu pod requiera, de forma imperativa, dicho servicio para poder funcionar, no tiene sentido que reciba peticiones nuevas.

Liveness Probe

Es usado por Kubernetes para saber si el pod está en un estado digamos, saludable. En caso contrario, Kubernetes lo reiniciará de forma automática. Un ejemplo de uso podría ser que nuestro pod tuviera algún tipo de problemas de recursos como la memoria, o el disco (volumen). Supongamos que escribimos los logs de pod en un volumen (no persistente) y, bueno, a veces por algún motivo la limpieza de esos logs falla y éste se llena.

El resultado es que nos hemos quedamos sin espacio y la mejor forma de recuperarnos del problema es reiniciando el pod. Normalmente, tiramos de este probe para recuperarnos de excepciones de las que nuestro pod no es capaz de recuperarse. Si un contenedor muere por algún tipo de error, Kubernetes reiniciaría el mismo de la misma forma que lo haría si el liveness probe fallara.

Startup Probe

Este apareció en la versión 1.16 de Kubernetes y actualmente está en versión alpha. El uso ideal del mismo es aplicarlo cuando nuestro pod tarda algún tiempo antes de arrancar por completo. Por ejemplo, hemos movido una aplicación antigua a un contenedor, y ésta tarda demasiado tiempo en levantarse. En este caso, podría ser problemático si no especificamos correctamente nuestro liveness probe ya que podríamos acabar en un reinicio constante del pod, debido a que Kubernetes podría pensar que el pod no responde propiamente y necesita reiniciarlo, cuando en realidad, el problema es que el pod está justo durante su proceso de arranque.

Cuando definimos el startup probe, Kubernetes no habilita el liveness probe para que le indique si el pod ya está arrancado. Si este probe fallara, Kubernetes reiniciaría el pod. Se recomienda que este se ejecute en el mismo chequeo que definamos para nuestro liveness probe. Para ello asignaremos el valor failureThreshold lo suficientemente alto para que nuestro pod tenga el tiempo suficiente para arrancar.

Figura 3: Esquema de un nodo y las "probe"

Vale, ya conocemos los probe, pero ¿cómo los definimos? Existen básicamente tres formas de definir la comprobación de un probe:
· HTTP: quizás la forma más utilizada. En este caso, Kubernetes consulta a través de una petición GET el punto de acceso de nuestro servicio. Si la respuesta se encuentra en el rango de los 200s o 300s, le indica que el probe está saludable. Cualquier otro código de respuesta implica algún tipo de anomalía o error.
· Comando: en este caso, Kubernetes ejecuta el comando indicado. Si éste devuelve 0, el probe se considera saludable, en cualquier otro caso, el resultado se considera problemático .
· TCP: no todos los servicios no son necesariamente HTTP. Por eso, Kubernetes nos ofrece la oportunidad de definir probes basados en TCP. En esta caso, intentaría establecer una conexión TCP al puerto especificado. Si la conexión es satisfactoria, el probe se considera en buena salud, en caso contrario, existe algún problema.
Ok, entonces ¿cuál es la frecuencia de consulta a nuestros probes? ¿cuántos intentos son necesarios para considerar un probe en buen o mal estado? Existen varios parámetros que nos permite definir dicho comportamiento:
· initialDelaySeconds: número de segundos que Kubernetes espera después de que un contenedor se haya inicializado para activar los probes liveness y readiness. Por defecto su valor es 0.
· periodSeconds: Con qué frecuencia Kubernetes ejecuta el probe. Por defecto su valor es 10, y el valor mínimo es 1.
· timeoutSeconds: tiempo, en segundos, que Kubernetes espera cuando ejecuta el probe. El valor por defecto es 1, así como su valor mínimo.
· successThreshold: número de veces consecutivas en que el probe se ejecuta de manera satisfactoria después de un fallo, para que el pod se considere saludable de nuevo. Valor por defecto y mínimo es 1. Para un probe tipo liveness debe ser 1.
· failureThreshold: número de veces consecutivas que debe fallar un probe para que Kubernetes lo considere con problemas. En cuyo caso, si hablamos de liveness, reiniciará el pod, y el caso de readiness, cortará el tráfico a dicho pod. El valor por defecto es 3 y el mínimo 1.
Cada probe puede devolver uno de los tres valores siguientes:
· Success: el contenedor pasa el diagnóstico. 
· Failure: el diagnóstico ha fallado. 
· Unknown: el diagnóstico ha fallado, pero no se toma ninguna acción.
Ahora que ya tenemos la teoría, vamos a pasar a la práctica. Los probes se configuran dentro de la especificación del contenedor.

Ejemplo de Liveness Probe

Veamos algún ejemplo con liveness probe:
    apiVersion: v1
    kind: Pod
    metadata:
        labels:
            test: liveness
        name: liveness-http
        spec:
        containers:
        - name: liveness
            image: k8s.gcr.io/liveness
            args:
            - /server
            livenessProbe:
            httpGet:
                path: /healthz
                port: 8080
                httpHeaders:
                - name: Custom-Header
                  value: Awesome
            initialDelaySeconds: 3
            periodSeconds: 3
Como se puede ver en el ejemplo, el probe se define bajo “livenessProbe:”. En este caso definimos un probe del tipo HTTP, se mandará una petición GET a la IP_CONTENEDOR/healthz:8080, en dicha petición, además se manda una cabecera llamada Custom-Header con el valor Awesome.

Figura 4: PoC Kubernetes Liveness Probe

También se establece que Kubernetes que espere 3 segundos antes de que empiece a mandar dichas peticiones, y que estas se repitan cada 3 segundos. Como no definimos el valor failureThreshold, en el momento en el que Kubernetes reciba tres fallos (valor fuera del rango 200-399) reiniciará el pod.

Ejemplo de Readiness Probe

Ahora veamos un ejemplo para readiness:
    ...
    containers:
    - name: readiness
        image: k8s.gcr.io/busybox
        args:
        - /bin/sh
        - -c
        - touch /tmp/healthy; sleep 10; rm -rf /tmp/healthy; sleep 10; touch /tmp/healthy; sleep 600
        readinessProbe:
          exec:
            command:
            - cat
            - /tmp/healthy
          initialDelaySeconds: 2
          periodSeconds: 2
En este caso, lo que hacemos es cuando arranca nuestro contenedor crea un fichero /tmp/healthy, espera 10 segundos, borra dicho fichero, espera otros 10 segundos y vuelve a crear el mismo fichero y luego espera 5 minutos (después de los 5 minutos, el contenedor morirá y Kubernetes reiniciará el pod).

En este caso nuestro probe lo que hace es ejecutar el comando `cat /tmp/healthy`. Este comando se ejecutará de forma satisfactoria cuando /tmp/healthy exista y fallará cuando éste no exista. El chequeo empieza 2 segundos después de que el contenedor se haya arrancado y lo efectúa cada 2 segundos. En el siguiente vídeo veremos como Kubernetes muestra cuando el pod está listo para recibir tráfico y cuando no.


Figura 5: Kuberneters: PoC Readiness Probe

Definir estos chequeos se consideran buenas prácticas y son aconsejables tenerlos definidos, pero hay que tener cuidado con los parámetros ya que podríamos crear un pequeño caos y hacernos a nosotros mismos un DoS ;)

Reflexión final

Para terminar, estos son algunos consejos sobre cómo utilizar los probes:
· Si defines startup probe, usa la misma comprobación que liveness. 
· No uses la misma comprobación para liveness y readiness. 
· No uses ninguna dependencia en liveness. Por ejemplo, no definas en liveness ninguna lógica conectando a una base de datos. Si la base de datos se cae, Kubernetes reiniciará tu pod y esto no arreglaría el problema y acabaría reiniciado el pod de forma constante. En esta caso readiness sería una mejor opción. 
· Si no tienes ninguna razón por la que reiniciar tu contenedor, no definas liveness. Si el contenedor por algún motivo se rompe, Kubernetes se encargará de reiniciarlo de todas formas. 
· Si tu contenedor tiene algún bug en el que hay veces que deja de funcionar, pero el contenedor sigue vivo, define liveness de forma que chequee esa condición extraordinaria para así poder indicarle a Kubernetes que reinicie el pod. Asegúrate de que implementas bien este chequeo. 
· Conoce los valores por defecto de tiempos. Para asegurarte y evitar confusiones declaralos de forma explícita.
Y esto ha sido todo en este artículo. Esperamos que os sean de utilidad estos ejemplos y consejos en vuestro trabajo con Docker y Kubernetes.

Happy Hacking Hackers!!!!

Autores:

Fran Ramírez, (@cyberhadesblog) es investigador de seguridad y miembro del equipo de Ideas Locas en CDO en Telefónica, co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps", también de "Machine Learning aplicado a la Ciberseguridad” además del blog CyberHades. Puedes contactar con Fran Ramirez en MyPublicInbox.


Figura 6: Contactar con Fran Ramírez en MyPublicInbox

Rafael Troncoso (@tuxotron) es Senior Software Engineer en SAP Concur, co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps" además del blog CyberHades. Puedes contactar con Rafael Troncoso en MyPublicInbox.


Figura 7: Contactar con Rafael Troncoso en MyPublicInbox

miércoles, noviembre 20, 2019

Kubernetes: Gestionar políticas de seguridad de red “Like a Boss” (1 de 3)

Kubernetes se está convirtiendo no sólo en el estándar para desplegar contenedores, sino también incluso en el elemento más utilizado para gestionar infraestructuras virtualizadas. Por lo tanto, la gestión de su seguridad es algo que necesitamos tener en cuenta a la hora de instalarlo. Por este motivo, ya hablamos de las políticas de seguridad de pods en una serie tres artículos centrándonos en las características de seguridad ofrecidas por Kubernetes a la hora de restringir el despliegue de pods que no cumplan con ciertos requisitos.

Figura 1: Kubernetes: Gestionar políticas de seguridad de red “Like a Boss” (1 de 3)

La seguridad en el mundo Docker es una prioridad, por eso escribimos el libro “Docker: SecDevOps”, el cual además de servir de iniciación a este apasionante mundo de los contenedores, hablamos de buenas prácticas de seguridad así como la posición de Docker dentro del ciclo DevOps aportando el facto de seguridad (“Sec”) para finalmente obtener un cadena SecDevOps.

Figura 2: Libro Docker: SecDevOps

En estos nuevos artículos vamos a hablar de otro componente fundamental en un despliegue de Kubernetes: Las políticas de red y su seguridad. Hablando en términos generales, las políticas de red en Kubernetes son un concepto muy sencillo, pero muy potente. En pocas palabras, una política de red nos permite establecer de una forma declarativa restricciones de comunicación entre los pods de nuestro clúster.

Antes de entrar más en detalle sobre el tema, demos un muy rápido repaso a las redes en Kubernetes. Internamente existen 4 tipos comunicación por red en Kubernetes:
· Contenedor a contenedor: los contenedores que se ejecutan dentro de un pod, comparten el mismo espacio de red del pod, es decir, dichos contenedores comparten la misma IP y se pueden comunicar a través de “localhost”, por tanto, dos contenedores que se ejecuten en un mismo pod no escuchan por el mismo puerto.
· Pod a Pod: cada pod recibe su propia dirección IP y todos los pods, por defecto, se pueden comunicar entre ellos a través de NAT.
· Servicios a Pods: los servicios en Kubernetes no son más que IP virtuales (distinto segmento de la red de pods) que pueden apuntar a cero (idealmente uno como mínimo) o más pods. Los servicios actúan más como balanceadores de carga. Estas IPs no son enrutable, es decir, no responden a “pings”.
· Tráfico externo a interno: en los tres casos anteriores hemos hablado del tráfico interno del clúster. En este caso hablamos del tráfico externo hacia dentro del clúster. Esto normalmente se consigue implementando algún tipo de balanceador de carga externo que interactúe con todos los nodos del clúster.
Una de las razones por la que Kubernetes ha ganado tanta atención, es por la posibilidad de “upgrade” o ampliación, permitiendo el reemplazo de varios de sus componentes principales, como por ejemplo el motor de contenedores (por defecto usa Docker, pero se puede reemplazar), el controlador de red, etcétera. El controlador de red en Kubernetes está basado en el proyecto CNI (Container Network Interface), el cual es más que un conjunto de especificaciones y librerías, que nos permite la implementación del componente que manejaría la red dentro de Kubernetes.

Figura 3: CNI en GitHub

Por lo tanto, nosotros podríamos crear un controlador de red e instalarlo en nuestro clúster, reemplazando el que Kubernetes use por defecto. De todas formas es posible encontrar otros proyectos que usan CNI como base para la implementación de la red.

Figura 4: Ejemplo de implementación TLS dentro de Kubernetes

Esto abre la posibilidad de escribir tus propios plugins y como es lógico, muchas empresas han escrito sus propios plugins de red para Kubernetes. Por lo tanto, y aquí viene el pequeño inconvenientes, no todos los plugins se comportan de la misma manera debido a esta variedad de implementaciones personalizadas. E incluso algunos de ellos incluso no soportan las políticas de red. Por ejemplo, AWS-CNI, el plugin de Amazon para su nube AWS, aunque éste permite ser extendido para soportar dicha características.

Ejemplos con plugins CNI

En nuestro caso, para ejecutar los ejemplos que veremos a continuación usaremos de nuevo “minikube”, el cual por defecto no soporta las políticas de red, así que instalaremos un plugin CNI llamado Cilium que sí las soporta. Cilium es un proyecto Open Source y usa Linux BPF para el filtrado de paquetes de red.

El primer paso será arrancar nuestro clúster con minikube (usaremos la versión 1.5.2 y la versión 1.16.2 de Kubernetes). Para ello, le tenemos que decir a “minikube” que vamos a usar un plugin de red basado en CNI. Además, le dedicaremos a nuestro clúster 4Gb de memoria:
minikube start --network-plugin=cni --memory=4096
Una vez esté el clúster arriba, montamos el sistema de ficheros BPF:
minikube ssh -- sudo mount bpffs -t bpf /sys/fs/bpf
Finalmente instalamos Cilium (asumimos que tienes instalado kubectl):
kubectl create -f https://raw.githubusercontent.com/cilium/cilium/v1.6/install/kubernetes/quick-install.yaml
El proceso puede tardar varios minutos. Puedes observar la creación de los componentes con el siguiente comando:
kubectl -n kube-system get pods --watch
Aquí podéis ver un vídeo con todos esos pasos.


Figura 5: Instalacion de Cilium en minikube

Como con el resto de los objetos en Kubernetes, las políticas de red pueden ser definidas en ficheros YAML. Siguiendo el mismo criterio que el resto, tenemos tres atributos que son requeridos a la hora definir nuestro fichero manifiesto:
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
        name: test-network-policy
        namespace: default
    ...
    ...
En este caso apiVersion y kind serían siempre el mismo, pero el atributo metadata varía, ya que ahí es dónde especificas el nombre de la política, el nombre de espacio, etcétera. Las políticas de red se definen a nivel del nombre de espacio, así que puedes crear políticas con el mismo nombre, siempre y cuando pertenezcan a distintos espacios de nombre. Veamos un ejemplo más completo:
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
        name: test-network-policy
        namespace: default
    spec:
        podSelector:
            matchLabels:
                role: db
        policyTypes:
        - Ingress
        - Egress
        ingress:
        - from:
          - ipBlock:
              cidr: 172.17.0.0/16
              except:
             - 172.17.1.0/24
          - namespaceSelector:
              matchLabels:
                project: myproject
          - podSelector:
              matchLabels:
                role: frontend
          ports:
          - protocol: TCP
            port: 6379
        egress:
        - to:
            - ipBlock:
                cidr: 10.0.0.0/24
            ports:
            - protocol: TCP
              port: 5978
Vamos a explicar especificación de este ejemplo (toda la parte que se encuentra por debajo de spec).
· podSelector: se especifica la selección de pods a los que la política de red será aplicada. Si el podSelector se define como vacío {}, la política se aplica a todos los pods. 
· policyTypes: actualmente acepta dos valores Ingress (tráfico de entrada) y Egress (tráfico de salida). Si no se especifica este atributo, el valor por defecto es Ingress.
· ingress: puede incluir una lista de reglas asociadas a puertos. Se permitirá el tráfico de entrada que venga de alguna de las fuentes especificadas, al puerto o los puertos definidos. 
En el ejemplo anterior, permitimos que los pods del espacio de nombre default con la etiqueta role=db (spec.podSelector.matchLabels) se puedan conectar los pods cuya IP se encuentren en el rango 172.17.0.0/16 (spec.ingress.from.ipBlock.cidr), excepto los que se encuentren en el rango 172.17.1.0/24 (spec.ingress.from.ipBlock.except). 
También se pueden conectar los pods que pertenezcan al espacio de nombres que contengan la etiqueta project=myproject (spec.ingress.from.namespaceSelector) y aquellos pods, sin importar el espacio de nombres, que tengan la etiqueta role=frontend (spec.ingress.from.podSelector). Estas restricciones se aplican sólo al puerto 6379/TCP (spec.ingress.from.ports...).
· egress: aquí igualmente se puede incluir una lista con varias reglas que restrinja hacia dónde se puede conectar nuestro pod. Siguiendo el ejemplo anterior, el pod o pods en el nombre de espacio default con la etiqueta role=db, sólo se puede conectar a pods en el rango de IP 10.0.0.0/24 (spec.egress.to.ipBlock) y al puerto 5978/TCP (spec.egress.to.ports…). El resto de las conexiones estarían cortadas.
Como se ha visto en el ejemplo anterior existen cuatro formas de seleccionar los pods en las reglas de ingress y egress:
· podSelector 
· namespaceSelector 
· podSelector y namespaceSelector 
· ipBlock
Y aquí dejamos esta primera parte. En la siguiente continuaremos profundizando en todas las posibilidades que permite el uso de estas políticas de seguridad de red en entornos Kubernetes.

Happy Hacking Hackers!!!

*********************************************************************************************
Kubernetes: Gestionar políticas de seguridad de red “Like a Boss” (1 de 3)
Kubernetes: Gestionar políticas de seguridad de red “Like a Boss” (2 de 3)
Kubernetes: Gestionar políticas de seguridad de red “Like a Boss” (3 de 3)
*********************************************************************************************

Autores:

Fran Ramírez, (@cyberhadesblog) es investigador de seguridad y miembro del equipo de Ideas Locas en CDO en Telefónica, co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps", también de "Machine Learning aplicado a la Ciberseguridad” además del blog CyberHades. Puedes contactar con Fran Ramirez en MyPublicInbox.

Rafael Troncoso (@tuxotron) es Senior Software Engineer en SAP Concur, co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps" además del blog CyberHades. Puedes contactar con Rafael Troncoso en MyPublicInbox.

jueves, noviembre 29, 2018

SuperLatch Docker: Integrar Latch con Docker y Kubernetes en tus aplicaciones (3 de 3)

Al finalizar la segunda parte de este artículo habíamos visto como las aplicaciones en Go y Java están Up & Running, al mismo tiempo que teníamos pareadas ambas con el SuperLacth Docker en nuestra aplicación móvil.

Figura 17: SuperLatch Docker: Integrar Latch con Docker y Kubernetes en tus aplicaciones (3 de 3);

A partir de este momento podemos ver que cuando activamos Latch para poner el estado en OFF de nuestra app SuperLatch Docker las aplicaciones pasan a estar deshabilitadas y no funcionan, tal y como se puede ver en las imágenes siguientes.

Figura 18: Aplicación Go se deshabilita porque el SuperLatch Docker está cerrado
Figura 19: Aplicación Java deshabilitada también desde el SuperLatch Docker

El funcionamiento descrito en este proceso está disponible en el siguiente vídeo, donde se puede observar todo el proceso activación y bloqueo de la aplicación utilizando Latch:

Figura 20: Demo de Activación y Desactivación de SuperLatch Docker

Como podéis observar, cada segundo (tiempo preestablecido para que la aplicación compruebe el estado) se activa el popup en la aplicación Latch, indicando que se ha bloqueado una aplicación. Esto ocurre porque estamos utilizando la versión Comunidad de Latch (en la versión comercial se puede desactivar este popup con un simple flag).

SuperLatch en Kuberneters

Para correr esta misma idea sobre kubernetes, usaremos minikube. Uno de los cambios que haremos con respecto a la versión de docker-compose es que los valores que necesitamos para conectar con Latch (secret, account_id y app_id) se almacenarán en secretos de kubernetes, en vez de en variables de entorno. Para ello tenemos que modificar el fichero secrets.yaml que se encuentra dentro del directorio kube.

Figura 21: Arquitectura de SuperLatch Kubernetes

Los datos de los secretos se asignan codificados en Base64, así que lo primero que necesitamos hacer es codificar nuestros valores:

Account id:
echo -n "QNmcFJuPdqG3fdAUy2GqBw2Ehn2VF8ranuzFbvMHj2h27WPgbrnMmyGTwzqBFvda" | base64 UU5tY0ZKdVBkcUczZmRBVXkyR3FCdzJFaG4yVkY4cmFudXpGYnZNSGoyaDI3V1BnYnJuTW15R1R3enFCRnZkYQ==
app_id:
echo -n "PAyrhmA3Hb8Qmf84N2Js" | base64 UEF5cmhtQTNIYjhRbWY4NE4ySnM=
secret key:
echo -n "isiBUL6PMXgc7EfkVkZgbZirwfK9d7gPtfDVKrDt" | base64 aXNpQlVMNlBNWGdjN0Vma1ZrWmdiWmlyd2ZLOWQ3Z1B0ZkRWS3JEdA==
Ahora ponemos esos valores en nuestro secrets.yaml:
apiVersion: v1
kind: Secret
metadata:
name: latch-secret
type: Opaque
data:
app_id: UEF5cmhtQTNIYjhRbWY4NE4ySnM=
account_id: UU5tY0ZKdVBkcUczZmRBVXkyR3FCdzJFaG4yVkY4cmFudXpGYnZNSGoyaDI3V1BnYnJuTW15R1R3enFCRnZkYQ==
key: aXNpQlVMNlBNWGdjN0Vma1ZrWmdiWmlyd2ZLOWQ3Z1B0ZkRWS3JEdA==
Una vez tenemos dicho fichero modificado y grabado, lo siguiente sería crear nuestros objetos. Para ello asegúrate que minikube está arrancado:

minikube start 
Starting local Kubernetes v1.10.0 cluster... 
Starting VM...
Getting VM IP address...
Moving files into cluster...
Setting up certs... 
Connecting to cluster... 
Setting up kubeconfig...
Starting cluster components... 
Kubectl is now configured to use the cluster. 
Loading cached images from config file. 

Una vez minikube esté arrancado, ejecutamos:
kubectl create -f secrets.yaml -f deployment.yaml -f service.yaml
Asumiendo que estamos situado dentro del directorio kube, si estamos en otro directorio distinto al de nuestros ficheros yaml, pues tendrás que prefijar el fichero con la ruta correcta. Para comprobar que nuestro Pod se ha creado de forma correcta:

kubectl get pod 

NAME                                    READY   STATUS    RESTARTS  
 
latch-poc-deployment-66d8f6c966-vslf7   3/3     Running   0     
     

Como se puede observar en la columna READY, los tres contenedores están corriendo (3/3). Una vez echo esto pues acceder a los servicios, para ello tenemos que ver que puertos a mapeado kubernetes:

minikube service list
|-------------|----------------------|--------------------------------|
|  NAMESPACE  |         NAME         |              URL               |
|-------------|----------------------|--------------------------------|
| default     | kubernetes           | No node port                   |
| default     | latch-poc-service    | http://192.168.99.100:30823    |
|             |                      | http://192.168.99.100:31723    |
| kube-system | kube-dns             | No node port                   |
| kube-system | kubernetes-dashboard | No node port                   |
|-------------|----------------------|--------------------------------|

Vemos que el servicio latch-poc-service tiene dos puertos mareados, pero no sabemos cuál es cuál. Podemos abrir nuestro navegador y probar a ver que puerto esta mapeado al servicio Java y cuál al servicio Go. O podemos ver la descripción del servicio:

kubectl describe service latch-poc-service             
Name:                     latch-poc-service
Namespace:                default
Labels:                   
Annotations:              
Selector:                 app=latch-poc-deployment
Type:                     NodePort
IP:                       10.99.73.112
Port:                     java-port  8080/TCP
TargetPort:               8080/TCP
NodePort:                 java-port  30823/TCP
Endpoints:                172.17.0.5:8080
Port:                     go-port  8081/TCP
TargetPort:               8081/TCP
NodePort:                 go-port  31723/TCP
Endpoints:                172.17.0.5:8081
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

Aquí podemos ver que el servido Java está mapeado al puerto del nodo 30823 y el de Go al 31723. A continuación podéis ver un vídeo completo de la PoC de SuperLatch Kubernetes:

Figura 22 : PoC de SuperLatch Kubernetes

En el caso de kubernetes estamos desplegando los tres contenedores en un mismo Pod. Si el servicio latch-master estuviera protegiendo sólo un servicio, desplegar ambos contenedores en un mismo Pod sería aceptable. En este caso donde tenemos dos contenedores (servicios) que proteger, idealmente se desplegaría cada contenedor en un Pod distinto y el volumen se haría global (PersistentVolume) o el estado de latch se almacenaría en algún lugar global dentro del cluster. En nuestro caso y para mostrar la prueba de concepto, lo consideramos aceptable poner todos los contenedores en un mismo Pod por temas de simplicidad.

Conclusiones finales

En esta prueba de concepto no sólo podemos ver como añadir una capa más de seguridad protegiendo nuestros contenedores con Latch, si no que además, como los contenedores que queremos proteger sólo necesitan leer de un fichero del sistema y no tienen que acceder a los servidores de Latch para comprobar el estado del mismo, a menos que estos se tuvieran que conectar con otros servidores externos, podrías bloquear las conexiones outbound, es decir, que no podrían salir a Internet como comentamos al principio de este artículo, lo cual añade una capa más de seguridad.

Otro beneficio que esta PoC nos muestra, éste desde el punto de vista del programador, es al ahorro en código y dependencias. Es decir, los servicios protegidos por Latch cómo no necesitan conectar y hablar el “protocolo Latch”, no tienes que añadir las dependencias de las SDK de Latch y por lo tanto no tienes que escribir código para integrar la misma. Esto, además, nos permitiría proteger con Latch cualquier servicio ser necesario un SDK de Latch específico para el lenguaje utilizado. Vamos que podrías crear un servicio en COBOL y protegerlo con Latch sin ningún tipo de problemas :)

Esperamos que esta PoC sirva tanto como idea para implementarlo en alguna aplicación con Docker o como simplemente una forma de aprender un poco más de Docker y kubernetes. Y por supuesto, en nuestro libro Docker: SecDevOps también puedes aprender más de Docker y kubernetes ;)

Happy Hacking Hackers!!!

***********************************************************************************
- SuperLatch Docker: Integrar Latch con Docker y Kubernetes en tus apps (1 de 3)
- SuperLatch Docker: Integrar Latch con Docker y Kubernetes en tus apps (2 de 3)
- SuperLatch Docker: Integrar Latch con Docker y Kubernetes en tus apps (3 de 3)
***********************************************************************************

Autores:

Fran Ramírez, (@cyberhadesblog) miembro del equipo de Crazy Ideas en CDO en Telefónica, co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps" y del blog Cyberhades.

Rafael Troncoso (@tuxotron) es DevOps Tech Lead en USCIS/DHS, co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps" y del blog Cyberhades.

sábado, octubre 08, 2022

Kubernetes para profesionales: Desde cero al despliegue de aplicaciones seguras y resilientes. Nuevo libro de @0xWord

Desde hoy tenemos a la venta el nuevo libro en 0xWord de "Kubernetes para profesionales: Desde cero al despliegue de aplicaciones seguras y resilientes", escrito por Rafael Troncoso y centrado en ser un "pro", un "máster", un "groso", un "duro"... o un hacker que diríamos nosotros, desplegando Kubernetes
El libro, como es de esperar, pone mucho foco en conocer a fondo cómo desplegar servicios de forma profesional, poniendo especial énfasis en todas las opciones de seguridad. En desplegar de la manera más robusta cualquier aplicación utilizado la tecnología Kubernetes en sus más de 270 páginas. Así que, si eres de los que cree que hay que fortificar las aplicaciones en modo "Paranoid", este es tu libro si vas a hacerlo aprovechando Kubernetes.
El libro, como podéis leer en la descripción del mismo, te da más motivos por los que comprarse y estudiarse en profundidad este nuevo libro de Rafael Troncoso 

"Predeterminado a convertirse en el “sistema operativo de la nube”. Así es como muchos ven a Kubernetes. La plataforma que está revolucionando el despliegue de aplicaciones modernas en sistemas de producción. Kubernetes es actualmente “el” orquestador de contenedores, y ha llegado para quedarse. No tiene actualmente rival alguno. Cualquier profesional que se dedique al desarrollo de software, operaciones o a la seguridad, si se quiere mantener relevante en esta industria, debe estar familiarizado con el funcionamiento y uso de Kubernetes. En este libro, aprenderás desde los conceptos básicos sobre dicha plataforma, hasta el despliegue de aplicaciones de forma segura y resilientes.

Para que podáis ver en detalle el contenido, os he subido a mi cuenta de SlideShare el documento con el índice del mismo, con todos los temas que se tratan en el compendio que Rafael Troncoso  ha escrito sobre Kubernetes.


Por supuesto, con la compra del libro tendrás también Tempos de  MyPublicInbox, y podrás utilizarlos para consultar cualquier duda, enviar cualquier consulta o sugerencia a Rafael Troncoso, con el que puedes contactar a través de su buzón público.


Este es su tercer libro, ya que, como sabéis, Rafael Troncoso es también co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps" además de ser uno de los fundadores del blog CyberHades. Así que si quieres aprender mucho sobre Kubernetes, éste es tu libro.

¡Saludos Malignos!

Autor: Chema Alonso (Contactar con Chema Alonso)  


miércoles, julio 03, 2019

Gestionar la política de seguridad de pods en Kubernetes “Like a Boss” (Parte 2 de 3)

Vamos a continuar con la segunda parte de nuestro artículo de Cómo gestionar la política de de seguridad de pods en Kubernetes "Like a Boss" justo donde nos quedamos ayer. Cuando se crea una política de seguridad, por sí sola no hace nada, el usuario o la cuenta de servicio del pod necesita tener acceso para poder usar el verbo "use" de dicha política.

Figura 4: Gestionar la política de seguridad de pods en Kubernetes
“Like a Boss” (Parte 2 de 3)

La forma estándar en Kubernetes de dar acceso a recursos es a través de RBAC, del cual no entraremos en detalles ya que anteriormente hemos publicado un artículo de dos partes:

Kubernetes: Cómo gestionar autorización de recursos con RBAC (Parte 1)
Kubernetes: Cómo gestionar autorización de recursos con RBAC (Parte 2)

Para poder hacer uso de la política de seguridad, nuestro clúster debe tener habilitado un controlador de admisión para dichas políticas, concretamente para PodSecurityPolicy. Un controlador de admisión en Kubernetes es un componente que intercepta las llamadas al servidor de API del mismo justo antes de persistir dicha llamada, pero esto ocurre una vez la llamada ha sido autenticada y autorizada.

Unos ejemplos con minikube

Para ver algunos ejemplos haremos uso de minikube. Lo primero es arrancar minikube con el controlador de admisión de PodSecurityPolicy. Esta parte tiene un poco de truco, ya que cuando activamos dicho controlador, si no existe un objeto PodSecurityPolicy en el clúster, minikube rechaza la creación de pods, incluido los del sistema, por lo que minikube después de un buen rato de espera termina por parar la espera y nos da un error.

Aunque hay formas de solucionar este problema modificando la configuración de minikube (añadiendo un fichero dentro de ´~/.minikube/files/etc/kubernetes/addons´ PodSecurityPolicy), una forma muy sencilla es arrancando el clúster sin pasar ningún parámetro adicional:

Figura 5: Salida del comando de minikube start

Luego creamos un objeto PodSecurityPolicy con privilegios altos, ya que asignaremos esta política al group de sistema que levanta el clúster:

    apiVersion: extensions/v1beta1
    kind: PodSecurityPolicy
    metadata:
      name: privileged
      annotations:
        seccomp.security.alpha.kubernetes.io/allowedProfileNames: "*"
      labels:
        addonmanager.kubernetes.io/mode: EnsureExists
    spec:
      privileged: true
      allowPrivilegeEscalation: true
      allowedCapabilities:
      - "*"
      volumes:
      - "*"
      hostNetwork: true
      hostPorts:
      - min: 0
        max: 65535
      hostIPC: true
      hostPID: true
      runAsUser:
        rule: 'RunAsAny'
      seLinux:
        rule: 'RunAsAny'
      supplementalGroups:
        rule: 'RunAsAny'
      fsGroup:
        rule: 'RunAsAny'

Crea un fichero con ese contenido llamado psp-privileged.yaml (el nombre es indiferente y puedes elegir el que quieras) y ejecuta el siguiente comando para crear dicho objeto en el clúster:

    kubectl apply -f psp-privileged.yaml

Luego vamos a crear un Role a nivel de clúster. Recuerda que las políticas de seguridad deben ser asignadas a través de algún método de autorización, en nuestro caso RBAC:

    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: psp:privileged
      labels:
        addonmanager.kubernetes.io/mode: EnsureExists
    rules:
    - apiGroups: ['extensions']
      resources: ['podsecuritypolicies']
      verbs:     ['use']
      resourceNames:
      - privileged

Volcamos dicho contenido a un fichero llamado cr-privileged.yaml y ejecutamos el siguiente comando:

    kubectl apply -f cr-privileged.yaml

Y por último vamos a asignar dicho Role al grupo system:serviceaccounts:kube-system que es quién levanta el clúster:

    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: default:privileged
      namespace: kube-system
      labels:
        addonmanager.kubernetes.io/mode: EnsureExists
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: psp:privileged
    subjects:
    - kind: Group
      name: system:masters
      apiGroup: rbac.authorization.k8s.io
    - kind: Group
      name: system:nodes
      apiGroup: rbac.authorization.k8s.io
    - kind: Group
      name: system:serviceaccounts:kube-system
      apiGroup: rbac.authorization.k8s.io

De nuevo, volcamos ese contenido a otro fichero llamado rb-system.yaml y creamos dicho objeto:

    kubectl apply -f rb-system.yaml

Resumiendo, lo que acabamos de hacer es crear una política de seguridad de pods bastante permisiva, un role a nivel de clúster asociado a dicha política y por último le hemos dado permiso para usar dicha política al grupo de sistema kube-system.

Si no hacemos esto, el clúster no puede crear los pods de sistema necesarios. Ahora ya podemos habilitar en el clúster el controlador de admisión:
minikube start --extra-config=apiserver.
enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,
DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,
ValidatingAdmissionWebhook,ResourceQuota,PodSecurityPolicy
--extra-config=apiserver.authorization-mode=RBAC
En la siguiente imagen se puede ver  cuál es la salida de la ejecución de minikube, esta vez habilitando los plugins que se pueden ver en el comando.

Figura 6: Salida de la ejecución del comando con plugins activados
Y para que podáis ver el proceso completo de lo que hemos descrito en estas dos primeras partes del artículo, os hemos hecho este pequeño vídeo que resume el proceso completo de todo, en algo más de dos minutos y medio.


Figura 7: Demo de configuración de seguridad de pods en minikube

Pero aún nos quedan muchas cosas que ver, así que en la tercera parte del artículo continuaremos configurando la política de seguridad de pods en Kuberneters "like a boss"... mientras tanto.

Happy Hacking Hackers!!

Fran Ramírez, (@cyberhadesblog) es investigador de seguridad y miembro del equipo de Ideas Locas en CDO en Telefónica, co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps" y del blog Cyberhades

Rafael Troncoso (@tuxotron) es Senior Software Engineer en SAP Concur, co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps" y del blog Cyberhades.

**************************************************************************************************
**************************************************************************************************

lunes, octubre 21, 2024

Platform Engineering as a Service con Axebow: La encrucijada de la Nube y la ilusión del progreso.

Desde hace más de una década la industria tecnológica ha estado experimentado una evolución constante hacia la computación en la nube, impulsada por las promesas de escalabilidad, flexibilidad y eficiencia en costes. Evolución que ha ido acompañada por el surgimiento de una plétora de herramientas y plataformas, intencionalmente diseñadas para simplificar el desarrollo y la gestión de recursos en la nube. Pero... ¿hemos avanzado lo suficiente en la última década?.
Si nos paramos a analizar la situuación actual, a pesar de estos avances, la complejidad fundamental de aprovisionar y gestionar recursos virtualizados sigue siendo prácticamente la misma. Hemos pasado de escribir scripts personalizados para orquestar nuestra infraestructura a utilizar herramientas más sofisticadas, como por ejemplo Terraform.

Paralelamente, y a un nivel superior, hemos introducido un mayor grado de automatizaciones con orquestadores de contenedores como Kubernetes. Sin duda hemos ido progresando, pero, ¿estamos significativamente mejor que hace diez años a la hora de simplificar la puesta a punto de servicios basados en software?

La Evolución de las Herramientas de Desarrollo Cloud

En los primeros días de la computación en la nube, desarrolladores y administradores de sistemas dependían en gran medida de scripts manuales para gestionar máquinas virtuales y otros recursos. Scripts de shell, Python y otras soluciones ad hoc fueron la norma (aún lo son en algunos casos). Estos scripts a menudo son específicos de la plataforma, carecen de estandarización y son difíciles de mantener. Lo que es peor, en muchos casos son scripts específicos para la puesta en producción de servicios concretos, por lo tanto no generalizables.

La llegada de la aproximación de Infraestructura como Código (IaC, en sus siglas en inglés) y sus herramientas (Terraform, CloudFormation, Ansible, ...), prometió poner orden en el caos. Estas herramientas permiten a los ingenieros definir configuraciones de infraestructura en código, versionarlas y desplegarlas de manera confiable en diferentes entornos. A primera vista, esto parece un avance significativo.

También hemos visto una proliferación de marcos y herramientas que intentan simplificar el desarrollo en la nube, introduciendo nuevas abstracciones que, por desgracia, conllevan curvas de aprendizaje importantes y muchas oportunidades para errar en su uso.
Kubernetes es un excelente ejemplo. Nació de la necesidad de facilitar la orquestación de contenedores, y ha tenido éxito hasta cierto punto. Pero para muchos desarrolladores, la transición a Kubernetes a menudo se siente como intercambiar un conjunto de complejidades (p.e., gestión de servidores) por otro (gestión de manifiestos, clústeres, políticas de red, etc...). El viejo dolor de cabeza de gestionar recursos ha sido reemplazado por nuevas complejidades en la gestión de objetos de Kubernetes.

La Persistencia de la Complejidad

Por lo tanto, a pesar de la adopción de herramientas como las ya expuestas, la complejidad asociada con el desarrollo en la nube no ha disminuido sustancialmente. Podemos enumerar algunas de sus razones:

1. Curvas de Aprendizaje nada despreciables: Herramientas como Terraform (o incluso Kubernetes) introducen sus propios lenguajes específicos de dominio (DSL) (interno, en el caso de Kubernetes, basado en YAML), y conceptos que sus usuarios deben aprender. Comprender las sutilezas de estos lenguajes puede ser tan desafiante como dominar un nuevo lenguaje de programación.

2. Características Específicas de la Plataforma: Aunque las herramientas de IaC intentan ser independientes de la plataforma, la realidad es que proveedores cloud como AWS, Azure, Google Cloud, etc... tienen servicios, configuraciones y peculiaridades únicas. Esto requiere un profundo conocimiento específico del proveedor cloud, lo que va en contra del objetivo de simplificación de las herramientas. Plataformas como Kubernetes tampoco se salvan de tratar con esta especificidad.

3. Servicios en la Nube en Evolución Constante: Los proveedores Cloud lanzan continuamente nuevos servicios y características. Mantenerse al día con estos cambios requiere aprendizaje constante y actualizaciones al código de infraestructura existente, añadiendo una carga adicional de mantenimiento.

4. Complejidad de los Sistemas Distribuidos: Los servicios basados en software son inherentemente aplicaciones distribuidas. Utilizan microservicios (posiblemente basados en contenedores), arquitecturas sin servidor o una combinación de ambas. Gestionar su ciclo de vida en la nube introduce capas adicionales de complejidad que las herramientas de IaC por sí solas no pueden abstraer (ni es su objetivo).

5. Gestión de Estado y Depuración: Manejar el estado de los recursos en la nube es una tarea no trivial. Herramientas como Terraform mantienen archivos de estado que pueden convertirse en fuentes de conflictos, llevando a problemas de despliegue difíciles de depurar.

Caso concreto I: Scripts de Terraform vs. Scripts Tradicionales

Consideremos la transición de scripts tradicionales a scripts de Terraform. Si bien Terraform proporciona una forma estructurada de definir recursos, los scripts pueden volverse extremadamente complejos en infraestructuras grandes. Módulos, variables y gráficos de dependencias intrincados pueden hacer que las configuraciones de Terraform sean tan difíciles de leer y mantener como los scripts que reemplazaron.

Además, errores en las configuraciones de Terraform pueden conducir a despliegues parciales o modificaciones no intencionadas de recursos, requiriendo una planificación cuidadosa y pruebas exhaustivas, prácticas que eran igualmente necesarias con los scripts tradicionales.

Caso concreto II: Kubernetes vs. Métodos de Implementación Tradicionales

Consideremos el auge de Kubernetes como la solución de facto para la orquestación de contenedores. Kubernetes promete simplificar la implementación, escalado y gestión de aplicaciones en contenedores. Sin embargo, esta simplificación aparente viene con su propio conjunto de complejidades.

• Configuraciones Complejas: Kubernetes utiliza archivos YAML para definir recursos como Pods, Servicios y Deployments. Estos archivos pueden volverse extremadamente detallados y difíciles de gestionar, especialmente en aplicaciones grandes con múltiples microservicios.

• Curva de Aprendizaje Pronunciada: Dominar Kubernetes requiere una comprensión profunda de conceptos como namespaces, ingress controllers, volúmenes persistentes y políticas de red. Esto puede ser abrumador para equipos que migran desde entornos tradicionales.

• Infraestructura Adicional: Para ejecutar Kubernetes, a menudo se necesita infraestructura adicional, como sistemas de almacenamiento distribuidos y soluciones de red avanzadas. Esto añade más capas que deben configurarse y mantenerse.

• Herramientas Complementarias Necesarias: La gestión efectiva de un clúster de Kubernetes a menudo requiere herramientas adicionales como Helm para la gestión de paquetes, Prometheus para monitorización y Grafana para visualización, cada una con sus propias complejidades. No sólo esto, configurar un clúster Kubernetes para dotarlo de funciones básicas (ie. ingress, networking, ...) requiere tener que elegir de entre un nutrido elenco de soluciones, cada una con sus pros y sus cons, así como sus propias complejidades de configuración y gestión.

• Depuración y Resolución de Problemas: Cuando algo sale mal en Kubernetes, identificar y resolver el problema puede ser significativamente más difícil debido a la naturaleza distribuida y dinámica del sistema.

En comparación con los métodos de implementación tradicionales, donde las aplicaciones se despliegan en servidores físicos o máquinas virtuales con configuraciones más estáticas, Kubernetes introduce un nivel de abstracción que, si bien es poderoso, también puede ser difícil de manejar sin la experiencia adecuada.

El Problema Subyacente

En el fondo, el problema es la complejidad inherente de los entornos en la nube. Las herramientas sólo pueden abstraer la complejidad hasta cierto punto. Mientras los servicios en la nube sigan siendo tan diversos y complejos como lo son, gestionarlos requerirá un esfuerzo y conocimiento significativos.

La consecuencia es que es necesario un buen grado de especialización para gestionar buena parte de las tareas de gestión de recursos que es preciso tener en cuenta no sólo a la hora de poner servicios en producción, sino también durante el proceso de desarrollo del software, creando un buen número de ineficiencias.

¿Qué Necesitamos Cambiar?

Para responder a esta pregunta, debemos clarificar cuales son (o deberían ser) nuestros objetivos. La IaC y sus herramientas tienen como objetivos simplificar (¿?) el proceso de aprovisionamiento de recursos y servicios en la nube. Sin embargo, podemos argumentar que esto no es realmente el objetivo último. El objetivo último debería ser doble:

1. Por una parte habilitar a los equipos de desarrollo el acceso transparente a aquellos recursos virtualizados que necesitan para apoyar su proceso de desarrollo.

2. Por otra parte, permitir la gestión ágil del ciclo de vida de los servicios basados en el software producido por esos equipos de desarrollo.

Es nuestro punto de vista que atender dichos objetivos sólo va a ser posible elevando el nivel de las abstracciones manejadas por desarrolladores y gestores de servicios de modo que la gestión de los recursos virtualizados se transparente gracias a la automatización que esos niveles de abstracción permiten.


Esta aproximación no es novedosa. Baste ver la evolución de los sistemas operativos modernos: el desarrollador no se preocupa de la gestión de los recursos existentes en el ordenador. Confía en el sistema operativo subyacente, y todos los actores que operan por encima del sistema operativo manejan un conjunto de abstracciones simples y a la vez potentes que les permiten ignorar totalmente la gestión de los recursos necesarios para las tareas de cómputo soportadas.


Esta es también la dirección tomada por sistemas que, como Kubernetes, introducen un alto grado de automatización, aunque en este caso a un precio de complejidad que, en nuestra opinión, genera sus propios problemas.


En conclusión, para lograr un progreso significativo, debemos poner el foco en la simplificación de las plataformas que ponemos a disposición de los equipos de desarrollo. La complejidad debe residir en la implementación de la plataforma, no en su uso, como frecuentemente sucede hoy en día. Solo cuando logremos que el acceso a la tecnología de la nube sea tan transparente como el acceso a la electricidad podremos constatar la dimensión de un auténtico progreso.


Es lo que se ha pretendido con Axebow simplificar el proceso de despliegue reduciendo la complejidad existente y descrita. Podéis probar el servicio SIN COSTE durante ellos meses de octubre y noviembre.

Saludos,

jueves, septiembre 12, 2019

Plugins para kubectl que te harán la vida más fácil al gestionar Kubernetes

Kubernetes y Docker están revolucionando el mundo de la informática, el desarrollo de aplicaciones y en concreto SecDevOps. Ambas tecnologías combinadas nos ofrecen beneficios como escalar y gestionar la implementación de una aplicación o un servicio de manera sencilla utilizando contenedores, hasta el punto de convertirse hoy día en un auténtico estándar para la orquestación. Como cualquier otra infraestructura, debemos tener precauciones a la hora de su implementación para intentar construirla de manera más segura posible, así como ofrecer el mejor rendimiento final.

Figura 1: Plugins para kubectl que te harán la vida más fácil al gestionar Kubernetes

Ya hemos hablado varias veces en este blog sobre cómo securizar Kubernetes (también de Docker y su seguridad, aunque en nuestro libro “Docker:SecDevOps” lo hacemos en profundidad), pero tampoco viene mal una ayuda extra a la hora de realizar este trabajo. Y es aquí donde los plugins de Kubernetes nos pueden echar una mano.

Figura 2: Libro Docker:SecDevOps de la editorial 0xWord

Existen multitud de plugins para kubectl para interactuar y realizar todo tipo de operaciones contra nuestro clúster. Todos sabéis que kubectl es la herramienta de línea de comandos para interactuar directamente con Kubernetes y ésta además, permite crear plugins a medida aumentando sus posibilidades añadiendo comandos ad-hoc a los ya existentes. En nuestro blog de CyberHades puedes encontrar un pequeño tutorial sobre cómo comenzar a escribirlos.

6+1 Plugins para Kubectl

Hemos seleccionado 6 + 1 plugins (este último no es exactamente un plugin) los cuales nos ofrecen diferentes características de seguridad y control para de esta forma hacer mucho más segura nuestra implementación con Kubernetes. Algunos están centrados por ejemplo en la seguridad de los pods, otros en RABC e incluso veremos uno que nos permitirá “esnifar” todo el tráfico de red generado hacia o desde un pod.

El primero de ellos se llama kubectl-trace. Este plugin nos permite utilizar bpftrace en un clúster Kubernetes. Gracias a bpftrace podemos crear, por ejemplo, tracepoints (puntos de control en la ejecución para gestionar su flujo o incluso parada del mismo) para poder detectar problemas y hacer un análisis en profundidad de la infraestructura (del mismo modo que se utilizan en C y AWK). Estos puntos de control se pueden establecer tanto en nodos como en pods. En este enlace puedes encontrar el manual completo de bpftrace.

Figura 3: Secuencia "tracepoint" del plugin kubectl-trace

El siguiente plugin se complementa perfectamente con kubectl-trace para tareas de debug y se llama precisamente kubctl-debug. Este nos permite ejecutar un contenedor dentro de un pod que se encuentre en ejecución. Comparte el espacio de nombres del procesos (pid), red, usuario e intercomunicación entre procesos (ipc) del contenedor a analizar, con lo que nos permite depurarlos sin tener que instalar nada de antemano. En este enlace puedes ver una demostración de su utilización.

Figura 4: Ejemplo de ejecución del plugin kubectl-debug

Este otro plugin llamado ksniff nos ofrece la posibilidad de analizar todo el tráfico de red de un pod de Kubernetes utilizando tcpdump y WireShark, todo ello con un impacto mínimo en la infraestructura.

Figura 5: Ejecución del plugin ksniff contra un pod del clúster

Ksniff utilizará los datos recopilados por tcpdump asociados a un pod y luego los enviará WireShark para realizar el análisis exhaustivo. Este plugin es imprescindible si estás trabajando con microservicios, ya que es tremendamente útil para identificar errores y problemas entre ellos, así como sus dependencias.

Figura 6: Volcado a WireShark de la inspección realizada con ksniff

A veces, sacar la información de un clúster de Kubernetes requiere de la utilización de varios comandos los cuales, a su vez, nos devuelven todo tipo de información. Gracias a este plugin llamado kubectl-dig, es posible instalar una UI (User Interface) más amigable para ver de una forma más sencilla toda la información relativa al clúster de Kubernetes.

Figura 7: Interfaz de Kubctl-dig

Sólo tenemos que pasar como parámetro el nombre del nodo y de esta forma obtendremos todo tipo de información detallada y formateada sobre el mismo.
NOTA: Los siguientes tres plugins de los que vamos a hablar a continuación, hemos querido probarlos nosotros mismos. Así que para ello, hemos utilizado la misma infraestructura que ya montamos en su día para nuestro artículo sobre la gestión de la autorización de recursos con RBAC.
El control de accesos a todos los elementos de un clúster Kubernetes es una de las principales tareas dentro de la securización del mismo. Desde kubectl es posible obtener esta información de un recurso, pero no es posible conseguir una vista general. Esto es precisamente de lo que se encarga rakkess, el cual nos permite obtener una lista completa en forma de matriz de la situación actual de los derechos de acceso entre los usuarios y todos los recursos del servidor. En el siguiente vídeo puedes ver una demostración de su funcionamiento:


Figura 8: Demo de kubectl-rakness

El plugin que viene a continuación llamado kubectl-who-can viene perfectamente complementado con el anterior. En este caso será posible mostrar quién tiene permisos RBAC para realizar cualquier tipo de acción en los diferentes recursos Kubernetes que tengamos instalados. En la salida de la ejecución de este plugin podremos ver un listado completo con información como el tipo de cuenta, recurso, etc. El siguiente vídeo muestra cómo funciona:


Figura 9: Demo de kubectl-who-can

Hemos dejado kubectl-auth-can-I para el final. Exactamente no es un plugin de kubectl sino un subcomando que es parte de dicha utilidad. Este nos permite identificar si un usuario puede ejecutar ciertas acciones sobre ciertos recursos. Las acciones vienen dadas por los verbos definidos en Kubernetes (list, create, get, watch, delete, etc) y los recursos podrían ser: pod, namespace, secret, configMap, logs, etc.


Figura 10: Demo de kubectl-auth-can-I

Además, no sólo podemos preguntar por las acciones que podemos ejecutar, sino también por las acciones que otros usuarios o cuentas de servicio pueden ejecutar. Nos parece muy interesante y también lo hemos querido probar. En el vídeo anterior puedes ver los resultados de la prueba que hemos realizado.

Un hasta pronto

Seguiremos echando un vistazo a los diferentes plugins que existan y que nos puedan servir de ayuda, tanto para securizar nuestro clúster Kubernetes como para ofrecer el mejor rendimiento posible a nuestra infraestructura.

Happy Hacking Hackers!

Autores:

Fran Ramírez, (@cyberhadesblog) es investigador de seguridad y miembro del equipo de Ideas Locas en CDO en Telefónica, co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps" y del blog Cyberhades.Para consultas y mensajes puedes utilizar el Buzón Público para contactar con Fran Ramírez

Rafael Troncoso (@tuxotron) es Senior Software Engineer en SAP Concur, co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps" y del blog Cyberhades. Para consultas y mensajes puedes utilizar el Buzón Público para contactar con Rafael Troncoso

Entrada destacada

Hacking IA: Jailbreak, Prompt Injection, Hallucinations & Unalignment. Nuestro nuevo libro en 0xWord

Pocas veces me ha hecho tanta ilusión que saliera un nuevo libro en 0xWord como con este libro de " Hacking IA: Jailbreak, Prompt Inje...

Entradas populares