Bezpieczna brama ruchu przychodzącego dla dodatku siatki usługi Istio dla usługi Azure Kubernetes Service
W artykule Deploy external or internal Istio Ingress (Wdrażanie zewnętrznego lub wewnętrznego ruchu przychodzącego) opisano sposób konfigurowania bramy ruchu przychodzącego w celu uwidocznienia usługi HTTP na ruch zewnętrzny/wewnętrzny. W tym artykule pokazano, jak uwidocznić bezpieczną usługę HTTPS przy użyciu prostego lub wzajemnego protokołu TLS.
Wymagania wstępne
Wdrażanie zewnętrznej bramy ruchu przychodzącego Istio zgodnie z dokumentacją
Uwaga
W tym artykule opisano zewnętrzną bramę ruchu przychodzącego na potrzeby pokazu. Te same kroki dotyczą konfigurowania wzajemnego protokołu TLS dla wewnętrznej bramy ruchu przychodzącego.
Wymagane certyfikaty i klucze klienta/serwera
Ten artykuł wymaga kilku certyfikatów i kluczy. Możesz użyć ulubionego narzędzia do ich utworzenia lub użyć następujących poleceń openssl .
Utwórz certyfikat główny i klucz prywatny na potrzeby podpisywania certyfikatów dla przykładowych usług:
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
Wygeneruj certyfikat i klucz prywatny dla elementu
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
Wygeneruj certyfikat klienta i klucz prywatny:
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
Konfigurowanie bramy ruchu przychodzącego TLS
Utwórz wpis tajny PROTOKOŁU TLS platformy Kubernetes dla bramy ruchu przychodzącego; Usługa Azure Key Vault umożliwia hostowanie certyfikatów/kluczy i dodatku dostawcy wpisów tajnych usługi Azure Key Vault w celu synchronizacji wpisów tajnych z klastrem.
Konfigurowanie usługi Azure Key Vault i synchronizowanie wpisów tajnych z klastrem
Tworzenie usługi Azure Key Vault
Potrzebny jest zasób usługi Azure Key Vault, aby podać dane wejściowe certyfikatu i klucza do dodatku Istio.
export AKV_NAME=<azure-key-vault-resource-name> az keyvault create --name $AKV_NAME --resource-group $RESOURCE_GROUP --location $LOCATION
Włącz dostawcę usługi Azure Key Vault dla dodatku sterownika CSI magazynu wpisów tajnych w klastrze.
az aks enable-addons --addons azure-keyvault-secrets-provider --resource-group $RESOURCE_GROUP --name $CLUSTER
Autoryzuj tożsamość zarządzaną przypisaną przez użytkownika dodatku, aby uzyskać dostęp do zasobu usługi Azure Key Vault przy użyciu zasad dostępu. Alternatywnie, jeśli usługa Key Vault używa kontroli dostępu opartej na rolach platformy Azure dla modelu uprawnień, postępuj zgodnie z instrukcjami w tym miejscu , aby przypisać rolę platformy Azure usługi Key Vault dla tożsamości zarządzanej przypisanej przez użytkownika dodatku.
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
Tworzenie wpisów tajnych w usłudze Azure Key Vault przy użyciu certyfikatów i kluczy.
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
Użyj następującego manifestu, aby wdrożyć klasę SecretProviderClass w celu udostępnienia parametrów specyficznych dla usługi Azure Key Vault dla sterownika 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
Użyj następującego manifestu, aby wdrożyć przykładowy zasobnik. Sterownik CSI magazynu wpisów tajnych wymaga zasobnika, aby odwoływać się do zasobu SecretProviderClass w celu zapewnienia synchronizacji wpisów tajnych z usługi Azure Key Vault do klastra.
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
Sprawdź
productpage-credential
wpis tajny utworzony w przestrzeniaks-istio-ingress
nazw klastra zgodnie z definicją w zasobie SecretProviderClass.kubectl describe secret/productpage-credential -n aks-istio-ingress
Przykładowe wyjście:
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
Konfigurowanie bramy ruchu przychodzącego i usługi wirtualnej
Kierowanie ruchu HTTPS za pośrednictwem bramy ruchu przychodzącego Istio do przykładowych aplikacji. Użyj następującego manifestu, aby wdrożyć bramę i zasoby usługi wirtualnej.
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
Uwaga
W definicji credentialName
bramy musi być zgodna z zasobem secretName
SecretProviderClass i selector
musi odwoływać się do zewnętrznej bramy ruchu przychodzącego według etykiety, w której klucz etykiety to istio
, a wartość to aks-istio-ingressgateway-external
. Dla wewnętrznej etykiety bramy ruchu przychodzącego jest istio
i wartość to aks-istio-ingressgateway-internal
.
Ustaw zmienne środowiskowe dla zewnętrznego hosta i portów przychodzących:
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"
Weryfikacja
Wyślij żądanie HTTPS, aby uzyskać dostęp do usługi productpage za pośrednictwem protokołu 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>"
Upewnij się, że strona produktu przykładowej aplikacji jest dostępna. Oczekiwane dane wyjściowe to:
<title>Simple Bookstore App</title>
Uwaga
Aby skonfigurować dostęp przychodzący HTTPS do usługi HTTPS, tj. skonfigurować bramę ruchu przychodzącego do wykonywania przekazywania SNI zamiast kończenia żądań przychodzących protokołu TLS, zaktualizuj tryb tls w definicji bramy na PASSTHROUGH
wartość . Spowoduje to, że brama przekaże ruch przychodzący "tak, jak to jest", bez przerywania protokołu TLS.
Konfigurowanie wzajemnej bramy ruchu przychodzącego TLS
Rozszerz definicję bramy, aby obsługiwać wzajemne protokoły TLS.
Zaktualizuj poświadczenia bramy ruchu przychodzącego, usuwając bieżący wpis tajny i tworząc nowy. Serwer używa certyfikatu urzędu certyfikacji do zweryfikowania swoich klientów i musimy użyć klucza ca.crt do przechowywania certyfikatu urzędu certyfikacji.
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
Użyj następującego manifestu, aby ponownie utworzyć klasę SecretProviderClass z certyfikatem urzędu certyfikacji.
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
Użyj następującego manifestu, aby ponownie wdrożyć przykładowy zasobnik, aby zsynchronizować wpisy tajne z usługi Azure Key Vault z klastrem.
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
Sprawdź
productpage-credential
wpis tajny utworzony w przestrzeni nazwaks-istio-ingress
klastra .kubectl describe secret/productpage-credential -n aks-istio-ingress
Przykładowe wyjście:
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
Użyj następującego manifestu, aby zaktualizować definicję bramy, aby ustawić tryb TLS na WARTOŚĆ 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
Weryfikacja
Spróbuj wysłać żądanie HTTPS przy użyciu wcześniejszego podejścia — bez przekazywania certyfikatu klienta — i zobacz, że kończy się niepowodzeniem.
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"
Przykładowe wyjście:
...
* 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
Przekaż certyfikat klienta z flagą --cert
i kluczem prywatnym z flagą --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>"
Upewnij się, że strona produktu przykładowej aplikacji jest dostępna. Oczekiwane dane wyjściowe to:
<title>Simple Bookstore App</title>
Usuwanie zasobów
Jeśli chcesz wyczyścić siatkę usługi Istio i ruch przychodzący (pozostawiając za klastrem), uruchom następujące polecenie:
az aks mesh disable --resource-group ${RESOURCE_GROUP} --name ${CLUSTER}
Jeśli chcesz wyczyścić wszystkie zasoby utworzone na podstawie dokumentów z instrukcjami istio, uruchom następujące polecenie:
az group delete --name ${RESOURCE_GROUP} --yes --no-wait
Azure Kubernetes Service