Захист Gateways

Завдання Контроль вхідного трафіку описує, як налаштувати ingress gateway, щоб відкрити HTTP-сервіс для зовнішнього трафіку. Це завдання показує, як експонувати захищений HTTPS-сервіс за допомогою простого або взаємного TLS.

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

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

  • Запустіть httpbin:

    Zip
    $ kubectl apply -f samples/httpbin/httpbin.yaml
  • Для користувачів macOS переконайтеся, що ви використовуєте curl, скомпільований з бібліотекою LibreSSL:

    $ curl --version | grep LibreSSL
    curl 7.54.0 (x86_64-apple-darwin17.0) libcurl/7.54.0 LibreSSL/2.0.20 zlib/1.2.11 nghttp2/1.24.0

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

Генерація сертифікатів та ключів для клієнта і сервера

Це завдання вимагає кілька наборів сертифікатів та ключів, які використовуються в наведених нижче прикладах. Ви можете скористатися улюбленим інструментом для їх створення або скористатися командами нижче для генерації за допомогою openssl.

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

    $ mkdir example_certs1 $ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example_certs1/example.com.key -out example_certs1/example.com.crt
  2. Згенеруйте сертифікат та приватний ключ для httpbin.example.com:

    $ openssl req -out example_certs1/httpbin.example.com.csr -newkey rsa:2048 -nodes -keyout example_certs1/httpbin.example.com.key -subj "/CN=httpbin.example.com/O=httpbin organization" $ openssl x509 -req -sha256 -days 365 -CA example_certs1/example.com.crt -CAkey example_certs1/example.com.key -set_serial 0 -in example_certs1/httpbin.example.com.csr -out example_certs1/httpbin.example.com.crt
  3. Створіть другий набір таких самих сертифікатів та ключів:

    $ mkdir example_certs2 $ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example_certs2/example.com.key -out example_certs2/example.com.crt $ openssl req -out example_certs2/httpbin.example.com.csr -newkey rsa:2048 -nodes -keyout example_certs2/httpbin.example.com.key -subj "/CN=httpbin.example.com/O=httpbin organization" $ openssl x509 -req -sha256 -days 365 -CA example_certs2/example.com.crt -CAkey example_certs2/example.com.key -set_serial 0 -in example_certs2/httpbin.example.com.csr -out example_certs2/httpbin.example.com.crt
  4. Згенеруйте сертифікат та приватний ключ для helloworld.example.com:

    $ openssl req -out example_certs1/helloworld.example.com.csr -newkey rsa:2048 -nodes -keyout example_certs1/helloworld.example.com.key -subj "/CN=helloworld.example.com/O=helloworld organization" $ openssl x509 -req -sha256 -days 365 -CA example_certs1/example.com.crt -CAkey example_certs1/example.com.key -set_serial 1 -in example_certs1/helloworld.example.com.csr -out example_certs1/helloworld.example.com.crt
  5. Згенеруйте клієнтський сертифікат та приватний ключ:

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

Налаштування TLS ingress gateway для одного хоста

  1. Створіть секрет для ingress gateway:

    $ kubectl create -n istio-system secret tls httpbin-credential \ --key=example_certs1/httpbin.example.com.key \ --cert=example_certs1/httpbin.example.com.crt
  2. Налаштуйте ingress gateway:

Спочатку визначте шлюз з розділом servers: для порту 443 і вкажіть значення для credentialName, яке має бути httpbin-credential. Значення збігається з назвою секрету. Режим TLS повинен мати значення SIMPLE.

$ cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1 kind: Gateway metadata: name: mygateway spec: selector: istio: ingressgateway # використовуйте станадртний istio ingress gateway servers: - port: number: 443 name: https protocol: HTTPS tls: mode: SIMPLE credentialName: httpbin-credential # має збігатись з secret hosts: - httpbin.example.com EOF

Далі налаштуйте маршрути вхідного трафіку шлюзу, визначивши відповідний віртуальний сервіс:

$ cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1 kind: VirtualService metadata: name: httpbin spec: hosts: - "httpbin.example.com" gateways: - mygateway http: - match: - uri: prefix: /status - uri: prefix: /delay route: - destination: port: number: 8000 host: httpbin EOF

