Использование TLS с контроллером объекта ingress в Службе Azure Kubernetes (AKS)

Протокол TLS — это протокол для обеспечения безопасности при обмене данными, например с помощью шифрования, аутентификации и обеспечения целостности, путем использования сертификатов. Использование TLS с контроллером объекта ingress в AKS позволяет защитить обмен данными между приложениями, а также получить все преимущества контроллера объекта ingress.

Вы можете использовать собственные сертификаты и интегрировать их с драйвером CSI хранилища секретов. Кроме того, можно использовать cert-manager, который используется для автоматического создания и настройки сертификатов Let's Encrypt. Наконец, в кластере AKS запущено два приложения, каждое из которых доступно по одному IP-адресу.

Примечание

Существует два контроллера объекта ingress с открытым исходным кодом для Kubernetes на основе Nginx: один поддерживается сообществом Kubernetes (kubernetes/ingress-nginx), а второй — компанией Nginx, Inc. (nginxinc/kubernetes-ingress). В этой статье будет использоваться контроллер объекта ingress сообщества Kubernetes.

Подготовка к работе

В этой статье также предполагается, что у вас есть контроллер объекта ingress и настроенные приложения. Если вам нужен контроллер объекта ingress или примеры приложений, см. статью Создание контроллера входящего трафика в Службе Azure Kubernetes (AKS).

В данной статье используется Helm 3 для установки контроллера объекта ingress NGINX в поддерживаемую версию Kubernetes. Убедитесь, что используете последний выпуск Helm. Вам также понадобится доступ к репозиториям Helm ingress-nginx и jetstack. Порядок действий, описанный в этой статье, может не подходить для предыдущих версий диаграммы Helm, контроллера объекта ingress NGINX или Kubernetes.

Дополнительную информацию о настройке и использовании Helm см. в статье Использование Helm со службой Azure Kubernetes. Инструкции по обновлению см. в документации по установке Helm.

Кроме того, предполагается, что у вас уже есть кластер AKS с интегрированным Реестром контейнеров Azure (ACR). Дополнительные сведения о создании кластера AKS с интегрированным ACR см. в статье Проверка подлинности в Реестре контейнеров Azure из Службы Azure Kubernetes.

Для работы с этой статьей требуется Azure CLI 2.0.64 или более поздней версии. Чтобы узнать версию, выполните команду az --version. Если вам необходимо выполнить установку или обновление, см. статью Установка Azure CLI 2.0.

Использование TLS с собственными сертификатами с драйвером CSI хранилища секретов

Чтобы использовать TLS с собственными сертификатами с драйвером CSI хранилища секретов, вам потребуется кластер AKS с настроенным драйвером CSI хранилища секретов и экземпляром Azure Key Vault. Дополнительные сведения см. в статье Настройка драйвера CSI хранилища секретов для включения контроллера объекта ingress NGINX с протоколом TLS.

Использование протокола TLS с сертификатами Let's Encrypt

Чтобы использовать TLS с сертификатами Let's Encrypt, вы развернете cert-manager, который используется для автоматического создания и настройки сертификатов Let's Encrypt.

Импорт образов cert-manager, используемых чартом Helm, в ACR

Для импорта этих образов в ACR используйте команду az acr import.

REGISTRY_NAME=<REGISTRY_NAME>
CERT_MANAGER_REGISTRY=quay.io
CERT_MANAGER_TAG=v1.8.0
CERT_MANAGER_IMAGE_CONTROLLER=jetstack/cert-manager-controller
CERT_MANAGER_IMAGE_WEBHOOK=jetstack/cert-manager-webhook
CERT_MANAGER_IMAGE_CAINJECTOR=jetstack/cert-manager-cainjector

az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_CONTROLLER:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_CONTROLLER:$CERT_MANAGER_TAG
az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_WEBHOOK:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_WEBHOOK:$CERT_MANAGER_TAG
az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_CAINJECTOR:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_CAINJECTOR:$CERT_MANAGER_TAG

Примечание

Помимо импорта в ACR образов контейнеров, туда также можно импортировать чарты Helm. Дополнительные сведения см. в статье Отправка чартов Helm в Реестр контейнеров Azure и их извлечение оттуда.

Параметры конфигурации контроллера объекта ingress

По умолчанию контроллер входящего трафика NGINX создается с новым назначением общедоступного IP-адреса. Этот общедоступный IP-адрес является статическим только на время жизненного цикла контроллера входящего трафика и теряется, если контроллер удаляется и создается повторно.

Вы можете выбрать один из следующих способов:

  • использование динамического общедоступного IP-адреса;
  • использование статического общедоступного IP-адреса.

Использование статического общедоступного IP-адреса

