系列文章目录


前言

一个k8s集群每个node节点上都有 kubelet服务、kube-proxy容器、calico容器,主节点上有 kube-apiserver、kube-proxy、kube-controller-manager、kube-scheduler,这四个被称为静态Pod,其次,主节点上还有 kube-dns/coredns 域名解析 和 etcd 配置中心。

本文讲解 kube-apiserver,直译为网关,所有的发送给 k8s 集群的请求会从 kube-apiserver 经过,类似写 spring 服务端程序的拦截器。对于 kube-apiserver 静态Pod,与工程开发相关,有四个方面需要学习:所有的kubectl底层都是http请求、rbac 权限机制、audit 审计日志。

本文介绍两点:
第一,kubectl底层都是https请求,三种访问方式:匿名访问、bearer Token访问、x509客户端证书访问;
第二,k8s打开外网,然后集群外通过 x509客户端证书 连接上。

API Server的验证环节支持多种身份校验方式:CA 证书认证、Token 认证、Base 认证

一、所有的kubectl底层都是https请求

1.1 所有的kubectl底层都是https请求

对于k8s集群而言,kubectl、kubelet、kubeadm是版本是一致的,kubectl是操作命令,kubeadm是安装工具(安装kubeadm init,重置kubeadm reset),kubelet是linux服务(systemctl status kubelet查看)。

kubectl作为命令操作工具,其实每一条kubectl命令底层本质都是restful风格的https请求。

注意:所有对于k8s的都是https请求,没有http请求。

以 kubectl get ns 为例,如下:

在这里插入图片描述

使用Postman发送请求也可以使用相同的效果,如下:

先查询到对应的 url,如下

在这里插入图片描述

然后使用Postman发送请求,如下:

GET /api/v1/namespaces

在这里插入图片描述
在这里插入图片描述

现在就验证了,所有的kubectl底层都是https请求,对于k8s api而言,这里提供三个官方链接,可方便日常使用,如下:

restful接口:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/
kubectl命令:https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#patch
swagger:https://raw.githubusercontent.com/kubernetes/kubernetes/master/api/openapi-spec/swagger.json

1.2 从集群外使用https访问k8s集群(打开匿名权限)

在提供https访问的时候,常见的问题是:User “system:anonymous” cannot list resource “configmaps”

https://192.168.100.155:6443/api/v1/namespaces

在这里插入图片描述
因为是Get请求,在chrome浏览器中也可以尝试,如下:
在这里插入图片描述

最简单的解决方式是去掉鉴权,主节点上执行:kubectl create clusterrolebinding test:anonymous --clusterrole=cluster-admin --user=system:anonymous

然后,Postman这边关闭SSL,就可以发送成功了。

在这里插入图片描述

1.3 从集群外使用https访问k8s集群(使用bearer token)

第二种方法,手动新建一个sa账号,给这个sa账号binding足够的role权限,然后这个sa账号一定会以secret的方式保存,取出secret中的三个属性(cr.crt namespace token)中的token属性(base64解密之后的),然后放到postman中作为header请求头中的Authorizaion中的bearer,带密钥发送https请求,如下:

步骤1:先获得token
步骤2:使用token访问

步骤1:先获得token

1.创建一个k8s-admin.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: dashboard-admin
  namespace: kube-system
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: dashboard-admin
subjects:
  - kind: ServiceAccount
    name: dashboard-admin
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

在RBAC权限中,能够与 role/clusterrole 绑定的只有三种资源,分别是:kind: User、kind: Group、kind: ServiceAccount ,所以,这里ServiceAccount绑定ClusterRole,很正常
注意:从来没有一种 kind: UserAcccount 的资源

2.应用k8s-admin.yaml配置

kubectl apply -f k8s-admin.yaml

3.获取admin-token名字

kubectl get secret -n kube-system|grep admin

4.Describe查询token内容

kubectl describe secret dashboard-admin-token-slc8x -n kube-system

在这里插入图片描述

步骤2:使用token访问

在这里插入图片描述
在这里插入图片描述
请求头上增加 bearer 具体token

在这里插入图片描述

篇外知识:无论是默认的名为default的serviceAccount,还是kubectl命令新建的serviceAccount,创建出来之后,都会带有一个secret,这secret里面存放数据data包含三个东西,加密的namespace、加密的token、加密的ca.crt,如下:

在这里插入图片描述

在这里插入图片描述

1.4 从集群外使用https访问k8s集群(三个证书)

步骤1:关闭匿名权限

开始,去掉匿名权限,尝试让Postman使用三个证书访问k8s集群

在这里插入图片描述

先在master节点上使用curl测试,成功之后再到 Postman 上测试。

步骤2:在master节点上使用curl测试

先不使用三个证书,curl https://127.0.0.1:6443/api/v1/namespaces,一定会报错,如下:

在这里插入图片描述

这个报错信息是 https 请求缺乏SSL证书,要解决这个错误,要么加上证书,要么加上 -k 或者 --insecure,要么直接curl http,发送http请求,但是这种k8s内部接口,服务端只能处理 https 请求,会报错 send http request to https server.

然后加上三个证书,curl --cert /etc/kubernetes/pki/client.crt --key /etc/kubernetes/pki/client.key --cacert /etc/kubernetes/pki/ca.crt https://127.0.0.1:6443/api/v1/namespaces

还是错误,但是错误日志发生了改变
在这里插入图片描述

