K3s 上的 RBAC(基于角色的访问控制)

RBAC (Role Based Access Control) on K3s

在 kubernetes 上观看了关于 RBAC(基于角色的访问控制)的视频后(this one 对我来说是最透明的),我按照这些步骤操作,但是在 k3s 上,而不是 k8s所有消息来源都暗示。据我所知(无法正常工作),问题不在于实际的角色绑定过程,而在于 API 服务

未确认的 x509 用户证书

$ kubectl get pods --kubeconfig userkubeconfig

error: You must be logged in to the server (Unauthorized)

Rancher's wiki on security for K3s (while documented for their k8s implementation)?, while described for rancher 2.x 本身也没有记录,不确定这是我的实现问题,还是 k3s <-> k8s 问题。

$ kubectl version --short
Client Version: v1.20.5+k3s1
Server Version: v1.20.5+k3s1


有重复的过程,我的步骤如下:

  1. 获取 k3s ca 证书

这被描述为在 /etc/kubernetes/pki (k8s) 下,但是根据 this 似乎在 /var/lib/rancher/k3s/server/tls/ (server-ca.crt & server-ca.key).

  1. 来自 ca 证书的生成用户证书
#generate user key
$ openssl genrsa -out user.key 2048

#generate signing request from ca
openssl req -new -key user.key -out user.csr -subj "/CN=user/O=rbac"

# generate user.crt from this
openssl x509 -req -in user.csr -CA server-ca.crt -CAkey server-ca.key -CAcreateserial -out user.crt -days 365

...一切都很好:

  1. 正在根据证书为用户创建 kubeConfig 文件:
# Take user.crt and base64 encode to get encoded crt
cat user.crt | base64 -w0

# Take user.key and base64 encode to get encoded key
cat user.key | base64 -w0
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: <server-ca.crt base64-encoded>
    server: https://<k3s masterIP>:6443
  name: home-pi4
contexts:
- context:
    cluster: home-pi4
    user: user
    namespace: rbac
  name: user-homepi4
current-context: user-homepi4
kind: Config
preferences: {}
users:
- name: user
  user:
    client-certificate-data: <user.crt base64-encoded>
    client-key-data: <user.key base64-encoded>
  1. 设置角色和角色绑定(在指定的命名空间内'rbac')
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: user-rbac
  namespace: rbac
rules:
- apiGroups:
  - "*"
  resources:
  - pods
  verbs:
  - get
  - list
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: user-rb
  namespace: rbac
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: user-rbac
subjects:
  apiGroup: rbac.authorization.k8s.io
  kind: User
  name: user 

经历了这一切之后,我获得了...

的快乐时光
$ kubectl get pods --kubeconfig userkubeconfig
error: You must be logged in to the server (Unauthorized)

有什么建议吗?

