Безопасный шлюз входящего трафика для надстройки сетки службы Istio для Служба Azure Kubernetes
В статье "Развертывание внешнего или внутреннего Istio Ingress" описывается, как настроить шлюз входящего трафика для предоставления http-службы внешнему или внутреннему трафику. В этой статье показано, как предоставить безопасную службу HTTPS с помощью простого или взаимного TLS.
Необходимые компоненты
Включение надстройки Istio в кластере в зависимости от документации
Примечание.
Эта статья относится к внешнему шлюзу ingress для демонстрации, те же действия будут применяться для настройки взаимной TLS для внутреннего шлюза входящего трафика.
Обязательные сертификаты и ключи клиента или сервера
В этой статье требуется несколько сертификатов и ключей. Вы можете использовать избранное средство для их создания или использовать следующие команды opensl .
Создайте корневой сертификат и закрытый ключ для подписывания сертификатов для примеров служб:
mkdir bookinfo_certs openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=bookinfo Inc./CN=bookinfo.com' -keyout bookinfo_certs/bookinfo.com.key -out bookinfo_certs/bookinfo.com.crt
Создание сертификата и закрытого ключа для
productpage.bookinfo.com
:openssl req -out bookinfo_certs/productpage.bookinfo.com.csr -newkey rsa:2048 -nodes -keyout bookinfo_certs/productpage.bookinfo.com.key -subj "/CN=productpage.bookinfo.com/O=product organization" openssl x509 -req -sha256 -days 365 -CA bookinfo_certs/bookinfo.com.crt -CAkey bookinfo_certs/bookinfo.com.key -set_serial 0 -in bookinfo_certs/productpage.bookinfo.com.csr -out bookinfo_certs/productpage.bookinfo.com.crt
Создайте сертификат клиента и закрытый ключ:
openssl req -out bookinfo_certs/client.bookinfo.com.csr -newkey rsa:2048 -nodes -keyout bookinfo_certs/client.bookinfo.com.key -subj "/CN=client.bookinfo.com/O=client organization" openssl x509 -req -sha256 -days 365 -CA bookinfo_certs/bookinfo.com.crt -CAkey bookinfo_certs/bookinfo.com.key -set_serial 1 -in bookinfo_certs/client.bookinfo.com.csr -out bookinfo_certs/client.bookinfo.com.crt
Настройка шлюза входящего трафика TLS
Создайте секрет TLS Kubernetes для шлюза входящего трафика; используйте Azure Key Vault для размещения сертификатов и ключей и надстройки поставщика секретов Azure Key Vault для синхронизации секретов с кластером.
Настройка Azure Key Vault и синхронизация секретов с кластером
Создание хранилища Azure Key Vault
Для предоставления входных данных сертификата и ключа надстройке Istio требуется ресурс Azure Key Vault.
export AKV_NAME=<azure-key-vault-resource-name> az keyvault create --name $AKV_NAME --resource-group $RESOURCE_GROUP --location $LOCATION
Включите поставщик Azure Key Vault для надстройки CSI Driver для хранилища секретов в кластере.
az aks enable-addons --addons azure-keyvault-secrets-provider --resource-group $RESOURCE_GROUP --name $CLUSTER
Авторизация управляемого удостоверения, назначаемого пользователем надстройки, для доступа к ресурсу Azure Key Vault с помощью политики доступа. Кроме того, если хранилище ключей использует Azure RBAC для модели разрешений, следуйте инструкциям, приведенным здесь , чтобы назначить роль Key Vault для управляемого удостоверения, назначаемого пользователем надстройки.
OBJECT_ID=$(az aks show --resource-group $RESOURCE_GROUP --name $CLUSTER --query 'addonProfiles.azureKeyvaultSecretsProvider.identity.objectId' -o tsv | tr -d '\r') CLIENT_ID=$(az aks show --resource-group $RESOURCE_GROUP --name $CLUSTER --query 'addonProfiles.azureKeyvaultSecretsProvider.identity.clientId') TENANT_ID=$(az keyvault show --resource-group $RESOURCE_GROUP --name $AKV_NAME --query 'properties.tenantId') az keyvault set-policy --name $AKV_NAME --object-id $OBJECT_ID --secret-permissions get list
Создайте секреты в Azure Key Vault с помощью сертификатов и ключей.
az keyvault secret set --vault-name $AKV_NAME --name test-productpage-bookinfo-key --file bookinfo_certs/productpage.bookinfo.com.key az keyvault secret set --vault-name $AKV_NAME --name test-productpage-bookinfo-crt --file bookinfo_certs/productpage.bookinfo.com.crt az keyvault secret set --vault-name $AKV_NAME --name test-bookinfo-crt --file bookinfo_certs/bookinfo.com.crt
Используйте следующий манифест для развертывания SecretProviderClass, чтобы предоставить Azure Key Vault определенные параметры драйверу CSI.
cat <<EOF | kubectl apply -f - apiVersion: secrets-store.csi.x-k8s.io/v1 kind: SecretProviderClass metadata: name: productpage-credential-spc namespace: aks-istio-ingress spec: provider: azure secretObjects: - secretName: productpage-credential type: tls data: - objectName: test-productpage-bookinfo-key key: key - objectName: test-productpage-bookinfo-crt key: cert parameters: useVMManagedIdentity: "true" userAssignedIdentityID: $CLIENT_ID keyvaultName: $AKV_NAME cloudName: "" objects: | array: - | objectName: test-productpage-bookinfo-key objectType: secret objectAlias: "test-productpage-bookinfo-key" - | objectName: test-productpage-bookinfo-crt objectType: secret objectAlias: "test-productpage-bookinfo-crt" tenantId: $TENANT_ID EOF
Используйте следующий манифест для развертывания примера pod. Драйвер CSI для хранилища секретов требует, чтобы модуль pod ссылались на ресурс SecretProviderClass, чтобы обеспечить синхронизацию секретов из Azure Key Vault в кластер.
cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: secrets-store-sync-productpage namespace: aks-istio-ingress spec: containers: - name: busybox image: mcr.microsoft.com/oss/busybox/busybox:1.33.1 command: - "/bin/sleep" - "10" volumeMounts: - name: secrets-store01-inline mountPath: "/mnt/secrets-store" readOnly: true volumes: - name: secrets-store01-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "productpage-credential-spc" EOF
Проверьте
productpage-credential
секрет, созданный в пространствеaks-istio-ingress
имен кластера, как определено в ресурсе SecretProviderClass.kubectl describe secret/productpage-credential -n aks-istio-ingress
Пример результата:
Name: productpage-credential Namespace: aks-istio-ingress Labels: secrets-store.csi.k8s.io/managed=true Annotations: <none> Type: tls Data ==== cert: 1066 bytes key: 1704 bytes
Настройка шлюза входящего трафика и виртуальной службы
Маршрутизация трафика HTTPS через шлюз Istio ingress в примеры приложений. Используйте следующий манифест для развертывания ресурсов шлюза и виртуальной службы.
cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
istio: aks-istio-ingressgateway-external
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: productpage-credential
hosts:
- productpage.bookinfo.com
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: productpage-vs
spec:
hosts:
- productpage.bookinfo.com
gateways:
- bookinfo-gateway
http:
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
port:
number: 9080
host: productpage
EOF
Примечание.
В определении credentialName
шлюза должен соответствовать ресурсу secretName
SecretProviderClass и selector
должен ссылаться на внешний шлюз входящего трафика по метке, в которой ключ метки и istio
значение равно aks-istio-ingressgateway-external
. Для внутренней метки шлюза входящего трафика задано istio
значение aks-istio-ingressgateway-internal
.
Задайте переменные среды для внешнего узла и портов входящего трафика:
export INGRESS_HOST_EXTERNAL=$(kubectl -n aks-istio-ingress get service aks-istio-ingressgateway-external -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
export SECURE_INGRESS_PORT_EXTERNAL=$(kubectl -n aks-istio-ingress get service aks-istio-ingressgateway-external -o jsonpath='{.spec.ports[?(@.name=="https")].port}')
export SECURE_GATEWAY_URL_EXTERNAL=$INGRESS_HOST_EXTERNAL:$SECURE_INGRESS_PORT_EXTERNAL
echo "https://$SECURE_GATEWAY_URL_EXTERNAL/productpage"
Проверка
Отправьте HTTPS-запрос для доступа к службе productpage через HTTPS:
curl -s -HHost:productpage.bookinfo.com --resolve "productpage.bookinfo.com:$SECURE_INGRESS_PORT_EXTERNAL:$INGRESS_HOST_EXTERNAL" --cacert bookinfo_certs/bookinfo.com.crt "https://productpage.bookinfo.com:$SECURE_INGRESS_PORT_EXTERNAL/productpage" | grep -o "<title>.*</title>"
Убедитесь, что страница продукта примера приложения доступна. Ожидаемые выходные данные:
<title>Simple Bookstore App</title>
Примечание.
Чтобы настроить входящий трафик HTTPS к службе HTTPS, т. е. настройте шлюз входящего трафика для выполнения сквозного руководства SNI вместо завершения TLS для входящих запросов, обновите режим tls в определении PASSTHROUGH
шлюза. Это указывает шлюзу передавать трафик входящего трафика "как есть", не завершая TLS.
Настройка шлюза взаимной входящего трафика TLS
Расширение определения шлюза для поддержки взаимной TLS.
Обновите учетные данные шлюза входящего трафика, удалив текущий секрет и создав новый. Сервер использует сертификат ЦС для проверки своих клиентов, и для хранения сертификата ЦС необходимо использовать ключ ca.crt.
kubectl delete secretproviderclass productpage-credential-spc -n aks-istio-ingress kubectl delete secret/productpage-credential -n aks-istio-ingress kubectl delete pod/secrets-store-sync-productpage -n aks-istio-ingress
Используйте следующий манифест, чтобы повторно создать SecretProviderClass с сертификатом ЦС.
cat <<EOF | kubectl apply -f - apiVersion: secrets-store.csi.x-k8s.io/v1 kind: SecretProviderClass metadata: name: productpage-credential-spc namespace: aks-istio-ingress spec: provider: azure secretObjects: - secretName: productpage-credential type: opaque data: - objectName: test-productpage-bookinfo-key key: tls.key - objectName: test-productpage-bookinfo-crt key: tls.crt - objectName: test-bookinfo-crt key: ca.crt parameters: useVMManagedIdentity: "true" userAssignedIdentityID: $CLIENT_ID keyvaultName: $AKV_NAME cloudName: "" objects: | array: - | objectName: test-productpage-bookinfo-key objectType: secret objectAlias: "test-productpage-bookinfo-key" - | objectName: test-productpage-bookinfo-crt objectType: secret objectAlias: "test-productpage-bookinfo-crt" - | objectName: test-bookinfo-crt objectType: secret objectAlias: "test-bookinfo-crt" tenantId: $TENANT_ID EOF
Используйте следующий манифест, чтобы повторно развернуть пример pod для синхронизации секретов из Azure Key Vault с кластером.
cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: secrets-store-sync-productpage namespace: aks-istio-ingress spec: containers: - name: busybox image: registry.k8s.io/e2e-test-images/busybox:1.29-4 command: - "/bin/sleep" - "10" volumeMounts: - name: secrets-store01-inline mountPath: "/mnt/secrets-store" readOnly: true volumes: - name: secrets-store01-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "productpage-credential-spc" EOF
Проверьте
productpage-credential
секрет, созданный в пространствеaks-istio-ingress
имен кластера.kubectl describe secret/productpage-credential -n aks-istio-ingress
Пример результата:
Name: productpage-credential Namespace: aks-istio-ingress Labels: secrets-store.csi.k8s.io/managed=true Annotations: <none> Type: opaque Data ==== ca.crt: 1188 bytes tls.crt: 1066 bytes tls.key: 1704 bytes
Используйте следующий манифест, чтобы обновить определение шлюза, чтобы задать для режима TLS значение MUTUAL.
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: bookinfo-gateway spec: selector: istio: aks-istio-ingressgateway-external # use istio default ingress gateway servers: - port: number: 443 name: https protocol: HTTPS tls: mode: MUTUAL credentialName: productpage-credential # must be the same as secret hosts: - productpage.bookinfo.com EOF
Проверка
Попытайтесь отправить HTTPS-запрос с помощью предыдущего подхода , не передавая сертификат клиента, и увидите его сбоем.
curl -v -HHost:productpage.bookinfo.com --resolve "productpage.bookinfo.com:$SECURE_INGRESS_PORT_EXTERNAL:$INGRESS_HOST_EXTERNAL" --cacert bookinfo_certs/bookinfo.com.crt "https://productpage.bookinfo.com:$SECURE_INGRESS_PORT_EXTERNAL/productpage"
Пример результата:
...
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS alert, unknown (628):
* OpenSSL SSL_read: error:0A00045C:SSL routines::tlsv13 alert certificate required, errno 0
* Failed receiving HTTP2 data
* OpenSSL SSL_write: SSL_ERROR_ZERO_RETURN, errno 0
* Failed sending HTTP2 data
* Connection #0 to host productpage.bookinfo.com left intact
curl: (56) OpenSSL SSL_read: error:0A00045C:SSL routines::tlsv13 alert certificate required, errno 0
Передайте сертификат клиента с флагом --cert
и закрытым ключом с помощью флага --key
в curl.
curl -s -HHost:productpage.bookinfo.com --resolve "productpage.bookinfo.com:$SECURE_INGRESS_PORT_EXTERNAL:$INGRESS_HOST_EXTERNAL" --cacert bookinfo_certs/bookinfo.com.crt --cert bookinfo_certs/client.bookinfo.com.crt --key bookinfo_certs/client.bookinfo.com.key "https://productpage.bookinfo.com:$SECURE_INGRESS_PORT_EXTERNAL/productpage" | grep -o "<title>.*</title>"
Убедитесь, что страница продукта примера приложения доступна. Ожидаемые выходные данные:
<title>Simple Bookstore App</title>
Удаление ресурсов
Если вы хотите очистить сетку службы Istio и входящий трафик (выход из кластера), выполните следующую команду:
az aks mesh disable --resource-group ${RESOURCE_GROUP} --name ${CLUSTER}
Если вы хотите очистить все ресурсы, созданные из документов руководства Istio, выполните следующую команду:
az group delete --name ${RESOURCE_GROUP} --yes --no-wait
Azure Kubernetes Service