kiam で Kubernetes の Pod に IAM role を割り当てる

概要

GitHub - uswitch/kiam: Integrate AWS IAM with Kubernetes

Integrate AWS IAM with Kubernetes. Contribute to uswitch/kiam development by creating an account on GitHub.
  • uswitch/kiam で Kubernetes Pod に対して IAM role を割り当て、動作を確認する
  • Kubernetes cluster は kops で AWS 上に構築したものを使う
  • 検証用の S3 bucket を使い Pod に割り当てた role の有無で参照可能/不可能になることを確認する

前回検証した kube2iam と同様に、 IAM role を Pod に対して割り当てられるようにしてくれるやーつ。

kube2iamの記事:

kube2iam で Kubernetes の Pod に IAM role を割り当てる - yukirii blog

kube2iam を使用して AWS 上の Kubernetes Pod に対して IAM role を割り当てます。

検証

以下をやってみる:

  • kiam のインストール
  • S3 バケットを参照する IAM role を作成
  • Pod に role を割り当てたり外したりして挙動を確認してみる

kiam のインストール

git clone https://github.com/uswitch/kiam.git
cd kiam/deploy
kubectl create -f agent.yaml
kubectl create -f server-rbac.yaml
kubectl create -f server.yaml

kiam は2つのプロセスから成り立つ:

  • Agent
    • Pod からのメタデータ API に対するクレデンシャル要求の HTTP リクエストを受け付ける
      • それ以外のリクエストは AWS API に転送する
    • Server と gRPC で通信を行う
  • Server
    • Agent から利用される gRPC サーバとして動作する
    • Pod に必要な role を決定しクレデンシャルを取得する

kops で構築したクラスタの場合、 kiam-server のマニフェストに以下の変更を加える必要があった。

参考:

failed to load system roots and no roots provided - TLS error · Issue #36 · uswitch/kiam

{"generation.metadata":0,"level":"error","msg":"error warming credentials: RequestError: send request failed\ncaused by: Post https://sts.amazonaws.com/: x509: failed to load system roots and no ro...

DaemonSet kiam-server has zero pods · Issue #15 · uswitch/kiam

When deploying kiam using the yaml files in /deploy, both DaemonSets are created, but only the kiam-agent DaemonSet actually has any pods. kiam-server has no pods at all, there are no failures and ...
@@ -15,12 +19,16 @@ spec:
         role: server
     spec:
       serviceAccountName: kiam-server
+      tolerations:
+        - key: "node-role.kubernetes.io/master"
+          effect: "NoSchedule"
+          operator: "Exists"
       nodeSelector:
         kubernetes.io/role: master
       volumes:
         - name: ssl-certs
           hostPath:
-            path: /usr/share/ca-certificates
+            path: /etc/ssl/certs
         - name: tls
           secret:
             secretName: kiam-server-tls

インストール後、 Kubernetes node の iptables ルールには以下が追加された:

-A PREROUTING -d 169.254.169.254/32 -i cni0 -p tcp -m tcp --dport 80 -j DNAT --to-destination {{ Node IP }}:8181
-A PREROUTING -d 169.254.169.254/32 -i cali+ -p tcp -m tcp --dport 80 -j DNAT --to-destination {{ Node IP }}:8181

TLS

uswitch/kiam/docs/TLS.md

Agent - Server 間でのみ通信を可能にするために TLS 相互認証が使われる。 必要な証明書は自動的には作成されないため、証明書を作成して Server と Agent のプロセスだけがアクセス可能な secrets に保存する必要がある。

ドキュメントに記載の方法でセットアップすればおk。cfssl をインストールして証明書を生成、 secrets として Kubernetes クラスタに配置する。

IAM

uswitch/kiam/docs/IAM.md

Cluster Node Policy

サーバプロセスを実行するノードには sts:AssumeRole を呼び出す権限が必要。

今回は kops を使用しているため、 kops edit cluster で編集できる cluster 設定の spec.additionalPolicies.master に、以下の内容を追加した。

spec:
  additionalPolicies:
    master: |
      [
        {
          "Effect": "Allow",
          "Action": ["sts:AssumeRole"],
          "Resource": ["*"]
        }
      ]      

Application Roles

Pod に割り当てる IAM Role には、その Role を実際に引き受けるノード (kiam のサーバプロセスを実行するノード) を信頼するための ポリシー (AssumeRolePolicyDocument) を設定する必要がある。

今回は特定の S3 Bucket に対して s3:ListBucket するための Role を用意した。 Role とポリシーは Terraform で作った。

#
# variables
#
variable "test-kiam-bucket-name" {
  type    = "string"
  default = "test-kiam-bucket"
}

#
# test-kiam-bucket role & policy
#
## role
resource "aws_iam_role" "test-kiam-bucket" {
  name = "${var.test-kiam-bucket-name}"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    },
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111111111111:role/masters.test.k8s.example.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF
}

