TLS を使用して NGINX イングレス コントローラーを有効にするようにシークレット ストア CSI ドライバーを設定する
この記事では、Azure Kubernetes Service (AKS) クラスターと Azure Key Vault (AKV) インスタンスで TLS を使用して NGINX イングレス コントローラーをセキュリティで保護するプロセスについて説明します。 詳細については、Kubernetes の TLS に関するページを参照してください。
次のいずれかの方法でイングレス TLS 証明書をクラスターにインポートできます。
- アプリケーション: アプリケーション配置マニフェストによって、プロバイダー ボリュームが宣言されてマウントされます。 アプリケーションをデプロイした場合にのみ、クラスターで証明書を利用できます。 アプリケーションを削除すると、シークレットも削除されます。 このシナリオは、アプリケーションのセキュリティ インフラストラクチャおよびクラスターとの統合を担当する開発チームに適しています。
- イングレス コントローラー: プロバイダー ボリュームを宣言してマウントするようにイングレス デプロイが変更されます。 シークレットは、イングレス ポッドの作成時にインポートされます。 アプリケーションのポッドは TLS 証明書にアクセスできません。 このシナリオは、あるチーム (つまり、IT) がインフラストラクチャとネットワーク コンポーネント (HTTPS TLS 証明書を含む) を管理および作成し、他のチームがアプリケーションのライフサイクルを管理するシナリオに適しています。
前提条件
- Azure サブスクリプションをお持ちでない場合は、開始する前に 無料アカウント を作成してください。
- 開始する前に、Azure CLI バージョンが
2.30.0
以上であることを確認するか、最新バージョンをインストールしてください。 - シークレット ストア CSI ドライバーが構成されている AKS クラスター。
- Azure Key Vault インスタンス。
TLS 証明書を生成する
次のコマンドを使用して TLS 証明書を生成します。
export CERT_NAME=aks-ingress-cert openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -out aks-ingress-tls.crt \ -keyout aks-ingress-tls.key \ -subj "/CN=demo.azure.com/O=aks-ingress-tls"
AKV に証明書をインポートする
次のコマンドを使用して、証明書を PFX ファイルにエクスポートします。
export AKV_NAME="[YOUR AKV NAME]" openssl pkcs12 -export -in aks-ingress-tls.crt -inkey aks-ingress-tls.key -out $CERT_NAME.pfx # skip Password prompt
az keyvault certificate import
コマンドを使用して証明書をインポートします。az keyvault certificate import --vault-name $AKV_NAME --name $CERT_NAME --file $CERT_NAME.pfx
SecretProviderClass をデプロイする
次のコマンドを使用して、新しい名前空間をエクスポートします。
export NAMESPACE=ingress-basic
kubectl create namespace
コマンドを使って名前空間を作成します。kubectl create namespace $NAMESPACE
アクセス ID を提供する方法を選択し、それに従って SecretProviderClass YAML を構成します。
- 必ず
objectType=secret
を使用してください。これは、AKV からプライベート キーと証明書を取得する唯一の方法です。 secretObjects
セクションにtype
としてkubernetes.io/tls
を設定します。
SecretProviderClass の例については、次を参照してください:
apiVersion: secrets-store.csi.x-k8s.io/v1 kind: SecretProviderClass metadata: name: azure-tls spec: provider: azure secretObjects: # secretObjects defines the desired state of synced K8s secret objects - secretName: ingress-tls-csi type: kubernetes.io/tls data: - objectName: $CERT_NAME key: tls.key - objectName: $CERT_NAME key: tls.crt parameters: usePodIdentity: "false" useVMManagedIdentity: "true" userAssignedIdentityID: <client id> keyvaultName: $AKV_NAME # the name of the AKV instance objects: | array: - | objectName: $CERT_NAME objectType: secret tenantId: $TENANT_ID # the tenant ID of the AKV instance
- 必ず
kubectl apply
コマンドを使って Kubernetes クラスターに SecretProviderClass を適用します。kubectl apply -f secretProviderClass.yaml -n $NAMESPACE
イングレス コントローラーをデプロイする
公式のイングレス チャート リポジトリを追加する
次の
helm
コマンドを使用して、公式のイングレス チャート リポジトリを追加します。helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update
NGINX イングレスを構成してデプロイする
シナリオにしたがって、証明書をアプリケーションとイングレス コントローラーのどちらにバインドするかを選択できます。 選択内容に応じて、以下の手順に従います。
証明書をアプリケーションにバインドする
helm install
コマンドを使用して証明書をアプリケーションにバインドします。 アプリケーションのデプロイでは、シークレット ストア CSI ドライバーの Azure Key Vault プロバイダーが参照されます。helm install ingress-nginx/ingress-nginx --generate-name \ --namespace $NAMESPACE \ --set controller.replicaCount=2 \ --set controller.nodeSelector."kubernetes\.io/os"=linux \ --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \ --set defaultBackend.nodeSelector."kubernetes\.io/os"=linux
証明書をイングレス コントローラーにバインドする
helm install
コマンドを使用して、証明書をイングレス コントローラーにバインドします。 イングレス コントローラーのデプロイでは、シークレット ストア CSI ドライバーの Azure Key Vault プロバイダーが参照されます。Note
アクセス方法として Microsoft Entra ポッドマネージド ID を使わない場合は、
--set controller.podLabels.aadpodidbinding=$AAD_POD_IDENTITY_NAME
を含む行を削除します。また、SecretProviderClass をポッドにバインドすることは、Secrets Store CSI Driver でそれをマウントし、Kubernetes シークレットを生成するために必要です。 「マウントされたコンテンツを Kubernetes シークレットと同期する」を参照してください。
helm install ingress-nginx/ingress-nginx --generate-name \ --namespace $NAMESPACE \ --set controller.replicaCount=2 \ --set controller.nodeSelector."kubernetes\.io/os"=linux \ --set defaultBackend.nodeSelector."kubernetes\.io/os"=linux \ --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \ --set controller.podLabels.aadpodidbinding=$AAD_POD_IDENTITY_NAME \ -f - <<EOF controller: extraVolumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "azure-tls" extraVolumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true EOF
kubectl get secret
コマンドを使用して、Kubernetes シークレットが作成されたことを確認します。kubectl get secret -n $NAMESPACE NAME TYPE DATA AGE ingress-tls-csi kubernetes.io/tls 2 1m34s
アプリケーションをデプロイする
ここでも、シナリオに応じて手順は若干変わります。 選択したシナリオに対応する指示に従ってください。
アプリケーション参照を使用してアプリケーションをデプロイする
次の内容を含む
aks-helloworld-one.yaml
という名前のファイルを作成します。apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-one spec: replicas: 1 selector: matchLabels: app: aks-helloworld-one template: metadata: labels: app: aks-helloworld-one spec: containers: - name: aks-helloworld-one image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "Welcome to Azure Kubernetes Service (AKS)" volumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true volumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "azure-tls" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-one spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-one
次の内容を含む
aks-helloworld-two.yaml
という名前のファイルを作成します。apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-two spec: replicas: 1 selector: matchLabels: app: aks-helloworld-two template: metadata: labels: app: aks-helloworld-two spec: containers: - name: aks-helloworld-two image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "AKS Ingress Demo" volumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true volumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "azure-tls" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-two spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-two
kubectl apply
コマンドを使用して YAML ファイルをクラスターに適用します。kubectl apply -f aks-helloworld-one.yaml -n $NAMESPACE kubectl apply -f aks-helloworld-two.yaml -n $NAMESPACE
kubectl get secret
コマンドを使用して、Kubernetes シークレットが作成されたことを確認します。kubectl get secret -n $NAMESPACE NAME TYPE DATA AGE ingress-tls-csi kubernetes.io/tls 2 1m34s
イングレス コントローラー参照を使用してアプリケーションをデプロイする
次の内容を含む
aks-helloworld-one.yaml
という名前のファイルを作成します。apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-one spec: replicas: 1 selector: matchLabels: app: aks-helloworld-one template: metadata: labels: app: aks-helloworld-one spec: containers: - name: aks-helloworld-one image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "Welcome to Azure Kubernetes Service (AKS)" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-one spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-one
次の内容を含む
aks-helloworld-two.yaml
という名前のファイルを作成します。apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-two spec: replicas: 1 selector: matchLabels: app: aks-helloworld-two template: metadata: labels: app: aks-helloworld-two spec: containers: - name: aks-helloworld-two image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "AKS Ingress Demo" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-two spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-two
kubectl apply
コマンドを使用して YAML ファイルをクラスターに適用します。kubectl apply -f aks-helloworld-one.yaml -n $NAMESPACE kubectl apply -f aks-helloworld-two.yaml -n $NAMESPACE
シークレットを参照するイングレス リソースをデプロイする
シークレットを参照する Kubernetes イングレス リソースをデプロイできるようになりました。
次の内容を含む
hello-world-ingress.yaml
という名前のファイルを作成します。apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-tls annotations: nginx.ingress.kubernetes.io/rewrite-target: /$2 spec: ingressClassName: nginx tls: - hosts: - demo.azure.com secretName: ingress-tls-csi rules: - host: demo.azure.com 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
前に作成したシークレットを参照する
tls
セクションをメモし、kubectl apply
コマンドを使ってファイルをクラスターに適用します。kubectl apply -f hello-world-ingress.yaml -n $NAMESPACE
イングレス コントローラーの外部 IP アドレスを取得する
kubectl get service
コマンドを使用して、イングレス コントローラーの外部 IP アドレスを取得します。kubectl get service --namespace $NAMESPACE --selector app.kubernetes.io/name=ingress-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-ingress-1588032400-controller LoadBalancer 10.0.255.157 EXTERNAL_IP 80:31293/TCP,443:31265/TCP 19m nginx-ingress-1588032400-default-backend ClusterIP 10.0.223.214 <none> 80/TCP 19m
TLS でセキュリティ保護されたイングレスをテストする
次の
curl
コマンドを使用して、イングレスが TLS で正しく構成されていることを確認します。 前の手順の外部 IP を使用していることを確認します。curl -v -k --resolve demo.azure.com:443:EXTERNAL_IP https://demo.azure.com
アドレスにはほかのパスが指定されなかったため、イングレス コントローラーは既定の / ルートに設定されます。 次の簡約された出力例に示すように、最初のデモ アプリケーションが返されます。
[...] <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <link rel="stylesheet" type="text/css" href="/static/default.css"> <title>Welcome to Azure Kubernetes Service (AKS)</title> [...]
curl
コマンドの -v パラメーターにより、受信した TLS 証明書などの詳細な情報が出力されます。 curl の出力の途中で、独自の TLS 証明書が使用されたことを確認できます。 -k パラメーターにより、自己署名証明書を使用している場合でも、引き続きページが読み込まれます。 次の例は、issuer: CN=demo.azure.com; O=aks-ingress-tls 証明書が使用されたことを示しています。[...] * Server certificate: * subject: CN=demo.azure.com; O=aks-ingress-tls * start date: Oct 22 22:13:54 2021 GMT * expire date: Oct 22 22:13:54 2022 GMT * issuer: CN=demo.azure.com; O=aks-ingress-tls * SSL certificate verify result: self signed certificate (18), continuing anyway. [...]
/hello-world-two パスを
https://demo.azure.com/hello-world-two
などのアドレスに追加し、2 番目のデモ アプリケーションが正しく構成されていることを確認します。curl -v -k --resolve demo.azure.com:443:EXTERNAL_IP https://demo.azure.com/hello-world-two
次の簡約された出力例に示すように、カスタム タイトル付きの 2 番目のデモ アプリケーションが返されます。
[...] <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <link rel="stylesheet" type="text/css" href="/static/default.css"> <title>AKS Ingress Demo</title> [...]
Azure Kubernetes Service