KubernetesDocker&Kubernetes

k8s之user account

2020-08-24  本文已影响0人  分享放大价值

user account是在集群外部访问apiserver时使用的用户,比如kubectl命令就是作为kubernetes-admin用户来执行的,其中~/.kube/config指定了用户的证书,以便和apiserver互相认证。当然对于user account来说,是有多种认证方式的,参考官网,但是默认使能是x509客户端证书方式。

因为x509客户端证书认证采用双向认证,所以开始之前先通过此网址简单了解下https双向认证的原理和流程
一、Http
HyperText Transfer Protocol,超文本传输协议,是互联网上使用最广泛的一种协议,所有WWW文件必须遵循的标准。HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全。
使用TCP端口为:80

二、Https
Hyper Text Transfer Protocol over Secure Socket Layer,安全的超文本传输协议,网景公式设计了SSL(Secure Sockets Layer)协议用于对Http协议传输的数据进行加密,保证会话过程中的安全性。
使用TCP端口默认为443

三、SSL协议加密方式
SSL协议即用到了对称加密也用到了非对称加密(公钥加密),在建立传输链路时,SSL首先对对称加密的密钥使用公钥进行非对称加密,链路建立好之后,SSL对传输内容使用对称加密。

对称加密
速度高,可加密内容较大,用来加密会话过程中的消息

公钥加密
加密速度较慢,但能提供更好的身份认证技术,用来加密对称加密的密钥

四、双向认证
双向认证和单向认证原理基本差不多,只是除了客户端需要认证服务端以外,增加了服务端对客户端的认证,具体过程如下:


image.png

1、客户端向服务端发送SSL协议版本号、加密算法种类、随机数等信息。
2、服务端给客户端返回SSL协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书。
3、客户端使用服务端返回的信息验证服务器的合法性,包括:
(1)证书是否过期。
(2)发型服务器证书的CA是否可靠。
(3)返回的公钥是否能正确解开返回证书中的数字签名。
(4)服务器证书上的域名是否和服务器的实际域名相匹配。
(5)验证通过后,将继续进行通信,否则,终止通信。
4、服务端要求客户端发送客户端的证书,客户端会将自己的证书发送至服务端。
5、验证客户端的证书,通过验证后,会获得客户端的公钥。
6、客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择。
7、服务器端在客户端提供的加密方案中选择加密程度最高的加密方式。
8、将加密方案通过使用之前获取到的公钥进行加密,返回给客户端。
9、客户端收到服务端返回的加密方案密文后,使用自己的私钥进行解密,获取具体加密方式,而后,产生该加密方式的随机码,用作加密过程中的密钥,使用之前从服务端证书中获取到的公钥进行加密后,发送给服务端。
10、服务端收到客户端发送的消息后,使用自己的私钥进行解密,获取对称加密的密钥,在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全。

下面我们要生成一个新的用户,并通过新用户并访问apiserver。

生成客户端证书

//生成客户端私钥
root@master:~/client# openssl genrsa -out client.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
................................................................................................................+++++
.................................+++++
e is 65537 (0x010001)

//根据私钥生成csr,-subj 中/CN指定了用户名tester
root@master:~/client# openssl req -new -key client.key -out client.csr -subj "/CN=tester"

//根据csr和根证书/etc/kubernetes/pki/ca.crt生成客户端证书
root@master:~/client# openssl x509 -req -in client.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out client.crt -days 365
Signature ok
subject=CN = tester
Getting CA Private Key
//上面步骤生成了下面三个文件
root@master:~/client# ls
client.crt  client.csr  client.key

使用curl访问apiserver

这里验证使用curl命令携带客户端证书来访问apiserver,--insecure表示curl将跳过对server端证书的验证

root@master:~/client# curl --cert ./client.crt --key ./client.key --insecure -s $APISERVER/api
{
  "kind": "APIVersions",
  "versions": [
    "v1"
  ],
  "serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0",
      "serverAddress": "192.168.122.20:6443"
    }
  ]
}

使用客户端证书访问apiserver,--cacert指定了server端证书,以便curl可以验证server

