Egress Gateways зі створенням TLS

Приклад створення TLS для вихідного трафіку показує, як налаштувати Istio для виконання створення TLS для трафіку до зовнішнього сервісу. Приклад Налаштування Egress Gateway показує, як налаштувати Istio для направлення вихідного трафіку через спеціалізований сервіс egress gateway. Цей приклад поєднує два попередні, описуючи, як налаштувати вихідний шлюз для виконання створення TLS для трафіку до зовнішніх сервісів.

Перш ніж почати

  • Налаштуйте Istio, дотримуючись інструкцій з Посібника з встановлення.

  • Розгорніть демонстраційний застосунок curl, щоб використовувати його як джерело для надсилання тестових запитів.

    Якщо у вас увімкнено автоматичну інʼєкцію sidecar, виконайте наступну команду, розгорніть застосунок curl:

    Zip
    $ kubectl apply -f @samples/curl/curl.yaml@

    В іншому випадку вам потрібно вручну виконати інʼєкцію sidecar перед розгортанням застосунку curl:

    Zip
    $ kubectl apply -f <(istioctl kube-inject -f @samples/curl/curl.yaml@)

    Зверніть увагу, що будь-який pod, з якого ви можете виконати exec та curl, підійде для подальших процедур.

  • Створіть змінну оболонки, яка буде містити ім’я вихідного пакунка для надсилання запитів до зовнішніх сервісів. Якщо ви використовували приклад curl, запустіть його:

    $ export SOURCE_POD=$(kubectl get pod -l app=curl -o jsonpath={.items..metadata.name})
  • Для користувачів macOS переконайтеся, що ви використовуєте openssl версії 1.1 або новішої:

    $ openssl version -a | grep OpenSSL
    OpenSSL 1.1.1g  21 Apr 2020

    Якщо попередня команда виведе версію 1.1 або новішу, як показано, ваша команда openssl має працювати правильно з інструкціями в цьому завданні. В іншому випадку, оновіть ваш openssl або спробуйте іншу реалізацію openssl, наприклад, на машині з Linux.

  • Увімкніть ведення журналу доступу Envoy якщо його ще не ввімкнено. Наприклад, за допомогою istioctl:

    $ istioctl install <flags-you-used-to-install-Istio> --set meshConfig.accessLogFile=/dev/stdout
  • Якщо ви НЕ використовуєте інструкції Gateway API, переконайтесь що ви розгорнули Istio egress gateway.

Виконання створення TLS за допомогою egress gateway

У цьому розділі описується, як виконати таке ж створення TLS, як у Прикладі створення TLS для вихідного трафіку, але цього разу використовуючи egress gateway. Зверніть увагу, що в цьому випадку створення TLS буде здійснено egress gateway, на відміну від попереднього прикладу, де це робив sidecar.

  1. Визначте ServiceEntry для edition.cnn.com:

    $ kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1
    kind: ServiceEntry
    metadata:
      name: cnn
    spec:
      hosts:
      - edition.cnn.com
      ports:
      - number: 80
        name: http
        protocol: HTTP
      - number: 443
        name: https
        protocol: HTTPS
      resolution: DNS
    EOF
  2. Переконайтеся, що ваш ServiceEntry було застосовано правильно, надіславши запит до http://edition.cnn.com/politics.

    $ kubectl exec "${SOURCE_POD}" -c curl -- curl -sSL -o /dev/null -D - http://edition.cnn.com/politics
    HTTP/1.1 301 Moved Permanently
    ...
    location: https://edition.cnn.com/politics
    ...

    Ваш ServiceEntry було налаштовано правильно, якщо у виводі ви побачите 301 Moved Permanently.

  3. Створіть вихідний Gateway для edition.cnn.com, порт 80, і правило призначення для додаткових запитів, які будуть спрямовані на egress gateway.

$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
  name: istio-egressgateway
