AWS支持IAM服务帐户角色(IRSA),允许集群运营商将AWS IAM角色映射到Kubernetes服务帐户。
要做到这一点,必须在EKS集群中创建一个iamservice帐户:
eksctl create iamserviceaccount
--name <AUTOSCALER_NAME>
--namespace kube-system
--cluster <CLUSTER_NAME>
--attach-policy-arn <POLICY_ARN>
--approve
--override-existing-serviceaccounts
问题是我不想使用上面的eksctl
命令,因为我想使用terraform
声明我的基础结构。
除了创建服务帐户之外,eksctl命令还能执行其他操作吗?如果它只创建一个服务帐户,那么它的YAML
表示是什么?
我在这里添加我的答案是因为我偶然发现了相同的问题,并且接受了答案(以及上面的其他答案),但没有提供问题的完全解决方案-没有代码示例。它们只是我必须用来进行更深入研究的指导方针。有一些问题很容易被忽略,如果没有代码示例,很难得出正在发生的事情(尤其是在创建IAM角色时与Conditions/StringEquals相关的部分)
创建将与角色绑定的服务帐户的全部目的是从集群内创建aws资源的可能性(最常见的情况是负载均衡器,或将日志推送到cloudwatch的角色)。
所以,问题是我们如何做到这一点,使用地形,而不是使用eks命令。
我们需要做的是:
- 创建eks-oidc(可以用地形完成)
- 创建AWS IAM角色(可以使用terraform完成),创建并使用适当的策略
- 创建k8s服务帐户(需要使用kubectl命令或使用kubernetes资源的terraform来完成
- 用我们创建的IAM角色注释k8s服务帐户(意味着我们正在将k8s服务账户与IAM角色链接)
在此设置之后,我们的k8s服务帐户将具有k8s群集角色和k8s群集任务绑定(这将允许该服务帐户在k8s内执行操作),并且我们的k8s服务帐户将附加IAM角色,这将允许在群集外执行操作(如创建aws资源)
因此,让我们从它开始。下面的假设是,您的eks集群已经使用terraform创建,我们正在专注于创建工作服务帐户所需的资源和eks集群。
创建eks_oidc
### First we need to create tls certificate
data "tls_certificate" "eks-cluster-tls-certificate" {
url = aws_eks_cluster.eks-cluster.identity[0].oidc[0].issuer
}
# After that create oidc
resource "aws_iam_openid_connect_provider" "eks-cluster-oidc" {
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = [data.tls_certificate.eks-cluster-tls-certificate.certificates[0].sha1_fingerprint]
url = aws_eks_cluster.eks-cluster.identity[0].oidc[0].issuer
}
现在,让我们使用所有必要的策略创建AWS IAM角色
Terraform声明性代码如下所示:
- 创建ALIngressControllerIAMPolicy策略
- 创建alb入口控制器角色
- 将alb入口控制器IAMPolicyr策略附加到alb入口控制器角色
- 将已存在的AmazonEKS_CNI_Policy策略附加到角色
请注意,我在这里使用后缀作为alb入口控制器,因为这是我在集群中角色的主要用途。您可以更改角色的策略名称,也可以更改策略的权限访问权限,这取决于您计划对其执行的操作。
data "aws_caller_identity" "current" {}
locals {
account_id = data.aws_caller_identity.current.account_id
eks_oidc = replace(replace(aws_eks_cluster.eks-cluster.endpoint, "https://", ""), "/\..*$/", "")
}
# Policy which will allow us to create application load balancer from inside of cluster
resource "aws_iam_policy" "ALBIngressControllerIAMPolicy" {
name = "ALBIngressControllerIAMPolicy"
description = "Policy which will be used by role for service - for creating alb from within cluster by issuing declarative kube commands"
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Action = [
"elasticloadbalancing:ModifyListener",
"wafv2:AssociateWebACL",
"ec2:AuthorizeSecurityGroupIngress",
"ec2:DescribeInstances",
"wafv2:GetWebACLForResource",
"elasticloadbalancing:RegisterTargets",
"iam:ListServerCertificates",
"wafv2:GetWebACL",
"elasticloadbalancing:SetIpAddressType",
"elasticloadbalancing:DeleteLoadBalancer",
"elasticloadbalancing:SetWebAcl",
"ec2:DescribeInternetGateways",
"elasticloadbalancing:DescribeLoadBalancers",
"waf-regional:GetWebACLForResource",
"acm:GetCertificate",
"shield:DescribeSubscription",
"waf-regional:GetWebACL",
"elasticloadbalancing:CreateRule",
"ec2:DescribeAccountAttributes",
"elasticloadbalancing:AddListenerCertificates",
"elasticloadbalancing:ModifyTargetGroupAttributes",
"waf:GetWebACL",
"iam:GetServerCertificate",
"wafv2:DisassociateWebACL",
"shield:GetSubscriptionState",
"ec2:CreateTags",
"elasticloadbalancing:CreateTargetGroup",
"ec2:ModifyNetworkInterfaceAttribute",
"elasticloadbalancing:DeregisterTargets",
"elasticloadbalancing:DescribeLoadBalancerAttributes",
"ec2:RevokeSecurityGroupIngress",
"elasticloadbalancing:DescribeTargetGroupAttributes",
"shield:CreateProtection",
"acm:DescribeCertificate",
"elasticloadbalancing:ModifyRule",
"elasticloadbalancing:AddTags",
"elasticloadbalancing:DescribeRules",
"ec2:DescribeSubnets",
"elasticloadbalancing:ModifyLoadBalancerAttributes",
"waf-regional:AssociateWebACL",
"tag:GetResources",
"ec2:DescribeAddresses",
"ec2:DeleteTags",
"shield:DescribeProtection",
"shield:DeleteProtection",
"elasticloadbalancing:RemoveListenerCertificates",
"tag:TagResources",
"elasticloadbalancing:RemoveTags",
"elasticloadbalancing:CreateListener",
"elasticloadbalancing:DescribeListeners",
"ec2:DescribeNetworkInterfaces",
"ec2:CreateSecurityGroup",
"acm:ListCertificates",
"elasticloadbalancing:DescribeListenerCertificates",
"ec2:ModifyInstanceAttribute",
"elasticloadbalancing:DeleteRule",
"cognito-idp:DescribeUserPoolClient",
"ec2:DescribeInstanceStatus",
"elasticloadbalancing:DescribeSSLPolicies",
"elasticloadbalancing:CreateLoadBalancer",
"waf-regional:DisassociateWebACL",
"elasticloadbalancing:DescribeTags",
"ec2:DescribeTags",
"elasticloadbalancing:*",
"elasticloadbalancing:SetSubnets",
"elasticloadbalancing:DeleteTargetGroup",
"ec2:DescribeSecurityGroups",
"iam:CreateServiceLinkedRole",
"ec2:DescribeVpcs",
"ec2:DeleteSecurityGroup",
"elasticloadbalancing:DescribeTargetHealth",
"elasticloadbalancing:SetSecurityGroups",
"elasticloadbalancing:DescribeTargetGroups",
"shield:ListProtections",
"elasticloadbalancing:ModifyTargetGroup",
"elasticloadbalancing:DeleteListener"
],
Resource = "*"
}
]
})
}
# Create IAM role
resource "aws_iam_role" "alb-ingress-controller-role" {
name = "alb-ingress-controller"
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Federated": "${aws_iam_openid_connect_provider.eks-cluster-oidc.arn}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${replace(aws_iam_openid_connect_provider.eks-cluster-oidc.url, "https://", "")}:sub": "system:serviceaccount:kube-system:alb-ingress-controller",
"${replace(aws_iam_openid_connect_provider.eks-cluster-oidc.url, "https://", "")}:aud": "sts.amazonaws.com"
}
}
}
]
}
POLICY
depends_on = [aws_iam_openid_connect_provider.eks-cluster-oidc]
tags = {
"ServiceAccountName" = "alb-ingress-controller"
"ServiceAccountNameSpace" = "kube-system"
}
}
# Attach policies to IAM role
resource "aws_iam_role_policy_attachment" "alb-ingress-controller-role-ALBIngressControllerIAMPolicy" {
policy_arn = aws_iam_policy.ALBIngressControllerIAMPolicy.arn
role = aws_iam_role.alb-ingress-controller-role.name
depends_on = [aws_iam_role.alb-ingress-controller-role]
}
resource "aws_iam_role_policy_attachment" "alb-ingress-controller-role-AmazonEKS_CNI_Policy" {
role = aws_iam_role.alb-ingress-controller-role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
depends_on = [aws_iam_role.alb-ingress-controller-role]
}
在执行了上面的地形之后,您已经成功地创建了地形部分资源。现在我们需要创建一个k8s服务帐户,并将IAM角色与该服务帐户绑定。
创建集群角色、集群角色绑定和服务帐户
你可以使用
https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/master/docs/examples/rbac-role.yaml
直接(从master分支),但考虑到我们需要注释iam-arn,我倾向于下载这个文件,更新它,并将其存储在我的kubectl配置文件中。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/name: alb-ingress-controller
name: alb-ingress-controller
rules:
- apiGroups:
- ""
- extensions
resources:
- configmaps
- endpoints
- events
- ingresses
- ingresses/status
- services
- pods/status
verbs:
- create
- get
- list
- update
- watch
- patch
- apiGroups:
- ""
- extensions
resources:
- nodes
- pods
- secrets
- services
- namespaces
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/name: alb-ingress-controller
name: alb-ingress-controller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: alb-ingress-controller
subjects:
- kind: ServiceAccount
name: alb-ingress-controller
namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/name: alb-ingress-controller
name: alb-ingress-controller
namespace: kube-system
annotations:
eks.amazonaws.com/role-arn: <ARN OF YOUR ROLE HERE>
...
在该文件的底部,您将注意到需要放置ANR角色的注释。
双重检查
就是这样。之后你就有了一个与iam角色连接的k8s服务帐户。
检查方式:
kubectl get sa -n kube-system
kubectl describe sa alb-ingress-controller -n kube-system
您应该得到类似的输出(注释是最重要的部分,因为它确认了iam角色的附件):
Name: alb-ingress-controller
Namespace: kube-system
Labels: app.kubernetes.io/managed-by=Helm
app.kubernetes.io/name=alb-ingress-controller
Annotations: eks.amazonaws.com/role-arn: <YOUR ANR WILL BE HERE>
meta.helm.sh/release-name: testrelease
meta.helm.sh/release-namespace: default
Image pull secrets: <none>
Mountable secrets: alb-ingress-controller-token-l4pd8
Tokens: alb-ingress-controller-token-l4pd8
Events: <none>
从现在起,您可以使用此服务来管理您附加的策略允许的内部k8s资源和外部k8s资源。
在我的情况下,如前所述,我使用它(除其他外)创建alb入口控制器和负载均衡器,因此所有前缀都带有";alb进入";
首先,您应该在Terraform中定义IAM角色。
其次,您应该在Kubernetes中配置aws-auth-configmap,以将IAM角色映射到Kubernete用户或服务帐户。您可以使用Kubernetes提供程序在Terraform中实现这一点。
已经有一个Terraform模块Terraform aws-eks管理eks集群的各个方面。你可以从中得到一些想法。
在Vasili Angapov
的帮助下,现在我可以回答以下问题:
是的,它不仅仅是创建一个服务帐户。它做三件事:
- 创建IAM角色
- 它附加所需的iam策略(--attach policy arn<POLICY_ARN>)到创建的IAM角色
- 它创建了一个新的kubernetes服务帐户,用创建的IAM角色的arn进行注释
现在在terraform中使用kubernetes和aws提供程序可以很容易地声明上述步骤。
为此目的创建的角色如下所示:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<account-id>:oidc-provider/oidc.eks.<region>.amazonaws.com/id/<oidc-id>"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.<region>.amazonaws.com/id/<oidc-id>": "system:serviceaccount:<kube-serviceaccount-namespace>:<kube-serviceaccount-name>"
}
}
}
]
}
我强烈建议您使用iam_assumable_role_admin
地形模块为您创建此IAM角色。
- 文档
- 示例