Нарешті, дотримуйтесь цих інструкцій, щоб встановити змінні INGRESS_HOST та SECURE_INGRESS_PORT для доступу до шлюзу.

  1. Надішліть HTTPS-запит, щоб отримати доступ до сервісу httpbin через HTTPS:

    $ curl -v -HHost:httpbin.example.com --resolve "httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST" \ --cacert example_certs1/example.com.crt "https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418"
    ... HTTP/2 418 ... I'm a teapot! ...

    Сервіс httpbin поверне код 418 I’m a Teapot.

  2. Змініть облікові дані шлюзу, видаливши секрет шлюзу, а потім створивши його заново, використовуючи інші сертифікати та ключі:

    $ kubectl -n istio-system delete secret httpbin-credential $ kubectl create -n istio-system secret tls httpbin-credential \ --key=example_certs2/httpbin.example.com.key \ --cert=example_certs2/httpbin.example.com.crt
  3. Зверніться до сервісу httpbin за допомогою curl, використовуючи новий ланцюжок сертифікатів:

    $ curl -v -HHost:httpbin.example.com --resolve "httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST" \ --cacert example_certs2/example.com.crt "https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418"
    ... HTTP/2 418 ... I'm a teapot! ...
  4. Якщо ви спробуєте отримати доступ до httpbin, використовуючи попередній ланцюжок сертифікатів, спроба завершиться невдачею:

    $ curl -v -HHost:httpbin.example.com --resolve "httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST" \ --cacert example_certs1/example.com.crt "https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418"
    ... * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (OUT), TLS alert, Server hello (2): * curl: (35) error:04FFF06A:rsa routines:CRYPTO_internal:block type is not 01

Налаштування TLS ingress gateway для кількох хостів

Ви можете налаштувати ingress gateway для декількох хостів, наприклад, httpbin.example.com та helloworld.example.com. Ingress gateway налаштовується за допомогою унікальних облікових даних, що відповідають кожному хосту.

  1. Відновіть облікові дані httpbin з попереднього прикладу, видаливши і створивши заново секрет з оригінальними сертифікатами і ключами:

    $ kubectl -n istio-system delete secret httpbin-credential $ kubectl create -n istio-system secret tls httpbin-credential \ --key=example_certs1/httpbin.example.com.key \ --cert=example_certs1/httpbin.example.com.crt
  2. Запустіть приклад helloworld-v1:

    ZipZip
    $ kubectl apply -f samples/helloworld/helloworld.yaml -l service=helloworld $ kubectl apply -f samples/helloworld/helloworld.yaml -l version=v1
  3. Створіть секрет helloworld-credential:

    $ kubectl create -n istio-system secret tls helloworld-credential \ --key=example_certs1/helloworld.example.com.key \ --cert=example_certs1/helloworld.example.com.crt
  4. Налаштуйте ingress gatewayз хостами httpbin.example.com та helloworld.example.com:

Визначте шлюз з двома секціями server для порту 443. Встановіть значення параметра credentialName на кожному порту на httpbin-credential і helloworld-credential відповідно. Встановіть режим TLS на SIMPLE.

$ cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1 kind: Gateway metadata: name: mygateway spec: selector: istio: ingressgateway # використовуйте стандартний istio ingress gateway servers: - port: number: 443 name: https-httpbin protocol: HTTPS tls: mode: SIMPLE credentialName: httpbin-credential hosts: - httpbin.example.com - port: number: 443 name: https-helloworld protocol: HTTPS tls: mode: SIMPLE credentialName: helloworld-credential hosts: - helloworld.example.com EOF

Налаштуйте маршрути трафіку шлюзу, визначивши відповідну віртуальну службу.

$ cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1 kind: VirtualService metadata: name: helloworld spec: hosts: - helloworld.example.com gateways: - mygateway http: - match: - uri: exact: /hello route: - destination: host: helloworld port: number: 5000 EOF
  1. Надішліть запит HTTPS до helloworld.example.com:

    $ curl -v -HHost:helloworld.example.com --resolve "helloworld.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST" \ --cacert example_certs1/example.com.crt "https://helloworld.example.com:$SECURE_INGRESS_PORT/hello"
    ... HTTP/2 200 ...
  2. Надішліть запит HTTPS до httpbin.example.com і також отримайте відповідь HTTP 418:

    $ curl -v -HHost:httpbin.example.com --resolve "httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST" \ --cacert example_certs1/example.com.crt "https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418"
    ... HTTP/2 418 ... server: istio-envoy ...

Налаштуйте взаємний TLS ingress gateway

Ви можете розширити визначення вашого шлюзу підтримкою mutual TLS.

  1. Змініть облікові дані ingress gateway, видаливши його секрет і створивши новий. Сервер використовує сертифікат ЦС для перевірки своїх клієнтів, і ми повинні використовувати ключ ca.crt для зберігання сертифіката ЦС.

    $ kubectl -n istio-system delete secret httpbin-credential $ kubectl create -n istio-system secret generic httpbin-credential \ --from-file=tls.key=example_certs1/httpbin.example.com.key \ --from-file=tls.crt=example_certs1/httpbin.example.com.crt \ --from-file=ca.crt=example_certs1/example.com.crt
  2. Налаштуйте ingress gateway:

Змініть визначення шлюзу, щоб встановити режим TLS на MUTUAL.

$ cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1 kind: Gateway metadata: name: mygateway spec: selector: istio: ingressgateway # використовуйте стандартний istio ingress gateway servers: - port: number: 443 name: https protocol: HTTPS tls: mode: MUTUAL credentialName: httpbin-credential # має збігатись з secret hosts: - httpbin.example.com EOF
  1. Спробуйте надіслати HTTPS-запит, використовуючи попередній підхід, і подивіться, що це не вдасться:

    $ curl -v -HHost:httpbin.example.com --resolve "httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST" \ --cacert example_certs1/example.com.crt "https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418"
    * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, Request CERT (13): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (IN), TLS handshake, CERT verify (15): * TLSv1.3 (IN), TLS handshake, Finished (20): * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.3 (OUT), TLS handshake, Certificate (11): * TLSv1.3 (OUT), TLS handshake, Finished (20): * TLSv1.3 (IN), TLS alert, unknown (628): * OpenSSL SSL_read: error:1409445C:SSL routines:ssl3_read_bytes:tlsv13 alert certificate required, errno 0
  2. Передайте сертифікат клієнта і приватний ключ curl і повторно надішліть запит. Передайте сертифікат клієнта з прапорцем --cert і ваш приватний ключ з прапорцем --key в curl:

    $ curl -v -HHost:httpbin.example.com --resolve "httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST" \ --cacert example_certs1/example.com.crt --cert example_certs1/client.example.com.crt --key example_certs1/client.example.com.key \ "https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418"
    ... HTTP/2 418 ... server: istio-envoy ... I'm a teapot! ...

Додаткова інформація

Формати ключів

Istio підтримує кілька різних форматів секретів для інтеграції з різними інструментами, такими як cert-manager:

  • TLS Secret з ключами tls.key та tls.crt, як описано вище. Для взаємного TLS можна використовувати ключ ca.crt.
  • TLS Secret з ключами tls.key і tls.crt, як описано вище. Для взаємного TLS, окремий загальний Secret з назвою <secret>-cacert, з ключем cacert. Наприклад, httpbin-credential має tls.key і tls.crt, а httpbin-credential-cacert має cacert.
  • Загальний Secret з ключами key та cert. Для взаємного TLS можна використовувати ключ cacert.
  • Загальний Secret з ключами key та cert. Для взаємного TLS можна використовувати окремий загальний секрет з назвою <secret>-cacert, який містить ключ cacert. Наприклад, httpbin-credential має key та cert, а httpbin-credential-cacert має cacert.
  • Значення ключа cacert може бути зв’язкою сертифікатів CA, яка складається з окремих об’єднаних сертифікатів CA.

SNI маршрутизація

HTTPS Gateway здійснює SNI зіставлення з його сконфігурованими хостами перед пересиланням запиту, що може призвести до збою деяких запитів. Дивіться налаштування SNI маршрутизації для отримання деталей.

Усунення несправностей

  • Перевірте значення змінних середовища INGRESS_HOST та SECURE_INGRESS_PORT. Переконайтеся, що вони мають дійсні значення відповідно до результатів наступних команд:

    $ kubectl get svc -n istio-system $ echo "INGRESS_HOST=$INGRESS_HOST, SECURE_INGRESS_PORT=$SECURE_INGRESS_PORT"
  • Переконайтеся, що значення INGRESS_HOST є IP-адресою. У деяких хмарних платформах, наприклад, AWS, ви можете отримати доменне імʼя замість IP-адреси. Це завдання очікує IP-адресу, тому вам потрібно буде перетворити її за допомогою команд, схожих на такі:

    $ nslookup ab52747ba608744d8afd530ffd975cbf-330887905.us-east-1.elb.amazonaws.com $ export INGRESS_HOST=3.225.207.109
  • Перевірте журнал контролера шлюзу на наявність повідомлень про помилки:

    $ kubectl logs -n istio-system <gateway-service-pod>
  • Якщо ви використовуєте macOS, перевірте, чи використовуєте ви curl, скомпільований з бібліотекою LibreSSL, як описано в розділі Перш ніж розпочати.

  • Перевірте, чи секрети успішно створені в просторі імен istio-system:

    $ kubectl -n istio-system get secrets

    Секрети httpbin-credential та helloworld-credential повинні бути показані у переліку секретів.

  • Перевірте журнали, щоб підтвердити, що агент ingress gateway надіслав пару ключ/сертифікат до шлюзу входу:

    $ kubectl logs -n istio-system <gateway-service-pod>

    Журнал має показувати, що секрет httpbin-credential був доданий. Якщо використовується взаємний TLS, то також має зʼявитися секрет httpbin-credential-cacert. Перевірте, що в журналі відображається, що агент шлюзу отримав запити SDS від шлюзу входу, що імʼя ресурсу є httpbin-credential, і що шлюз входу отримав пару ключ/сертифікат. Якщо використовується взаємний TLS, журнал має показувати, що ключ/сертифікат був надісланий до шлюзу входу, що агент шлюзу отримав запит SDS з імʼям ресурсу httpbin-credential-cacert, і що шлюз входу отримав кореневий сертифікат.

Очищення

  1. Видаліть конфігурацію шлюзу та маршрути:
$ kubectl delete gateway mygateway $ kubectl delete virtualservice httpbin helloworld
  1. Видаліть секрети, сертифікати та ключі:

    $ kubectl delete -n istio-system secret httpbin-credential helloworld-credential $ rm -rf ./example_certs1 ./example_certs2
  2. Вимкніть служби httpbin і helloworld:

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

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