kube2iam で Kubernetes の Pod に IAM role を割り当てる
概要
- kube2iam で Kubernetes Pod に対して IAM role を割り当て、動作を確認する
- Kubernetes cluster は kops で AWS 上に構築したものを使う
- 検証用の S3 bucket を使い Pod に割り当てた role の有無で参照可能/不可能になることを確認する
kube2iam とは
AWS 環境では EC2 インスタンスに IAM role を割り当て、サービスの呼び出し時に資格情報を使用することができます。この仕組を、Kubernetes のように1つの EC2 インスタンスで複数のコンテナが稼働する状況で利用すると、セキュリティ上の問題が生じる可能性があります。
- EC2 には各コンテナで必要な権限を集約した role を割り当てる必要がある
- 神 role が誕生してしまう
- コンテナ上からそのコンテナでは必要としない role の資格情報まで見えてしまう
Kubernetes クラスタを AWS 上に構築しているケースでは、 kube2iam を使うと IAM role を Kubernetes の Pod に対して割り当てることができるようになります。
EC2 メタデータ API に送られるトラフィックは kube2iam のコンテナにリダイレクトされ、 AWS API を呼び出して一時的な資格情報を取得し、呼び出し元のコンテナに返すという仕組みで実現しているようです。
検証
kube2iam のインストール
kube2iam.yml
を作成し、 kubectl apply -f kube2iam.yaml
でインストールする。
以下の yaml では k8s node に設定する iptables ルールを自動設定するために、使用するネットワークインターフェース名などのオプション指定を追加している。
参考: Updated to README.md for RBAC #99
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: kube2iam
namespace: kube-system
---
apiVersion: v1
items:
- apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: kube2iam
rules:
- apiGroups: [""]
resources: ["namespaces","pods"]
verbs: ["get","watch","list"]
- apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: kube2iam
subjects:
- kind: ServiceAccount
name: kube2iam
namespace: kube-system
roleRef:
kind: ClusterRole
name: kube2iam
apiGroup: rbac.authorization.k8s.io
kind: List
---
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: kube2iam
namespace: kube-system
labels:
app: kube2iam
spec:
template:
metadata:
labels:
name: kube2iam
spec:
serviceAccountName: kube2iam
hostNetwork: true
containers:
- image: jtblin/kube2iam:latest
imagePullPolicy: Always
name: kube2iam
args:
- "--base-role-arn=arn:aws:iam::111111111111:role/"
- "--iptables=true"
- "--host-ip=$(HOST_IP)"
- "--host-interface=cni0"
- "--verbose"
env:
- name: HOST_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
ports:
- containerPort: 8181
hostPort: 8181
name: http
securityContext:
privileged: true
EC2 メタデータ API へのアクセス制限
Pod が kube2iam をバイパスして EC2 メタデータ API にアクセスすることを防ぐために、 k8s node の iptables にルール追加をする。 このルールは DaemonSet の配置時に自動追加することも可能。(上記の yaml ではそうしている)
以下のようなルールを追加することで、 EC2 メタデータ API へのアクセスを kube2iam コンテナに転送する。
iptables \
--append PREROUTING \
--protocol tcp \
--destination 169.254.169.254 \
--dport 80 \
--in-interface docker0 \
--jump DNAT \
--table nat \
--to-destination `curl 169.254.169.254/latest/meta-data/local-ipv4`:8181
Pod から S3 bucket へのアクセスを許可する例
kube2iam は EC2 に割り当てられた中間的な Role を使い、Pod に割り当てる Role を引き受け (AssumeRole) 一時的なクレデンシャルを取得するために使われる。
Pod に割り当てる Application Role には、その Role を実際に引き受ける中間 Role を信頼するための AssumeRolePolicyDocument を設定する必要がある。
Role を引き受けるための AssumeRole 許可を行う記述を k8s node に割り当てる。
kops edit cluster
で編集できる yaml に以下のポリシーを追加した。
編集が完了したら kops cluster update --yes
で反映する。
spec:
additionalPolicies:
node: |
[
{
"Effect": "Allow",
"Action": ["sts:AssumeRole"],
"Resource": ["*"]
}
]
今回は Application Role として特定の S3 バケットを ListBucket できる Role を Terraform で作った。 kops が作った k8s node に割り当てられている Role の ARN を、 variable で持たせておき Principal の指定に使っている。
provider "aws" {
region = "ap-northeast-1"
}
#
# variables
#
variable "test-kube2iam-bucket-name" {
type = "string"
default = "test-kube2iam-bucket"
}
variable "iam-role-arn_test-k8s" {
type = "string"
default = "arn:aws:iam::111111111111:role/nodes.test.k8s.example.com"
}
#
# test-kube2iam-bucket role & policy
#
## role
resource "aws_iam_role" "test-kube2iam-bucket" {
name = "${var.test-kube2iam-bucket-name}"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": "${var.iam-role-arn_test-k8s}"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}
## policy
resource "aws_iam_role_policy" "test-kube2iam-bucket" {
name = "test-kube2iam-bucket"
role = "${aws_iam_role.test-kube2iam-bucket.id}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::test-kube2iam-bucket"
]
}
]
}
EOF
}
Pod への IAM ロールの割り当て
Pod マニフェストに annotation をつけ、 割り当てる role の ARN を書く。
apiVersion: v1
kind: Pod
metadata:
annotations: iam.amazonaws.com/role: arn:aws:iam::ACCOUNTID:role/S3-BUCKET-NAME
kubectl でつけるなら、こんな感じ
kubectl annotate pods <PodName> iam.amazonaws.com/role='arn:aws:iam::111111111111:role/test-kube2iam-bucket'
annotation を外すときは -
をつけると消せる
kubectl annotate pods <PodName> iam.amazonaws.com/role-
動作確認
aws-cli の使える適当な Pod を配置して、 Pod から EC2 メタデータ API へアクセスしたときや aws cli を実行したときの挙動の違いについて確認する。
a. kube2iam を使う場合/使わない場合 b. kube2iam で 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:/# cat > ~/.aws/config <<EOF
> [default]
> region = ap-northeast-1
> EOF
EC2 メタデータ API への Pod からのアクセス
kube2iam インストール前
## EC2 に割り当てられた IAM Role が見えている
root@mypod:/# curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
nodes.test.k8s.example.com
## クレデンシャル情報以外の API アクセスも可能
root@mypod:/# curl http://169.254.169.254/latest/meta-data/local-ipv4
10.xxx.xxx.xxx
kube2iam インストール後
インストール後、 k8s の worker node には iptables のルールが追加された。
# iptables-save | grep 169.254
-A PREROUTING -d 169.254.169.254/32 -i cni0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.xxx.xxx.xxx:8181
## security-credentials の中身は空になり見えなくなった
root@mypod:/# curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
root@mypod:/#
## クレデンシャル情報以外の API アクセスも可能
root@mypod:/# curl http://169.254.169.254/latest/meta-data/local-ipv4
10.xxx.xxx.xxx
Pod に IAM ロールを付与し S3 バケットの内容が取得できるか確認
IAM ロールは Pod に annotation をつけることで付与できる
annotation 付与前
## 必要なクレデンシャルを取得できない状況なので S3 バケットの中身を見ることはできない。
root@mypod:/# aws s3 ls s3://test-kube2iam-bucket
Unable to locate credentials. You can configure credentials by running "aws configure".
annotation 付与後
## Pod に対して annotation を付与し IAM Role を割り当てる
% kubectl annotate pods mypod iam.amazonaws.com/role='arn:aws:iam::111111111111:role/test-kube2iam-bucket'
pod "mypod" annotated
## S3 バケットの中身が見えるようになった
root@mypod:/# aws s3 ls s3://test-kube2iam-bucket
2018-02-26 12:31:57 306 chart.txt
## 先ほど付与した annotation を外す
% kubectl annotate pods mypod iam.amazonaws.com/role-
pod "mypod" annotated
## S3 バケットの中身は見えなくなった
root@mypod:/# aws s3 ls s3://test-kube2iam-bucket
Unable to locate credentials. You can configure credentials by running "aws configure".
まとめ
- Pod に対して IAM role を付与することで S3 bucket の参照が可能になることを確認した
- 各 Pod のための IAM role をどう準備するかは何かうまい方法を考えたい
- kops と Terraform で二重管理のようになってしまうのをどうにかしたい
- 安定性とセキュリティ面で kiam のほうが良いらしいのでコチラも試してみる
参考
Previous Post
Next Post