Общее требование конфигурации — предоставить контроллеру входящего трафика NGINX имеющийся статический общедоступный IP-адрес. Статический общедоступный IP-адрес останется, если контроллер входящего трафика будет удален.

Приведенные ниже команды создают IP-адрес, который будет удален при удалении кластера AKS.

Сначала получите имя группы ресурсов для кластера ASK, выполнив команду az aks show:

az aks show --resource-group myResourceGroup --name myAKSCluster --query nodeResourceGroup -o tsv

Создайте общедоступный IP-адрес с помощью метода статического выделения, используя команду az network public-ip create. В следующем примере создается общедоступный IP-адрес myPublicIP в группе ресурсов AKS, о которой говорилось на предыдущих шагах.

az network public-ip create --resource-group MC_myResourceGroup_myAKSCluster_eastus --name myAKSPublicIP --sku Standard --allocation-method static --query publicIp.ipAddress -o tsv

Вы также можете создать IP-адрес в другой группе ресурсов, которой можно управлять отдельно от кластера AKS. Если вы создаете IP-адрес в другой группе ресурсов, проверьте следующие характеристики:

  • Удостоверение кластера, используемое кластером AKS, имеет делегированные разрешения на доступ к группе ресурсов, например участник сетей.
  • Добавьте параметр --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-resource-group"="<RESOURCE_GROUP>". Замените <RESOURCE_GROUP> именем группы ресурсов, в которой находится IP-адрес.

При обновлении контроллера объекта ingress необходимо передать параметр в выпуск Helm, чтобы контроллер объекта ingress был осведомлен о статичном IP-адресе подсистемы балансировки нагрузки, выделяемом службе контроллера объекта ingress. Чтобы обеспечить правильную работу сертификатов HTTPS, для настройки полного доменного имени для IP-адреса контроллера объекта ingress используется метка DNS-имени.

  1. Добавьте параметр --set controller.service.loadBalancerIP="<EXTERNAL_IP>". Укажите собственный общедоступный IP-адрес, созданный на предыдущем шаге.
  2. Добавьте параметр --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"="<DNS_LABEL>". Метку DNS можно задать либо при первом развертывании контроллера объекта ingress, либо настроить позже.
DNS_LABEL="demo-aks-ingress"
NAMESPACE="ingress-basic"
STATIC_IP=<STATIC_IP>

helm upgrade nginx-ingress ingress-nginx/ingress-nginx \
  --namespace $NAMESPACE \
  --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DNS_LABEL \
  --set controller.service.loadBalancerIP=$STATIC_IP

Дополнительные сведения см. в статье Использование статического общедоступного IP-адреса и DNS-метки с подсистемой балансировки нагрузки Службы Azure Kubernetes (AKS).

Использование динамического IP-адреса

При создании контроллера объекта ingress для него создается общедоступный IP-адрес Azure. Этот IP-адрес является статическим только на время жизненного цикла контроллера входящего трафика. При удалении контроллера входящего трафика этот общедоступный IP-адрес теряется. Если создать дополнительный контроллер объекта ingress, ему назначается новый общедоступный IP-адрес.

Чтобы получить общедоступный IP-адрес, используйте команду kubectl get service.

kubectl --namespace ingress-basic get services -o wide -w nginx-ingress-ingress-nginx-controller

В примере выходных данных показаны сведения о контроллере объекта ingress:

NAME                                     TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)                      AGE   SELECTOR
nginx-ingress-ingress-nginx-controller   LoadBalancer   10.0.74.133   EXTERNAL_IP     80:32486/TCP,443:30953/TCP   44s   app.kubernetes.io/component=controller,app.kubernetes.io/instance=nginx-ingress,app.kubernetes.io/name=ingress-nginx

Если вы используете личный домен, необходимо добавить запись A в зону DNS. В противном случае необходимо настроить общедоступный IP-адрес с полным доменным именем (FQDN).

Добавление записи A в зону DNS

Добавьте запись A в зону DNS с внешним IP-адресом службы NGINX с помощью команды az network dns record-set a add-record.

az network dns record-set a add-record \
    --resource-group myResourceGroup \
    --zone-name MY_CUSTOM_DOMAIN \
    --record-set-name "*" \
    --ipv4-address MY_EXTERNAL_IP

Настройка полного доменного имени контроллера объекта ingress

При необходимости можно настроить полное доменное имя для IP-адреса контроллера входящего трафика вместо личного домена. Полное доменное имя будет иметь вид <CUSTOM LABEL>.<AZURE REGION NAME>.cloudapp.azure.com.

Метод 1. Задание метки DNS с помощью Azure CLI

Этот пример предназначен для оболочки Bash.

# Public IP address of your ingress controller
IP="MY_EXTERNAL_IP"

# Name to associate with public IP address
DNSNAME="demo-aks-ingress"