最后发现,使用 127.0.0.1:6443 错误,但是,使用 192.168.100.155:6443 正确,因为三个证书是通过ip为 192.168.100.155 生成的。

curl --cert /etc/kubernetes/pki/client.crt --key /etc/kubernetes/pki/client.key --cacert /etc/kubernetes/pki/ca.crt https://192.168.100.155:6443/api/v1/namespaces

成功了。

另外,如果只使用 curl https://192.168.100.155:6443/api/v1/namespaces 也是会出现缺少 – cacert 证书的错误,如下:

在这里插入图片描述

小结:需要三个证书,而且对应的IP正确。

特别注意1:curl命令中,三个证书一定要使用绝对路径,一定不能使用相对路径
正确:curl --cert /etc/kubernetes/pki/client.crt --key /etc/kubernetes/pki/client.key --cacert /etc/kubernetes/pki/ca.crt https://192.168.100.155:6443/api/v1/namespaces
错误:cd /etc/kubernetes/pki
curl --cert client.crt --key client.key --cacert ca.crt https://192.168.100.155:6443/api/v1/namespaces

特别注意2:curl命令中,一定要写 宿主机内网ip/外网ip ,一定不能写 127.0.0.1,因为三个证书是通过ip生成的
正确:curl --cert /etc/kubernetes/pki/client.crt --key /etc/kubernetes/pki/client.key --cacert /etc/kubernetes/pki/ca.crt https://192.168.100.155:6443/api/v1/namespaces
错误:curl --cert /etc/kubernetes/pki/client.crt --key /etc/kubernetes/pki/client.key --cacert /etc/kubernetes/pki/ca.crt https://127.0.0.1:6443/api/v1/namespaces

常用的base64命令
base64 xxx.txt # 对文件内容加密
echo “xxx” | base64 # 对字符串xxx加密
echo “xxx” | base64 --decode # 对字符串xxx加密

步骤3:在postman上带证书发出https请求给K8S集群

接下来,postman如何带证书发出https请求,关闭了匿名认证之后,直接发送一定是 403 forbidden,如下:
在这里插入图片描述

(1) 在集群上生成三个pem文件
# .key 转换成 .pem:
openssl rsa -in client.key -out client_key.pem

# .crt 转换成 .pem:
openssl x509 -in client.crt -out client_crt.pem

# .crt 转换成 .pem:
openssl x509 -in ca.crt -out ca.pem

生成三个pem文件中,需要注意如下:
在这里插入图片描述

.key 和 .crt 文件中,前后两行不能去掉,否则无法使用 openssl 命令,从 .key/.crt 生成 .pem 文件,报错信息如下:

在这里插入图片描述

(2) Postman访问

Postman配置三个证书,就是因为 postman 必须使用 pem 文件,所有才需要生成三个 pem 文件。

在这里插入图片描述

配置三个证书之后,成功发送,注意Postman上的URL,一定要加上https,postman即使你配置了证书,也不会自动切https,需要你在url中明确表示。

在这里插入图片描述

打开SSL也是可以发送成功
在这里插入图片描述

二、打开外网

2.1 理论: 打开外网的需求

搭建 k8s 集群使用的是kubeadm init命令,这个命令要求使用的是内网ip,使用外网ip/公网ip是无法搭建成功的。所以默认的集群,各个node节点的内网ip写入到了k8s集群的密钥里面去,但是公网ip没有写入到密钥里面去的。

我现在直接搭建的是在vmware上的,因为 windows 和 vmware 在同一局域网里面,所以因为在 windows 直接使用内网ip 192.168.100.155 ,所以在 windows 的 Postman 可以访问到。

如果是使用 云服务器搭建的话,使用公网ip在Postman调用,是无法成功的,所以需要手动打开外网,将外网ip添加到密钥里面去。

2.2 实践: 打开外网的操作

本质就是到 /etc/kubernetes/pki 目录下,重新生成 apiserver.key apiserver.crt 这两个证书。

步骤1:查看当前允许哪些通过哪些ip操作k8s集群 (默认只允许 内网ip:6443 操作k8s集群,不允许外网ip:6443 操作k8s集群)

cd /etc/kubernetes/pki
openssl x509 -noout -text -in apiserver.crt |grep IP

在这里插入图片描述

步骤2:移走 apiserver.key apiserver.crt 两个证书

mkdir -pv /opt/cert
mv apiserver.* /opt/cert  (这里必须移走,否则生成报错,不是可选操作)

注意:这里必须移走,否则生成报错,不是可选操作

步骤3:重新生成 apiserver.key apiserver.crt 这两个证书

kubeadm init phase certs apiserver \
--apiserver-advertise-address 内网ip \
--apiserver-cert-extra-sans  apiserver.xxx域名 或者 本机外网ip 或者 代理机外网ip 

这里有两个参数:

–apiserver-advertise-address 后面接内网ip
–apiserver-cert-extra-sans 后面接apiserver.xxx域名 或者 本机外网ip 或者 代理机外网ip

步骤4:重启主节点上的kubelet服务 (各个从节点上的kubelet服务不需要重启)

systemctl restart kubelet.service

我是使用vmware虚拟机,没有外网ip,所以这里无法截图演示了。没有云服务器,穷。

总结

本文介绍所有的kubectl底层都是https请求,并且k8s打开外网,然后集群外访问到。

天天打码,天天进步!

参考资料:x509: certificate is valid for xxx, not xxx

Logo

加入社区!打开量化的大门,首批课程上线啦!

更多推荐