例如,假设你在亚马逊云科技上托管 Kubernetes 集群,并希望将文件从集群上传到 S3 存储桶。
请注意,这同样适用于Microsoft Azure和Google Cloud Platform。
你可能需要分配角色才能执行此操作,但 AWS IAM 角色不能分配给 Pod,你只能将它们分配给计算实例(即 AWS 不知道 Pod 是什么)。
自 2019 年底以来,AWS 在 Kubernetes 和 IAM 之间提供了一种名为 IAM 服务账户角色 (IRSA) 的原生集成,它利用了联合身份和预计的服务账户令牌。
这是它的工作原理。
你创建一个 IAM 策略,用于描述你有权访问的资源(例如,你可以将文件上传到远程存储桶)。你可以使用该策略创建角色并记下其 ARN。创建投影服务帐户令牌并将其装载为文件。
你将角色 ARN 和预计的服务帐户令牌添加为 Pod 中的变量:
pod-s3.yaml
apiVersion: apps/v1
kind: Pod
metadata:
name: myapp
spec:
serviceAccountName: my-serviceaccount
containers:
- name: myapp
image: myapp:1.2
env:
- name: AWS_ROLE_ARN
value: arn:aws:iam::111122223333:policy/my-role
- name: AWS_WEB_IDENTITY_TOKEN_FILE
value: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
volumeMounts:
- mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount
name: aws-iam-token
readOnly: true
volumes:
- name: aws-iam-token
projected:
defaultMode: 420
sources:
- serviceAccountToken:
audience: sts.amazonaws.com
expirationSeconds: 86400
path: token
如果你的应用程序使用 AWS 开发工具包上传到 S3,这足以使其正常工作。
应用程序将使用这两个环境变量作为连接到 S3 的令牌。
但是怎么做呢?
Kubernetes,而不是AWS,生成了挂载在Pod中的令牌。
AWS IAM 如何知道此令牌有效?
AWS 开发工具包使用角色 ARN 和预计的服务账户令牌,并将它们交换为标准 AWS 访问密钥和私有密钥。
如果你不使用 AWS 开发工具包或想知道会发生什么,让我解释一下。
该应用程序向 AWS IAM 发出请求,以代入当前身份的角色。
当 IAM 收到令牌时,它会通过解压缩并检查 iss 字段来验证 JWT 令牌是否合法。
此字段通常配置为指向用于创建令牌的公共签名密钥。
如果你还记得,URL指向Kubernetes集群:
nginx-token.json
{
"aud": [
"https://kubernetes.default.svc.cluster.local"
],
"exp": 1686617744,
"iat": 1655081744,
"iss": "https://kubernetes.default.svc.cluster.local",
// truncated
请注意,你应该将颁发者 URL 自定义为完全限定的域名;否则,AWS IAM 将无法访问该终端节点。你可以使用 --service-account-issuer 标志执行此操作。
颁发者 URL 是标准的 OIDC 提供程序,AWS IAM 将查找两个特定路径:
请注意,默认情况下,公开的两个终结点是公开的,群集管理员的工作是设置它们。
让我们检查一下 JWKS(JSON Web 密钥集)端点:
curl {Issuer URL}/openid/v1/jwks
"keys": [
{
"use": "sig",
"kty": "RSA",
"kid": "ZO4TUgVjBzMWKVP8mmBwKLvsuyn8z-gfqUp27q9lO4w",
"alg": "RS256",
"n": "34a81xuMe…",
"e": "AQAB"
}
]
}
AWS IAM 检索公有密钥并验证令牌。
验证代码类似于以下内容:
验证-JWT.js
var jwt = require('jsonwebtoken')
var jwkToPem = require('jwk-to-pem')
var pem = jwkToPem(jwk /* "kid" value from the jkws file */)
jwt.verify(token /* this is the token to verify */, pem, { algorithms: ['RS256'] }, function(err, decodedToken) {
// rest of the code
})
如果令牌有效,它将生成具有当前角色权限的访问令牌(例如,将文件上传到 S3 存储桶),如下所示:
sts-response.json
{
"Credentials": {
"AccessKeyId": "ASIAWY4CVPOBS4OIBWNL",
"SecretAccessKey": "02n52u8Smc76…",
"SessionToken": "IQoJb3JpZ…",
"Expiration": "2022-06-13T10:50:25+00:00"
},
"SubjectFromWebIdentityToken": "system:serviceaccount:default:test",
"AssumedRoleUser": {
"AssumedRoleId": "AROAWY4CVPOBXUSBA5C2B:test",
"Arn": "arn:aws:sts::[aws account id]:assumed-role/oidc/test"
},
"Provider": "arn:aws:iam::[aws account id]:oidc-provider/[bucket name].s3.amazonaws.com",
"Audience": "test"
}
从此时开始,你可以使用凭证访问 S3 存储桶。
下面记录了整个过程,有关如何手动创建集成的完整教程可在此处获得。
总结:对于外部用户应该使用哪个身份验证插件?
Kubernetes 有以下插件用于验证用户身份:
你应该使用哪一个?
在上一节中,我们讨论了静态令牌如何具有一些限制:
你需要提前知道所有用户的名称。编辑 CSV 文件需要重新启动 API 服务器。令牌不会过期。
静态令牌不是生产环境的最佳选择。
稍微好一点的选择是使用 X.509 客户端证书。
使用 X.509 客户端证书:
配置为指向带有 的证书颁发机构 (CA) 文件。kube-apiserver--client-ca-file=FILE管理员向外部用户颁发客户端证书。这些 X.509 客户端证书是独立的,包括用户名和组。用户使用 TLS 字段中的客户端证书与 API 服务器进行标识。根据根 CA 验证客户端证书。然后,它继续提取用户名和组。kube-apiserver
工作流类似于静态令牌,但存在一些关键差异:
但是,X.509 客户端证书通常不是一个好主意,应不鼓励使用。
X.509 客户端证书通常具有较长的生存期(即数年)。CA 基础设施提供了一种吊销证书的方法,但 Kubernetes 不支持检查吊销。由于客户端证书是独立的,因此很难将组与 RBAC 一起使用。要使客户端进行身份验证,它必须与 API 服务器建立点对点连接。这意味着你的 API 服务器前面没有反向代理或 Web 应用程序防火墙。
对于任何其他身份验证机制(暂时不可用)的紧急情况,证书是一个很好的解决方案。
作为最后的手段,你可以使用 X.509 证书访问群集。
Kubeadm 和 OpenShift 默认这样做,在 API 主服务器上设置证书,以便 kubectl 可以在本地使用。
除此之外,最好使用 OIDC 作为身份验证机制。
如果你已经拥有管理用户的 OpenID Connect 基础设施,那么 Open ID Connect 特别有用——在这种情况下,你可以像管理组织中的所有其他用户一样继续管理 Kubernetes 用户。
Open ID Connect 提供商颁发 JSON Web Token (JWT)。
这意味着它们可以自主验证,而无需联系令牌的发行者,并且它们也会过期。
最后两个身份验证插件是:
身份验证代理。网络钩子。
身份验证代理身份验证插件允许用户通过外部身份验证代理透明地向 Kubernetes 进行身份验证。
当用户向 Kubernetes 集群发出请求时,该请求首先被身份验证代理拦截。
如果你已经在组织中使用了身份验证代理,或者想要实现任何其他身份验证插件不支持的自定义身份验证方法,则此身份验证插件非常有用 - 这是因为身份验证代理可以实现你喜欢的任何身份验证方法。
最后,Webhook Tokens 身份验证插件允许用户使用由外部自定义身份验证服务验证的 HTTP 持有者令牌向 Kubernetes 进行身份验证。
如果要实现任何其他身份验证插件未提供的自定义身份验证方法,Webhook 令牌身份验证插件非常有用。