kiamをEKS/Fargateでいい感じに動かす
この記事はAmazon EKS Advent Calendar 2019 8日目の記事です。 また、OpenSaaS Studio Advent Calendar 2019 9日目の記事としてクロスポストをしています。
TL;DR
- kiam-serverはFargateを使うといい感じに動く
- 古いaws-sdkに依存したツールを使うとIAM Role for ServiceAccountは使えない
- kiam-agentを動かすとiptables書き換えにより、ノード側でできなくなることがあるから気をつけて
はじめに
AWS Fargate for AWS EKSがRe:InventのKeynoteで発表されましたね! Twitterの反応を見る限り非常に評価が高いようです。 が、個人的にはアプリケーションとObservability系のツールは引き離したいため1にDaemonSetの使えないFargateを常駐アプリの展開に使いたいとは基本的には思いません。 詰まるところ現状EKSをフルFargateの構成にできるとは考えておらず、ノード管理をしなくていい世界線が来るのはまだ先のようです。
一方でバッチジョブなどではノード管理したくないですし、常駐アプリのリソースをバッチに掻き回されるのも嫌なので非常に向いているように思えます。 要するに適材適所、使い所を考える必要があるわけです。今日はFargateに非常にむいていると自分が思っているユースケースを1つ紹介しようかなと思います。
EKSでの権限管理
2019年の9月くらいにIAM Role for ServiceAccountという機能が発表されました。 これにより技術書典で書いていた本の権限管理の章を大幅に書き直すことになったことが記憶に新しいです。 このブログでも
で触ってみた記事を上げています。
記事内でも触れていますがIAM Role for ServiceAccountはそこそこ新しいaws-sdkでないと動作しません。 これはServiceAccountによってPodにアタッチされたファイルをAWSのcredentialとして認識する機能が元々は存在しなかったというのが原因なわけですが、みなさんが開発しているアプリやその依存ライブラリは対応しているでしょうか? 自分の開発しているアプリの依存ライブラリは対応していませんでした。悲しいですね。
そういった人がEKSでPod単位の権限管理を行う場合、kiamやkube2iamを利用することが多いでしょう。 kiamとkube2iamの違いとしてkiamはkube2iamにインスパイアされて作られたものでkube2iamの"レースコンディションが発生し、間違ったRoleがPodに割り当てられる場合がある"という不具合を解消しています。 一方、権限をアタッチするエージェントとSTSとやり取りするサーバを別のノードで動かす必要があり、EKSで動かすためにはtaintをつけたり、Node Affinityをつけるなど工夫やアーキテクチャ的な汚さを許容する必要がありました。 しかしFargateをkiam-serverで動かすことでこれを解決できます。嬉しいですね。
kiamとは
kind: Pod annotations: iam.amazonaws.com/role: hogehoge
みたいな感じでPodのannotationにIAM Roleの名称を渡すことでPodとIAM Roleを対応させるツールです。
やり方
K8sのワーカーノードのメタデータサーバ(169.254.169.254)とのアクセスをiptablesの書き換えによりジャックすることで、kiam-agentの動作するノードで動いているPodにIAM Roleを錯覚させる2というような権限管理ツールです。 この方法はAWS Traditional IAM Managementであるために古いaws-sdkでも動作します。嬉しいですね。 namespaceごとにアタッチされるIAM Roleの名称を制限したりすることもでき、この辺りは地味に嬉しいです。
そもそもIAM Roleをアタッチするってどういうこと?
メタデータサーバにアクセスして、IAM Roleの名称とcredentialを取得できる状態を指すようです(間違っていたら教えてください)。
hogehogeというRoleがノードにアタッチされている場合下記のようなデータをメタデータサーバへのアクセスで取得可能です。
$ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ hogehoge $ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/hogehoge { "Code" : "Success", "LastUpdated" : "2019-12-08T07:20:38Z", "Type" : "AWS-HMAC", "AccessKeyId" : "*****", "SecretAccessKey" : "******", "Token" : "*****", "Expiration" : "2019-12-08T13:49:31Z" }
kiamでは 169.254.169.254
へのアクセスをkiamに向け3、STSと疎通して取得したIAMの情報をいい感じに返却することで、PodにIAM Roleを錯覚させています。
kiamのアーキテクチャ
kiamのアーキテクチャは以下のようになっています.
IAM Access in Kubernetes: kube2iam vs kiamから引用
kiam-agentはWorker Nodeのiptablesを書き換え、169.254.169.254
へのアクセスをkiam-agentへと誘導するようにしています。
また、kiam-agentはkiam-serverとやり取りすることで自身のノードで動いているPodとIAMの対応をいい感じに管理し、PodからIAM周辺のアクセスが来た時にPodのannotationで指定されたIAM Roleの情報を返却しています。
kiam-serverはK8sのイベントを監視し、必要なcredentialをSTSから取得します。 なおkiam-serverはメタデータサーバとやり取りし、STSと通信する権限を得る必要があるため、kiam-agentと同一のノードに同居することはできません。
ここまで来ると気づくわけです。kiam-serverを動かすためのnamespaceを作ってFargateで動かしてやればkiam-server専用ノード作らなくてもいい感じに管理できるんじゃね? さらにいえばkiam-serverは結構センシティブな存在で、クラスタアップグレードのときはデプロイする順番に注意しないといい感じにIAM Roleをアタッチできません。 この辺りをノードレスに管理することができればtaintやNodeAffinityなんかの設定をUserDataやmanifestから一掃することができ、最高です。ではやっていきましょう
Fargateでkiam-serverを動かしてみる
Gistに必要なファイルが列挙しています。必要なファイルはここから拾ってください。 必要に応じて確認してください。なお、パッと動かすためにTLSの秘密鍵なんかも上げています。真似しないようにしてください。 kiamはリリースされていないものの最新のものであればIAM Role for ServiceAccountに対応しているため、kiam-serverの権限管理に利用していきましょう。
files to use kiam on EKS/Fargate · GitHub
下準備
kiam-serverが利用するIAM Policyを作成する
aws iam create-policy --policy-name kiam-server --policy-document file://kiam-server.json
クラスタとServiceAccountと紐づくIAMの作成
eksctl create cluster -f cluster.yaml eksctl utils associate-iam-oidc-provider --config-file=cluster.yaml --approve eksctl create iamserviceaccount --config-file=cluster.yaml --approve
テスト用のIAMの作成
aws iam create-role \ --role-name kiam-test \ --assume-role-policy-document file://kiam-test.json aws iam attach-role-policy \ --role-name kiam-test \ --policy-arn "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess"
Fargate用のnamespace作成
kubectl apply -f namespace.yaml
実際にデプロイする
kiam-serverのデプロイ
kubectl apply -f kiam-server.yaml
kiam-agentのデプロイ
kubectl apply -f kiam-agent.yaml
test用コンテナのデプロイ
kubectl apply -f kiam-test.yaml
IAM Roleの確認をしてみる
kubectl exec
で適当にコンテナに入ってawscliをインストールして aws ec2 describe-instances
を叩いてみる。
root@kiam-test:/# aws configure AWS Access Key ID [None]: AWS Secret Access Key [None]: Default region name [None]: ap-northeast-1 Default output format [None]: json root@kiam-test:/# aws ec2 describe-instances { "Reservations": [ { "Instances": [ { "Monitoring": { "State": "disabled" }, "PublicDnsName": "", "State": { "Code": 16, "Name": "running" }, "EbsOptimized": false, "LaunchTime": "2019-12-09T13:45:59.000Z",
いい感じにみれましたね。
補足: kiamがTLSするためのオレオレ証明書作成コマンド
cfssl gencert -initca ca.json | cfssljson -bare ca cfssl gencert -ca=ca.pem -ca-key=ca-key.pem server.json | cfssljson -bare server cfssl gencert -ca=ca.pem -ca-key=ca-key.pem agent.json | cfssljson -bare agent
解説
kiam-server
IAM Role for ServiceAccountに対応したイメージがリリースされていないのでイメージタグはコミットハッシュを直で指定しています。趣があっていいですね。
containers: - name: kiam image: quay.io/uswitch/kiam:b4a4891b136469511b3b011d38147cc1640b152e
kaimは元々ホストマシンの証明書を利用してHTTPS通信を行っているため証明書を適当に用意してあげる必要があります。 本来はDockerfileで対応するのがいいですが、コンテナレジストリを作るのが面倒くさいため、適当に当て込みます。 伴って、kiamのリポジトリのサンプルにはホストマシンへのマウントパスがありますが削除しています。
lifecycle: postStart: exec: command: - "/bin/sh" - "-c" - "apk update && apk add --no-cache ca-certificates && update-ca-certificates" env: - name: SSL_CERT_FILE value: /etc/ssl/certs/ca-certificates.crt - name: SSL_CERT_DIR value: /etc/ssl/certs
role-base-arnのauto-detectにはホストマシンのENIを利用しているためbase-arnのauto-detectはできません。 自身で使っているAWS IAM Roleのbase-arnを指定してあげましょう。
command: - /kiam args: - server - --json-log - --level=warn - --bind=0.0.0.0:443 - --cert=/etc/kiam/tls/server.pem - --key=/etc/kiam/tls/server-key.pem - --ca=/etc/kiam/tls/ca.pem - --role-base-arn=arn:aws:iam::${ACCOUNT_ID}:role/ - --sync=1m
参考URL https://github.com/uswitch/kiam/issues/194
kiam-agent
kiam-serverは同一namespaceにありませんので適当に向き先を変えましょう。
args: - agent - --iptables - --host-interface=eni+ - --json-log - --port=8181 - --cert=/etc/kiam/tls/agent.pem - --key=/etc/kiam/tls/agent-key.pem - --ca=/etc/kiam/tls/ca.pem - --server-address=kiam-server.kiam:443 - --gateway-timeout-creation=1s
server証明書の設定でもnamespaceまたぎの通信を許可するようにしています。
"hosts": [ "kiam-server.kiam", "kiam-server.kiam.svc", "kiam-server.kiam.svc.cluster", "kiam-server.kiam.svc.cluster.local", "127.0.0.1", "localhost" ],
まとめ
AWS Fargate for AWS EKSにより、kiam利用時のアーキテクチャの気持ち悪さを一層し、管理コストをかなり下げることができました! EKS/Fargateは現状はwebアプリケーションを動かすための最適解とは自分は考えていません。 一方で、バッチ処理や必ず異なるノードで動かす必要があるアプリケーションとは一定の親和性があると考えています。今回はその一例を紹介してみました。 このようにEKS/EC2とEKS/Fargateを組み合わせることで管理コスト下げたり、アプリケーションを安定稼働させることができると思っています! kubeconでのManaged Worker Nodeの発表など2019年はEKSの進化が目覚ましい1年でしたね。来年も楽しみにしています。 みなさんはEKS/Fargate、何に使っていきますか?