Apparently this presented a solution to the problem, but following the github feed, it came more-or-less down to the same approach followed here (unless I'm missing something)?

As we can find in the Kubernetes Certificate Signing Requests documentation:

A few steps are required in order to get a normal user to be able to authenticate and invoke an API.


I will create an example to illustrate how you can get a normal user who is able to authenticate and invoke an API (I will use the user john as an example).


First, create PKI private key and CSR:

# openssl genrsa -out john.key 2048

NOTE: CN is the name of the user and O is the group that this user will belong to

# openssl req -new -key john.key -out john.csr -subj "/CN=john/O=group1"

# ls
john.csr  john.key

Then create a CertificateSigningRequest and submit it to a Kubernetes Cluster via kubectl.

# cat <<EOF | kubectl apply -f -
> apiVersion: certificates.k8s.io/v1
> kind: CertificateSigningRequest
> metadata:
>   name: john
> spec:
>   groups:
>   - system:authenticated
>   request: $(cat john.csr | base64 | tr -d '\n')
>   signerName: kubernetes.io/kube-apiserver-client
>   usages:
>   - client auth
> EOF
certificatesigningrequest.certificates.k8s.io/john created


# kubectl get csr
NAME   AGE   SIGNERNAME                            REQUESTOR      CONDITION
john   39s   kubernetes.io/kube-apiserver-client   system:admin   Pending

# kubectl certificate approve john
certificatesigningrequest.certificates.k8s.io/john approved

# kubectl get csr
NAME   AGE   SIGNERNAME                            REQUESTOR      CONDITION
john   52s   kubernetes.io/kube-apiserver-client   system:admin   Approved,Issued

Export the issued certificate from the CertificateSigningRequest:

# kubectl get csr john -o jsonpath='{.status.certificate}'  | base64 -d > john.crt

# ls
john.crt  john.csr  john.key

With the certificate created, we can define the Role and RoleBinding for this user to access Kubernetes cluster resources. I will use the Role and RoleBinding similar to yours.

# cat role.yml 
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: john-role
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
  - list
  
# kubectl apply -f role.yml 
role.rbac.authorization.k8s.io/john-role created

# cat rolebinding.yml 
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: john-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: john-role
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: john
  
# kubectl apply -f rolebinding.yml 
rolebinding.rbac.authorization.k8s.io/john-binding created

The last step is to add this user into the kubeconfig file (see: Add to kubeconfig)

# kubectl config set-credentials john --client-key=john.key --client-certificate=john.crt --embed-certs=true
User "john" set.

# kubectl config set-context john --cluster=default --user=john
Context "john" created.

Finally, we can change the context to john and check if it works as expected.

# kubectl config use-context john
Switched to context "john".

# kubectl config current-context
john

# kubectl get pods
NAME   READY   STATUS    RESTARTS   AGE
web    1/1     Running   0          30m

# kubectl run web-2 --image=nginx
Error from server (Forbidden): pods is forbidden: User "john" cannot create resource "pods" in API group "" in the namespace "default"

As you can see, it works as expected (user john only has get and list permissions).

谢谢你matt_j的例子|回答了我的问题。将其标记为答案,因为它是通过 certificates 直接回答我关于 RBAC 的问题。除此之外,我还想通过 服务帐户 为 RBAC 提供一个示例,作为变体(对于那些喜欢特定用例的人)。

  1. 创建服务帐户

//kubectl create serviceaccount name -n namespace

$ kubectl create serviceaccount udef -n rbac

这会创建服务帐户 + 自动生成相应的密码 (udef-token-lhvm8)。查看 yaml 输出:

  1. 从创建的秘密中获取令牌:

// kubectl describe secret secretName -o yaml

$ kubectl describe secret udef-token-lhvm8 -o yaml

secret 将包含 3 个对象,(1) ca.crt (2) namespace (3) token

# ... other secret context

Data
====
ca.crt: x bytes
namespace: x bytes
token: xxxx token xxxx 
  1. 将令牌放入配置文件

可以先获取您的 'admin' 配置文件并输出到文件

// location of **k3s** kubeconfig
$ sudo cat /etc/rancher/k3s/k3s.yaml > /home/{userHomeFolder}/userKubeConfig

users 部分下,可以用 token 替换证书数据:

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: xxx root ca cert content xxx
    server: https://<host IP>:6443
  name: home-pi4
contexts:
- context:
    cluster: home-pi4
    user: nametype
    namespace: rbac
  name: user-homepi4
current-context: user-homepi4
kind: Config
preferences: {}
users:
- name: nametype
  user:
    token: xxxx token xxxx
  1. 可以根据需要创建角色和角色绑定清单,就像之前指定的那样(nb 在同一命名空间中),在这种情况下链接到服务帐户:
# role manifest
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: user-rbac
  namespace: rbac
rules:
- apiGroups:
  - "*"
  resources:
  - pods
  verbs:
  - get
  - list

---
# rolebinding manifest
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: user-rb
  namespace: rbac
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: user-rbac
subjects:
- kind: ServiceAccount
  name: udef
  namespace: rbac


完成此操作后,您将能够进行远程测试:

// show pods -> will be allowed

$ kubectl get pods --kubeconfig

..... valid response provided

// get namespaces (or other types of commands) -> should not be allowed

$ kubectl get namespaces --kubeconfig

Error from server (Forbidden): namespaces is forbidden: User bla-bla