kubernetes的认证和授权(RBAC)

1.认识k8s中的用户账号:生成证书

1.1 用户账号(UA UserAccount)

UA代表的是集群外部的实际用户,如开发人员、系统管理员等。 UA并不是 Kubernetes 原生的资源类型,通常是通过外部身份提供者(如 LDAP、OAuth、OIDC 等)来管理的。UA是为集群管理员和开发人员设计的,用于直接访问和操作集群资源。Kubernetes 不管理UA,而是依赖外部的认证机制。认证插件负责将外部用户的身份信息传递给 Kubernetes API Server。UA主要用于对 Kubernetes API Server 的访问控制。用于管理、监控和配置集群资源。
例如kubectl get pods -n kube-system,像这种命令还有go程序访问k8s都是访问某个api,这就是UA。

例如我们正在做一个普通的网站

  1. 首先会有不同的用户
  2. 登录时需要认证用户的账号
  3. 查看账号的权限—涉及到角色、权限、用户和角色绑定—RABC
  4. 再根据权限决定是否可以访问

我们在使用各种命令的时候并不是没有用户,而是之前就配置好了。
cat ~/.kube/config

admin拥有所有权限。

1.2 服务账号(SA ServiceAccount)

SA是 Kubernetes 原生的资源类型,主要用于在集群内运行的 Pod 之间的身份验证和授权。SA 是为自动化流程和应用程序设计的。SA 代表的是在集群内部运行的应用程序、Pod 等。每个命名空间默认创建一个 default SA。SA 由 Kubernetes 管理,并存储在 etcd 中。可以通过 YAML 文件创建和管理SA。

1.3 创建客户端证书

在k8s中,UserAccount也就是集群外部访问时使用的用户。最常见的就是kubectl命令就是作为kubernetes-admin用户来执行的,k8s本身不记录这些账号。
我们首先来学习默认的认证方式 :客户端证书