# Get the resource-id of the public ip
PUBLICIPID=$(az network public-ip list --query "[?ipAddress!=null]|[?contains(ipAddress, '$IP')].[id]" --output tsv)

# Update public ip address with DNS name
az network public-ip update --ids $PUBLICIPID --dns-name $DNSNAME

# Display the FQDN
az network public-ip show --ids $PUBLICIPID --query "[dnsSettings.fqdn]" --output tsv

Метод 2. Задание метки DNS с помощью параметров чарта Helm

Вы можете передать параметр заметки в конфигурацию чарта Helm с помощью параметра --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name". Этот параметр можно задать либо при первом развертывании контроллера объекта ingress, либо настроить позже. В следующем примере показано, как обновить этот параметр после развертывания контроллера.

DNS_LABEL="demo-aks-ingress"
NAMESPACE="ingress-basic"

helm upgrade nginx-ingress ingress-nginx/ingress-nginx \
  --namespace $NAMESPACE \
  --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DNS_LABEL

Установка cert-manager

Контроллер входящего трафика NGINX поддерживает обработку подключений TLS для последующей передачи. Получить и настроить сертификаты для HTTPS можно несколькими способами. В этой статье демонстрируется использование проекта cert-manager, который обеспечивает автоматические функции создания сертификатов Lets Encrypt и управления ими.

Установка контроллера cert-manager:

# Set variable for ACR location to use for pulling images
ACR_URL=<REGISTRY_URL>

# Label the ingress-basic namespace to disable resource validation
kubectl label namespace ingress-basic cert-manager.io/disable-validation=true

# Add the Jetstack Helm repository
helm repo add jetstack https://charts.jetstack.io

# Update your local Helm chart repository cache
helm repo update

# Install the cert-manager Helm chart
helm install cert-manager jetstack/cert-manager \
  --namespace ingress-basic \
  --version $CERT_MANAGER_TAG \
  --set installCRDs=true \
  --set nodeSelector."kubernetes\.io/os"=linux \
  --set image.repository=$ACR_URL/$CERT_MANAGER_IMAGE_CONTROLLER \
  --set image.tag=$CERT_MANAGER_TAG \
  --set webhook.image.repository=$ACR_URL/$CERT_MANAGER_IMAGE_WEBHOOK \
  --set webhook.image.tag=$CERT_MANAGER_TAG \
  --set cainjector.image.repository=$ACR_URL/$CERT_MANAGER_IMAGE_CAINJECTOR \
  --set cainjector.image.tag=$CERT_MANAGER_TAG

Дополнительные сведения о конфигурации cert-manager см. в описании проекта cert-manager.

Создание издателя кластера ЦС

Для выдачи сертификатов средству cert-manager нужен ресурс Issuer или ClusterIssuer. Эти ресурсы Kubernetes имеют аналогичную функциональность, однако Issuer работает в отдельном пространстве имен, а ClusterIssuer — во всех. Дополнительные сведения см. в документации по издателю cert-manager.

Создайте издатель кластера, например cluster-issuer.yaml, используя приведенный ниже пример манифеста. Измените адрес электронной почты на действительный адрес вашей организации:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: MY_EMAIL_ADDRESS
    privateKeySecretRef:
      name: letsencrypt
    solvers:
    - http01:
        ingress:
          class: nginx
          podTemplate:
            spec:
              nodeSelector:
                "kubernetes.io/os": linux

Чтобы создать издатель, используйте команду kubectl apply.

kubectl apply -f cluster-issuer.yaml

Обновление маршрутов входящего трафика

Вам потребуется обновить маршруты входящего трафика для направления трафика на полное доменное имя или личный домен.

В следующем примере трафик к адресу hello-world-ingress.MY_CUSTOM_DOMAIN перенаправляется к службе aks-helloworld-one. Трафик к адресу hello-world-ingress.MY_CUSTOM_DOMAIN/hello-world-two перенаправляется к службе aks-helloworld-two. Трафик к hello-world-ingress.MY_CUSTOM_DOMAIN/static перенаправляется к службе aks-helloworld-one для статических ресурсов.

Примечание

Если вы настроили полное доменное имя для IP-адреса контроллера входящего трафика вместо личного домена, используйте полное доменное имя вместо hello-world-ingress.MY_CUSTOM_DOMAIN. Например, если полное доменное имя — demo-aks-ingress.eastus.cloudapp.azure.com, замените hello-world-ingress.MY_CUSTOM_DOMAIN на demo-aks-ingress.eastus.cloudapp.azure.com в hello-world-ingress.yaml.

