aws-auth ConfigMap Deep Dive
aws-auth は廃止がアナウンス済みですが、EKS における認証の仕組みを学ぶうえで理解しておくことは有益なので調べた内容をまとめました。
[aws-auth ConfigMap] は廃止されました。Kubernetes API へのアクセスを管理する推奨手段については、「EKS アクセスエントリを使用して Kubernetes へのアクセスを IAM ユーザーに許可する」を参照してください。
認証の流れ
以下公式ブログ記載の図を参考にしつつ、一部古くなっている箇所があったのでアップデートしました(+若干の加筆)。
この図をもとに以降解説を進めます。
k8s の認証方式
各ステップの説明に入る前に k8s の認証方式について軽く触れます。
k8s では複数の認証方式がサポートされており、EKS では webhook トークン認証を利用しています。webhook トークン認証ではおおまかに以下の流れで認証が行われます。
- クライアントから API サーバへ Bearer トークン付きのリクエストを送信
- API サーバは認証を別プロセスへ移譲
- 別プロセスでの認証が成功すると次のフェース(Authorization)に移る
aws-auth では別プロセスに相当する箇所を aws-iam-authenticator が担っており、ここで aws-auth ConfigMap を利用した認証を行っています。
各ステップの詳細
1. client-go credential plugins と Bearer Token の取得
EKS では kubectl コマンドを実行すると、まず始めに API サーバへのリクエストに使用する Bearer Token を取得します。
KUBECONFIG(k8s の認証ファイル)は以下のようになっており、API サーバにリクエストを送る前に aws eks get-token
を実行します。
なお、EKS では aws eks update-kubeconfig --cluster <クラスタ名>
で KUBECONFIG を取得できます。
users:
- name: arn:aws:eks:ap-northeast-1:11111111:cluster/test-cluster
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
args:
- --region
- ap-northeast-1
- eks
- get-token
- --cluster-name
- test-cluster
- --output
- json
command: aws
env: null
interactiveMode: IfAvailable
provideClusterInfo: false
これは client-go credential pluginsという機能で k8s.io/client-go
がネイティブでサポートしていない認証プロトコルを利用できるようにしています。
.user.exec
がある場合は TransportConfig をアップデートしつつ、API サーバへのリクエスト前に exec.command を実行して Bearer Token を設定しています(該当コード)。
ちなみに上記のコマンド(aws eks get-token
)を実行すると以下のようなレスポンスが返ってきてます。ここから status.token を取り出して Bearer Token としてセットするようにな処理の流れになっています(該当コード)。
❯ aws eks get-token --cluster-name test-cluster
{
"kind": "ExecCredential",
"apiVersion": "client.authentication.k8s.io/v1beta1",
"spec": {},
"status": {
"expirationTimestamp": "2025-01-04T10:47:49Z",
"token": "<トークンの値>"
}
}
2. aws-iam-authenticator に認証を委譲
ここからは k8s の control plane で行われる処理になります。
上述の通り EKS では webhook トークン認証を利用しているのでリクエストを受け取った API サーバは認証を aws-iam-authenticator に委譲します。具体的には TokenReview という JSON オブジェクトを作成して、これを POST body に詰めて aws-iam-authenticator にリクエストを送信しています(該当コード)。
TokenReview は以下のような形式になります。
{
"apiVersion": "authentication.k8s.io/v1beta1",
"kind": "TokenReview",
"spec": {
"token": "(Bearerトークン)"
}
}
ちなみに API サーバの起動オプションのログから webhook トークン認証 が利用されていることを確認できます。
❯ aws logs get-log-events --log-group-name /aws/eks/$CLUSTER_NAME/cluster --log-stream-name kube-apiserver-xxxxxxxxx | jq -r '.events[].message' | grep authentication-token-webhook-config-file
I0104 10:59:02.379582 11 flags.go:64] FLAG: --authentication-token-webhook-config-file="/etc/kubernetes/authenticator/apiserver-webhook-kubeconfig.yaml"
3-5. aws-iam-authenticator の認証
次に API サーバ から TokenReview を受け取った aws-iam-authenticator が認証を行います。
まず API サーバから送られてきた Bearer Token を取り出して、そこから prefix(k8s-aws-v1.)を除き、更には base64 デコードして parsedURL としてセットします(該当コード)。
AWS CLI で同等の処理をすると以下のようになります。つまり API サーバから送られてきた Bearer Token から STS へのリクエスト URL を生成しているのです。
❯ aws eks get-token --cluster-name $CLUSTER_NAME \
| jq -r '.status.token' \
| sed 's/k8s-aws-v1.//g' \
| base64 -d
https://sts.ap-northeast-1.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...
その後は以下のような流れで認証を完結させます。
- STS へリクエストを送り STS 側で Barer Token を検証し、結果をレスポンスとして受け取る(該当コード)
- STS のレスポンス等のデータから認証する ID を確定する(該当コード)
- この ID が aws-auth ConfigMap の mapRoles/mapUsers に含まれているかをチェック(該当コード)
- 結果を TokenReview に詰めて API サーバに返却する(該当コード)
認証プロセスとしては以上になります。以降は認証した ID に対して Authrization 処理を実行することになります。
6. Access Grant
認証と同じく認可も複数のモードが用意されていますが、aws-auth では RBAC を利用しています。
実際の処理としては以下でやっていて、クライアントから送られたリクエストと RoleBinding/ClusterRoleBinding を照合して、結果(authorizer.Decision)と理由をセットで返却しています。
(具体的にどういう照合しているのかまで踏み込みたかったですが力尽きたのでここまで)
おわりに
aws-auth の仕組みを見ていきましたが、Access Entry も認証までは概ね同じ仕組みで動いている(aws-iam-authenticator を使っている)ので、やる気が出れば詳細調べてみようと思います。
また、記事本文ではコード解説は概略に留めているので、詳細が気になる方は以下スクラップも見てみてください。
Discussion