首先假设你装好了openssl(如果没有安装,请执行sudo apt install openssl

  1. 创建一个文件夹叫做 ua/horizon
  2. cd 到 ua/horizon 下
  3. 执行
    1. openssl genrsa -out client.key 2048生成客户端私钥。
    2. openssl req -new -key client.key -out client.csr -subj "/CN=horizon"根据私钥生成csr,/CN指定了用户名horizon。
    3. sudo openssl x509 -req -in client.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out client.crt -days 365根据k8s的CA证书生成我们用户的客户端证书

2.用户账号:使用证书初步请求api、设置上下文

如果你忘了证书这是的CN(Common name)是啥 可以用下面的命令搞定
openssl x509 -noout -subject -in client.crt

首先我们把client.crt加入到 ~/.kube/config,执行kubectl命令时切换成我们的用户(虽然现在还没设置权限)

kubectl config --kubeconfig=/home/horizon/.kube/config set-credentials horzion --client-certificate=/home/horizon/client.crt --client-key=/home/horizon/client.key

cat ~/.kube/config可以看到多了一组-name: horizon user: …

接下来我们要创建一个上下文。可以使用kubectl config current-context来查看当前的上下文。
使用以下两条命令设置新的上下文并使用。

kubectl config --kubeconfig=/home/horizon/.kube/config set-context user_context --cluster=kubernetes --user=horizon
kubectl config --kubeconfig=/home/horizon/.kube/config use-context user_context

此时,再次使用命令kubectl get pods -n kube-system发现已经没有权限了。

3.入门Role和RoleBinding、创建一个角色

3.1 RABC

RBAC(Role-Based Access Control,基于角色的访问控制)是 Kubernetes 中用于管理权限的机制。 RBAC 允许管理员通过定义角色和绑定,将特定的权限分配给用户、组或服务账号,从而控制谁可以对哪些资源执行哪些操作。

3.1.1 RBAC 组件

  1. Role:定义一组权限,仅在特定命名空间内有效。
  2. ClusterRole:定义一组权限,可以在集群范围内使用。
  3. RoleBinding:将一个 Role 绑定到一个用户或组,使其在特定命名空间内生效。
  4. ClusterRoleBinding:将一个 ClusterRole 绑定到一个用户或组,使其在整个集群范围内生效。

3.1.2 创建role

上一小节我们把horiozn这个用户(UA)加入到kubectl config中, 并且用了kubectl config use-context user_context来切换上下文。
切回管理员使用命令kubectl config use-context kubernetes-admin@kuberneres
我们可以使用kubectl get role --all-namespaces来查看所有命名空间下的role。

接下来我们要做的是让horizon这个用户账号能查看pod
我们创建一个一个文件mypod_role.yaml

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: mypod
rules:
- apiGroups: ["*"]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

关于apiversion:查文档Using RBAC Authorization
关于资源:可以用 kubectl api-resources -o wide 查看
例如 role 对应的操作如下:create、delete、deletecollection、get、list、patch、update、wath

接下来执行kubectl apply -f mypod_role.yaml
查看 kubectl get role -n default
删除role kubectl delete role mypod不加 -n 默认就是default

4.用户和角色进行绑定(RoleBinding)

上节中介绍到,Role可以包含很多权限,用于授予对单个命名空间的资源访问。RoleBinding,将一个 Role 绑定到一个用户或组,使其在特定命名空间内生效。
接下来我们进行绑定。

第一种方式:
执行命令,这个要在kubectl config use-context kubernetes-admin@kubernetes下执行,然后再切换回去测试。

kubectl create rolebinding mypodbinding -n default --role mypod --user horizon
kubectl get rolebinding 

kubectl config use-context user_context
测试
kubectl get pods -n default

第二种方式:
创建文件mypod_rolebinding.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  creationTimestamp: null
  name: mypodrolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: mypod
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: horizon

5.ClusterRole和RoleBinding

ClusterRole:管理多个namespace,就需要使用到clusterrole,绑定既可以使用RoleBinding,也可以使用ClusterRoleBinding(两者效果不同)

第一种:ClusterRole+RoleBinding
创建mypod-cluster.yaml

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: mypod-cluster
rules:
- apiGroups: ["*"]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

然后绑定,mypodrolebinding-cluster.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: mypodrolebinding-cluster
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: mypod-cluster
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: horzion
测试
kukectl config use-config user_context
kubectl get pods -n kube-system

6.ClusterRole和CluserRoleBinding

第二种:ClusterRole+ClusterRoleBinding
首先把之前的role和rolebinding都删除掉,

kubectl delete rolebinding mypodrolebinding-cluster -n kube-system
kubectl delete rolebinding mypodrolebinding
kubectl delete role mypod

创建 mypod-clusterrolebinding.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: mypod-clusterrolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: mypod-cluster
subjects:
 - apiGroup: rbac.authorization.k8s.io
   kind: User
   name: horizon
测试
首先切换上下文
kukectl config use-config user_context
kubectl get pods -n kube-system

7.配置使用token的方式请求API(UserAccount)

之前我们介绍了用证书访问api,接下来我们使用token的方式。
首先测试一下:curl https://192.168.22.142:6443,这是不可以访问的。
接下来我们我们设置一个token(使用上节的普通用户horizon)

head -c 16 /dev/urandom | od -An -t x | tr -d ' '
kubectl config set-credentials horzion --token=456sd53sdf1e976d7f78ac7fcxgf9adc

测试:cat ~/.kube/config,发现-name: horzion下面多了一个token

找一个获取pod的api试一试

curl -H "Authorization: Bearer 456sd53sdf1e976d7f78ac7fcxgf9adc" https://192.168.22.142:6443/api/v1/namespaces/default/pods --insecure
curl --cert ./client.crt --key ./client.key --cacert /etc/kubernetes/pki/ca.crt -s https://192.168.22.142:6443/api/v1/namespaces/default/pods

测试一下:还是不行的,若是使用kubeadm配置的集群,没有加载我们的token file,只能支持证书验证的方式,需要去修改一下api server启动的参数

首先创建
sudo vi /etc/kubernetes/pki/token_auth 
加入一下内容
456sd53sdf1e976d7f78ac7fcxgf9adc,horzion,1001
然后是修改api-server启动参数
sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
加入
--token-auth-file=/etc/kubernetes/pki/token_auth

设置完之后再次进行测试

curl -H "Authorization: Bearer 456sd53sdf1e976d7f78ac7fcxgf9adc" https://192.168.22.142:6443/api/v1/namespaces/default/pods --insecure

8.ServiceAccount(1):创建账号

image.png
查看ServiceAccount:kubectl get sa 等于 kubectl get sa -n defaultkubectl get sa --all-namespaces
创建:kubectl create serviceaccount mysa
使用kubectl describe sa mysa查看,发现各个参数都为空,这是因为:

在 Kubernetes 1.24 版本之后,ServiceAccount 令牌控制器的行为发生了变化,默认情况下不会自动为每个 ServiceAccount 创建秘密令牌(Secrets)。相反,你需要显式地请求或引用一个投影的令牌。

  1. 创建 ServiceAccount

mysa:

kubectl create serviceaccount mysa
2. 创建一个包含投影令牌的 Secret:
创建一个 YAML 文件,例如 mysa-token.yaml,以请求投影令牌:

apiVersion: v1
kind: Secret
metadata:
  name: mysa-token
  annotations:
    kubernetes.io/service-account.name: mysa
type: kubernetes.io/service-account-token

应用此配置:kubectl apply -f mysa-token.yaml
3. 查看 Secret:kubectl get secret mysa-token -o yaml
4. 在 Pod 中使用投影令牌:然后apply pod

首先kubectl delete sa mysa

kubectl create serviceaccount mysa -o yaml --dry-run=client
或者
kubectl create serviceaccount mysa -o yaml --dry-run=client > mysa.yaml
cat mysa.yaml

image.png

kubtctl appy -f mysa.yaml
kubectl describe sa mysa

image.png

注意这里还是没有Tokens,需要手动映射,下面再介绍

9.ServiceAccount(2):赋予权限、外部访问API

接下来做的实验:外部请求依然用ServiceAccount

首先装个软件jq:是一个json处理命令,可以对json数据进行分片、过滤、映射和转换jq。对数据进行格式化输出.sudo apt install jq
绑定角色:之前我们创建了一个clusterrole叫做mypod-cluster,此权限可以查看pods列表

kubectl create clusterrolebinding mysa-crb --clusterrole=mypod-cluster --serviceaccount=default:mysa
kubectl get clusterrolebinding


接下来,如何对api server进行请求,这里暂时使用外部,

kubectl get sa mysa
kubectl get sa mysa -o json

image.png

这里发现根本没有secrets,需自己手动映射,根据上节。
发现get sa mysa -o json中还是没有secret,但是没关系,创建好的secret中已将包含sa的映射,在使用此sa访问api是只需指定此secret中的token即可。

kubectl get sa mysa -o json | jq '.secrets[0].name'
kubectl get sa  mysa -o json | jq -Mr '.secrets[0].name'

假设得到的值是mysa-token-6tggr
kubectl get secret mysa-token-6tggr
kubectl get secret mysa-token-6tggr -o json | jq -Mr '.data.token'
kubectl get secret mysa-token-6tggr -o json | jq -Mr '.data.token' | base64 -d

连接起来

kubectl get secret  $(kubectl get sa  mysa -o json | jq -Mr '.secrets[0].name'
) -o json | jq -Mr '.data.token' | base64 -d

mysatoken=$(kubectl get secret  $(kubectl get sa  mysa -o json | jq -Mr '.secrets[0].name'
) -o json | jq -Mr '.data.token' | base64 -d)

在我的集群中应该这样写
mysatoken=$(kubectl get secret mysa-token -o json | jq -Mr '.data.token' | base64 -d)
测试
curl -H "Authorization: Bearer $mysatoken" --insecure  https://192.168.22.142:6443/api/v1/namespaces/default/pods 

10.ServiceAccount(3):在Pod里访问k8sAPI(token的方式)

创建一个pod
myngx.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myngx
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      serviceAccountName: mysa # 注意这里一定要指明
      containers:
        - name: nginxtest
          image: nginx:1.18-alpine
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
kubectl apply -f myngx.yaml

进入该容器
kubectl exec -it myngx-575cf56d8-nb4sz -- sh
在容器中执行
echo $KUBERNETES_SERVICE_HOST   
echo $KUBERNETES_PORT_443_TCP_PORT
于是
echo $KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT

临时设置的环境变量,退出容器后就没有了,需要重新设置
TOKEN=`cat /var/run/secrets/kubernetes.io/serviceaccount/token`
APISERVER="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT"

测试

curl --header "Authorization: Bearer $TOKEN" --insecure -s $APISERVER/api
curl --header "Authorization: Bearer $TOKEN" --insecure -s $APISERVER/api/v1/namespaces/default/pods 

这里两个都可以,因为我们已经把myngx.yaml中加入了serviceAccountName: mysa,已经有了权限。

11.ServiceAccount(4):在Pod里访问k8sAPI(token+证书的方式)

更常用的方式是直接使用证书
cd到存放证书的位置,进入容器后执行,cd /var/run/secrets/kubernetes.io/serviceaccount
执行

注意两个临时环境变量要重新设置

TOKEN=`cat /var/run/secrets/kubernetes.io/serviceaccount/token`
APISERVER="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT"
测试
curl --header "Authorization: Bearer $TOKEN" --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt $APISERVER/api/v1/namespaces/default/pods 

image.png

12.写在最后

当然,以上只是k8s中最基础的认证与授权功能,更高阶的也都在此基础之上,如果大家有兴趣请自行探索。如果大家觉得有用,欢迎大家点赞、收藏、关注我,有什么问题可以在评论区讨论或者私信我。在码字的过程中难免会出错,欢迎大家批评指正。我会长期分享K8s、CloudNative方面的知识。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值