如果在AWS中使用Jenkins,可能会遇到需要跨AWS账号来部署的情况。比如把Jenkins搭建在non-prod
账号中,然后在这个账号里构建、部署产品到低环境,然后把高环境部署到prod
账号中。
这里面最棘手的大概会是权限的问题,大致可以归为两类:
- AWS IAM的权限问题
- Kubernetes中的权限问题
Solution
解决方案如上图,整个过程中一个用到了4个IAM Role,每个账号两个。
详细解释如下:
Non-Prod Account
Jenkins Master运行在AWS EKS中,这个pod刚被创建出来的时候,默认的IAM Role来自于EKS Node的Role,这个
non-prod node role
在创建EKS时自动生成。使用kube2iam来为EKS pod分配自定义的role,这里将
kube2iam
部署到kube-system
的namesapce下,kube2iam
部署后就可以在K8s中用注解来指定想要分配给pod的role,比如:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
template:
metadata:
annotations:
iam.amazonaws.com/role: role-arn
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.9.1
ports:
- containerPort: 80这里为了简单让EKS下的所有pod共享一个
non-prod EKS cluster role
,这个role需要提前创建,然后赋予它所有pod所需的权限。同时需要更新EKS的设置,为
non-prod EKS cluster role
提供集群的访问权限。默认情况下只有集群的创建者拥有集群的访问权限,所以如果non-prod EKS cluster role
不是集群的创建者的话,就需要手动加入。这时候Jenkins Master已经带入到了
non-prod EKS cluster role
中,利用这个role所定义的权限去和AWS CodeCommit交互,检测是否有代码的改动。Jenkins Master检测到代码变动,触发build,动态创建出一个Jenkins Slave。创建slave所用到的权限来自于K8s的RBAC,而非AWS IAM。这里为Jenkins Master创建一个集群范围内的role binding,让它具有在所有命名空间下执行集群操作的admin权限。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19apiVersion: v1
kind: ServiceAccount
metadata:
name: cluster-account
namespace: somens
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: cluster-role-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: admin
subjects:
- kind: ServiceAccount
name: cluster-account
namespace: somenskube2iam自动为新创建出来的Jenkins Slave赋予
non-prod EKS cluster role
的角色。Jenkins Slave开始build,利用
non-prod EKS cluster role
的权限从AWS CodeCommit中拉取代码。Jenkins Slave build出docker镜像,利用
non-prod EKS cluster role
的权限将镜像推送到AWS ECR中去。Jenkins Slave利用RBAC定义的权限创建k8s deployment和service,完成部署。
产品pod利用
non-prod node role
的角色去AWS ECR中拉取镜像。这里需要注意:- 用的role不再是前面的cluster role,而是node role,因为拉取镜像是创建pod时k8s内部的操作,这时候kube2iam还没有将cluster role赋予该pod,所以这个时刻pod的role还是默认的node role。
- non-prod node role与ECR在同一个账号下,所以只需要赋予non-prod node role与ECR交互的权限,ECR无需任何设置。
kube2iam
为产品pod分配non-prod EKS cluster role
,低环境的部署完成。
Prod Account
开始进行prod的跨账号部署,Jenkins Slave这时候手动带入到
prod EKS cluster role
中去。这里需要:- 提前创建好
prod EKS cluster role
- 在
prod EKS cluster role
的信任关系中允许non-prod EKS cluster role
的带入。 - 提前更新prod账号的EKS设置,为
prod EKS cluster role
提供集群的访问权限。默认情况下只有集群的创建者拥有集群的访问权限,所以如果prod EKS cluster role
不是集群的创建者的话,就需要手动加入。 - 更新kubectl,让其连接上prod账号的EKS集群。
成功带入
prod EKS cluster role
后,Jenkins Slave开始部署。- 提前创建好
新创建出的pod被赋予
prod node role
的默认权限。产品pod利用
prod node role
的角色去AWS ECR中拉取镜像。这里需要注意:prod node role
需要具有访问ECR的权限- ECR的permission设置中需要允许
prod node role
来访问。因为ECR在non-prod账号而产品pod是在另一个账号,所以这里需要显示的指定。
prod集群下的
kube2iam
为产品pod分配prod EKS cluster role
,部署完成。最后一步也是很重要的一步,如果Jenkins Slave被设置成长期存活而不是用完就删除的话,需要重新带入回
non-prod EKS cluster role
,这样下一次build使用的才会是non-prod账号。(这一步没画在图中)
总结
总结一下,简单来说就是:
- 用kube2iam在pod创建时为pod分配IAM role
- 用RBAC来赋予Jenkins操纵k8s的权限
- Jenkins Slave带入到prod账号的角色中来完成对prod账号的操作
有用的资料
- https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html
- https://aws.amazon.com/premiumsupport/knowledge-center/eks-api-server-unauthorized-error/
- https://docs.aws.amazon.com/cli/latest/reference/sts/assume-role.html
- https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_roles_common-scenarios_aws-accounts.html
- https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/managing-auth.html
- https://www.kloia.com/blog/aws-resource-access-with-iam-role-from-kubernetes
- https://aws.amazon.com/cn/premiumsupport/knowledge-center/amazon-eks-cluster-access/
评论(需梯子)