Cloud Service Mesh con el ejemplo mTLS


En Cloud Service Mesh 1.5 y versiones posteriores, la TLS mutua automática (mTLS automática) está habilitada de forma predeterminada. Con la mTLS automática, un proxy de sidecar de cliente detecta si el servidor tiene un sidecar de forma automática. El sidecar del cliente envía mTLS a las cargas de trabajo con sidecars y envía el texto simple a las cargas de trabajo sin sidecars. Sin embargo, ten en cuenta que los servicios aceptan el texto simple y el tráfico mTLS. A medida que inyectes proxies de sidecar a tus Pods, recomendamos que también configures tus servicios para que solo acepten tráfico mTLS.

Con Cloud Service Mesh, puedes aplicar un solo archivo YAML para aplicar mTLS fuera del código de tu aplicación. Cloud Service Mesh te brinda la flexibilidad para aplicar una política de autenticación a toda la malla de servicios, a un espacio de nombres o a una carga de trabajo individual.

mTLS mutua

Costos

En este documento, usarás los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios.

Es posible que los usuarios Google Cloud nuevos cumplan con los requisitos para obtener una prueba gratuita.

Cuando completes el instructivo puedes borrar los recursos que hayas creado para evitar que se te sigan cobrando. Para obtener más información, consulta Cómo realizar una limpieza.

Antes de comenzar

Implementa una puerta de enlace de entrada

  1. Establece el contexto actual para kubectl en el clúster:

    gcloud container clusters get-credentials CLUSTER_NAME  \
    --project=PROJECT_ID \
    --zone=CLUSTER_LOCATION 
    
  2. Crea un espacio de nombres para tu puerta de enlace de entrada:

    kubectl create namespace asm-ingress
    
  3. Habilita el espacio de nombres para la inserción. Los pasos dependen de tu implementación del plano de control.

    Administrada (TD)

    Aplica la etiqueta de inserción predeterminada al espacio de nombres:

    kubectl label namespace asm-ingress \
        istio.io/rev- istio-injection=enabled --overwrite
    

    Administrada (Istiod)

    Recomendación: Ejecuta el siguiente comando para aplicar la etiqueta de inserción predeterminada al espacio de nombres:

      kubectl label namespace asm-ingress \
          istio.io/rev- istio-injection=enabled --overwrite
    

    Si ya eres usuario del plano de control de Istiod administrado, te recomendamos que uses la inserción predeterminada, pero también se admite la inserción basada en revisiones. Sigue estas instrucciones:

    1. Ejecuta el siguiente comando para ubicar los canales de versiones disponibles:

      kubectl -n istio-system get controlplanerevision
      

      El resultado es similar a este:

      NAME                AGE
      asm-managed-rapid   6d7h
      

      En el resultado, el valor en la columna NAME es la etiqueta de revisión que corresponde al canal de versiones disponible para la versión de Cloud Service Mesh.

    2. Aplica la etiqueta de revisión al espacio de nombres:

      kubectl label namespace asm-ingress \
          istio-injection- istio.io/rev=REVISION_LABEL --overwrite
      
  4. Implementa la puerta de enlace de ejemplo en el repositorio anthos-service-mesh-samples:

    kubectl apply -n asm-ingress \
    -f docs/shared/asm-ingress-gateway
    

    Resultado esperado:

    serviceaccount/asm-ingressgateway configured
    service/asm-ingressgateway configured
    deployment.apps/asm-ingressgateway configured
    gateway.networking.istio.io/asm-ingressgateway configured
    

