kubernetes创建用户和ServiceAccount并设置RoleBinding
本文在 Kubernetes-Dashboard 一文基础上,深入学习了 Kubernetes 的RBAC 权限策略,然后在集群创建用户和ServiceAccount,设置Role 和 RoleBinding, 实现指定权限用户的授权。

update @2018/04/25
update @2018/12/21
简介
kubernetes中, 安全登录kubernetes-dashboard
有3种方式:
- 基本的
用户名/密码
方式: 被Kubernetes API默认禁用 - 使用kubeconfig文件: dashboard目录尚不支持
- 使用Token: 仅限
ServiceAccount
账户的token
综上,访问kubernetes-dashboard
目前我们能选的只有第三种方式。
在命令行下,我们还可以通过设置用户的context
文件对kubectl
操作进行授权。
因此,本文会结合两种方式,达到既可以访问dashboard,又可以在命令行操作的目的。
创建SA账户并添加Role绑定
- 生成
SA
文件
cat > developer-sa.yaml << EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: developer-sa
namespace: default
EOF
- 生成
Role
文件
cat > developer-role.yaml << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: developer-role
rules:
- apiGroups: ["", "extensions", "apps", "batch"]
resources: ["services", "deployments", "statefulsets", "replicasets", "replicationcontrollers", "pods", "pods/log", "configmaps", "jobs", "events", "persistentvolumeclaims", "secrets", "cronjobs", "daemonsets", "ingresses"]
#verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # You can also use ["*"]
verbs: ["get", "list", "watch"]
EOF
- 生成
RoleBinding
文件
cat > developer-rolebinding.yaml << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: developer-rolebinding
namespace: default
subjects:
- kind: ServiceAccount
name: developer-sa
namespace: default
roleRef:
kind: Role
name: developer-role
apiGroup: ""
EOF
- 使用
kubectl
创建相应资源
kubectl create -f developer-sa.yaml
kubectl create -f developer-role.yaml
kubectl create -f developer-rolebinding.yaml
- 获取
sa
的token
kubectl describe secret $(kubectl get secret | grep developer-sa | awk '{print $1}') | awk '$1=="token:"{print $2}'
复制这个token, 到dashboard登录就可以了:
但是, 我们不可能总是使用dashboard
来查看应用的状态和做相关的操作, 并且dashboard
并不支持应用的实时日志, 这一点就不能满足目前阶段测试的需求了(后面会上日志收集工具), 那么就需要使用到命令行下的操作。
且看下面↓
创建用户在命令行下的kubeconfig文件
命令行下只能通过设置用户context方式来授权,我们需要创建用户、私钥、证书请求文件,并使用Kubernetes
的CA文件给用户签发证书(certificate),然后通过kubectl
创建许可(credentials)和上下文(context), 最后通过Rolebinding
为用户绑定角色,实现授权访问。
-
新建用户及相应目录
useradd developer passwd developer mkdir -pv /home/developer/{.kube,.certs}
-
使用
openssl
生成证书对cd /home/developer/.certs/ # 本条视情况而定 kubectl create namespace default openssl genrsa -out developer.key 2048 openssl req -new -key developer.key -out developer.csr -subj "/CN=developer/OU=Development" openssl x509 -req -in developer.csr -CA /etc/kubernetes/ssl/ca.pem -CAkey /etc/kubernetes/ssl/ca-key.pem -CAcreateserial -out developer.crt -days 3660
-
使用
kubectl
创建用户的context
kubectl config set-credentials developer --client-certificate=./developer.crt --client-key=./developer.key kubectl config set-context developer-context --cluster=cluster.local --namespace=default --user=developer
此时使用新增的
context
是无法获取pods的, 因为没有绑定角色:kubectl --context=developer-context get pods
-
修改
rolebinding
yaml文件
在subjects
下面增加一个User
cat > developer-rolebinding.yaml << EOF apiVersion: rbac.authorization.k8s.io/v1a kind: RoleBinding metadata: name: developer-rolebinding namespace: default subjects: - kind: ServiceAccount name: developer-sa namespace: default - kind: User name: developer namespace: default roleRef: kind: Role name: developer-role apiGroup: "" EOF
-
重新应用一下配置
kubectl apply -f developer-rolebinding.yaml
-
使用指定context进行查询
kubectl --context=developer-context get pods
-
设置默认
context
kubectl config use-context developer-context
-
提取
kubeconfig
文件并放到用户developer
主目录下cp /root/.kune/config /home/developer/.kube chown -R developer.developer /home/developer
-
最后还原默认
context
kubectl config use-context admin-cluster.local
自动创建脚本
使用上面的步骤总是很不方便,我写了一个通用的脚本,传入username
、password
、namespace
,即可一键完成授权,目前授予的是只读权限,其它权限可自行增减,也可以在创建完成后按需添加。
从 Kubernetes 1.11 开始,kubespray 将默认的 context 名字由原来的 admin-cluster.local
改成了 [email protected]
, 这里添加了逻辑判断并实现了兼容。
脚本内容:
vim create_user_sa.sh
#!/bin/env bash
# Description:
# package chart
# @Date: 2018-02-27
# @Author: Tima Ops
# @Version:
#
# funtion
Usage() {
echo "Usage:"
echo " $0 [username] [password] [namespace] [project]"
echo " You must specify the user's username, password and the namespace he/she belongs to."
}
[[ -z "$1" ]] || [[ -z "$2" ]] || [[ -z "$3" ]] || [[ -z "$4" ]] && Usage && exit 1
USER_NAME="$1"
PASS_WORD="$2"
NAME_SPACE="$3"
PROJECT="$4"
CA_HOME="/etc/kubernetes/ssl"
USER_HOME="/home/${USER_NAME}"
ADMIN_CONTEXT="admin-cluster.local"
CA_FILE="ca.pem"
CA_KEY_FILE="ca-key.pem"
kubectl config get-contexts | grep "admin-cluster.local" 2>/dev/null 1>&2
if [[ $? != 0 ]]; then
ADMIN_CONTEXT="[email protected]"
CA_FILE="ca.crt"
CA_KEY_FILE="ca.key"
fi
export PATH=$PATH:/usr/local/bin/
kubectl config use-context ${ADMIN_CONTEXT}
# Create namespace
echo -ne "\n"
echo "[Info] Check if namespace ${NAME_SPACE} exsits."
COUNT=$(kubectl get namespace | grep -w "${NAME_SPACE}" | wc -l)
if [[ ${COUNT} = 1 ]]; then
echo "[Info] Namespace ${NAME_SPACE} exsits, will be used instead of created."
else
kubectl create namespace ${NAME_SPACE}
fi
# Create user
echo -ne "\n"
echo "[Info] Check if user ${USER_NAME} exsits."
id -u ${USER_NAME} > /dev/null 2>&1
if [[ $? = 0 ]]; then
echo "[Info] User ${USER_NAME} exsits."
else
echo "[Info] Creating user ${USER_NAME}"
useradd ${USER_NAME}
fi
# Set password
echo "[Info] Setting password now..."
echo -e "${PASS_WORD}\n${PASS_WORD}" | passwd ${USER_NAME}
[[ -d ${USER_HOME}/.kube ]] && rm -rf ${USER_HOME}/.kube
[[ -d ${USER_HOME}/.certs ]] && rm -rf ${USER_HOME}/.certs
mkdir -pv ${USER_HOME}/{.kube,.certs} > /dev/null 2>&1
# Generate user certs
echo -ne "\n"
echo "[Info] Generate user certs now..."
cd ${USER_HOME}/.certs
openssl genrsa -out ${USER_NAME}.key 2048
openssl req -new -key ${USER_NAME}.key -out ${USER_NAME}.csr -subj "/CN=${USER_NAME}/OU=${PROJECT}"
openssl x509 -req -in ${USER_NAME}.csr -CA ${CA_HOME}/${CA_FILE} -CAkey ${CA_HOME}/${CA_KEY_FILE} -CAcreateserial -out ${USER_NAME}.crt -days 3660
# Create user context
echo -ne "\n"
echo "[Info] Create user context now..."
kubectl config set-credentials ${USER_NAME} --client-certificate=./${USER_NAME}.crt --client-key=./${USER_NAME}.key
kubectl config set-context ${USER_NAME}-context --cluster=cluster.local --namespace=${NAME_SPACE} --user=${USER_NAME}
# Generate service account YAML
echo -ne "\n"
echo "[Info] Generate ServiceAccount for ${USER_NAME} in ${NAME_SPACE} now..."
cat > ${USER_NAME}-sa.yaml << EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: ${USER_NAME}-sa
namespace: ${NAME_SPACE}
EOF
# Generate role YAML
echo -ne "\n"
echo "[Info] Generate Role for ${USER_NAME} in ${NAME_SPACE} now..."
cat > ${USER_NAME}-role.yaml << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: ${USER_NAME}-role
namespace: ${NAME_SPACE}
rules:
- apiGroups: ["", "extensions", "apps", "batch"]
resources: ["services", "deployments", "statefulsets", "replicasets", "replicationcontrollers", "pods", "pods/log", "configmaps", "jobs", "events", "persistentvolumeclaims", "secrets", "cronjobs", "daemonsets", "ingresses"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # You can also use ["*"]
#verbs: ["get", "list", "watch"]
EOF
# Generate rolebinding YAML
echo -ne "\n"
echo "[Info] Generate RoleBinding for ${USER_NAME} in ${NAME_SPACE} now..."
cat > ${USER_NAME}-rolebinding.yaml << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ${USER_NAME}-rolebinding
namespace: ${NAME_SPACE}
subjects:
- kind: ServiceAccount
name: ${USER_NAME}-sa
namespace: ${NAME_SPACE}
- kind: User
name: ${USER_NAME}
namespace: ${NAME_SPACE}
roleRef:
kind: Role
name: ${USER_NAME}-role
apiGroup: ""
EOF
# Use kubectl to create resources
echo -ne "\n"
kubectl get sa ${USER_NAME}-sa --namespace ${NAME_SPACE} > /dev/null 2>&1
if [[ $? = 0 ]]; then
echo "[Info] ${USER_NAME}-sa exsits, will delete it and regenerate it."
kubectl delete sa ${USER_NAME}-sa --namespace ${NAME_SPACE}
fi
kubectl create -f ${USER_NAME}-sa.yaml
kubectl get role ${USER_NAME}-role --namespace ${NAME_SPACE} > /dev/null 2>&1
if [[ $? = 0 ]]; then
echo "[Info] ${USER_NAME}-role exsits, will delete it and regenerate it."
kubectl delete role ${USER_NAME}-role --namespace ${NAME_SPACE}
fi
kubectl create -f ${USER_NAME}-role.yaml
kubectl get rolebinding ${USER_NAME}-rolebinding --namespace ${NAME_SPACE} > /dev/null 2>&1
if [[ $? = 0 ]]; then
echo "[Info] ${USER_NAME}-rolebinding exsits, will delete it and regenerate it."
kubectl delete rolebinding ${USER_NAME}-rolebinding --namespace ${NAME_SPACE}
fi
kubectl create -f ${USER_NAME}-rolebinding.yaml
# Fetch user token
echo -ne "\n"
echo "[Info] The token of ${USER_NAME} is:"
kubectl describe secret --namespace ${NAME_SPACE} $(kubectl get secret --namespace ${NAME_SPACE} | grep ${USER_NAME}-sa | awk '{print $1}') | awk '$1=="token:"{print $2}'
echo -ne "\n"
echo "[Info] You can use the token above to login kubernetes-dashboard."
# Test user context
echo -ne "\n"
echo "[Info] Testing user context ${USER_NAME}-context"
kubectl --context=${USER_NAME}-context get pods > /dev/null 2>&1
if [[ $? != 0 ]]; then
echo "[Info] context tested failed, please check the certs and YAML files" && exit 1
else
echo "[Info] context tested successfully! Set it for user ${USER_NAME} now..."
kubectl config use-context ${USER_NAME}-context
cp /root/.kube/config ${USER_HOME}/.kube
chown -R ${USER_NAME}.${USER_NAME} ${USER_HOME}
echo -ne "\n"
echo "[Info] The context of ${USER_NAME} has been set successfully, you can use it like below:"
echo " su - ${USER_NAME}"
echo " kubectl get pods"
echo -ne "\n"
fi
# Reset context to admin
kubectl config use-context ${ADMIN_CONTEXT}