root@master:~/client# curl --cert ./client.crt --key ./client.key --cacert /etc/kubernetes/pki/ca.crt -s $APISERVER/api
{
  "kind": "APIVersions",
  "versions": [
    "v1"
  ],
  "serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0",
      "serverAddress": "192.168.122.20:6443"
    }
  ]
}

上面使用client.crt证书访问apiserver时,首先经过了认证模块的认证,会被分配一个group system:authenticated,此group是系统自动创建的group,并且已经被默认关联到了下面的三个clusterrole,他们是有查看资源的权利,但是很受限,比如上面 访问/api是可以的

system:public-info-viewer
system:discovery
system:basic-user

下面尝试访问更多的资源,比如pod,就会报错,此请求被Forbidden,因为上面的三个clusterrole都没有访问pod的权利。

root@master:~/client# curl --cert ./client.crt --key ./client.key --cacert /etc/kubernetes/pki/ca.crt -s $APISERVER/api/v1/namespaces/test/pods
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {

  },
  "status": "Failure",
  "message": "pods is forbidden: User \"tester\" cannot list resource \"pods\" in API group \"\" in the namespace \"test\"",
  "reason": "Forbidden",
  "details": {
    "kind": "pods"
  },
  "code": 403
}

下面创建一个clusterrole,指定访问pod的权限后,将用户tester绑定到此clusterrole

//创建clusterrole,可以获取pod
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  namespace: test
  name: test-pod
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]
EOF
//查看刚创建的ClusterRole
root@master:~# kubectl describe ClusterRole test-pod
Name:         test-pod
Labels:       <none>
Annotations:  <none>
PolicyRule:
  Resources  Non-Resource URLs  Resource Names  Verbs
  ---------  -----------------  --------------  -----
  pods       []                 []              [get list]

将用户tester绑定到刚创建的ClusterRole,再次尝试获取pod可以成功。

root@master:~# kubectl create rolebinding test  -n test --clusterrole test-pod --user tester
rolebinding.rbac.authorization.k8s.io/test created