Implementa la aplicación de muestra de Online Boutique.

  1. Si no lo hiciste, establece el contexto actual para kubectl en el clúster:

      gcloud container clusters get-credentials CLUSTER_NAME  \
        --project=PROJECT_ID \
        --zone=CLUSTER_LOCATION 
    
  2. Crea el espacio de nombres para la aplicación de ejemplo:

      kubectl create namespace onlineboutique
    
  3. Etiqueta el espacio de nombres onlineboutique para insertar de forma automática los proxies de Envoy. Sigue los pasos para habilitar la inserción automática de sidecar.

  4. Implementa la app de ejemplo, el VirtualService para el frontend y las cuentas de servicio para las cargas de trabajo. En este instructivo, implementarás Online Boutique, una app de demo de microservicios.

      kubectl apply \
      -n onlineboutique \
      -f docs/shared/online-boutique/virtual-service.yaml
      kubectl apply \
      -n onlineboutique \
      -f docs/shared/online-boutique/service-accounts
    

Cómo ver tus servicios

  1. Visualiza los Pods en el espacio de nombres onlineboutique:

    kubectl get pods -n onlineboutique
    

    Resultado esperado:

    NAME                                     READY   STATUS    RESTARTS   AGE
    adservice-85598d856b-m84m6               2/2     Running   0          2m7s
    cartservice-c77f6b866-m67vd              2/2     Running   0          2m8s
    checkoutservice-654c47f4b6-hqtqr         2/2     Running   0          2m10s
    currencyservice-59bc889674-jhk8z         2/2     Running   0          2m8s
    emailservice-5b9fff7cb8-8nqwz            2/2     Running   0          2m10s
    frontend-77b88cc7cb-mr4rp                2/2     Running   0          2m9s
    loadgenerator-6958f5bc8b-55q7w           2/2     Running   0          2m8s
    paymentservice-68dd9755bb-2jmb7          2/2     Running   0          2m9s
    productcatalogservice-84f95c95ff-c5kl6   2/2     Running   0          114s
    recommendationservice-64dc9dfbc8-xfs2t   2/2     Running   0          2m9s
    redis-cart-5b569cd47-cc2qd               2/2     Running   0          2m7s
    shippingservice-5488d5b6cb-lfhtt         2/2     Running   0          2m7s
    

    Todos los Pods de tu aplicación deben estar en funcionamiento, con un 2/2 en la columna READY. Esto indica que los Pods tienen un proxy de sidecar de Envoy insertado de forma correcta. Si no aparece 2/2 después de un par de minutos, consulta la Guía de solución de problemas.

  2. Obtén la IP externa y configúrala en una variable:

    kubectl get services -n asm-ingress
    export FRONTEND_IP=$(kubectl --namespace asm-ingress \
    get service --output jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}' \
    )
    

    Verás un resultado similar al siguiente:

    NAME                   TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                                      AGE
    asm-ingressgateway   LoadBalancer   10.19.247.233   35.239.7.64   80:31380/TCP,443:31390/TCP,31400:31400/TCP   27m
    
    
  3. Visita la dirección EXTERNAL-IP en tu navegador web. Deberías ver la tienda Online Boutique en tu navegador.

    Frontend de la boutique en línea

Crea un pod de TestCurl

Crea un pod TestCurl para enviar tráfico de texto sin formato para las pruebas.

  apiVersion: v1
  kind: Pod
  metadata:
    name: testcurl
    namespace: default
    annotations:
      sidecar.istio.io/inject: "false"
  spec:
    containers:
    - name: curl
      image: curlimages/curl
      command: ["sleep", "600"]

