
AWS IAM 認証情報を使用して Kubernetes クラスターに認証するためのツール
AWS IAM 認証情報を使用して Kubernetes クラスターに認証するためのツールです。 このツールの初期開発は Heptio によって推進されました。このプロジェクトは複数のコミュニティエンジニアからの貢献を受けており、現在は Heptio と Amazon EKS OSS エンジニアによってメンテナンスされています。
AWS 上で Kubernetes クラスターを運用している管理者であれば、クラスターのプロビジョニングと更新のために AWS IAM 認証情報を管理する必要がすでにあります。 AWS IAM Authenticator for Kubernetes を使用することで、Kubernetes アクセス用に別の認証情報を管理する必要がなくなります。 また、AWS IAM には、(CloudTrail 経由の) 帯域外監査証跡や 2FA/MFA の強制など、多くの優れた特性があります。
AWS 上で Kubernetes インストーラーを構築している場合、AWS IAM Authenticator for Kubernetes はブートストラッププロセスを簡素化できます。
新しくインストールしたクラスターから初期管理者認証情報を何とかして安全に持ち出す必要はありません。
代わりに、クラスターのプロビジョニング時に専用の KubernetesAdmin ロールを作成し、Authenticator を設定してクラスター管理者のログインを許可できます。
AWS で稼働中のクラスターがあり、AWS IAM Authenticator for Kubernetes サポートを追加したい場合、次の手順が必要です:
まず、Kubernetes クラスター内のユーザー/グループにマッピングされる 1 つ以上の IAM ロールを作成する必要があります。 これを行う最も簡単な方法は、AWS コンソールにログインすることです:
これにより、アカウント内の承認されたユーザー/ロールが引き受けることができる、権限のない IAM ロールが作成されます。 以下の手順で必要になるため、ロールの Amazon リソースネーム (ARN) をメモしておいてください。
AWS コンソールの代わりに AWS CLI を使用して、この操作を 1 つのステップで行うこともできます:```sh
ACCOUNT_ID=$(aws sts get-caller-identity --output text --query 'Account')
POLICY=$(echo -n '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"arn:aws:iam::'; echo -n "$ACCOUNT_ID"; echo -n ':root"},"Action":"sts:AssumeRole","Condition":{}}]}')
aws iam create-role
--role-name KubernetesAdmin
--description "Kubernetes administrator role (for AWS IAM Authenticator for Kubernetes)."
--assume-role-policy-document "$POLICY"
--output text
--query 'Role.Arn'
この手順を省略して、以下を使用することもできます:
- 既存のロール(クロスアカウントアクセスロールなど)。
- IAM ユーザー(下記の `mapUsers` を参照)。
- EC2 インスタンスまたはフェデレーティッドロール(下記の `mapRoles` を参照)。
### 2. サーバーを起動する
このサーバーは、各マスターノード上で、ホストネットワーキングを使用した DaemonSet として実行され、localhost ポートを公開できるように設計されています。
ConfigMap と DaemonSet の設定例については、[`deploy/example.yaml`](https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/HEAD/deploy/example.yaml) を参照してください。
適用する前に、クラスターに合わせて次の値を更新してください:
- `config.yaml` 内のプレースホルダーの IAM ARN(`arn:aws:iam::000000000000:...`)を置き換えてください。
- クラスターごとに一意の値になるよう `clusterID` を設定してください。
- DaemonSet のスケジューリングルールが、コントロールプレーンノードのラベル/テイントと一致していることを確認してください。
その後、デプロイしてください:```sh
kubectl apply -f deploy/example.yaml
kubectl -n kube-system rollout status daemonset/aws-iam-authenticator
kubectl -n kube-system get pods -l k8s-app=aws-iam-authenticator
Pod がコントロールプレーンノード上で実行されると、aws-iam-authenticator server はホスト上の /etc/kubernetes/aws-iam-authenticator/kubeconfig.yaml(または --generate-kubeconfig で設定したパス)に webhook kubeconfig を作成します。
自動化されたインストーラを構築している場合は、aws-iam-authenticator init を使用して、証明書、キー、webhook kubeconfig ファイルを簡単に事前生成することもできます。
このコマンドはファイルを生成し、設定された出力ディレクトリに配置します。
このコマンドは、API サーバーを起動する前に各マスターノード上で実行できます。 また、マスターノードをプロビジョニングする前に生成し、適切なホストパスにインストールすることもできます。
ファイルを事前生成しない場合、aws-iam-authenticator server が必要に応じて生成します。
これは機能しますが、インストール後に Kubernetes API サーバーを再起動する必要があります。
Kubernetes API は、トークン認証 webhook を使用して AWS IAM Authenticator for Kubernetes と統合します。
aws-iam-authenticator server を実行すると、webhook 設定ファイルが生成され、ホストのファイルシステムに保存されます。
API サーバーの設定に、追加のフラグを 1 つ加える必要があります。```
--authentication-token-webhook-config-file=/etc/kubernetes/aws-iam-authenticator/kubeconfig.yaml
多くのクラスターでは、API サーバーは静的 Pod として実行されます。
フラグは `/etc/kubernetes/manifests/kube-apiserver.yaml` に追加できます。
ホストディレクトリ `/etc/kubernetes/aws-iam-authenticator/` が API サーバーの Pod にマウントされていることを確認してください。
更新された静的 Pod 定義を反映させるには、マスターノードで kubelet デーモンを再起動する必要がある場合もあります:```
systemctl restart kubelet.service
サーバーのデフォルトの動作は、設定ファイルの mapUsers フィールドと mapRoles フィールドからのみマッピングを取得することです。詳細については、下記の 完全な設定形式 を参照してください。
--backend-mode フラグを使用すると、サーバーがマッピングを取得する追加のバックエンドを 2 つ設定できます。EKS スタイルの ConfigMap (--backend-mode=EKSConfigMap) または IAMIdentityMapping カスタムリソース (--backend-mode=CRD) です。デフォルトのバックエンドは、サーバーポッドによってマウントされるサーバー設定ファイルで、--backend-mode=MountedFile に対応します。
これらのバックエンドをカンマ区切りのリストで渡すと、サーバーはその順序で検索します。たとえば、--backend-mode=EKSConfigMap,MountedFile の場合、サーバーはまず EKS スタイルの ConfigMap でマッピングを検索し、そこに指定された IAM ロール/ユーザーのマッピングが見つからなければ、サーバー設定ファイルを検索します。同じ IAM ロール/ユーザーのマッピングが複数のバックエンドに存在する場合、サーバーはカンマ区切りリストで最初に出現するバックエンドのマッピングを使用します。この例では、EKS ConfigMap にマッピングが見つかった場合、サーバー設定ファイルに重複または競合するマッピングが存在するかどうかに関係なく、そのマッピングが使用されます。
単一のバックエンドを設定した場合、サーバーは そのバックエンドのみ から取得し、他のバックエンドが存在しても無視することに注意してください。たとえば、--backend-mode=CRD の場合、サーバーは IAMIdentityMappings のみ から取得し、マウントされたファイルと EKS ConfigMap は無視します。
MountedFileこれはマッピングのデフォルトのバックエンドであり、ほとんどのユーザーにとって十分です。詳細については、下記の 完全な設定形式 を参照してください。
CRD (アルファ)このバックエンドは、各 IAM マッピングを IAMIdentityMapping Kubernetes カスタムリソース としてモデル化します。このアプローチにより、kubectl または API を使用して、Kubernetes ネイティブな方法でマッピングを維持できます。さらに、構文エラー(YAML のインデントずれなど)をより簡単に検出でき、すべてのマッピングに影響を与えることはありません。
IAMIdentityMapping CRD をセットアップするには、最初に CRD マニフェストを apply する必要があります。```
kubectl apply -f deploy/iamidentitymapping.yaml
CRDをデプロイすると、IAMアイデンティティをモデル化するカスタムリソースを作成できます。
以下を参照してください:
[`./deploy/example-iamidentitymapping.yaml`](https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/HEAD/deploy/example-iamidentitymapping.yaml)```
---
apiVersion: iamauthenticator.k8s.aws/v1alpha1
kind: IAMIdentityMapping
metadata:
name: kubernetes-admin
spec:
# Arn of the User or Role to be allowed to authenticate
arn: arn:aws:iam::XXXXXXXXXXXX:user/KubernetesAdmin
# Username that Kubernetes will see the user as, this is useful for setting
# up allowed specific permissions for different users
username: kubernetes-admin
# Groups to be attached to your users/roles. For example `system:masters` to
# create cluster admin, or `system:nodes`, `system:bootstrappers` for nodes to
# access the API server.
groups:
- system:masters
EKSConfigMapEKSスタイルのkube-system/aws-auth ConfigMapがバックエンドとして機能します。
ConfigMapは、EKSクラスターとまったく同じ形式であることが想定されています:
https://docs.aws.amazon.com/eks/latest/userguide/add-user-role.html。これは、
EKSとの間で移行する際にマッピングを維持したい場合や、
他のAWSクラスターに加えてEKSも運用しており、各クラスターで同じマッピングを
使用したい場合に役立ちます。
DynamicFilecfg.dynamicfilepathで指定されたローカルファイルをバックエンドとして使用できます。
ファイルの内容は、EKSConfigMapとまったく同じ形式であることが想定されています。
このファイルの内容が変更されるたびに、authenticatorは自動的にそれを再読み込みします。 これにより、
ARNマッピングの管理においてより柔軟性が得られます。
DynamicFileモードの設定方法については、https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/master/hack/dev/authenticator_with_dynamicfile_mode.yaml を確認してください。
DynamicFileモードを有効にしたkindクラスターで試すには、make e2e RUNNER=kindを実行してください。
aws-iam-authenticatorはk8sユーザー名の予約プレフィックスをサポートできます。予約プレフィックスが 設定されている場合、その予約プレフィックスを持つユーザー名は認証されず、次のエラーが返されます: "username must not begin with with the following prefixes:".
予約プレフィックスの設定方法については、https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/master/hack/dev/authenticator_with_dynamicfile_mode.yaml を確認してください。
最後に、サーバーをセットアップしたら、認証したくなるでしょう。
クラスターの公開データ(クラスターCA証明書、エンドポイントアドレス)を含むkubeconfigが引き続き必要です。
ただし、設定のusersセクションにはexecセクションを含める必要があります(kubectl資格情報プラグインのドキュメントを参照):```yaml
users:
これは、`kubeconfig` が完全に公開データであり、すべての Authenticator ユーザー間で共有できることを意味します。
AWS S3 などの信頼できる公開場所にアップロードすることも合理的です。
`aws-iam-authenticator` バイナリがインストールされていることを確認してください。
`go install sigs.k8s.io/aws-iam-authenticator/cmd/aws-iam-authenticator@latest` でインストールできます。
認証するには、`kubectl --kubeconfig /path/to/kubeconfig" [...]` を実行します。
kubectl は kubeconfig 内で指定されたパラメータを使って `aws-iam-authenticator` バイナリを `exec` し、トークンを生成して apiserver に渡します。
トークンの有効期限は 15 分(AWS が許可する最短の値)で、複数回再利用できます。
トークン生成時に `--session-name` または `-s` パラメータを指定してセッション名を設定することもできます。このパラメータは `--forward-session-name` と併用できません。
また、専用ロールを引き受けることなく、既存の認証情報でトークンに署名するには `-r ROLE_ARN` を省略できます。
これは、IAM ユーザーとして直接認証したい場合や、EC2 インスタンスロールまたはフェデレーテッドロールを使用して認証したい場合に便利です。
## Kops の使用法
[Kops](https://github.com/kubernetes/kops) が管理するクラスターは Authenticator を使用するように設定できます。使用方法については [Kops ドキュメント](https://kops.sigs.k8s.io/authentication/#aws-iam-authenticator) を参照してください。
## 仕組み
AWS の [`sts:GetCallerIdentity`](https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html) API エンドポイントを使用して動作します。
このエンドポイントは、接続に使用した AWS IAM 認証情報に関する情報を返します。
#### クライアント側 (`aws-iam-authenticator token`)
Authenticator クライアントがエンドポイントへのリクエストを生成して事前署名することで、この API をやや変わった方法で使用します。
そのリクエストをシリアライズして、Kubernetes 認証システムを通過できるトークンに変換します。
#### サーバー側 (`aws-iam-authenticator server`)
トークンは Kubernetes API サーバーを経由し、webhook 設定を通じて Authenticator サーバーの `/authenticate` エンドポイントに渡されます。
Authenticator サーバーは、事前署名されたリクエストのすべてのパラメータを検証して、異常がないことを確認します。
次に、実際の `https://sts.amazonaws.com` サーバーにリクエストを送信します。このサーバーがクライアントの HMAC 署名を検証し、ユーザーに関する情報を返します。
サーバーがクライアントの AWS アイデンティティを把握すると、単純な静的マッピングを通じて、このアイデンティティを Kubernetes ユーザーとグループに変換します。
このメカニズムは、いくつかの変更を加えて [Vault](https://www.vaultproject.io/docs/auth/aws.html#iam-auth-method) から借用したものです。
## クラスター ID とは?
Authenticator のクラスター ID は、特定のリプレイ攻撃を防ぐためのクラスターごとに一意の識別子です。
具体的には、ある Authenticator サーバー(例: 開発環境)が、クライアントのトークンを使用して別のクラスター内の別の Authenticator サーバーに認証することを防ぎます。
クラスター ID はクラスターごとに一意である必要がありますが、秘密にする必要はありません。
適切な選択肢は次のとおりです:
- `openssl rand 16 -hex` などで生成したランダム ID
- Kubernetes API サーバーのドメイン名
[Vault ドキュメント](https://www.vaultproject.io/docs/auth/aws.html#iam-auth-method) にもこの攻撃の説明があります(`X-Vault-AWS-IAM-Server-ID` を参照)。
## 認証情報の指定と AWS プロファイルの使用
`aws-iam-authenticator` で使用する認証情報は、[AWS SDK for Go](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials) で利用可能な任意の方法で指定できます。
これには、環境変数での AWS 認証情報の指定や、認証情報ファイルの利用が含まれます。
`aws-iam-authenticator` は、`AWS_PROFILE` 環境変数を介して AWS の[名前付きプロファイル](https://docs.aws.amazon.com/cli/latest/userguide/cli-multiple-profiles.html)をサポートしています。たとえば、_dev_ プロファイルで指定された認証情報で認証するには、`AWS_PROFILE` をエクスポートするか、明示的に指定します(例: `AWS_PROFILE=dev kubectl get all`)。`AWS_PROFILE` が設定されていない場合は、_default_ プロファイルが使用されます。
`AWS_PROFILE` は、kubeconfig ファイル内で直接指定することもできます([`exec` フローの一部として](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#configuration))。たとえば、_dev_ という名前付きプロファイルの認証情報が `aws-iam-authenticator` によって常に使用されるように指定するには、kubeconfig にプロファイルを設定する `env` キーを含めます:```yaml
apiVersion: v1
clusters:
- cluster:
server: ${server}
certificate-authority-data: ${cert}
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: aws
name: aws
current-context: aws
kind: Config
preferences: {}
users:
- name: aws
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: aws-iam-authenticator
env:
- name: "AWS_PROFILE"
value: "dev"
args:
- "token"
- "-i"
- "mycluster"
このメソッドを使用すると、適切なプロファイルを暗黙的に使用できます。exec フローの一部として設定された環境変数は、
お使いの環境に既に設定されているものより優先されることに注意してください。
フェデレーテッド AWS ユーザーは、アカウントの AWS 設定を通じて、メールアドレスなどの "意味のある" 属性が引き受けたロールにマッピングされていることがよくあります。
これらの引き受けたセッションにはいくつかの部分、role id
と caller-specified-role-name があります。デフォルトでは、フェデレーテッドユーザーが aws-iam-authenticator の --role オプションを使用して新しいロールを引き受けると、
caller-specified-role-name はランダムなトークンに変換され、role id は新しく引き受けたロールに引き継がれます。
aws-iam-authenticator token ... --forward-session-name を使用すると、元の caller-specified-role-name 属性が新しい STS 引き受けセッションにマッピングされます。
これは、"K8 クラスター上でアクション X を実行したのは誰か" をすばやく関連付けようとする場合に役立ちます。
なお、これは決定的なものと見なすべきではありません。role id(一貫性が保たれます)を介して CloudTrail ログと相互参照する必要があります。
これは、ユーザーがクライアント側でこれを変更できる可能性があるためです。
クラスターの外部にあるクライアントから Kubernetes API へのリクエストを行うことが可能です。使用するのは、
素の Kubernetes REST API か、言語固有の Kubernetes クライアントのいずれかです。
(例: Python)。これを行うには、API へのリクエストに含まれるベアラートークンを
作成する必要があります。このベアラートークンは、k8s-aws-v1. という文字列に、
STS GetCallerIdentity Query API への署名付き HTTP リクエストの base64 エンコード文字列を追加する必要があります。これはその後、
リクエストの Authorization ヘッダーに送信されます。 ただし、IAM Authenticator は明示的に
base64 パディングを省略して = 文字を避けることで、URL で安全に使用できる文字列が保証されます。以下は、
このトークンを構築する方法の Python の例です。```python
import base64
import boto3
import re
from botocore.signers import RequestSigner
def get_bearer_token(cluster_id, region): STS_TOKEN_EXPIRES_IN = 60 session = boto3.session.Session()
client = session.client('sts', region_name=region)
service_id = client.meta.service_model.service_id
signer = RequestSigner(
service_id,
region,
'sts',
'v4',
session.get_credentials(),
session.events
)
params = {
'method': 'GET',
'url': 'https://sts.{}.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15'.format(region),
'body': {},
'headers': {
'x-k8s-aws-id': cluster_id
},
'context': {}
}
signed_url = signer.generate_presigned_url(
params,
region_name=region,
expires_in=STS_TOKEN_EXPIRES_IN,
operation_name=''
)
base64_url = base64.urlsafe_b64encode(signed_url.encode('utf-8')).decode('utf-8')
# remove any base64 encoding padding:
return 'k8s-aws-v1.' + re.sub(r'=*', '', base64_url)
headers = {'Authorization': 'Bearer ' + get_bearer_token('my_cluster', 'us-east-1')}
## トラブルシューティング
クライアントが `could not get token: AccessDenied [...]` のようなエラーで失敗する場合は、AWS CLI を使って直接ロールを引き受けることを試せます:```sh
# AWS CLI version of `aws-iam-authenticator token -r arn:aws:iam::ACCOUNT:role/ROLE`:
$ aws sts assume-role --role-arn arn:aws:iam::ACCOUNT:role/ROLE --role-session-name test
それが失敗した場合、確認すべき問題がいくつかあります:
シェルで基本のAWS認証情報が利用可能であることを確認してください(aws sts get-caller-identity がこのトラブルシューティングに役立ちます)。
ターゲットロールがソースアカウントのアクセスを許可していることを確認してください(ロールの信頼ポリシー内)。
ソースプリンシパル(ユーザー/ロール/グループ)に、ターゲットロールに対する sts:AssumeRole を許可するIAMポリシーがあることを確認してください。
ユーザー、グループ、またはAWS Organizationsに、sts:AssumeRole を妨げる明示的な拒否ポリシーがアタッチされていないことを確認してください。
Policy Simulator で sts:AssumeRole コールのシミュレーションを試してください。
クライアントとサーバーは同じ設定形式を持ちます。 設定にシークレットが保存されないため、両者はまったく同じ設定ファイルを共有できます。```yaml
clusterID: my-dev-cluster.example.com
aws-iam-authenticator tokendefaultRole: arn:aws:iam::000000000000:role/KubernetesAdmin
server:
port: 21362 # (default)
stateDir: /var/aws-iam-authenticator # (default)
path where a generated webhook kubeconfig will be stored.generateKubeconfig: /etc/kubernetes/aws-iam-authenticator.kubeconfig # (default)
ec2DescribeInstancesRoleARN: arn:aws:iam::000000000000:role/DescribeInstancesRole
scrubbedAccounts:
@ characters- characters.mapRoles:
mapUsers:
mapAccounts:
backendMode:
## 開発
[開発](https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/HEAD/docs/development.md) ページを参照してください。
## コミュニティ、ディスカッション、コントリビューション、サポート
Kubernetesコミュニティへの参加方法は、[コミュニティページ](http://kubernetes.io/community/)をご覧ください。
このプロジェクトのメンテナには、以下の場所で連絡できます:
- [Slack](https://kubernetes.slack.com/messages/sig-aws)
- [メーリングリスト](https://groups.google.com/forum/#!forum/kubernetes-sig-aws)
### 行動規範
Kubernetesコミュニティへの参加は、[Kubernetes行動規範](https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/HEAD/code-of-conduct.md)に従います。