spec:
  selector:
    istio: egressgateway
  servers:
  - port:
      number: 80
      name: https-port-for-tls-origination
      protocol: HTTPS
    hosts:
    - edition.cnn.com
    tls:
      mode: ISTIO_MUTUAL
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: egressgateway-for-cnn
spec:
  host: istio-egressgateway.istio-system.svc.cluster.local
  subsets:
  - name: cnn
    trafficPolicy:
      loadBalancer:
        simple: ROUND_ROBIN
      portLevelSettings:
      - port:
          number: 80
        tls:
          mode: ISTIO_MUTUAL
          sni: edition.cnn.com
EOF
  1. Налаштуйте правила маршруту, щоб спрямовувати трафік через egress gateway:
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: direct-cnn-through-egress-gateway
spec:
  hosts:
  - edition.cnn.com
  gateways:
  - istio-egressgateway
  - mesh
  http:
  - match:
    - gateways:
      - mesh
      port: 80
    route:
    - destination:
        host: istio-egressgateway.istio-system.svc.cluster.local
        subset: cnn
        port:
          number: 80
      weight: 100
  - match:
    - gateways:
      - istio-egressgateway
      port: 80
    route:
    - destination:
        host: edition.cnn.com
        port:
          number: 443
      weight: 100
EOF
  1. Визначте DestinationRule для створення TLS для запитів до edition.cnn.com:

    $ kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1
    kind: DestinationRule
    metadata:
      name: originate-tls-for-edition-cnn-com
    spec:
      host: edition.cnn.com
      trafficPolicy:
        loadBalancer:
          simple: ROUND_ROBIN
        portLevelSettings:
        - port:
            number: 443
          tls:
            mode: SIMPLE # initiates HTTPS for connections to edition.cnn.com
    EOF
  2. Надішліть HTTP-запит до [http://edition.cnn.com/politics] (https://edition.cnn.com/politics).

    $ kubectl exec "${SOURCE_POD}" -c curl -- curl -sSL -o /dev/null -D - http://edition.cnn.com/politics
    HTTP/1.1 200 OK
    ...

    The output should be the same as in the TLS Origination for Egress Traffic example, with TLS origination: without the 301 Moved Permanently message.

  3. Перевірте журнал проксі egress gateway.

Якщо Istio розгорнуто у просторі імен istio-system, команда для друку журналу буде такою:

$ kubectl logs -l istio=egressgateway -c istio-proxy -n istio-system | tail

Ви повинні побачити рядок, схожий на наступний:

[2020-06-30T16:17:56.763Z] "GET /politics HTTP/2" 200 - "-" "-" 0 1295938 529 89 "10.244.0.171" "curl/7.64.0" "cf76518d-3209-9ab7-a1d0-e6002728ef5b" "edition.cnn.com" "151.101.129.67:443" outbound|443||edition.cnn.com 10.244.0.170:54280 10.244.0.170:8080 10.244.0.171:35628 - -

Видалення прикладу створення TLS

Видаліть створені вами елементи конфігурації Istio:

$ kubectl delete gw istio-egressgateway
$ kubectl delete serviceentry cnn
$ kubectl delete virtualservice direct-cnn-through-egress-gateway
$ kubectl delete destinationrule originate-tls-for-edition-cnn-com
$ kubectl delete destinationrule egressgateway-for-cnn

Виконання створення взаємного TLS за допомогою egress gateway

Аналогічно до попереднього розділу, у цьому розділі описується, як налаштувати egress gateway для виконання створення TLS для зовнішнього сервісу, але цього разу з використанням сервісу, який потребує взаємного TLS.

Цей приклад є значно складнішим, оскільки спочатку потрібно:

  1. згенерувати сертифікати клієнта і сервера
  2. розгорнути зовнішній сервіс, який підтримує протокол взаємного TLS
  3. перезавантажити вихідний шлюз з потрібними сертифікатами взаємного TLS

Лише після цього можна налаштувати зовнішній трафік для проходження через вихідний шлюз, який виконає створення TLS.

Створення сертифікатів і ключів клієнта та сервера

Для цього завдання ви можете скористатися вашим улюбленим інструментом для генерації сертифікатів і ключів. У наведених нижче командах використовуються openssl

  1. Створіть кореневий сертифікат і приватний ключ для підписання сертифіката для ваших сервісів:

    $ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example.com.key -out example.com.crt
  2. Створіть сертифікат і приватний ключ для my-nginx.mesh-external.svc.cluster.local:

    $ openssl req -out my-nginx.mesh-external.svc.cluster.local.csr -newkey rsa:2048 -nodes -keyout my-nginx.mesh-external.svc.cluster.local.key -subj "/CN=my-nginx.mesh-external.svc.cluster.local/O=some organization"
    $ openssl x509 -req -sha256 -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in my-nginx.mesh-external.svc.cluster.local.csr -out my-nginx.mesh-external.svc.cluster.local.crt

    За бажанням ви можете додати SubjectAltNames до сертифіката, якщо хочете увімкнути перевірку SAN для місця призначення. Наприклад:

    $ cat > san.conf <<EOF
    [req]
    distinguished_name = req_distinguished_name
    req_extensions = v3_req
    x509_extensions = v3_req
    prompt = no
    [req_distinguished_name]
    countryName = US
    [v3_req]
    keyUsage = critical, digitalSignature, keyEncipherment
    extendedKeyUsage = serverAuth, clientAuth
    basicConstraints = critical, CA:FALSE
    subjectAltName = critical, @alt_names
    [alt_names]
    DNS = my-nginx.mesh-external.svc.cluster.local
    EOF
    $
    $ openssl req -out my-nginx.mesh-external.svc.cluster.local.csr -newkey rsa:4096 -nodes -keyout my-nginx.mesh-external.svc.cluster.local.key -subj "/CN=my-nginx.mesh-external.svc.cluster.local/O=some organization" -config san.conf
    $ openssl x509 -req -sha256 -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in my-nginx.mesh-external.svc.cluster.local.csr -out my-nginx.mesh-external.svc.cluster.local.crt -extfile san.conf -extensions v3_req
  3. Згенеруйте клієнтський сертифікат і приватний ключ:

    $ openssl req -out client.example.com.csr -newkey rsa:2048 -nodes -keyout client.example.com.key -subj "/CN=client.example.com/O=client organization"
    $ openssl x509 -req -sha256 -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 1 -in client.example.com.csr -out client.example.com.crt

Розгортання сервера взаємного TLS

Щоб змоделювати реальний зовнішній сервіс, який підтримує протокол взаємного TLS, розгорніть сервер NGINX у вашому кластері Kubernetes, але розмістіть його поза межами сервісної мережі Istio, тобто в просторі імен, де не включена інʼєкція sidecar проксі Istio.

  1. Створіть простір імен для представлення сервісів поза межами мережі Istio, а саме mesh-external. Зауважте, що sidecar проксі не буде автоматично додано до podsʼів у цьому просторі імен, оскільки автоматичне додавання sidecar не було увімкнено.

    $ kubectl create namespace mesh-external
  2. Створіть Kubernetes [Secrets] (https://kubernetes.io/docs/concepts/configuration/secret/) для зберігання сертифікатів сервера та центру сертифікації.

    $ kubectl create -n mesh-external secret tls nginx-server-certs --key my-nginx.mesh-external.svc.cluster.local.key --cert my-nginx.mesh-external.svc.cluster.local.crt
    $ kubectl create -n mesh-external secret generic nginx-ca-certs --from-file=example.com.crt
  3. Створіть конфігураційний файл для сервера NGINX:

    $ cat <<\EOF > ./nginx.conf
    events {
    }
    
    http {
      log_format main '$remote_addr - $remote_user [$time_local]  $status '
      '"$request" $body_bytes_sent "$http_referer" '
      '"$http_user_agent" "$http_x_forwarded_for"';
      access_log /var/log/nginx/access.log main;
      error_log  /var/log/nginx/error.log;
    
      server {
        listen 443 ssl;
    
        root /usr/share/nginx/html;
        index index.html;
    
        server_name my-nginx.mesh-external.svc.cluster.local;
        ssl_certificate /etc/nginx-server-certs/tls.crt;
        ssl_certificate_key /etc/nginx-server-certs/tls.key;
        ssl_client_certificate /etc/nginx-ca-certs/example.com.crt;
        ssl_verify_client on;
      }
    }
    EOF
  4. Створіть Kubernetes ConfigMap для зберігання конфігурації сервера NGINX:

    $ kubectl create configmap nginx-configmap -n mesh-external --from-file=nginx.conf=./nginx.conf
  5. Розгорніть сервер the NGINX:

    $ kubectl apply -f - <<EOF
    apiVersion: v1
    kind: Service
    metadata:
      name: my-nginx
      namespace: mesh-external
      labels:
        run: my-nginx
    spec:
      ports:
      - port: 443
        protocol: TCP
      selector:
        run: my-nginx
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-nginx
      namespace: mesh-external
    spec:
      selector:
        matchLabels:
          run: my-nginx
      replicas: 1
      template:
        metadata:
          labels:
            run: my-nginx
        spec:
          containers:
          - name: my-nginx
            image: nginx
            ports:
            - containerPort: 443
            volumeMounts:
            - name: nginx-config
              mountPath: /etc/nginx
              readOnly: true
            - name: nginx-server-certs
              mountPath: /etc/nginx-server-certs
              readOnly: true
            - name: nginx-ca-certs
              mountPath: /etc/nginx-ca-certs
              readOnly: true
          volumes:
          - name: nginx-config
            configMap:
              name: nginx-configmap
          - name: nginx-server-certs
            secret:
              secretName: nginx-server-certs
          - name: nginx-ca-certs
            secret:
              secretName: nginx-ca-certs
    EOF

Налаштування створення взаємного TLS для вихідного трафіку

  1. Створіть Secret у тому ж просторі імен, де розгорнуто egress gateway, для зберігання сертифікатів клієнта:
$ kubectl create secret -n istio-system generic client-credential --from-file=tls.key=client.example.com.key \
  --from-file=tls.crt=client.example.com.crt --from-file=ca.crt=example.com.crt

Для підтримки інтеграції з різними інструментами, Istio підтримує кілька різних форматів секретів. У цьому прикладі використовується один загальний Secret з ключами tls.key, tls.crt і ca.crt.

  1. Створіть вихідний Gateway для my-nginx.mesh-external.svc.cluster.local, порт 443 і правило призначення для sidecar запитів, які будуть спрямовані на вихідний шлюз:
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
  name: istio-egressgateway
spec:
  selector:
    istio: egressgateway
  servers:
  - port:
      number: 443
      name: https
      protocol: HTTPS
    hosts:
    - my-nginx.mesh-external.svc.cluster.local
    tls:
      mode: ISTIO_MUTUAL
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: egressgateway-for-nginx
spec:
  host: istio-egressgateway.istio-system.svc.cluster.local
  subsets:
  - name: nginx
    trafficPolicy:
      loadBalancer:
        simple: ROUND_ROBIN
      portLevelSettings:
      - port:
          number: 443
        tls:
          mode: ISTIO_MUTUAL
          sni: my-nginx.mesh-external.svc.cluster.local
EOF
  1. Налаштуйте правила маршруту, щоб спрямовувати трафік через egress gateway:
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: direct-nginx-through-egress-gateway
spec:
  hosts:
  - my-nginx.mesh-external.svc.cluster.local
  gateways:
  - istio-egressgateway
  - mesh
  http:
  - match:
    - gateways:
      - mesh
      port: 80
    route:
    - destination:
        host: istio-egressgateway.istio-system.svc.cluster.local
        subset: nginx
        port:
          number: 443
      weight: 100
  - match:
    - gateways:
      - istio-egressgateway
      port: 443
    route:
    - destination:
        host: my-nginx.mesh-external.svc.cluster.local
        port:
          number: 443
      weight: 100
EOF
  1. Додайте DestinationRule для виконання створення взаємного TLS:
$ kubectl apply -n istio-system -f - <<EOF
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: originate-mtls-for-nginx
spec:
  host: my-nginx.mesh-external.svc.cluster.local
  trafficPolicy:
    loadBalancer:
      simple: ROUND_ROBIN
    portLevelSettings:
    - port:
        number: 443
      tls:
        mode: MUTUAL
        credentialName: client-credential # має збігатися з секретом, створеним раніше для зберігання клієнтських сертифікатів
        sni: my-nginx.mesh-external.svc.cluster.local
        # subjectAltNames: # можна ввімкнути, якщо сертифікат було згенеровано за допомогою SAN, як зазначено в попередньому розділі
        # - my-nginx.mesh-external.svc.cluster.local
EOF
  1. Переконайтеся, що облікові дані передано на вихідний шлюз і вони активні:
$ istioctl -n istio-system proxy-config secret deploy/istio-egressgateway | grep client-credential
kubernetes://client-credential            Cert Chain     ACTIVE     true           1                                          2024-06-04T12:46:28Z     2023-06-05T12:46:28Z
kubernetes://client-credential-cacert     Cert Chain     ACTIVE     true           16491643791048004260                       2024-06-04T12:46:28Z     2023-06-05T12:46:28Z
  1. Надішліть HTTP-запит на адресу http://my-nginx.mesh-external.svc.cluster.local:

    $ kubectl exec "$(kubectl get pod -l app=curl -o jsonpath={.items..metadata.name})" -c curl -- curl -sS http://my-nginx.mesh-external.svc.cluster.local
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    ...
  2. Перевірте журнал проксі egress gateway:

Якщо Istio розгорнуто у просторі імен istio-system, команда для друку журналу буде такою:

$ kubectl logs -l istio=egressgateway -n istio-system | grep 'my-nginx.mesh-external.svc.cluster.local' | grep HTTP

Ви повинні побачити рядок, схожий на наступний:

[2018-08-19T18:20:40.096Z] "GET / HTTP/1.1" 200 - 0 612 7 5 "172.30.146.114" "curl/7.35.0" "b942b587-fac2-9756-8ec6-303561356204" "my-nginx.mesh-external.svc.cluster.local" "172.21.72.197:443"

Вилучення прикладу створення взаємного TLS

  1. Видаліть ресурси сервера взаємного TLS NGINX:

    $ kubectl delete secret nginx-server-certs nginx-ca-certs -n mesh-external
    $ kubectl delete configmap nginx-configmap -n mesh-external
    $ kubectl delete service my-nginx -n mesh-external
    $ kubectl delete deployment my-nginx -n mesh-external
    $ kubectl delete namespace mesh-external
  2. Видаліть ресурси конфігурації шлюзу:

$ kubectl delete secret client-credential -n istio-system
$ kubectl delete gw istio-egressgateway
$ kubectl delete virtualservice direct-nginx-through-egress-gateway
$ kubectl delete destinationrule -n istio-system originate-mtls-for-nginx
$ kubectl delete destinationrule egressgateway-for-nginx
  1. Видаліть сертифікати та приватні ключі:

    $ rm example.com.crt example.com.key my-nginx.mesh-external.svc.cluster.local.crt my-nginx.mesh-external.svc.cluster.local.key my-nginx.mesh-external.svc.cluster.local.csr client.example.com.crt client.example.com.csr client.example.com.key
  2. Видаліть згенеровані конфігураційні файли, використані у цьому прикладі:

    $ rm ./nginx.conf

Очищення

Видаліть сервіс та розгортання curl:

Zip
$ kubectl delete -f @samples/curl/curl.yaml@
Чи була ця інформація корисною?
Чи є у вас пропозиції щодо покращення?

Дякуємо за ваш відгук!