Azure Firewall を使用して Azure Kubernetes Service (AKS) クラスターを保護する
この記事では、Azure Firewall を使用して送信トラフィックと受信トラフィックを保護することで、Azure Kubernetes Service (AKS) クラスターを保護する方法について説明します。
背景
Azure Kubernetes Service (AKS) では、Azure 上にマネージド Kubernetes クラスターが提供されます。 詳細については、「Azure Kubernetes Service」を参照してください。
AKS はフル マネージド ソリューションですが、クラスターと外部ネットワーク間のイングレス トラフィックとエグレス トラフィックをセキュリティで保護する組み込みソリューションを提供していません。 Azure Firewall は、これに対するソリューションを提供します。
AKS クラスターは仮想ネットワークにデプロイされます。 このネットワークは、(AKS によって作成された) マネージドでも、(ユーザーによって事前に構成された) カスタムでもかまいません。 どちらの場合も、クラスターには、その仮想ネットワークの外部にあるサービスに対する送信依存関係があります (サービスには受信依存関係はありません)。 管理および運用の目的で、AKS クラスター内のノードは、これらのアウトバウンドの依存関係を記述する特定のポートおよび完全修飾ドメイン名 (FQDN) にアクセスする必要があります。 これは、Kubernetes API サーバーと通信するノードを含むがこれに限定されないさまざまな関数に必要です。 それらは、コア Kubernetes クラスター コンポーネントとノード セキュリティ更新プログラムをダウンロードしてインストールしたり、Microsoft Container Registry (MCR) から基本システム コンテナー イメージを取得したりします。 これらのアウトバウンド依存関係は、ほぼすべて、背後に静的アドレスがない FQDN を使用して定義されています。 静的アドレスがないということは、ネットワーク セキュリティ グループを使用して AKS クラスターからの送信トラフィックをロック ダウンできないことを意味します。 このため、既定では、AKS クラスターには無制限の送信 (エグレス) インターネット アクセスがあります。 このレベルのネットワーク アクセスでは、実行しているノードやサービスから必要に応じて外部リソースにアクセスできます。
ただし、運用環境では、Kubernetes クラスターとの通信を保護して、他の脆弱性と共にデータが流出するのを防ぐ必要があります。 すべての送受信ネットワーク トラフィックは、一連のセキュリティ ルールに基づいて監視と制御を行う必要があります。 これを行う場合は、エグレス トラフィックを制限する必要がありますが、正常なクラスター メンテナンス タスクを維持し、前述の送信依存関係を満たすために、限られた数のポートとアドレスに引き続きアクセスできる必要があります。
最も簡単なソリューションは、ドメイン名に基づいて送信トラフィックを制御できるファイアウォール デバイスを使用することです。 通常、ファイアウォールは、信頼されたネットワークと信頼されていないネットワーク (インターネットなど) との間にバリアを確立します。 たとえば、Azure Firewall では、送信先の FQDN に基づいて送信 HTTP および HTTPS トラフィックを制限できるため、きめ細かいエグレス トラフィック制御が可能になりますが、同時に、AKS クラスターの送信依存関係 (NSG では実行できないこと) を含む FQDN へのアクセスを提供できます。 同様に、共有境界ネットワークにデプロイされた Azure Firewall で脅威インテリジェンスベースのフィルター処理を有効にすることで、イングレス トラフィックを制御し、セキュリティを強化することができます。 このフィルター処理では、既知の悪意のある IP アドレスとドメインとの間のアラートを提供し、トラフィックを拒否することができます。
これがサンプル環境で実際にどのように動作するのかを簡単に確認するには、次のビデオをご覧ください。
bash スクリプト ファイルと yaml ファイルを含む zip ファイルを Microsoft ダウンロード センター からダウンロードして、ビデオで使用されるサンプル環境を自動的に構成できます。 イングレス トラフィックとエグレス トラフィック両方を保護するように Azure Firewall を構成します。 次のガイドでは、カスタム構成を設定できるように、スクリプトの各手順について詳しく説明します。
次の図は、スクリプトとガイドが構成するビデオのサンプル環境を示しています。
スクリプトと次のガイドには 1 つの違いがあります。 スクリプトはマネージド ID を使用しますが、ガイドではサービス プリンシパルを使用します。 ここでは、クラスター・リソースを管理および作成するための ID を作成する 2 つの異なる方法を示します。
Azure Firewall を使用したエグレス トラフィックの制限
環境変数を使用して構成を設定する
リソースの作成に使用する一連の環境変数を定義します。
PREFIX="aks-egress"
RG="${PREFIX}-rg"
LOC="eastus"
PLUGIN=azure
AKSNAME="${PREFIX}"
VNET_NAME="${PREFIX}-vnet"
AKSSUBNET_NAME="aks-subnet"
# DO NOT CHANGE FWSUBNET_NAME - This is currently a requirement for Azure Firewall.
FWSUBNET_NAME="AzureFirewallSubnet"
FWNAME="${PREFIX}-fw"
FWPUBLICIP_NAME="${PREFIX}-fwpublicip"
FWIPCONFIG_NAME="${PREFIX}-fwconfig"
FWROUTE_TABLE_NAME="${PREFIX}-fwrt"
FWROUTE_NAME="${PREFIX}-fwrn"
FWROUTE_NAME_INTERNET="${PREFIX}-fwinternet"
複数のサブネットを含んだ仮想ネットワークを作成する
クラスター用とファイアウォール用の 2 つのサブネットを持つ仮想ネットワークを作成します。 必要に応じて、内部サービス イングレス用のものを作成することもできます。
すべてのリソースを保持するリソース グループを作成します。
# Create Resource Group
az group create --name $RG --location $LOC
AKS クラスターと Azure Firewall をホストするための 2 つのサブネットを含む仮想ネットワークを作成します。 それぞれに独自のサブネットがあります。 AKS ネットワークから始めましょう。
# Dedicated virtual network with AKS subnet
az network vnet create \
--resource-group $RG \
--name $VNET_NAME \
--location $LOC \
--address-prefixes 10.42.0.0/16 \
--subnet-name $AKSSUBNET_NAME \
--subnet-prefix 10.42.1.0/24
# Dedicated subnet for Azure Firewall (Firewall name cannot be changed)
az network vnet subnet create \
--resource-group $RG \
--vnet-name $VNET_NAME \
--name $FWSUBNET_NAME \
--address-prefix 10.42.2.0/24
UDR を使用する Azure ファイアウォールの作成と設定
Azure Firewall の受信および送信規則を構成する必要があります。 ファイアウォールの主な目的は、組織が AKS クラスターに対してきめ細かなイングレスおよびエグレス トラフィック規則を設定できるようにすることです。
重要
クラスターまたはアプリケーションにより、同じ送信先または送信先の小さいサブセットに対して多数の送信接続が作成される場合、フロントエンド IP あたりのポート数の上限に達するのを防ぐため、より多くのファイアウォール フロントエンド IP が必要になることがあります。 複数の IP を持つ Azure ファイアウォールを作成する方法の詳細については、「こちら」を参照してください
Azure Firewall フロントエンド アドレスとして使用される Standard SKU のパブリック IP リソースを作成します。
az network public-ip create -g $RG -n $FWPUBLICIP_NAME -l $LOC --sku "Standard"
Azure ファイアウォールを作成するには、プレビューの cli 拡張機能を登録します。
# Install Azure Firewall preview CLI extension
az extension add --name azure-firewall
# Deploy Azure Firewall
az network firewall create -g $RG -n $FWNAME -l $LOC --enable-dns-proxy true
これで、以前に作成した IP アドレスをファイアウォール フロントエンドに割り当てることができるようになります。
Note
Azure Firewall へのパブリック IP アドレスの設定には数分かかる場合があります。 ネットワーク規則で FQDN を利用するには、DNS プロキシを有効にする必要があります。有効にすると、ファイアウォールではポート 53 でリッスンが行われ、先ほど指定した DNS サーバーに DNS 要求が転送されます。 これにより、ファイアウォールでその FQDN を自動的に変換できるようになります。
# Configure Firewall IP Config
az network firewall ip-config create -g $RG -f $FWNAME -n $FWIPCONFIG_NAME --public-ip-address $FWPUBLICIP_NAME --vnet-name $VNET_NAME
前のコマンドが正常に完了したら、後で構成できるようにファイアウォールのフロントエンド IP アドレスを保存します。
# Capture Firewall IP Address for Later Use
FWPUBLIC_IP=$(az network public-ip show -g $RG -n $FWPUBLICIP_NAME --query "ipAddress" -o tsv)
FWPRIVATE_IP=$(az network firewall show -g $RG -n $FWNAME --query "ipConfigurations[0].privateIPAddress" -o tsv)
# set fw as vnet dns server so dns queries are visible in fw logs
az network vnet update -g $RG --name $VNET_NAME --dns-servers $FWPRIVATE_IP
Note
承認済み IP アドレス範囲で AKS API サーバーへのセキュリティで保護されたアクセスを使用する場合は、承認された IP 範囲にファイアウォール パブリック IP を追加する必要があります。
Azure Firewall へのホップがある UDR を作成する
Azure では、Azure のサブネット、仮想ネットワーク、およびオンプレミスのネットワーク間のトラフィックが自動的にルーティングされます。 Azure の既定のルーティングを変更する場合は、ルート テーブルを作成して変更します。
特定のサブネットに関連付ける空のルート テーブルを作成します。 ルート テーブルには、ネクスト ホップを先ほど作成した Azure Firewall に定義します。 各サブネットには、0 個または 1 個のルート テーブルを関連付けることができます。
# Create UDR and add a route for Azure Firewall
az network route-table create -g $RG -l $LOC --name $FWROUTE_TABLE_NAME
az network route-table route create -g $RG --name $FWROUTE_NAME --route-table-name $FWROUTE_TABLE_NAME --address-prefix 0.0.0.0/0 --next-hop-type VirtualAppliance --next-hop-ip-address $FWPRIVATE_IP
az network route-table route create -g $RG --name $FWROUTE_NAME_INTERNET --route-table-name $FWROUTE_TABLE_NAME --address-prefix $FWPUBLIC_IP/32 --next-hop-type Internet
Azure の既定のシステム ルートをオーバーライドする方法、またはサブネットのルート テーブルに新しいルートを追加する方法については、仮想ネットワークのルート テーブルに関するドキュメントを参照してください。
ファイアウォール規則の追加
注意
kube-system または gatekeeper-system 名前空間の外部にあるアプリケーションが API サーバーと通信する必要がある場合は、FQDN タグ AzureKubernetesService に対するアプリケーション規則の追加に加えて、API サーバー IP 用のポート443 への TCP 通信を許可する追加のネットワーク規則が必要です。
次の 3 つのネットワーク規則を使用して、ファイアウォールを構成できます。 デプロイに基づいてこれらの規則を調整することが必要な場合があります。 最初の規則では、TCP 経由でのポート 9000 へのアクセスが許可されます。 2 番目のルールでは、UDP 経由でポート 1194 と 123 へのアクセスが許可されます。 どちらの規則でも、使っている Azure リージョン CIDR (この場合は米国東部) 宛てのトラフィックのみが許可されます。
最後に、UDP 経由でインターネット タイム サーバーの FQDN (例:ntp.ubuntu.com
) に対してポート 123 を開く 3 つ目のネットワーク規則を追加します。 ネットワーク規則として FQDN を追加することは、Azure Firewall の固有の機能の 1 つであり、独自のオプションを使用する場合はそれを調整する必要があります。
ネットワーク規則を設定した後、TCP ポート 443 およびポート 80 を通してアクセスできる必要な FQDN を対象とするアプリケーション規則も、AzureKubernetesService
を使用して追加します。 さらに、デプロイに基づいて追加のネットワークおよびアプリケーションの規則を構成する必要がある場合があります。 詳細については、「Azure Kubernetes Service (AKS) クラスターのアウトバウンド ネットワークと FQDN の規則」を参照してください。
FW ネットワーク規則を追加する
az network firewall network-rule create -g $RG -f $FWNAME --collection-name 'aksfwnr' -n 'apiudp' --protocols 'UDP' --source-addresses '*' --destination-addresses "AzureCloud.$LOC" --destination-ports 1194 --action allow --priority 100
az network firewall network-rule create -g $RG -f $FWNAME --collection-name 'aksfwnr' -n 'apitcp' --protocols 'TCP' --source-addresses '*' --destination-addresses "AzureCloud.$LOC" --destination-ports 9000
az network firewall network-rule create -g $RG -f $FWNAME --collection-name 'aksfwnr' -n 'time' --protocols 'UDP' --source-addresses '*' --destination-fqdns 'ntp.ubuntu.com' --destination-ports 123
FW アプリケーション規則を追加する
az network firewall application-rule create -g $RG -f $FWNAME --collection-name 'aksfwar' -n 'fqdn' --source-addresses '*' --protocols 'http=80' 'https=443' --fqdn-tags "AzureKubernetesService" --action allow --priority 100
# set fw application rule to allow kubernettes to reach storage and image resources
az network firewall application-rule create -g $RG -f $FWNAME --collection-name 'aksfwarweb' -n 'storage' --source-addresses '10.42.1.0/24' --protocols 'https=443' --target-fqdns '*.blob.storage.azure.net' '*.blob.core.windows.net' --action allow --priority 101
az network firewall application-rule create -g $RG -f $FWNAME --collection-name 'aksfwarweb' -n 'website' --source-addresses '10.42.1.0/24' --protocols 'https=443' --target-fqdns 'ghcr.io' '*.docker.io' '*.docker.com' '*.githubusercontent.com'
Azure Firewall サービスの詳細については、Azure Firewall のドキュメントを参照してください。
ルート テーブルを AKS に関連付ける
クラスターをファイアウォールに関連付けるには、クラスターのサブネットの専用サブネットから、先ほど作成したルート テーブルを参照する必要があります。 関連付けを行うには、クラスターとファイアウォールの両方を保持する仮想ネットワークに対して、クラスターのサブネットのルート テーブルを更新するコマンドを発行します。
# Associate route table with next hop to Firewall to the AKS subnet
az network vnet subnet update -g $RG --vnet-name $VNET_NAME --name $AKSSUBNET_NAME --route-table $FWROUTE_TABLE_NAME
UDR の送信の種類を使用して AKS を既存のネットワークにデプロイする
これで、AKS クラスターを既存の仮想ネットワークにデプロイできるようになりました。 また、送信の種類 userDefinedRouting
も使います。この機能により、すべての送信トラフィックがファイアウォールの通過を強制され、他のエグレス パスが存在しないことが保証されます (既定では、Load Balancer の送信の種類を使用できます)。
デプロイ先のターゲット サブネットは、環境変数 $SUBNETID
で定義します。 前の手順では $SUBNETID
変数を定義しませんでした。 サブネット ID の値を設定するには、次のコマンドを使用します。
SUBNETID=$(az network vnet subnet show -g $RG --vnet-name $VNET_NAME --name $AKSSUBNET_NAME --query id -o tsv)
サブネット上に既に存在する UDR を使用するように、送信の種類を定義します。 この構成により、AKS ではロード バランサーに対するセットアップと IP のプロビジョニングをスキップできるようになります。
重要
制限など、送信の種類 UDR の詳細については、エグレス送信の種類 UDRに関する記事を参照してください。
ヒント
プライベート クラスターや、OS SKU の変更などの新しい機能をクラスターのデプロイに追加できます。
API サーバーの許可された IP 範囲に対して AKS 機能を追加し、API サーバーのアクセスをファイアウォールのパブリック エンドポイントのみに制限できます。 許可された IP 範囲の機能は、図ではオプションとして示されています。 許可された IP 範囲機能を有効にして API サーバーへのアクセスを制限する場合、開発者ツールでファイアウォールの仮想ネットワークからのジャンプボックスを使用するか、すべての開発者エンドポイントを許可された IP 範囲に追加する必要があります。
az aks create -g $RG -n $AKSNAME -l $LOC \
--node-count 3 \
--network-plugin azure \
--outbound-type userDefinedRouting \
--vnet-subnet-id $SUBNETID \
--api-server-authorized-ip-ranges $FWPUBLIC_IP
注意
独自の VNet とルート テーブルを作成して kubenet
ネットワーク プラグインで使用するには、ユーザー割り当てマネージド ID を使用する必要があります。 システム割り当てマネージド ID の場合、クラスターを作成する前に ID を取得できないため、ロールの割り当てが有効になるまでに延期期間が発生します。
独自の VNet とルート テーブルを作成して azure
ネットワーク プラグインで使用するために、システム割り当てマネージド ID とユーザー割り当てマネージド ID の両方がサポートされています。
開発者の API サーバーへのアクセスを有効にする
前のステップでクラスターに対して許可された IP 範囲を使用した場合、それらから API サーバーにアクセスするには、許可された IP 範囲の AKS クラスター一覧に開発者ツールの IP アドレスを追加する必要があります。 もう 1 つの方法は、ファイアウォールの仮想ネットワーク内の別のサブネット内に必要なツールを使用してジャンプボックスを構成することです。
次のコマンドを使用して、許可された範囲にもう 1 つの IP アドレスを追加します
# Retrieve your IP address
CURRENT_IP=$(dig @resolver1.opendns.com ANY myip.opendns.com +short)
# Add to AKS approved list
az aks update -g $RG -n $AKSNAME --api-server-authorized-ip-ranges $CURRENT_IP/32
新しく作成された Kubernetes クラスターに接続するように kubectl
を構成するには、az aks get-credentials コマンドを使用します。
az aks get-credentials -g $RG -n $AKSNAME
Azure Firewall を使用したイングレス トラフィックの制限
サービスの公開と、このクラスターへのアプリケーションのデプロイを始めることができます。 この例では、パブリック サービスを公開しますが、内部ロード バランサーを介して内部サービスを公開することもできます。
AKS Store Demo のクイック スタート マニフェストを確認して、作成されるすべてのリソースを確認します。
kubectl apply
コマンドを使用して、サービスをデプロイします。kubectl apply -f https://raw.githubusercontent.com/Azure-Samples/aks-store-demo/main/aks-store-quickstart.yaml
Azure Firewall に DNAT 規則を追加する
重要
Azure Firewall を使用してエグレス トラフィックを制限し、すべてのエグレス トラフィックを強制するユーザー定義ルート (UDR) を作成するときは、イグレス トラフィックを正しく許可するために、ファイアウォールで適切な DNAT 規則を作成する必要があります。 UDR で Azure Firewall を使用すると、非対称ルーティングによってイングレス設定が機能しなくなります (AKS サブネットにファイアウォールのプライベート IP アドレスに送信される既定のルートがあるのに、種類が LoadBalancer であるイングレスまたは Kubernetes サービスのパブリック ロード バランサーを使用している場合、この問題が発生します)。 この場合、ロード バランサーの受信トラフィックはパブリック IP アドレス経由で受信されますが、復路のパスはファイアウォールのプライベート IP アドレスを通過します。 ファイアウォールはステートフルであり、確立済みのセッションを認識しないため、返されるパケットは破棄されます。 Azure Firewall をイングレスまたはサービスのロード バランサーと統合する方法については、「Azure Firewall と Azure Standard Load Balancer を統合する」を参照してください。
受信接続を構成するには、DNAT 規則を Azure ファイアウォールに書き込む必要があります。 クラスターへの接続をテストするために、内部サービスによって公開されている内部 IP にルーティングされるように、ファイアウォール フロントエンド パブリック IP アドレスの規則を定義します。
送信先アドレスは、アクセス先のファイアウォールのポートなので、カスタマイズできます。 変換されたアドレスは、内部ロード バランサーの IP アドレスである必要があります。 変換されたポートは、Kubernetes サービスの公開ポートである必要があります。
Kubernetes サービスによって作成されたロード バランサーに割り当てられた内部 IP アドレスを指定する必要があります。 次を実行してアドレスを取得します。
kubectl get services
必要な IP アドレスは、次のように、EXTERNAL-IP 列に表示されます。
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.41.0.1 <none> 443/TCP 10h
store-front LoadBalancer 10.41.185.82 203.0.113.254 80:32718/TCP 9m
order-service ClusterIP 10.0.104.144 <none> 3000/TCP 11s
product-service ClusterIP 10.0.237.60 <none> 3002/TCP 10s
rabbitmq ClusterIP 10.0.161.128 <none> 5672/TCP,15672/TCP 11s
以下を実行して、サービス IP を取得します。
SERVICE_IP=$(kubectl get svc store-front -o jsonpath='{.status.loadBalancer.ingress[*].ip}')
以下を実行して、NAT 規則を追加します。
az network firewall nat-rule create --collection-name exampleset --destination-addresses $FWPUBLIC_IP --destination-ports 80 --firewall-name $FWNAME --name inboundrule --protocols Any --resource-group $RG --source-addresses '*' --translated-port 80 --action Dnat --priority 100 --translated-address $SERVICE_IP
接続の検証
ブラウザーで Azure Firewall フロントエンド IP アドレスに移動して、接続を検証します。
AKS ストア アプリが表示されます。 この例では、ファイアウォールのパブリック IP は 203.0.113.32
でした。
このページでは、製品を表示し、カートに追加して注文することができます。
リソースをクリーンアップする
Azure リソースをクリーンアップするには、AKS リソース グループを削除します。
az group delete -g $RG
次のステップ
- Azure Kubernetes Service の詳細については、「Azure Kubernetes Services (AKS) における Kubernetes の中心概念」を参照してください。