## role policy
resource "aws_iam_role_policy" "test-kiam-bucket" {
  name = "${var.test-kiam-bucket-name}"
  role = "${aws_iam_role.test-kiam-bucket.id}"

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::${var.test-kiam-bucket-name}"
      ]
    }
  ]
}
EOF
}

動作確認

aws-cli の使える適当な Pod を配置して、 Pod に IAM ロールを割り当てた場合/割り当てない場合の挙動の違いを確認する。

apiVersion: v1
kind: Pod
metadata:
  name: mypod
  labels:
    name: mypod 
spec:
  containers:
  - image: debian
    command: [ "/bin/bash", "-c", "--" ]
    args: [ "while true; do sleep 30; done;" ]
    name: mypod
$ kubectl create -f mypod.yml
pod "mypod" created

## aws-cli のインストール
$ kubectl exec -it mypod /bin/bash
root@mypod:/# apt-get update && apt-get install -y curl
root@mypod:/# apt-get install -y python && curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py" && python get-pip.py && pip install awscli
root@mypod:/# mkdir ~/.aws
root@mypod:/# cat > ~/.aws/config <<EOF
> [default]
> region = ap-northeast-1
> EOF

Pod に IAM ロールを付与し S3 バケットの内容が取得できるか確認

IAM Role は Pod に annotation を付与することで割り当てることができる。

annotation 付与前
## security-credentials 配下は empty
root@mypod:/# curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
empty role

## S3 bucket の中身は見ることができない
root@mypod:/# aws s3 ls s3://test-kiam-bucket
Unable to locate credentials. You can configure credentials by running "aws configure".
annotation 付与後
## Pod に用意した role 名で annotation をつける
% kubectl annotate pods mypod iam.amazonaws.com/role='test-kiam-bucket'
pod "mypod" annotated

## namespace にも利用できる role の許可設定を annotation で入れる
% kubectl annotate namespace default iam.amazonaws.com/permitted='.*'
namespace "default" annotated

## S3 バケットの中身が見られるか確認してみる
root@mypod:/# aws s3 ls s3://test-kube2iam-bucket
2018-02-26 12:31:57        306 chart.txt

Pod, namespase への annotation 付与後、 S3 bucket の中身が見えることが確認できた。

annotation を外せば bucket 内は再び見えなくなる。

% kubectl annotate pods mypod iam.amazonaws.com/role-
pod "mypod" annotated

root@mypod:/# aws s3 ls s3://test-kiam-bucket
Unable to locate credentials. You can configure credentials by running "aws configure".

Pod に付与する annotation は role の ARN でも指定可能。

kubectl annotate pods mypod iam.amazonaws.com/role='arn:aws:iam::111111111111:role/test-kiam-bucket'

また、 namespace に付与する annotation には正規表現が使用可能。

kubectl annotate namespace default iam.amazonaws.com/permitted='test-kiam-*'

まとめ

  • kiam を kops で構築した AWS 上の k8s cluster にインストールした
    • Agent と Server の2つのプロセスが必要
    • kops の場合 (現状は) Server の yaml manifest に変更を加える必要がある
  • 実際にクレデンシャルを取得するのは kiam-server プロセス
    • sts:AssumeRole は master node 側に必要
  • Pod に対して IAM role を付与することで S3 bucket の参照が可能になることを確認した
    • Role を割り当てるには namespace にも annotation 付与が必要
      • kube2iam は Pod に対してのみ annotation を付与する

参考

IAMロール徹底理解 〜 AssumeRoleの正体 | DevelopersIO

よく訓練されたアップル信者、都元です。最近私はIAM尽くしです。フルコースでIAM貪りまくりです。 さて、皆様はIAMにどのようなイメージをお持ちでしょうか。プロジェクトに関わる複数人で1つのAWSアカウントを扱う時、各 …

【そんなときどうする?】別のアカウントにセキュアにアクセスしたい! いまさらきけないSTSとは? - サーバーワークスエンジニアブログ

こんにちは。CS課の坂本です。 タイトルは違いますが、前回の続きです。前回の処理は、2つのアカウントにまたがって実行されていました。 開発アカウントのLambdaから処理を実行 本番アカウントのCloudWatchのデータを取得 取得したデータを開発アカウントのDynamoDBに入れる という流れでした。 このように別のアカウントにアクセスする場合、ユーザーの「アクセスキー、シークレットアクセスキー」をもう一方のアカウントに知らせて、そのキーを使ってアクセスすることもできますが、ユーザーとキーの管理をしっかりおこなわないといけません。しかし、「AWS STS」を使うとユーザーとキーの管理がいら…

comments powered by Disqus