Accede a Online Boutique

  1. Configura el contexto actual de kubectl en el clúster en el que implementaste Online Boutique:

    gcloud container clusters get-credentials CLUSTER_NAME  \
        --project=PROJECT_ID \
        --zone=CLUSTER_LOCATION 
    
  2. Enumera los servicios en el espacio de nombres frontend:

    kubectl get services -n frontend
    

    Ten en cuenta que frontend-external es un LoadBalancer y que tiene una dirección IP externa. La aplicación de muestra incluye un servicio que es un balanceador de cargas para que se pueda implementar en GKE sin Cloud Service Mesh.

  3. Visita la aplicación en tu navegador con la dirección IP externa del servicio frontend-external:

    http://FRONTEND_EXTERNAL_IP/
    
  4. Cloud Service Mesh te permite implementar una puerta de enlace de entrada. También puedes acceder a Online Boutique con la dirección IP externa de la puerta de enlace de entrada. Obtenga la IP externa de la aplicación. Reemplaza los marcadores de posición por la siguiente información:

    • GATEWAY_SERVICE_NAME: El nombre del servicio de puerta de enlace de entrada. Si implementaste la puerta de enlace de muestra sin modificación o si implementaste la puerta de enlace de entrada predeterminada, el nombre será istio-ingressgateway.
    • GATEWAY_NAMESPACE: Es el espacio de nombres en el que implementaste la puerta de enlace de entrada. Si implementaste la puerta de enlace de entrada predeterminada, el espacio de nombres es istio-system.
    kubectl get service GATEWAY_NAME -n GATEWAY_NAMESPACE
    
  5. Abre otra pestaña en tu navegador y visita la aplicación con la dirección IP externa de la puerta de enlace de entrada:

    http://INGRESS_GATEWAY_EXTERNAL_IP/
    
  6. Ejecuta el siguiente comando para curl el servicio frontend con HTTP simple desde otro pod. Debido a que los servicios están en diferentes espacios de nombres, debes aplicar curl el nombre de DNS del servicio frontend.

    kubectl debug --image istio/base --target istio-proxy -it \
      $(kubectl get pod -l app=productcatalogservice -n product-catalog -o jsonpath={.items..metadata.name}) \
      -n product-catalog -- \
      curl http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    Tu solicitud se ejecuta de forma correcta con el estado 200, porque, de forma predeterminada, se aceptan el tráfico de texto simple y el TLS.

Habilita TLS mutua por espacio de nombres

Aplica una política PeerAuthentication con kubectl para implementar mTLS.

  1. Guarda la siguiente política de autenticación como mtls-namespace.yaml.

    cat <<EOF > mtls-namespace.yaml
    apiVersion: "security.istio.io/v1beta1"
    kind: "PeerAuthentication"
    metadata:
      name: "namespace-policy"
    spec:
      mtls:
        mode: STRICT
    EOF
    

    La línea mode: STRICT en el YAML configura los servicios para que solo se acepten mTLS. De forma predeterminada, el mode es PERMISSIVE, y configura los servicios para que acepten textos simples y mTLS.

  2. Aplica la política de autenticación a fin de configurar todos los servicios de Online Boutique para que solo acepten mTLS:

    for ns in ad cart checkout currency email frontend loadgenerator \
         payment product-catalog recommendation shipping; do
    kubectl apply -n $ns -f mtls-namespace.yaml
    done
    

    Resultado esperado:

    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created

  3. Ve a la pestaña de tu navegador que accede a Online Boutique mediante la dirección IP externa del servicio frontend-external:

    http://FRONTEND_EXTERNAL_IP/
    
  4. Actualiza la página. El navegador muestra el siguiente error:

    No se puede acceder al sitio

    La actualización de la página hace que el texto simple se envíe al servicio frontend. Debido a la política de autenticación STRICT, el proxy de sidecar bloquea la solicitud al servicio.

  5. Ve a la pestaña de tu navegador que accede a Online Boutique con la dirección IP externa de istio-ingressgateway y actualiza la página, que se muestra de forma correcta. Cuando accedes a Online Boutique mediante la puerta de enlace de entrada, la solicitud toma la siguiente ruta:

    mTLS mutua

    Flujo de autenticación mTLS:

    1. El navegador envía una solicitud HTTP de texto simple al servidor.
    2. El contenedor del proxy de la puerta de enlace de entrada intercepta la solicitud.
    3. El proxy de la puerta de enlace de entrada realiza un protocolo de enlace TLS con el proxy del servidor (en este ejemplo, el servicio de frontend). Este protocolo de enlace incluye un intercambio de certificados. Cloud Service Mesh precarga estos certificados en los contenedores del proxy.
    4. El proxy de la puerta de enlace de entrada realiza una verificación de nombres segura en el certificado del servidor para corroborar que una identidad autorizada esté ejecutando el servidor.
    5. Los proxies de la puerta de enlace de entrada y del servidor establecen una conexión TLS mutua y el proxy del servidor reenvía la solicitud al contenedor de la aplicación del servidor (el servicio de frontend).
  6. Ejecuta el siguiente comando para curl el servicio frontend con HTTP simple desde otro pod.

    kubectl exec testcurl -n default -- curl \
      http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    Tu solicitud falla porque enviamos tráfico de texto sin formato desde una carga de trabajo sin sidecar en la que se aplica la política STRICT de peerAuthentication.

