IBM Cloud Kubernetes Service Ingress から Istio Ingress Gateway への暗号化されたトラフィックの直接送信
相互 TLS を使用して、IBM Cloud Kubernetes Service Application Load Balancer が Istio Ingress ゲートウェイにトラフィックを送信するように構成します。
このブログ記事では、Ingress Application Load Balancer(ALB)をIBM Cloud Kubernetes Service(IKS)上で構成し、相互 TLS 認証を使用して、それらの間のトラフィックを保護しながら、Istio Ingress ゲートウェイにトラフィックを送信する方法を示します。
Istio なしで IKS を使用する場合、提供された ALB を使用してイングレス トラフィックを制御できます。このイングレス トラフィックのルーティングは、Kubernetes のIngressリソースとALB 固有のアノテーションを使用して構成されます。IKS は、DNS ドメイン名、そのドメインに一致する TLS 証明書、および証明書の秘密鍵を提供します。IKS は、証明書と秘密鍵をKubernetes シークレットに保存します。
IKS クラスターで Istio の使用を開始する場合、Istio 対応のワークロードにトラフィックを送信するための推奨される方法は、Kubernetes Ingressを使用する代わりに、Istio Ingress Gatewayを使用することです。Istio Ingress ゲートウェイを使用する主な理由の 1 つは、STRICT 相互 TLS を有効にすると、IKS によって提供される ALB がメッシュ内のサービスと直接通信できなくなるという事実です。Istio Ingress ゲートウェイのみをメインのエントリポイントとする移行中に、非 Istio サービスには従来の Ingress を引き続き使用し、メッシュの一部であるサービスには Istio Ingress ゲートウェイを使用できます。
IKS は、Istio ゲートウェイの IP 用に新しい DNS サブドメインを登録できるようにすることで、クライアントが Istio Ingress ゲートウェイにアクセスするための便利な方法を提供します。ドメインは、次の形式です: <cluster_name>-<globally_unique_account_HASH>-0001.<region>.containers.appdomain.cloud
。たとえば、mycluster-a1b2cdef345678g9hi012j3kl4567890-0001.us-south.containers.appdomain.cloud
などです。ALB ドメインの場合と同じように、IKS は証明書と秘密鍵を提供し、別の Kubernetes シークレットに保存します。
このブログでは、IKS Ingress ALB と Istio Ingress ゲートウェイをチェーン接続して、ALB 固有の機能と ALB サブドメイン名を引き続き使用できるようにしながら、Istio 対応のワークロードにトラフィックを送信する方法について説明します。ALB とゲートウェイ間の相互 TLS 認証を使用しながら、Istio Ingress ゲートウェイを介して Istio サービス メッシュ内のサービスにトラフィックを送信するように、IKS Ingress ALB を構成します。相互 TLS 認証では、ALB と Istio Ingress ゲートウェイが、ALB および NLB サブドメイン用に IKS によって提供される証明書と鍵を使用するように構成します。IKS によって提供される証明書を使用すると、ALB と Istio Ingress ゲートウェイ間の接続用に独自の証明書を管理するオーバーヘッドを節約できます。
NLB サブドメイン証明書を、意図したとおり Istio Ingress ゲートウェイのサーバー証明書として使用します。NLB サブドメイン証明書は、特定の NLB サブドメイン、この場合は Ingress ゲートウェイを提供するサーバーの ID を表します。
ALB サブドメイン証明書を、ALB と Istio Ingress 間の相互 TLS 認証のクライアント証明書として使用します。ALB がサーバーとして動作する場合、クライアントが ALB を認証できるように、ALB 証明書をクライアントに提示します。ALB が Istio Ingress ゲートウェイのクライアントとして動作する場合、Istio Ingress ゲートウェイが ALB を認証できるように、同じ証明書を Istio Ingress ゲートウェイに提示します。
Istio サイドカーのないサービスへのトラフィックは、以前と同様に ALB から直接流れ続けることができます。
以下の図は、説明した設定を示しています。クラスター内の 2 つのサービス、サービス A
と サービス B
を示しています。サービス A
には Istio サイドカーが挿入されており、相互 TLS が必要です。サービス B
には Istio サイドカーがありません。サービス B
には、サービス B
と直接通信する ALB を介してクライアントがアクセスできます。サービス A
にも、ALB を介してクライアントがアクセスできますが、この場合は、トラフィックは Istio Ingress ゲートウェイを通過する必要があります。ALB とゲートウェイ間の相互 TLS 認証は、IKS によって提供される証明書に基づいています。クライアントは Istio Ingress ゲートウェイに直接アクセスすることもできます。IKS は、ALB と Ingress ゲートウェイに異なる DNS ドメインを登録します。
初期設定
httptools
名前空間を作成し、Istio サイドカーの挿入を有効にします。$ kubectl create namespace httptools $ kubectl label namespace httptools istio-injection=enabled namespace/httptools created namespace/httptools labeled
httpbin
サンプルをhttptools
にデプロイします。$ kubectl apply -f @samples/httpbin/httpbin.yaml@ -n httptools service/httpbin created deployment.apps/httpbin created
ALB および Istio Ingress ゲートウェイ用のシークレットを作成します。
IKS は、ibmcloud ks nlb-dns-create
コマンドを使用して外部 IP の DNS ドメインを登録すると、TLS 証明書と秘密鍵を生成し、それらをデフォルト名前空間にシークレットとして保存します。IKS は、ALB の証明書と秘密鍵も、デフォルト名前空間にシークレットとして保存します。これらの認証情報は、ALB と Istio Ingress ゲートウェイが相互 TLS 認証中に提示する ID を確立するために必要です。ALB と Istio Ingress ゲートウェイがこれらの証明書を交換し、互いの証明書を信頼し、秘密鍵を使用してトラフィックを暗号化および署名するように構成します。
クラスターの名前を
CLUSTER_NAME
環境変数に保存します。$ export CLUSTER_NAME=<your cluster name>
ALB のドメイン名を
ALB_INGRESS_DOMAIN
環境変数に保存します。$ ibmcloud ks cluster get --cluster $CLUSTER_NAME | grep Ingress Ingress Subdomain: <your ALB ingress domain> Ingress Secret: <your ALB secret>
$ export ALB_INGRESS_DOMAIN=<your ALB ingress domain> $ export ALB_SECRET=<your ALB secret>
istio-ingressgateway
サービスの外部 IP を環境変数に保存します。$ export INGRESS_GATEWAY_IP=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}') $ echo INGRESS_GATEWAY_IP = $INGRESS_GATEWAY_IP
Istio Ingress ゲートウェイサービスの IP の DNS ドメインと証明書を作成します。
$ ibmcloud ks nlb-dns create classic --cluster $CLUSTER_NAME --ip $INGRESS_GATEWAY_IP --secret-namespace istio-system Host name subdomain is created as <some domain>
前のコマンドのドメイン名を環境変数に保存します。
$ export INGRESS_GATEWAY_DOMAIN=<the domain from the previous command>
登録済みのドメイン名を一覧表示します。
$ ibmcloud ks nlb-dnss --cluster $CLUSTER_NAME Retrieving host names, certificates, IPs, and health check monitors for network load balancer (NLB) pods in cluster <your cluster>... OK Hostname IP(s) Health Monitor SSL Cert Status SSL Cert Secret Name Secret Namespace <your ingress gateway hostname> <your ingress gateway IP> None created <the matching secret name> istio-system ...
新しいドメイン名の証明書(4 番目のフィールド)のステータスが
enabled
になるまで待ちます(最初はpending
です)。新しいドメイン名のシークレットの名前を保存します。
$ export INGRESS_GATEWAY_SECRET=<the secret's name as shown in the SSL Cert Secret Name column>
ALB に提供されたシークレットから証明書と鍵を抽出します。
$ mkdir alb_certs $ kubectl get secret $ALB_SECRET --namespace=default -o yaml | grep 'tls.key:' | cut -f2 -d: | base64 --decode > alb_certs/client.key $ kubectl get secret $ALB_SECRET --namespace=default -o yaml | grep 'tls.crt:' | cut -f2 -d: | base64 --decode > alb_certs/client.crt $ ls -al alb_certs -rw-r--r-- 1 user staff 3738 Sep 11 07:57 client.crt -rw-r--r-- 1 user staff 1675 Sep 11 07:57 client.key
Let’s Encrypt証明書の発行者である、IKS によって提供される証明書の発行者証明書をダウンロードします。この証明書を、ALB と Istio Ingress ゲートウェイの両方で信頼する認証局の証明書として指定します。
$ curl https://letsencrypt.dokyumento.jp/certs/trustid-x3-root.pem --output trusted.crt
相互 TLS 接続を確立するために ALB によって使用される Kubernetes シークレットを作成します。
$ kubectl create secret generic alb-certs -n istio-system --from-file=trusted.crt --from-file=alb_certs/client.crt --from-file=alb_certs/client.key secret "alb-certs" created
相互 TLS の場合、
cacert
キーを持つ<tls-cert-secret>-cacert
という名前の別のシークレットがイングレス ゲートウェイに必要です。$ kubectl create -n istio-system secret generic $INGRESS_GATEWAY_SECRET-cacert --from-file=ca.crt=trusted.crt secret/cluster_name-hash-XXXX-cacert created
相互 TLS イングレス ゲートウェイを構成します。
このセクションでは、外部クライアントとゲートウェイの間で相互 TLS を実行するように Istio イングレス ゲートウェイを構成します。イングレス ゲートウェイと ALB に提供された証明書と鍵を使用します。
ポート 443 でのみ相互 TLS を使用したアクセスを許可する
Gateway
を定義します。$ kubectl apply -n httptools -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: default-ingress-gateway spec: selector: istio: ingressgateway # use istio default ingress gateway servers: - port: number: 443 name: https protocol: HTTPS tls: mode: MUTUAL credentialName: $INGRESS_GATEWAY_SECRET hosts: - "$INGRESS_GATEWAY_DOMAIN" - "httpbin.$ALB_INGRESS_DOMAIN" EOF
Gateway
を介して入るトラフィックのルートを構成します。$ kubectl apply -n httptools -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: default-ingress spec: hosts: - "$INGRESS_GATEWAY_DOMAIN" - "httpbin.$ALB_INGRESS_DOMAIN" gateways: - default-ingress-gateway http: - match: - uri: prefix: /status route: - destination: port: number: 8000 host: httpbin.httptools.svc.cluster.local EOF
クライアント証明書(
--cert
オプション)と秘密鍵(--key
オプション)をパラメータとして渡し、curl を使用してhttpbin
にリクエストを送信します。$ curl https://$INGRESS_GATEWAY_DOMAIN/status/418 --cert alb_certs/client.crt --key alb_certs/client.key -=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`
ALB およびイングレス ゲートウェイの証明書と鍵を含むディレクトリを削除します。
$ rm -r alb_certs trusted.crt
ALB を構成します。
alb-certs
シークレットに保存されている証明書を使用しながら、Istio イングレス ゲートウェイにトラフィックを送信するように、Ingress リソースを構成する必要があります。通常、ALB はトラフィックをアプリに転送する前に HTTPS リクエストを復号化します。Ingress リソースの ssl-services
アノテーションを使用すると、Istio イングレス ゲートウェイに転送する前にトラフィックを再暗号化するように ALB を構成できます。このアノテーションを使用すると、相互 TLS に必要な alb-certs
シークレットに保存されている証明書を指定することもできます。
ALB の
Ingress
リソースを構成します。トラフィックを Istio イングレス ゲートウェイに転送するには、istio-system
名前空間にIngress
リソースを作成する必要があります。$ kubectl apply -f - <<EOF apiVersion: extensions/v1beta1 kind: Ingress metadata: name: alb-ingress namespace: istio-system annotations: ingress.bluemix.net/ssl-services: "ssl-service=istio-ingressgateway ssl-secret=alb-certs proxy-ssl-name=$INGRESS_GATEWAY_DOMAIN" spec: tls: - hosts: - httpbin.$ALB_INGRESS_DOMAIN secretName: $ALB_SECRET rules: - host: httpbin.$ALB_INGRESS_DOMAIN http: paths: - path: /status backend: serviceName: istio-ingressgateway servicePort: 443 EOF
ALB イングレスをテストします。
$ curl https://httpbin.$ALB_INGRESS_DOMAIN/status/418 -=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`
おめでとうございます!IKS Ingress ALB が Istio イングレスゲートウェイに暗号化されたトラフィックを送信するように設定されました。Istio イングレスゲートウェイのホスト名と証明書を割り当て、その証明書を Istio イングレスゲートウェイのサーバー証明書として使用しました。ALB のクライアント証明書として、IKS が ALB に提供した証明書を使用しました。証明書を Kubernetes シークレットとしてデプロイしたら、特定のパスのイングレストラフィックを ALB から Istio イングレスゲートウェイに転送し、ALB と Istio イングレスゲートウェイ間の相互 TLS 認証に証明書を使用しました。
クリーンアップ
Gateway
設定、VirtualService
、およびシークレットを削除します。$ kubectl delete ingress alb-ingress -n istio-system $ kubectl delete virtualservice default-ingress -n httptools $ kubectl delete gateway default-ingress-gateway -n httptools $ kubectl delete secrets alb-certs -n istio-system $ rm -rf alb_certs trusted.crt $ unset CLUSTER_NAME ALB_INGRESS_DOMAIN ALB_SECRET INGRESS_GATEWAY_DOMAIN INGRESS_GATEWAY_SECRET
httpbin
サービスをシャットダウンします。$ kubectl delete -f @samples/httpbin/httpbin.yaml@ -n httptools
httptools
名前空間を削除します。$ kubectl delete namespace httptools