Azure Kubernetes Service (AKS) のイングレス コントローラーで TLS を使用する

トランスポート層セキュリティ (TLS) は、証明書を使用して、暗号化、認証、整合性などのセキュリティを通信に提供するためのプロトコルです。 AKS 上のイングレス コントローラーで TLS を使用すると、アプリケーション間の通信をセキュリティで保護しながら、イングレス コントローラーの利点も得ることができます。

独自の証明書を持ち込み、シークレット ストア CSI ドライバーを使用して統合できます。 または、cert-manager を使用することもできます。これは Let's Encrypt 証明書を自動的に生成して構成するために使用されます。 最後に、それぞれが 1 つの IP アドレスでアクセスできる、2 つのアプリケーションを AKS クラスターで実行します。

Note

Nginx に基づく Kubernetes 用のオープンソース イングレス コントローラーは 2 つあります。1 つは Kubernetes コミュニティによって管理され (kubernetes/ingress-nginx)、もう 1 つは NGINX, Inc. によって管理されています (nginxinc/kubernetes-ingress)。 この記事では、Kubernetes コミュニティのイングレス コントローラーを使用します。

開始する前に

この記事は、イングレス コントローラーとアプリケーションが設定されていることを前提としています。 イングレス コントローラーまたはサンプル アプリケーションが必要な場合は、「イングレス コントローラーを作成する」を参照してください。

この記事では Helm 3 を使用して、サポートされているバージョンの Kubernetes に NGINX イングレス コントローラーをインストールします。 最新リリースの Helm を使用しており、ingress-nginx および jetstack Helm リポジトリにアクセスできることを確認します。 この記事に記載されている手順は、以前のバージョンの Helm グラフ、NGINX イングレス コントローラー、または Kubernetes と互換性がない可能性があります。

Helm の構成および使用方法の詳細については、「Azure Kubernetes Service (AKS) での Helm を使用したアプリケーションのインストール」を参照してください。 アップグレード手順については、「Helm のインストール ドキュメント」を参照してください。Helm の構成と使用について詳しくは、「Azure Kubernetes Service (AKS) での Helm を使用したアプリケーションのインストール」を参照してください。

また、この記事では、Azure Container Registry が統合された既存の AKS クラスターがあることを前提としています。 ACR が統合された AKS クラスターを作成する方法の詳細については、「Azure Kubernetes Service から Azure Container Registry の認証を受ける」を参照してください。

この記事では、Azure CLI バージョン 2.0.64 以降を実行していることも必要です。 バージョンを確認するには、az --version を実行します。 インストールまたはアップグレードする必要がある場合は、Azure CLI のインストールに関するページを参照してください。

シークレット ストア CSI ドライバーを使用して独自の証明書で TLS を使用する

シークレット ストア CSI ドライバーを使用して独自の証明書で TLS を使用するには、シークレット ストア CSI ドライバーが構成された AKS クラスターと、Azure Key Vault インスタンスが必要です。 詳細については、「TLS を使用して NGINX イングレス コントローラーを有効にするようにシークレット ストア CSI ドライバーを設定する」を参照してください。

Let's Encrypt 証明書で TLS を使用する

Let's Encrypt 証明書で TLS を使用するには、Let's Encrypt 証明書を自動的に生成して構成するために使用される cert-manager をデプロイします。

Helm chart で使用される cert-manager イメージを 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

Note

コンテナー イメージを ACR にインポートするだけでなく、Helm Chart を ACR にインポートすることもできます。 詳細については、「Azure Container Registry に対する Helm chart のプッシュおよびプル」を参照してください。

イングレス コントローラーの構成オプション

既定では、NGINX イングレス コントローラーは新しいパブリック IP アドレスの割り当てによって作成されます。 このパブリック IP アドレスは、イングレス コントローラーの有効期間のみ静的で、コントローラーを削除して再作成すると失われます。

次のいずれかの方法を選択できます。

  • 動的パブリック IP アドレスの使用
  • 静的パブリック IP アドレスの使用

静的パブリック IP アドレスの使用

一般的な構成要件は、NGINX イングレス コントローラーに既存の静的パブリック IP アドレスを提供することです。 イングレス コントローラーが削除されても、静的パブリック IP アドレスはそのまま残ります。

下のコマンドでは、AKS クラスターを削除すると削除される IP アドレスが作成されます。

最初に、az aks show コマンドを使用して AKS クラスターのリソース グループ名を取得します。

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

次に、az network public-ip create コマンドを使用して、static 割り当て方式を使用してパブリック IP アドレスを作成します。 次の例では、前の手順で取得した AKS クラスター リソース グループに myAKSPublicIP という名前のパブリック IP アドレスを作成します。

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

または、AKS クラスターとは別に管理できる別のリソース グループに IP アドレスを作成することもできます。 別のリソース グループに IP アドレスを作成する場合は、次のことを確認します。

  • AKS クラスターで使用されるクラスター ID に、ネットワーク共同作成者などのリソース グループへの委任されたアクセス許可が含まれている。
  • --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-resource-group"="<RESOURCE_GROUP>"パラメーターを追加します。 <RESOURCE_GROUP> を IP アドレスが存在するリソース グループの名前に置き換える。

イングレス コントローラーを更新する場合は、イングレス コントローラーがイングレス コントローラー サービスに割り当てられるロード バランサーの静的 IP アドレスを認識できるように、Helm リリースにパラメーターを渡す必要があります。 HTTPS 証明書が正常に動作するには、DNS 名ラベルを使用して、イングレス コントローラーの IP アドレス向けに FQDN を構成します。

  1. --set controller.service.loadBalancerIP="<EXTERNAL_IP>"パラメーターを追加します。 前の手順で作成された独自のパブリック IP アドレスを指定します。
  2. --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"="<DNS_LABEL>"パラメーターを追加します。 DNS ラベルは、イングレス コントローラーを最初にデプロイするときに設定することも、後で構成することもできます。
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