Encuentra y borra políticas de autenticación

  1. Para obtener una lista de todas las políticas de PeerAuthentication en la malla de servicios, haz lo siguiente:

    kubectl get peerauthentication --all-namespaces
    

    El resultado es similar a este:

    NAMESPACE         NAME               MODE     AGE
    ad                namespace-policy   STRICT   17m
    cart              namespace-policy   STRICT   17m
    checkout          namespace-policy   STRICT   17m
    currency          namespace-policy   STRICT   17m
    email             namespace-policy   STRICT   17m
    frontend          namespace-policy   STRICT   17m
    loadgenerator     namespace-policy   STRICT   17m
    payment           namespace-policy   STRICT   17m
    product-catalog   namespace-policy   STRICT   17m
    recommendation    namespace-policy   STRICT   17m
    shipping          namespace-policy   STRICT   17m
    
  2. Borra la política de autenticación de todos los espacios de nombres de Online Boutique:

    for ns in ad cart checkout currency email frontend loadgenerator payment \
      product-catalog recommendation shipping; do
        kubectl delete peerauthentication -n $ns namespace-policy
    done;
    

    Resultado esperado:

    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    
  3. Accede a Online Boutique con la dirección IP externa del servicio frontend-external y actualiza la página. La página debe mostrarse como se espera.

  4. Ejecuta el siguiente comando para curl el servicio frontend con HTTP simple desde otro pod.

    kubectl debug --image istio/base --target istio-proxy -it \
      $(kubectl get pod -l app=productcatalogservice -n product-catalog -o jsonpath={.items..metadata.name}) \
      -n product-catalog -- \
      curl http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    Tu solicitud se ejecuta de forma correcta con el estado 200, porque, de forma predeterminada, se aceptan el tráfico de texto simple y el TLS.

Si actualizas la página en la consola de Google Cloud que muestra la listaCargas de trabajo, ahora aparece que el estado de mTLS es Permissive.

Habilita TLS mutua por carga de trabajo

Si quieres configurar una política PeerAuthentication para una carga de trabajo específica, debes configurar la sección selector y especificar las etiquetas que coincidan con la carga de trabajo deseada. Sin embargo, Cloud Service Mesh no puede agregar políticas a nivel de las cargas de trabajo para el tráfico mTLS saliente a un servicio. Debes configurar una regla de destino para administrar ese comportamiento.

  1. Aplica una política de autenticación a una carga de trabajo específica. Observa cómo la siguiente política usa etiquetas y selectores para orientar la implementación específica de frontend.

    cat <<EOF | kubectl apply -n frontend -f -
    apiVersion: "security.istio.io/v1beta1"
    kind: "PeerAuthentication"
    metadata:
      name: "frontend"
      namespace: "frontend"
    spec:
      selector:
        matchLabels:
          app: frontend
      mtls:
        mode: STRICT
    EOF
    

    Resultado esperado:

    peerauthentication.security.istio.io/frontend created
  2. Configura una regla de destino que coincida.

    cat <<EOF | kubectl apply -n frontend -f -
    apiVersion: "networking.istio.io/v1alpha3"
    kind: "DestinationRule"
    metadata:
      name: "frontend"
    spec:
      host: "frontend.demo.svc.cluster.local"
      trafficPolicy:
        tls:
          mode: ISTIO_MUTUAL
    EOF
    

    Resultado esperado:

    destinationrule.networking.istio.io/frontend created
  3. Accede a Online Boutique con la dirección IP externa del servicio frontend-external y actualiza la página. No se muestra la página porque frontend service se configuró como STRICT mTLS y el proxy de sidecar bloquea la solicitud.

  4. Ejecuta el siguiente comando para curl el servicio frontend con HTTP simple desde otro pod.

    kubectl exec testcurl -n default -- curl \
      http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    Tu solicitud falla porque enviamos tráfico de texto sin formato desde una carga de trabajo sin sidecar en la que se aplica la política STRICT de peerAuthentication.

  5. Borra la política de autenticación:

    kubectl delete peerauthentication -n frontend frontend
    

    Resultado esperado:

    peerauthentication.security.istio.io "frontend" deleted
    
  6. Borra la regla de destino:

    kubectl delete destinationrule -n frontend frontend
    

    Resultado esperado:

    destinationrule.networking.istio.io "frontend" deleted
    

