kube2iamの仕組みと使い方

はじめに

SREチームの須恵です。 SREとしてはDocker/Kubernetesを利用した環境の整備を主に推進するかたわら、ときおりフロントエンド開発にも自由に挑戦させてもらったりしています。

今回は、kube2iamの仕組みと使い方について書いてみようと思います。

これは何?

kube2iamとは、Amazon EKS上のPodごとにIAMロールを使い分けられるようにするためのツールです。

github.com

なぜ必要?

Amazon EKSにおいて、クラスターを構成するNodeはEC2インスタンスです。

AWSリソースにアクセスするようなPodを動かしたいとき、Podが持てるAWSリソースへの権限は、EC2インスタンスにアタッチされたインスタンスプロファイルに紐づくIAMロールに準じます。

参考) EC2にIAMRole情報を渡すインスタンスプロファイルを知っていますか? | DevelopersIO

ここで、「異なる種類のAWSリソースを使用する複数のPodを、同じクラスターにデプロイしたい」という状況について考えます。

このとき、クラスターのすべてのNodeに 「各Podが必要とする権限の和集合」を許可することになり、 Podが本来権限を持つべきでないリソースに誤ってアクセスできてしまうリスクが生じます。

そのため、「Node単位」でなく「Pod単位」で権限制御できることにニーズがあります。

どうやって実現?

kube2iamが何を行うのか、おおざっぱに説明すると下記です。

kube2iamなし

AWSに対して何かしたいPod

→コンテナが動作するNodeのEC2メタデータAPI

→インスタンスプロファイルに紐づくロールの一時クレデンシャルをコンテナに返す

kube2iamあり

AWSに対して何かしたいPod

→メタデータAPIへのリクエストをkube2iamコンテナにリダイレクト

→kube2iamが「何かしたいコンテナ」のアノテーションに記述されたロールを引き受け(Assume)

→当該ロールの一時クレデンシャルをコンテナに返す

kube2iamに使用させるIAMロールの作成

ここから実際にkube2iamを利用するための準備を進めます。

まず下記のポリシーを作成します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "sts:AssumeRole"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

次に、「使用サービス:EC2」のロールを作成し、このポリシーをアタッチします。 ロールを作成したら、信頼関係の編集を行います。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    },
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:role/kubernetes-worker-role" ←ここは各自の値
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

"arn:aws:iam::123456789012:role/kubernetes-worker-role" この部分には、ワーカーノード(にアタッチされたインスタンスプロファイル)のIAMロールを記載します。

ここまでの作業で、ワーカーノードに対して、AssumeRoleができる権限だけを与えました。

RBAC用リソース作成

ここからはKubernetesリソースを作成していきます。 まず作成するのはServiceAccount, ClusterRole, ClusterRoleBindingです。

このServiceAccountはkube2iamのPodがKubernetesのAPIサーバーにアクセスする際に利用します。

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: kube2iam
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kube2iam
rules:
  - apiGroups: [""]
    resources: ["namespaces","pods"]
    verbs: ["get","watch","list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kube2iam
subjects:
- kind: ServiceAccount
  name: kube2iam
  namespace: kube-system
roleRef:
  kind: ClusterRole
  name: kube2iam
  apiGroup: rbac.authorization.k8s.io

DaemonSet作成

ここからは、kube2iamのPodを稼働させるための作業です。

「EC2メタデータAPIへのリクエストを奪取する」という役割を遂行するためには、どのノードでリクエストが発生してもよい=すべてのワーカーノードでkube2iamが動作している必要があるので、DaemonSetリソースを作成します。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube2iam
  namespace: kube-system
  labels:
    app: kube2iam
spec:
  selector:
    matchLabels:
      name: kube2iam
  template:
    metadata:
      labels:
        name: kube2iam
    spec:
      serviceAccountName: kube2iam
      hostNetwork: true
      containers:
        - image: jtblin/kube2iam:latest
          imagePullPolicy: Always
          name: kube2iam
          args:
            - "--app-port=8181"
            - "--auto-discover-base-arn"
            - "--iptables=true"
            - "--host-ip=$(HOST_IP)"
            - "--host-interface=eni+"
            - "--verbose"
          env:
            - name: HOST_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP
          ports:
            - containerPort: 8181
              hostPort: 8181
              name: http
          securityContext:
            privileged: true

https://hub.docker.com/r/jtblin/kube2iam/ このイメージから起動したコンテナを持つPodが各ノードに配置されます。

privilegedが要る理由

--iptables=trueかつprivileged: trueとすることで、EC2メタデータAPIへのアクセスがkube2iamにプロキシされ、直接EC2メタデータAPIにアクセスしないようにすることができます。

kube2iamを利用してPodでロールを使用する

DaemonSetが作成できたら、任意のロールをPodで使用する準備は完了です。

Podのアノテーションにiam.amazonaws.com/roleを追加すると、任意のロールをPodで利用できます。

# Sample
apiVersion: v1
kind: Pod
metadata:
  name: aws-cli
  labels:
    name: aws-cli
  annotations:
    iam.amazonaws.com/role: role-arn ←ここです
spec:
  containers:
  - image: fstab/aws-cli
    command:
      - "/home/aws/aws/env/bin/aws"
      - "s3"
      - "ls"
      - "some-bucket"
    name: aws-cli

最後に

続編として、今回セットアップしたkube2iamともう一つのツールを組み合わせ、EKS上のアプリケーションへALBを使ってルーティングを行う方法について書こうと思います。

SREチームも人が少しずつ増えてきました。

オクトではエンジニアを積極採用中です。ぜひ気軽に採用サイトを見てみてください。

engineer.88oct.co.jp