Создайте или обновите файл hello-world-ingress.yaml с помощью приведенного ниже примера YAML. Обновите spec.tls.hosts и spec.rules.host, указав DNS-имя, которое вы создали на предыдущем шаге.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-world-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/use-regex: "true"
    cert-manager.io/cluster-issuer: letsencrypt
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - hello-world-ingress.MY_CUSTOM_DOMAIN
    secretName: tls-secret
  rules:
  - host: hello-world-ingress.MY_CUSTOM_DOMAIN
    http:
      paths:
      - path: /hello-world-one(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: aks-helloworld-one
            port:
              number: 80
      - path: /hello-world-two(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: aks-helloworld-two
            port:
              number: 80
      - path: /(.*)
        pathType: Prefix
        backend:
          service:
            name: aks-helloworld-one
            port:
              number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-world-ingress-static
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/rewrite-target: /static/$2
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - hello-world-ingress.MY_CUSTOM_DOMAIN
    secretName: tls-secret
  rules:
  - host: hello-world-ingress.MY_CUSTOM_DOMAIN
    http:
      paths:
      - path: /static(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: aks-helloworld-one
            port: 
              number: 80

Обновите ресурс входящего трафика с помощью команды kubectl apply.

kubectl apply -f hello-world-ingress.yaml --namespace ingress-basic

Проверка создания объекта сертификата

Далее нужно создать ресурс сертификата. Этот ресурс сертификата определяет необходимый сертификат X.509. Дополнительные сведения см. в описании сертификатов cert-manager. cert-manager автоматически создал объект сертификата с помощью ingress-shim — оболочки совместимости, которая автоматически развертывается с помощью cert-manager начиная с версии 0.2.2. Дополнительные сведения см. в документации по ingress-shim.

Чтобы убедиться, что сертификат успешно создан, используйте команду kubectl get certificate --namespace ingress-basic и убедитесь, что параметр READY имеет значение true. Это может занять несколько минут.

kubectl get certificate --namespace ingress-basic

В примере выходных данных ниже показано состояние сертификата:

NAME         READY   SECRET       AGE
tls-secret   True    tls-secret   11m

Проверка конфигурации входящего трафика

Откройте браузер по адресу hello-world-ingress.MY_CUSTOM_DOMAIN или по полному доменному имени контроллера объекта ingress в Kubernetes. Обратите внимание, что вы перенаправлены на использование протокола HTTPS, сертификат является доверенным, а демонстрационное приложение отображается в веб-браузере. Добавьте путь /hello-world-two и обратите внимание на второе демонстрационное приложение с пользовательским заголовком.

Очистка ресурсов

В этой статье для установки компонентов обработки входящего трафика, сертификатов и примеров приложений используется Helm. При развертывании чарта Helm создается множество ресурсов Kubernetes. К ним относятся элементы pod, развертывания и службы. Чтобы очистить эти ресурсы, можно удалить весь пример пространства имен либо отдельные ресурсы.

Удаление примера пространства имен и всех ресурсов

Чтобы удалить весь пример пространства имен, используйте команду kubectl delete и укажите имя пространства имен. Все ресурсы в пространстве имен будут удалены.

kubectl delete namespace ingress-basic

Удаление ресурсов по отдельности

Можно использовать более скрупулезный подход — удалить отдельные созданные ресурсы. Сначала удалите ресурсы издателя кластера:

kubectl delete -f cluster-issuer.yaml --namespace ingress-basic

Получите список выпусков Helm с помощью команды helm list. Найдите диаграммы nginx и cert-manager, как показано в следующем примере выходных данных:

$ helm list --namespace ingress-basic

NAME                    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
cert-manager            ingress-basic   1               2020-01-15 10:23:36.515514 -0600 CST    deployed        cert-manager-v0.13.0    v0.13.0    
nginx                   ingress-basic   1               2020-01-15 10:09:45.982693 -0600 CST    deployed        nginx-ingress-1.29.1    0.27.0  

Удалите выпуски командой helm uninstall. В следующем примере производится удаление развертываний входящего трафика NGINX и cert-manager.

$ helm uninstall cert-manager nginx --namespace ingress-basic

release "cert-manager" uninstalled
release "nginx" uninstalled

Затем удалите два примера приложений:

kubectl delete -f aks-helloworld-one.yaml --namespace ingress-basic
kubectl delete -f aks-helloworld-two.yaml --namespace ingress-basic

Удалите маршрут входящего трафика, направлявший трафик в пример приложения.

kubectl delete -f hello-world-ingress.yaml --namespace ingress-basic

Наконец, можно удалить само пространство имен. Используйте команду kubectl delete и укажите имя пространства имен:

kubectl delete namespace ingress-basic

Дальнейшие действия

В данной статье упоминаются некоторые внешние компоненты для AKS. Чтобы узнать больше об этих компонентах, см. следующие страницы проекта:

Кроме того, вы можете сделать следующее: