Configure a terminação do TLS no gateway de entrada

Vista geral

Esta página demonstra como configurar uma terminação TLS no gateway de entrada na malha de serviços na nuvem para gerir o tráfego HTTPS externo para os seus serviços. Para uma introdução mais básica sobre como configurar gateways, consulte o guia de gateways. Vai saber como configurar o gateway para uma comunicação segura através de TLS, o que permite o acesso encriptado às suas aplicações. Este processo tira partido das capacidades da Cloud Service Mesh para expor serviços em segurança.

Antes de começar

Precisa dos seguintes recursos para concluir os passos neste documento:

  • Um cluster do Kubernetes com o Cloud Service Mesh instalado. Consulte o guia de instalação para ver detalhes sobre como instalar o Cloud Service Mesh.

Configure o seu ambiente

Execute os seguintes comandos a partir de uma estação de trabalho que possa aceder ao cluster que pretende usar. Certifique-se de que a ferramenta kubectl está configurada para usar o contexto do cluster específico do seu cluster.

  1. Defina as variáveis de ambiente.

    export CSM_INGRESSGATEWAY_NAMESPACE=CSM_INGRESSGATEWAY_NAMESPACE
    export CSM_INGRESSGATEWAY_DEPLOYMENT_NAME=CSM_INGRESSGATEWAY_DEPLOYMENT_NAME
    export CSM_INGRESSGATEWAY_SERVICE_NAME=CSM_INGRESSGATEWAY_SERVICE_NAME
    
  2. Implemente a aplicação foo no seu cluster. Instale-o com o seguinte YAML:

    apiVersion: v1
    kind: Service
    metadata:
      name: foo
      namespace: foo
    spec:
      selector:
        app: test-backend
      ports:
      - port: 8080
        targetPort: 8080
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: foo
      namespace: foo
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: test-backend
      template:
        metadata:
          labels:
            app: test-backend
        spec:
          containers:
          - name: whereami
            image: gcr.io/google-samples/whereami:v1.2.23
            ports:
            - containerPort: 8080
    EOF
    
  3. Gerar certificados e chaves.

    Para proteger o gateway de entrada, precisa de certificados e chaves TLS. Pode usar qualquer ferramenta de geração de certificados ou seguir estes passos com o openssl para criar as credenciais necessárias.

    • Crie um certificado e uma chave da CA de raiz
    mkdir example_certs
    openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=Example Corp/CN=example.com' \
      -keyout example.com.key -out example.com.crt
    
    • Gere um certificado e uma chave para a entrada
    openssl req -out foo.example.com.csr -newkey rsa:2048 -nodes \
      -keyout foo.example.com.key -subj "/CN=foo.example.com/O=Foo Org"
    
    openssl x509 -req -sha256 -days 365 -CA example.com.crt \
      -CAkey example.com.key -set_serial 0 \
      -in foo.example.com.csr -out foo.example.com.crt
    

Armazene o certificado TLS

Armazene o certificado TLS como um Secret.

  1. Crie o espaço de nomes. Este espaço de nomes é usado para implementar o gateway de entrada.

    kubectl create namespace ${CSM_INGRESSGATEWAY_NAMESPACE}
    
  2. Aplique a etiqueta de injeção predefinida ao espaço de nomes:

    kubectl label namespace ${CSM_INGRESSGATEWAY_NAMESPACE} \
        istio.io/rev- istio-injection=enabled --overwrite
    
  3. Armazene as credenciais TLS num secret do Kubernetes:

    kubectl create -n ${CSM_INGRESSGATEWAY_NAMESPACE} secret tls foo-credential \
      --key=example_certs/foo.example.com.key \
      --cert=example_certs/foo.example.com.crt
    

Aplique o certificado TLS a um gateway

Existem duas formas de fazer com que o gateway use o certificado TLS recém-criado.

Implementação com credenciais montadas (preferencial)

  1. Copie o manifesto do gateway de entrada predefinido para um ficheiro local.

    curl https://raw.githubusercontent.com/GoogleCloudPlatform/anthos-service-mesh-samples/main/docs/ingress-gateway-external-lb/ingress-gateway.yaml > ingress-gateway.yaml
    
  2. Altere a especificação de implementação no ingress-gateway.yaml para montar a credencial secreta do TLS.

    apiVersion: apps/v1
    kind: Deployment
    ...
    spec:
      ...
        spec:
            ...
            volumeMounts:
            - name: foo-credential # Add new volume mount specifying mount path.
              mountPath: /etc/secrets/foo-credential 
              readOnly: true
          volumes:
          - name: foo-credential # Point volume mount to the Kubernetes secret holding the TLS certificate and keys.
            secret:
              secretName: foo-credential
    

    Em seguida, crie os recursos relativos ao gateway de entrada.

    kubectl --namespace ${CSM_INGRESSGATEWAY_NAMESPACE} apply --filename ingress-gateway.yaml 
    
  3. Defina o gateway de entrada.

    Crie um recurso Gateway para processar o tráfego HTTPS na porta 443 que referencie os segredos montados:

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.istio.io/v1
    kind: Gateway
    metadata:
      name: secure-gateway
      namespace: ${CSM_INGRESSGATEWAY_NAMESPACE}
    spec:
      selector:
        app: asm-ingressgateway
        istio: ingressgateway
      servers:
      - port:
          number: 443
          name: https
          protocol: HTTPS
        tls:
          mode: SIMPLE
          serverCertificate: /etc/secrets/foo-credential/foo.example.com.crt
          privateKey: /etc/secrets/foo-credential/foo.example.com.key
        hosts:
        - "foo.example.com"
    EOF
    

Implementação sem credenciais montadas

  1. Aplique o ficheiro de manifesto da gateway de entrada.

    kubectl --namespace ${CSM_INGRESSGATEWAY_NAMESPACE} apply --filename https://raw.githubusercontent.com/GoogleCloudPlatform/anthos-service-mesh-samples/main/docs/ingress-gateway-external-lb/ingress-gateway.yaml
    

    Resultado esperado:

    serviceaccount/asm-ingressgateway created
    role.rbac.authorization.k8s.io/asm-ingressgateway created
    rolebinding.rbac.authorization.k8s.io/asm-ingressgateway created
    deployment.apps/asm-ingressgateway created
    service/asm-ingressgateway created
    poddisruptionbudget.policy/asm-ingressgateway created
    horizontalpodautoscaler.autoscaling/asm-ingressgateway created
    
  2. Defina o gateway de entrada.

    Crie um recurso Gateway para processar o tráfego HTTPS na porta 443:

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.istio.io/v1
    kind: Gateway
    metadata:
      name: secure-gateway
      namespace: ${CSM_INGRESSGATEWAY_NAMESPACE}
    spec:
      selector:
        app: asm-ingressgateway
        istio: ingressgateway
      servers:
      - port:
          number: 443
          name: https
          protocol: HTTPS
        tls:
          mode: SIMPLE
          credentialName: foo-credential
        hosts:
        - "foo.example.com"
    EOF
    

Otimizar a implementação

Se usar a implementação sem credenciais montadas, os pods do gateway de entrada verificam periodicamente se as credenciais estão atualizadas. Por predefinição, demora até 60 minutos. Para alterar a frequência de sondagem, defina as variáveis de ambiente CSM_MIN_K8S_SECRET_REFRESH_INTERVAL e CSM_MAX_K8S_SECRET_REFRESH_INTERVAL para a implementação dos pods do gateway de entrada.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: asm-ingressgateway
  ...
spec:
  ...
  template:
    ...
    spec:
      containers:
      - name: istio-proxy
        image: auto
        env:
        - name: CSM_MIN_K8S_SECRET_REFRESH_INTERVAL
          value: "15m" # Half of the default minimum interval
        - name: CSM_MAX_K8S_SECRET_REFRESH_INTERVAL
          value: "30m" # Half of the default maximum interval
      ...

Tráfego de teste

  1. Encaminhe o tráfego para o serviço foo.

    Defina um VirtualService para direcionar o tráfego para a implementação foo:

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.istio.io/v1
    kind: VirtualService
    metadata:
      name: foo-routing
      namespace: ${CSM_INGRESSGATEWAY_NAMESPACE}
    spec:
      hosts:
      - "foo.example.com"
      gateways:
      - secure-gateway
      http:
      - match:
        - uri:
            prefix: /status
        - uri:
            prefix: /delay
        route:
        - destination:
            host: foo
            port:
              number: 8080
    EOF
    
  2. Configure o balanceador de carga externo para estabelecer ligação ao gateway de entrada a partir do cluster.

  3. Teste a ligação segura.

    Use o seguinte comando curl para validar a configuração:

    export EXTERNAL_LB_IP_ADDRESS=EXTERNAL_LB_IP_ADDRESS
    curl -v -H "Host: foo.example.com" --resolve "foo.example.com:443:$EXTERNAL_LB_IP_ADDRESS" \
      --cacert example_certs/example.com.crt "https://foo.example.com:443/ping"
    

    Substitua EXTERNAL_LB_IP_ADDRESS pelo IP do balanceador de carga externo.

    O resultado é semelhante ao seguinte:

      {
        "cluster_name": "gke-us",
        "host_header": "34.120.175.141",
        "pod_name": "whereami-deployment-954cbf78-mtlpf",
        "pod_name_emoji": "😎",
        "project_id": "my-project",
        "timestamp": "2021-11-29T17:01:59",
        "zone": "us-central1-b"
      }
    

O que se segue?