詳細については、「Azure Kubernetes Service (AKS) ロード バランサーで静的パブリック IP アドレスと DNS ラベルを使用する」を参照してください。

動的 IP アドレスを使用する

イングレス コントローラーが作成されると、イングレス コントローラー用に Azure のパブリック IP アドレスが作成されます。 このパブリック IP アドレスは、イングレス コントローラーが存続している間は静的です。 イングレス コントローラーを削除すると、パブリック IP アドレスの割り当てが失われます。 その後別のイングレス コントローラーを作成すると、新しいパブリック IP アドレスが割り当てられます。

パブリック IP アドレスを取得するには、kubectl get service コマンドを使います。

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

出力例は、イングレス コントローラーに関する詳細を示しています。

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

カスタム ドメインを使用している場合は、DNS ゾーンに A レコードを追加する必要があります。 それ以外の場合は、完全修飾ドメイン名 (FQDN) を使用してパブリック IP アドレスを構成する必要があります。

DNS ゾーンに A レコードを追加する

az network dns record-set a add-record を使用して、A レコードを NGINX サービスの外部 IP アドレスが使用された DNS ゾーンに追加します。

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

イングレス コントローラーの FQDN を構成する

必要に応じて、イングレス コントローラーの IP アドレスに、カスタム ドメインではなく FQDN を構成することもできます。 FQDN の形式は、<CUSTOM LABEL>.<AZURE REGION NAME>.cloudapp.azure.com のようになります。

方法 1: Azure CLI を使用して DNS ラベルを設定する

このサンプルは、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: Helm グラフの設定を使用して DNS ラベルを設定する

--set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name" パラメーターを使用することで、注釈の設定を、Helm グラフの構成に渡すことができます。 このパラメーターは、イングレス コントローラーを最初にデプロイするときに設定することも、後で構成することもできます。 次の例は、コントローラーをデプロイした後にこの設定を更新する方法を示しています。

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 の証明書を取得および構成するには、いくつかの方法があります。 この記事では、Lets Encrypt 証明書を自動的に作成および管理する機能を提供する cert-manager の使用方法を説明します。

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 プロジェクトについてのページを参照してください。

CA クラスター発行者を作成する

証明書を発行する前に、cert-manager には Issuer リソースまたは ClusterIssuer リソースが必要です。 これらの Kubernetes リソースは機能面では同一ですが、Issuer は単一の名前空間で機能し、ClusterIssuer はすべての名前空間にわたって機能します。 詳細については、cert-manager issuer についてのページを参照してください。

次のマニフェスト例を使用して、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

イングレス ルートを更新する

FQDN またはカスタム ドメインへのトラフィックを処理するようにイングレス ルートを更新する必要があります。

次の例では、アドレス 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 というサービスにルーティングされます。

Note

カスタム ドメインではなく、イングレス コントローラーの IP アドレスの FQDN を構成した場合は、hello-world-ingress.MY_CUSTOM_DOMAIN ではなく、FQDN を使用します。 たとえば、FQDN が demo-aks-ingress.eastus.cloudapp.azure.com の場合は、hello-world-ingress.yamlhello-world-ingress.MY_CUSTOM_DOMAINdemo-aks-ingress.eastus.cloudapp.azure.com に置き換えます。

下の例の YAML を使用して、hello-world-ingress.yaml ファイルを作成または更新します。 spec.tls.hostsspec.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 の証明書についてのページを参照してください。 証明書マネージャーによって証明書オブジェクトが ingress-shim を使用して自動的に作成されており、その証明書オブジェクトは v0.2.2 以降の証明書マネージャーで自動的にデプロイされます。 詳しくは、ingress-shim のドキュメントをご覧ください。

証明書が正常に作成されたことを確認するには、kubectl get certificate --namespace ingress-basic コマンドを使用して、READYTrue になっていることを確認します。これには数分かかることがあります。

kubectl get certificate --namespace ingress-basic

下の出力例は、証明書の状態を示しています。

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

イングレスの構成をテストする

Web ブラウザーを開いて、hello-world-ingress.MY_CUSTOM_DOMAIN またはお使いの Kubernetes イングレス コントローラーの FQDN にアクセスします。 HTTPS を使用するようにリダイレクトされ、証明書が信頼されると、Web ブラウザーにデモ アプリケーションが 表示されます。 /hello-world-two パスを追加すると、カスタム タイトルの付いた 2 番目のデモ アプリケーションが表示されます。

リソースをクリーンアップする

この記事では、Helm を使用して、イングレス コンポーネント、証明書、およびサンプル アプリをインストールしました。 Helm グラフをデプロイすると、多数の Kubernetes リソースが作成されます。 これらのリソースには、ポッド、デプロイ、およびサービスが含まれます。 これらのリソースをクリーンアップするには、サンプルの名前空間全体を削除するか、またはリソースを個々に削除します。

サンプルの名前空間とすべてのリソースを削除する

サンプルの名前空間全体を削除するには、kubectl delete コマンドを使用して、名前空間の名前を指定します。 名前空間内のすべてのリソースが削除されます。

kubectl delete namespace ingress-basic

リソースを個々に削除する

作成したリソースを個々に削除するという、きめ細かな方法もあります。 最初に、クラスター発行者リソースを削除します。

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

helm list コマンドを使用して、Helm リリースを一覧表示します。 次の出力例に示すように、nginxcert-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

次に、2 つのサンプル アプリケーションを削除します。

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 への外部コンポーネントが含まれています。 これらのコンポーネントの詳細については、次のプロジェクト ページを参照してください。

次のこともできます。