Aplica la mTLS en toda la malla

Para evitar que todos tus servicios de la malla acepten tráfico de texto simple, establece una política PeerAuthentication en toda la malla con el modo mTLS establecido en STRICT. La política PeerAuthentication de toda la malla no debe tener un selector y se debe aplicar en el espacio de nombres raíz, istio-system. Cuando implementas la política, el plano de control aprovisiona automáticamente certificados TLS para que las cargas de trabajo se puedan autenticar entre sí.

  1. Aplica la mTLS en toda la malla:

    kubectl apply -f - <<EOF
    apiVersion: "security.istio.io/v1beta1"
    kind: "PeerAuthentication"
    metadata:
      name: "mesh-wide"
      namespace: "istio-system"
    spec:
      mtls:
        mode: STRICT
    EOF
    

    Resultado esperado:

    peerauthentication.security.istio.io/mesh-wide created

  2. Accede a Online Boutique con la dirección IP externa del servicio frontend-external y actualiza la página. No se muestra la página.

  3. Ejecuta el siguiente comando para curl el servicio frontend con HTTP simple desde otro pod.

    kubectl exec testcurl -n default -- curl \
      http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    Tu solicitud falla porque enviamos tráfico de texto sin formato desde una carga de trabajo sin sidecar en la que se aplica la política STRICT de peerAuthentication.

  4. Borra la política mesh-wide:

    kubectl delete peerauthentication -n istio-system mesh-wide
    

    Resultado esperado:

    peerauthentication.security.istio.io "mesh-wide" deleted
    

Limpia

Para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos usados en este instructivo, borra el proyecto que contiene los recursos o conserva el proyecto y borra los recursos individuales.

  • Si deseas evitar cargos adicionales, borra el clúster:

    gcloud container clusters delete  CLUSTER_NAME  \
        --project=PROJECT_ID \
        --zone=CLUSTER_LOCATION 
    
  • Si deseas conservar el clúster y quitar la muestra de Online Retail, realiza la siguiente acción:

    1. Borra los espacios de nombres de la aplicación:
      kubectl delete -f online-boutique/kubernetes-manifests/namespaces
    

    Resultado esperado:

    namespace "ad" deleted
    namespace "cart" deleted
    namespace "checkout" deleted
    namespace "currency" deleted
    namespace "email" deleted
    namespace "frontend" deleted
    namespace "loadgenerator" deleted
    namespace "payment" deleted
    namespace "product-catalog" deleted
    namespace "recommendation" deleted
    namespace "shipping" deleted
    
    1. Borra las entradas de servicio:
      kubectl delete -f online-boutique/istio-manifests/allow-egress-googleapis.yaml
    

    Resultado esperado:

    serviceentry.networking.istio.io "allow-egress-googleapis" deleted
    serviceentry.networking.istio.io "allow-egress-google-metadata" deleted
    

¿Qué sigue?