IAM是AWS的实际的授权方法。大部分针对AWS的Kubernetes的“快速入门”指南并没有充分覆盖如何在你的Pod中管理IAM访问的相关内容。本系列文章讲探讨Kubernetes环境的AWS IAM特有的安全性问题,然后对比不同方案,并最终详细介绍如何选择一种方案来设置集群。
在之前的文章中,我们在生产kubernetes集群中安装了kiam。在本文中,我们将介绍在成产环境快速安装kube2iam的过程.
概述
本文将包含你在身缠环境部署kube2iamd的以下4步:
- 创建 IAM roles
- 增加Annotation到Pod
- 部署kube2iam
- 测试
- 全部部署kube2iam
浏览kube2iam概况及特性,请查看 Github Page。
1. 创建IAM Roles
使用kubeiam的第一步是为你的Pod创建IAM roles。kube2iam的工作方式是需要一个IAM策略附加到集群中每个节点以允许其为Pod委派roles。
创建为你的节点一个IAM策略并且附加到你的kubernetes节点的role上。
策略:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"sts:AssumeRole"
],
"Resource": "*"
}
]
}
接下来为每个pod创建role。每个role将需要一个策略,拥有Pod功能所需的最小权限,例如:列出S3对象,写入DynamoDB, 读取SQS等。你需要为每个所创建的role更新委派角色策略,以便使你的节点可以委派这些role。用kubernetes节点所附加role的arn
替换YOUR_NODE_ROLE
。
委派角色策略:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
},
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": "YOUR_NODE_ROLE"
},
"Action": "sts:AssumeRole"
}
]
}
2. 为pod
增加Annotations
下一步将你的pod将用的role注释到Pod。增加一个annotation
到pod 的metadata.spec
即可,kube2iam使用IAM对Pod进行身份认证时将使用这个role。如此配置后,kube2iam将为该role自动检查基础arn
,但是如果你需要委派角色给其他AWS账号也可以指定一个完整的arn
(以arn:aws:iam
开始)。kube2iam文档有一些不同pod控制器的例子。
annotations:
iam.amazonaws.com/role: MY_ROLE_NAME
3. 部署kubeiam
现在可以部署kube2iam。你可以参考kube2iam github repo 获取EKS和OpenShift的例子,但是这里也也会介绍一些通用deployment方法。第一步时配置RBAC:
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: kube2iam
namespace: kube-system
---
apiVersion: v1
items:
- 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
kind: List
因为kube2iam修改了kubernetes节点上的iptables规则来劫持到EC2 metadata服务的流量,我建议增加一个tainted
的新节点到集群,这样你可以在确保不影响你生产环境Pod的前提下测试控制器来配置正确。为集群增加一个节点然后为其打上五点钟,这样其他Pod就不会被调度到该节点。
export ALICLOUD_ACCOUNT=""
export ALICLOUD_ACCESS_KEY="your-access-key"
export ALICLOUD_SECRET_KEY="your-secret-key"
export ALICLOUD_REGION="cn-qingdao"
kubectl taint nodes NODE_NAME kube2iam=kube2iam:NoSchedule
接下来我们可以在该节点上配置agent。增加nodeName: NEW_NODE_NAME
到Pod.spec
,然后增加tolerations
这样它就可以被调度到该节点。设置镜像版本为标记过的发布版本而非latest
。还需要设置--host-interface
命令参数来适配你的CNI
。kube2iam页面有完整的支持列表。我也建议设置 --auto-discover-base-arn
和 --auto-discover-default-role
参数来时配置和迁移更容易。如果你的集群再单个可用区--use-regional-sts-endpoint
会很有用,但是你必须为其设置 AWS_REGION
环境变量。综上所述,配置大致如下:
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:
nodeName: NEW_NODE_NAME
tolerations:
- key: kube2iam
value: kube2iam
effect: NoSchedule
serviceAccountName: kube2iam
hostNetwork: true
containers:
- image: jtblin/kube2iam:0.10.6
imagePullPolicy: Always
name: kube2iam
args:
- "--app-port=8181"
- "--auto-discover-base-arn"
- "--iptables=true"
- "--host-ip=$(HOST_IP)"
- "--host-interface=weave"
- "--use-regional-sts-endpoint"
- "--auto-discover-default-role"
- "--log-level=info"
env:
- name: HOST_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: AWS_REGION
value: "us-east-1"
ports:
- containerPort: 8181
hostPort: 8181
name: http
securityContext:
privileged: true
接下来你可以创建agent并确认该agent运行于你的新节点上。你其他节点上的Pod不会有变更。
4. 测试
在这一步,开始测试以期望一切正常。你可以通过在该隔离节点部署一个Pod,然后在该POD中使用AWS CLI访问资源进行测试。当你做这些时,请检查kube2iam agent的日志来debug你遇到的的问题。这里有个deployment实例,你可以指定一个role然后用它进行访问测试。
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: aws-iam-tester
labels:
app: aws-iam-tester
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: aws-iam-tester
template:
metadata:
labels:
app: aws-iam-tester
annotations:
iam.amazonaws.com/role: TEST_ROLE_NAME
spec:
nodeSelector:
kubernetes.io/role: node
nodeName: NEW_NODE_NAME
tolerations:
- key: kube2iam
value: kube2iam
effect: NoSchedule
containers:
- name: aws-iam-tester
image: garland/aws-cli-docker:latest
imagePullPolicy: Always
command:
- /bin/sleep
args:
- "3600"
env:
- name: AWS_DEFAULT_REGION
value: us-east-1
Pod将会在一个小时后退出,你可以使用kubectl获取一个TTY到Pod。
kubectl exec -ti POD_NAME /bin/sh
一旦你确认你的role可以正常工作,并且kube2iam agent配置正常,你就可以部署agent到每个节点。
5. 全量部署kube2iam
从kube2iam Daemonset删除nodeName
和kub2iam:kub2iam
以允许它运行到每个节点。 在每个节点安装完成以后,应该对关键pod进行更新,以这些Pod立即使用kube2iam进行验证。其他曾经使用node role进行认证的的Pod当其临时凭据过期后将开始使用kube2iam进行认证(通常是一个小时)。若IAM认证有错,请检查你的应用及kubeiam日志。
当一切运行正常,你就可以删除再次之前添加的隔离节点。
遇到问题时,你可以删除所有节点上的agent,但是它不会自动清理它创建的iptable规则。这将导致所有发往EC2 metada的请求不起作用。你需要分别登录到每个节点并手动移除这些iptables规则。
首先列出iptable规则,找出kube2iam所创建的部分
sudo iptables -t nat -S PREROUTING | grep 169.254.169.254
输出大概如下:
-A PREROUTING -d 169.254.169.254/32 -i weave -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.0.101.101:8181
如果你意外的使用不同的--host-interface
选项部署agent你可能会看到多个结果。你可以一次删除他们。删除一条规则使用iptables的-D
选项并指定-A
选项输出的具体行号,例如:
sudo iptables -t nat -D PREROUTING -d 169.254.169.254/32 -i weave -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.0.101.101:8181
当每个节点上都执行过后,EC2 metadta请求将不在发往kube2iam.
结论
现在有kube2iam运行于你的生产集群以及,并为POD创建独立的角色。
如果你的对其他阿方案看兴趣,请查看我之前写的[kiam安装]()一文。它更加复杂,并且使用不同的方法解决IAM的问题。我也在关注 kube-aws-iam-controller作为替代方案,但是该项目一直不太成熟不适合生产环境。你可也可以查看本系列第一,第二篇文章来了解kubernetes中使用AWS IAM的问题,以及对kiam和kube2iam作为解决方案的深入比较。
因在下英文太烂,如果可以您阅读英文,强烈建议 查看原文
FAQ & Checklist
Question: Add support for Instance Metadata Service Version 2 (IMDSv2)Question: 注意你的集群所使用的网络方案,比如:文中例子为
weave
,我的集群为Calico
,所以应该修改为cali+
。否则会报如下错误:
$ k logs kube2iam-ltm7f -n kube-system
...
time="2020-07-17T10:47:30Z" level=fatal msg="route ip+net: no such network interface"
Question 2: 默认情况下kube2iam使用8181端口,因为我的worker node使用了8181端口,需要增加2个参数 --app-port=8182 --metrics-port=8183
,否则会报如下错误:
$ k logs kube2iam-bk59z -n kube-system
time="2020-07-18T03:42:04Z" level=info msg="Listening on port 8181"
time="2020-07-18T03:42:04Z" level=fatal msg="Error creating kube2iam http server: listen tcp :8181: bind: address already in use"
Question 3: 使用文中命令未找到相应的iptables规则
$ sudo iptables -t nat -S PREFOUTING | grep 169.254.169.254
iptables: No chain/target/match by that name.
# 尝试如下命令
sudo iptables -t nat -L | grep 169.254.169.254
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。