root@master:~/client# curl --cert ./client.crt --key ./client.key --cacert /etc/kubernetes/pki/ca.crt -s $APISERVER/api/v1/namespaces/test/pods
{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {
    "selfLink": "/api/v1/namespaces/test/pods",
    "resourceVersion": "14001793"
  },
  "items": [
    {
      "metadata": {
        "name": "test",
        "namespace": "test",
        "selfLink": "/api/v1/namespaces/test/pods/test",
        "uid": "9c478764-ba05-4d64-817b-81ac3e67c06c",
        "resourceVersion": "13943637",
        "creationTimestamp": "2020-08-23T15:20:10Z",
        "annotations": {
          "cni.projectcalico.org/podIP": "10.24.166.148/32",
          "cni.projectcalico.org/podIPs": "10.24.166.148/32",
          "k8s.v1.cni.cncf.io/network-status": "[{\n    \"name\": \"k8s-pod-network\",\n    \"ips\": [\n        \"10.24.166.148\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]",
          "k8s.v1.cni.cncf.io/networks-status": "[{\n    \"name\": \"k8s-pod-network\",\n    \"ips\": [\n        \"10.24.166.148\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]"
        }
      },
      "spec": {
  ...
  ...

配置kubeconfig,使用kubectl访问apiserver

平时我们执行kubectl命令时,它会先读取配置文件~/.kube/config(在k8s种,这种文件被称为kubeconfig),获取客户端证书后,再访问apiserver。
现在我们要把上面生成的client.crt证书配置到~/.kube/config,让kubectl执行命令时,使用我们的客户端证书。

kubeconfig文件格式如下,其中clusters指定了要访问的k8s集群,可以配置多个,users指定了user account,contexts指定了使用哪个user,访问哪个集群,current-context 表示使用哪个context。

apiVersion: v1
kind: Config

clusters:
- cluster:
  name: development

users:
- name: developer

contexts:
- context:
  name: dev-frontend
  user: test

current-context: ""

我们这里访问的是同一个集群,所以只需要修改user和context即可。使用下面三个命令进行设置,也可以直接修改配置文件。

//添加user tester,指定证书和key的位置
kubectl config --kubeconfig=/root/.kube/config set-credentials tester --client-certificate=/root/client/client.crt --client-key=/root/client/client.key
//创建一个context,指定访问的集群,用户和namespace。
//如果指定了namespace,则只能访问此namespace的资源
kubectl config --kubeconfig=/root/.kube/config set-context new_context --cluster=kubernetes --namespace=test --user=tester
//设置使用刚创建的context
kubectl config --kubeconfig=/root/.kube/config use-context new_context

在curl访问apiserver时已经将用户tester绑定到了ClusterRole test-pod,此ClusterRole只能访问test namespace下的pod,所以此时使用kubectl也只能访问test namespace下的pod。

root@master:~# kubectl describe rolebinding test -n test
Name:         test
Labels:       <none>
Annotations:  <none>
Role:
  Kind:  ClusterRole
  Name:  test-pod
Subjects:
  Kind  Name    Namespace
  ----  ----    ---------
  User  tester
root@master:~#
root@master:~#
root@master:~# kubectl describe ClusterRole test-pod
Name:         test-pod
Labels:       <none>
Annotations:  <none>
PolicyRule:
  Resources  Non-Resource URLs  Resource Names  Verbs
  ---------  -----------------  --------------  -----
  pods       []                 []              [get list]

kubectl可以获取 test namespace下的pod,并且不能获取kube-system下的pod

root@master:~/client# kubectl get pod -n test
NAME   READY   STATUS    RESTARTS   AGE
test   1/1     Running   0          7h31m
root@master:~/client# kubectl get pod -n kube-system
Error from server (Forbidden): pods is forbidden: User "tester" cannot list resource "pods" in API group "" in the namespace "kube-system"

验证完后,记得将context切换回默认的

kubectl config --kubeconfig=/root/.kube/config use-context kubernetes-admin@kubernetes

默认kubectl执行命令使用哪个用户呢?

在创建客户端证书时,需要在生成csr时会指定 -subj 的CN指定用户,说明证书中会保存用户的信息。在配置文件中~/.kube/config
client-certificate-data和client-key-data分别指定了客户端证书和私钥数据(经过base64加密),只要将client-certificate-data指向的数据base64解密后,就可以得知用户信息,操作如下:

//将client-certificate-data指向的数据复制到a.crt文件中
root@master:~/client# vim a.crt
//将a.crt中的数据解密
root@master:~/client# cat a.crt | base64 -d > b.crt
//通过openssl命令解析证书信息即可看到subject,O指定了用户组,CN指定了用户名
root@master:~/client# openssl x509 -in b.crt -text
Certificate:
    Data:
        ...
        Subject: O = system:masters, CN = kubernetes-admin
         ...

由上可知,该证书绑定的用户组是system:masters,用户名为kubernetes-admin。而集群中默认有个 ClusterRoleBinding 叫 cluster-admin,它将名为 cluster-admin 的 ClusterRole 和用户组 system:masters 进行了绑定,而名为 cluster-admin 的 ClusterRole 有集群范围的 Superadmin 权限,这也就理解了为什么默认的 Kubeconfig 能拥有极高的权限来操作 k8s 集群了。

root@master:~/client# kubectl describe ClusterRoleBinding cluster-admin
Name:         cluster-admin
Labels:       kubernetes.io/bootstrapping=rbac-defaults
Annotations:  rbac.authorization.kubernetes.io/autoupdate: true
Role:
  Kind:  ClusterRole
  Name:  cluster-admin
Subjects:
  Kind   Name            Namespace
  ----   ----            ---------
  Group  system:masters

root@master:~/client# kubectl describe ClusterRole cluster-admin
Name:         cluster-admin
Labels:       kubernetes.io/bootstrapping=rbac-defaults
Annotations:  rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
  Resources                       Non-Resource URLs  Resource Names  Verbs
  ---------                       -----------------  --------------  -----
  *.*                             []                 []              [*]
                                  [*]                []              [*]

参考

https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/
https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/
https://blog.csdn.net/qianghaohao/article/details/100012855

上一篇下一篇

猜你喜欢

热点阅读