こちらは Microsoft Azure Advent Calendar 2024 の 6 日目の記事です。
AKS の API サーバーアドレスの謎
Azure ポータルでいろいろな AKS クラスタの状態を眺めていたところ、AKS の概要ページにある 「API サーバーアドレス」に表示されている内容がクラスタによって異なることに気づきました。
当然クラスタごとに一意となる文字列は異なるのですが、ドメイン部分が大きく異なります。
以下は状況を再現したクラスタのスクショです。
表示されている API サーバーアドレスには hcp.<location>.azmk8s.io
と 00000000-0000-0000-0000-000000000000.privatelink.<location>.azmk8s.io
の 2 種類あります。
-
クラスタ A の API サーバーアドレス
- aks-public-aks-public-fqdn-c209fd-mytdol9d.hcp.japaneast.azmk8s.io
-
クラスタ B の API サーバーアドレス
- aks-public-aks-public-fqdn-c209fd-rzz0g24p.a47e9794-80a7-4088-9a92-3706e050f9cc.privatelink.japaneast.azmk8s.io
両クラスタともプライベート AKS クラスタとして構築しています。 パブリックアクセスはできないので、VPN などを使っていない端末では Azure ポータルからクラスタのリソースを見ようとしてもエラーになってしまいます。
同じプライベート AKS クラスタなのにどうして差が生まれてしまうのでしょうか?
結論から
AKS の「パブリック FQDN enablePrivateClusterPublicFqdn
」という設定によって API サーバーアドレスに表示される内容が変わります。
Azure CLI では --disable-public-fqdn
オプションをつけて新規クラスタを作成、または既存クラスタを更新することで「パブリック FQDN」を無効化できます。
つまりデフォルトは有効状態です。
このパブリック FQDN の設定によって、表示されていた API サーバーアドレスが異なりました。
パブリック FQDN | 表示される API サーバーアドレス |
---|---|
有効 | hcp.<location>.azmk8s.io |
無効 | 00000000-0000-0000-0000-000000000000.privatelink.<location>.azmk8s.io |
プライベート AKS クラスタとは
プライベート AKS クラスタは、インターネットから直接アクセスできないように構成されたクラスタのことです。
AKS は Azure 上で Kubernetes クラスタを管理・運用できるサービスです。 通常の AKS クラスタを作成した場合、API サーバーのエンドポイントは外部に公開されて直接アクセスできる状態になります。 プライベート AKS クラスタでは、クラスタの API サーバーが Azure ネットワーク内でのみアクセス可能となり、外部からの直接アクセスが制限されます。
AKS クラスタの API サーバーに直接アクセスできると言っても、認証・認可の仕組みもあるため誰でも AKS クラスタを利用できるわけではありません。 しかし、外部からの直接アクセス自体を防ぐことで AKS クラスタをセキュアに構築することができます。 それがプライベート AKS クラスタです。
直接アクセスできないということは、API サーバへアクセスする代わりの手段が必要ということでもあります。
プライベート AKS クラスタでは、API サーバー用のプライベート エンドポイントが AKS 用の VNet 内に作成されます。 このプライベート エンドポイントが Microsoft が管理する AKS クラスタのコントロール プレーンと Azure Private Link サービスで繋がっています。 クライアントはプライベート エンドポイントにアクセスできれば API サーバーにアクセスできることになります。
プライベート エンドポイントにアクセスするには、クライアントが AKS 用の VNet 内にいること、または VNet ピアリングして AKS 用 VNet にアクセスできること等の前提条件があります。
API サーバー の名前解決
プライベート AKS クラスタに作られたプライベート エンドポイントには AKS 用サブネットのアドレス範囲にある IP アドレスが割り当てられます。
通常は 10.224.0.4
のようなプライベート IP アドレス (RFC1918) です。
クライアントからこの IP アドレスにアクセスできればいいだけではなく、API サーバーが利用しているホスト名 (例えば aks-public-aks-public-fqdn-c209fd-mytdol9d.hcp.japaneast.azmk8s.io
) でアクセスする必要があります。
そのためには、プライベート AKS クラスタ用の名前解決の仕組みが必要です。
Azure には「プライベート DNS ゾーン」という VNet 内で使用するための DNS サービスがあります。 プライベート AKS クラスタを構築すると、プライベート エンドポイントとともにプライベート DNS ゾーンも作られます。 このプライベート DNS ゾーンは AKS 用 VNet とリンクされていて VNet 内から名前解決できるようになっています。
他の VNet からプライベート AKS クラスタにアクセスする場合でも、プライベート DNS ゾーンを対象の VNet とリンクさせることで名前解決できるようになります。
プライベート DNS ゾーンの状態
それでは、プライベート DNS ゾーンにはどのようなレコードが登録されているのでしょうか。
冒頭で紹介した API サーバーアドレスの表示が異なるクラスタ A と B のレコードは次のようになっていました。
両方とも 00000000-0000-0000-0000-000000000000.privatelink.<location>.azmk8s.io
というゾーンに aks-public-aks-public-fqdn-c209fd-xxxxxxx
という A レコードが登録されていました。
IP アドレスが両方とも 10.224.0.4
なのはクラスタ作成時に同じアドレス帯域の VNet をそれぞれ作ったためです。
API サーバーアドレス と プライベート DNS ゾーン
Azure ポータルの AKS 概要ページに表示されている「API サーバーアドレス」と「プライベート DNS ゾーンのレコード」を比較してみます。
クラスタ B の API サーバーアドレスには aks-public-aks-public-fqdn-c209fd-rzz0g24p.a47e9794-80a7-4088-9a92-3706e050f9cc.privatelink.japaneast.azmk8s.io
と表示されています。
このアドレスはプライベート DNS ゾーンに登録されたレコードと一致しています。
クライアントがプライベート DNS ゾーンで名前解決できる構成であれば、Azure ポータルに表示されている API サーバーアドレスでプライベート AKS クラスタにアクセスできることが分かりますね。
一方、クラスタ A の API サーバーアドレスには aks-public-aks-public-fqdn-c209fd-mytdol9d.hcp.japaneast.azmk8s.io
と表示されていました。
このアドレスはプライベート DNS ゾーンに登録されているレコードと一致していません。
当然、プライベート エンドポイントにアクセスできない環境からこの API サーバーアドレスにアクセスしても、対象がプライベート AKS クラスタなので繋がりません。
では、この hcp.<location>.azmk8s.io
は何者でしょうか。
Microsoft のドキュメントを探してみると次のような内容が見つかりました。
ノード <-> API サーバーの間の通信に必要です。
(略)
これは、プライベート クラスターでは必要ありません。
ということで、hcp.<location>.azmk8s.io
は AKS クラスタの API サーバーにアクセスするためのもので、プライベート AKS クラスタを使う場合には不要なようです。
でも Azure ポータルには API サーバーアドレスとして表示されている、どういうことでしょう? 調べていくため、API サーバーアドレスを名前解決してみます。
$ dig +short aks-public-aks-public-fqdn-c209fd-mytdol9d.hcp.japaneast.azmk8s.io
10.224.0.4
クライアントのプライベート DNS ゾーンの参照可否に関わらず、hcp.<location>.azmk8s.io
はプライベート エンドポイントのプライベート IP アドレスが返ってきました。
パブリックの DNS サーバにプライベート エンドポイントの IP アドレスのレコードが登録されているようです。
それでは、この API サーバーアドレスを使ってアクセスできるのでしょうか。
ネットワーク的にプライベート AKS クラスタにアクセスできるクライアントから hcp.<location>.azmk8s.io
にアクセスしてみます。
まずは、Azure ポータルからコマンドを拝借して、このクラスタ A に接続するための設定を入れます。
接続設定ができたら .kube/config
ファイルを見てみます。
次のように接続先のクラスタにはプライベート DNS ゾーンに登録された名前が使われています。
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
# プライベート DNS ゾーンに登録された API サーバーアドレス
server: https://aks-public-aks-public-fqdn-c209fd-lr5umuys.512317f1-59e4-4ef2-90c5-ae3724da2543.privatelink.japaneast.azmk8s.io:443
name: aks-public-fqdn-enable
contexts:
- context:
cluster: aks-public-fqdn-enable
user: clusterUser_aks-public-fqdn_aks-public-fqdn-enable
name: aks-public-fqdn-enable
current-context: aks-public-fqdn-enable
kind: Config
preferences: {}
users:
- name: clusterUser_aks-public-fqdn_aks-public-fqdn-enable
user:
client-certificate-data: DATA+OMITTED
client-key-data: DATA+OMITTED
token: REDACTED
ネットワーク的に繋がる環境であれば、この設定で プライベート AKS クラスタに繋がります。
この設定ファイルの接続先を Azure ポータルに表示されている API サーバーアドレス hcp.<location>.azmk8s.io
に置き換えてみます。
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
# ここを置き換える
server: https://aks-public-aks-public-fqdn-c209fd-mytdol9d.hcp.japaneast.azmk8s.io:443
name: aks-public-fqdn-enable
contexts:
- context:
cluster: aks-public-fqdn-enable
user: clusterUser_aks-public-fqdn_aks-public-fqdn-enable
name: aks-public-fqdn-enable
current-context: aks-public-fqdn-enable
kind: Config
preferences: {}
users:
- name: clusterUser_aks-public-fqdn_aks-public-fqdn-enable
user:
client-certificate-data: DATA+OMITTED
client-key-data: DATA+OMITTED
token: REDACTED
この状態で kubectl コマンドを実行すると問題なく繋がりました。
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
aks-nodepool1-19647154-vmss000001 Ready <none> 4h25m v1.29.9
このことから、「ネットワーク的に繋がる環境なら hcp.<location>.azmk8s.io
の API サーバーアドレスでもプライベート AKS クラスタにアクセスできる」ことが分かりました。
整理すると、以下の API サーバーアドレスが Azure ポータルに表示されていました。
hcp.<location>.azmk8s.io
- AKS クラスタの API サーバーにアクセスするためのアドレス
- プライベート AKS クラスタでは不要、つまりパブリック AKS クラスタで使われる
- ネットワーク的に繋がっていればこのアドレスでもプライベート AKS クラスタにアクセスできる
00000000-0000-0000-0000-000000000000.privatelink.<location>.azmk8s.io
- プライベート AKS クラスタの API サーバーにアクセスするためのアドレス
- プライベート DNS ゾーンに A レコードが登録されていて、コントロール プレーン用のプライベート エンドポイントの IP アドレスに名前解決される
どうして表示が変わるの?
Azure ポータルに表示されている API サーバーアドレスの正体が見えてきたところで、どうしてクラスタごとに表示される内容が変わるのか確認してみます。
各クラスタに対して az aks show
コマンドを実行して設定内容を比較したところ、リソース名以外で差分があったのは次の設定項目でした。
設定項目 | クラスタ A | クラスタ B |
---|---|---|
enablePrivateClusterPublicFqdn | true | false |
fqdn | (省略).hcp.japaneast.azmk8s.io | null |
どうやら enablePrivateClusterPublicFqdn
の有効/無効で AKS クラスタの FQDN の有無が決まり、FQDN がある場合は Azure ポータルの API サーバーアドレスに hcp.<location>.azmk8s.io
が表示されそうです。
残念ながら fqdn
の設定だけを null に更新することはできなそうで「fqdn
を null にして Azure ポータルの表示を変える」という検証はできませんでした。
enablePrivateClusterPublicFqdn
は「パブリック FQDN」という設定項目のようで、Microsoft のドキュメントにパブリック FQDN を無効化する手順が載っていました。
ということで、パブリック FQDN の有効/無効で Azure ポータルに表示されている API サーバーアドレスの表示が変わることが分かりました。
どういう時に使える?
それでは、パブリック FQDN の有効/無効はどのようなことを想定して設定すべきでしょうか。
無効するシーンとしては、よりセキュアな環境を構築したい場合かと思います。 パブリック FQDN が有効な場合、プライベート AKS クラスタにして外部から直接アクセスできない環境とはいえ、パブリック FQDN が分かっていれば名前解決することでプライベート エンドポイントのプライベート IP アドレスまで分かってしまいます。 セキュリティに厳しくあるべき環境では無効しておくのが無難です。
一方、パブリック FQDN を有効したほうが嬉しいシーンとしては、「プライベート エンドポイントにはアクセスできるけど、プライベート DNS ゾーンに問い合わせできない環境」ではないでしょうか。
たとえば、VPN を使ってクライアントから Azure ネットワーク内に繋がるようにしていても、VPN Gateway の VNet とプライベート DNS ゾーンをリンクできない環境の場合、パブリック FQDN を無効化しているとプライベート AKS クラスタにアクセスできません。
hosts ファイルに直接 API サーバーアドレスと IP アドレスを記述することでローカルで名前解決させて繋ぐことはできます。
しかし、パブリック FQDN を有効にしておくことで、パブリックな DNS サーバに問い合わせて API サーバーアドレスをプライベート IP アドレスに名前解決できるので、hosts を書き換えることなくプライベート AKS クラスタにアクセスできます。
まとめ
Azure ポータルに表示される AKS の API サーバーアドレスの違いを追ったところ、AKS の「パブリック FQDN」という設定に辿り着きました。
なんとなくでプライベート AKS クラスタを使っていたことが露呈した感ありますが、気になったところはちゃんと調べていくと理解が深まりますね、という感想で締めます。