Kubernetes检查ServiceAccount权限

70

在使用 Helm Chart 部署服务时,安装失败,因为 tiller serviceaccount 没有权限创建 ServiceMonitor 资源。

注意:

  • ServiceMonitor 是 Prometheus Operator 定义的 CRD,用于自动获取 Pod 中运行容器的指标。
  • Helm Tiller 在单个命名空间中安装,RBAC 已经使用 Role 和 RoleBinding 进行设置。

我想验证 tiller serviceaccount 的权限。
kubectlauth can-i 命令,像以下查询一样,总是返回 no

  • kubectl auth can-i list deployment --as=tiller
  • kubectl auth can-i list deployment --as=staging:tiller

如何正确检查 serviceaccount 的权限?
如何使 tiller 账户能够创建 ServiceMonitor 资源?

4个回答

120

经过尝试和在整个宇宙中搜索,我最终找到了这篇关于使用RBAC和PSP保护您的集群的博客文章,其中给出了一个示例,可以检查服务账户的访问权限。

正确的命令是:
kubectl auth can-i <verb> <resource> --as=system:serviceaccount:<namespace>:<serviceaccountname> [-n <namespace>]

检查tiller账户是否有创建ServiceMonitor对象的权限:
kubectl auth can-i create servicemonitor --as=system:serviceaccount:staging:tiller -n staging

注意:为了解决我的tiller账户问题,我不得不在monitoring.coreos.com apiGroup中添加servicemonitors资源的权限。更改后,上述命令最终返回了yes,我们的Helm Chart安装成功了。

更新的tiller-manager角色:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: tiller-manager
  labels:
    org: ipos
    app: tiller
  annotations:
    description: "Role to give Tiller appropriate access in namespace"
    ref: "https://docs.helm.sh/using_helm/#example-deploy-tiller-in-a-namespace-restricted-to-deploying-resources-only-in-that-namespace"
rules:
- apiGroups: ["", "batch", "extensions", "apps"]
  resources: ["*"]
  verbs: ["*"]
- apiGroups:
    - monitoring.coreos.com
  resources:
    - servicemonitors
  verbs:
    - '*'

7
"kubectl auth can-i" 是一条非常有用的命令,可以帮助解决这类问题。谢谢。 - Ivan Aracki
使用 kubectl auth can-i 的一个常见错误是忘记为 rolebinding 添加 -n <namespace>,因为 rolebinding 只在命名空间中授予权限。 - B.Z.
1
"--list"也可以用来显示给定帐户的所有权限,例如:kubectl auth can-i --as=system:serviceaccount:default:default --list - arve0

16

这将显示您在服务帐户prom-stack-grafana上拥有的权限:

例如:

kubectl -n monitoring auth can-i --list --as=system:serviceaccount:monitoring:prom-stack-grafana


8
注意:kubectl auth can-i 命令有一个需要避免的边缘情况/坑/错误,值得注意。
基本上,用户的命名方式可以与服务帐户的语法类似,并且它可以欺骗它。
这曾经让我陷入困境很长一段时间,所以我想分享一下。
alias k=kubectl
k create ns dev 
k create role devr --resource=pods --verb=get -n=dev 
k create rolebinding devrb --role=devr --user=system:serviceaccount:dev:default -n=dev # wrong syntax 
k auth can-i get pods -n=dev --as=system:serviceaccount:dev:default  # right syntax
# yes 

事实上,k auth can-i 命令的肯定回答使我认为我的角色绑定语法是正确的,但实际上是错误的。

以下内容是正确的:

k delete ns dev
k create ns dev 
k create role devr --resource=pods --verb=get -n=dev 
k create rolebinding devrb --role=devr --serviceaccount=dev:default -n=dev # right syntax 
k auth can-i get pods -n=dev --as=system:serviceaccount:dev:default  # right syntax
# yes

这里有可视化证据表明它是错误的:
k create rolebinding devrb1 --role=devr --user=system:serviceaccount:dev:default -n=dev --dry-run=client -o yaml | grep subjects -A 4
# subjects:
# - apiGroup: rbac.authorization.k8s.io
#   kind: User
#   name: system:serviceaccount:dev:default

k create rolebinding devrb2 --role=devr --serviceaccount=dev:default -n=dev --dry-run=client -o yaml | grep subjects -A 4
# subjects:
# - kind: ServiceAccount
#   name: default
#   namespace: dev

如果对RBAC命令的语法有任何疑问,这里是一个快速查找参考的方法:

  1. kubernetes.io/docs
  2. 搜索“rbac”
  3. 在页面上使用“控制+f”来查找“kubectl create rolebinding”,以获取正确语法的示例。

0

如果你想进行实时测试,请使用你的serviceAccount秘钥创建kube配置。我已经创建了上面的脚本来自动完成这个过程:

#!/usr/bin/env bash

set -euo pipefail

function generate_sa() {
  local sa
  local namespace
  local context
  local target_namespace
  local output_file
  local "${@}"
  sa=${sa:?set sa}
  namespace=${namespace:?set namespace of the service account}
  context=${context:?set context}
  target_namespace=${target_namespace:? set target context namespace}
  output_file=${output_file:-/tmp/kube.conf}

  cluster=$(kubectl config view -o yaml | yq '.contexts.[] | select ( .name == "'"${context}"'") | .context.cluster')
  if [ -z "${cluster}" ]; then
    echo "We didn't find the cluster from context ${context}"
    exit 1
  fi

  server=$(kubectl config view -o yaml | yq '.clusters.[] | select ( .name == "'"${cluster}"'") | .cluster.server')

  secret=$(kubectl get sa "${sa}" -o jsonpath='{.secrets[0].name}' -n "${namespace}")
  ca=$(kubectl get secret/"${secret}" -o jsonpath='{.data.ca\.crt}' -n "${namespace}")
  token=$(kubectl get secret/"${secret}" -o jsonpath='{.data.token}' -n "${namespace}" | base64 --decode)

  cat <<EOF > "${output_file}"
---
apiVersion: v1
kind: Config
clusters:
- name: ${cluster}
  cluster:
    certificate-authority-data: ${ca}
    server: ${server}
contexts:
- name: ${cluster}
  context:
    cluster: ${cluster}
    namespace: ${target_namespace}
    user: system:serviceaccount:${namespace}:${sa}
current-context: ${cluster}
users:
- name: system:serviceaccount:${namespace}:${sa}
  user:
    token: ${token}
EOF

echo >&2 "Now run: export KUBECONFIG=${output_file}"
}

generate_sa "${@}"

然后执行它,它将创建一个kubeconfig文件。

generate_sa_config.sh \
  sa=service-account-name \
  namespace=namespace-of-service-account \
  context=kubernetes-cluster-context-name \
  target_namespace=namespace-of-context

不要忘记导出 KUBECONFIG 环境变量。现在你就像真正的 ServiceAccount 一样,可以玩转角色了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接