[TOC]
当我们执行`kubectl exec -it pod [podName] sh`命令时,apiserver会向kubelet发起API请求。也就是说,kubelet会提供HTTP服务,而为了安全,kubelet必须提供HTTPS服务,且还要提供一定的认证与授权机制,防止任何知道kubelet端口的人都能访问它的API。
## **kubelet的认证**
默认情况下,没有携带身份凭证的匿名请求会被认证为用户`system:anonymous`以及组`system:unauthenticated`。如果要拒绝将匿名请求认证为以上的用户与组,配置kubelet的如下启动参数,那么匿名请求就会认证失败
```
--anonymous-auth=false
```
kubelet的认证方法与apiserver相似,有client证书认证及token认证。
要开启client证书认证:
* 配置kubelet的启动参数`--client-ca-file`,用来校验client证书
## **kubelet的授权**
kubelet的默认授权模式为`AlwaysAllow`,所有通过认证的请求(包括通过认证的匿名请求)有权限访问kubelet所有的API。这显然是不合理的,所以我们需要像apiserver那样对不同的请求赋予不同的权限。
kubelet可以通过如下的方法把授权委托给apiserver:
* 在apiserver中开启`authorization.k8s.io/v1beta1`这个API组
* 配置kubelet的启动参数`--authorization-mode=Webhook`以及`--kubeconfig`
* 然后kubelet就会通过apiserver的`SubjectAccessReview`API来决定是否给每一个请求授权
## **kubelet与apiserver的资源映射**
kubelet与apiserver的API不一样,当访问kubelet的API时,kubelet需要把这个API映射到apiserver的API,apiserver才知道该授予怎样的权限。kubelet与apiserver的资源映射如下。比如A用户访问kubelet的`Get /healthz`,那么会映射为apiserver的`Get /api/v1//nodes/<kubelet-name>/proxy`,然后kubelet会通过apiserver的`SubjectAccessReview`判断A用户是否有权限访问apiserver对应的API
| kubelet API | resource | sub-resource |
| --- | --- | --- |
| /stats/* | nodes | stats |
| /metrics/* | nodes | metrics |
| /logs/* | nodes | logs |
| /spec/* | nodes | spec |
| all others | nodes | proxy |
## **Apiserver访问kubelet**
在kubeadm安装方法中,apiserver要访问kubelet的API,会携带一个client证书,这个证书由apiserver的启动参数`--kubelet-client-certificate`和`--kubelet-client-key`指定。kubeadm为apiserver生成的client证书中的域名为与组织分别为`CN=kube-apiserver-kubelet-client`、`O=system:masters`。当apiserver携带这个证书去访问kubelet时,就会被认证为上面的用户与组,然后kubelet访问apiserver,检测这个用户与组的权限。kubeadm会在集群中为这个用户与组建立如下的ClusterRole与ClusterRoleBinding。可以看出,`system:masters`这个组拥有所有的权限
```
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:masters
```
```
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-admin
rules:
- apiGroups:
- '*'
resources:
- '*'
verbs:
- '*'
- nonResourceURLs:
- '*'
verbs:
- '*'
```
## **kubelet的TLS私钥与证书**
kubelet要提供HTTPS服务,那么它需要一个私钥和一个签名证书。我们可以通过kubelet的启动参数`--tls-cert-file`与`--tls-cert-private-key`来指定。如果这两个参数没有指定,那么kubelet会生成一个自签名证书,放在`--cert-dir`目录(默认`/var/lib/kubelet/pki`),自签名证书的名字为kubelet.key、kubelet.crt:
```
$ ls -lh /var/lib/kubelet/pki
-rw-------. 1 root root 2.8K Mar 10 11:26 kubelet-client-2023-03-10-11-26-25.pem
lrwxrwxrwx. 1 root root 59 Mar 10 11:26 kubelet-client-current.pem -> /var/lib/kubelet/pki/kubelet-client-2023-03-10-11-26-25.pem
-rw-r--r--. 1 root root 2.2K Mar 10 11:26 kubelet.crt
-rw-------. 1 root root 1.7K Mar 10 11:26 kubelet.key
```
我们查看kubelet.crt的Issure与Subject,可以发现是一样的(即自签名),就为主机名加一个数字后缀,DNS中有一个记录就为主机名:
```
$ openssl x509 -text -in /var/lib/kubelet/pki/kubelet.crt
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 2 (0x2)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=kata02-ca@1678418785
Validity
Not Before: Mar 10 02:26:24 2023 GMT
Not After : Mar 9 02:26:24 2024 GMT
Subject: CN=kata02@1678418785
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
...
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Authority Key Identifier:
keyid:C4:7A:AD:CC:65:73:17:07:3B:69:3A:C9:B7:53:EE:0C:CC:04:07:7C
X509v3 Subject Alternative Name:
DNS:kata02
...
```
我们可以查看[kubelet的源码](https://github.com/kubernetes/kubernetes/blob/master/cmd/kubelet/app/server.go),也可以确定,就是自签名的一个证书:
![](https://img.kancloud.cn/32/22/322286c000fea28bb80c809a2d66522d_1931x1491.png)
**由于kubelet默认情况下用的就是自签名证书,所以kube-apiserver在连接kubelet时(比如kubectl logs),并不会校验kubelet.crt证书。**
## **Reference**
[1] https://jvns.ca/blog/2017/08/05/how-kubernetes-certificates-work/
- 常用命令
- 安装
- 安装Kubeadm
- 安装单Master集群
- 安装高可用集群(手动分发证书)
- 安装高可用集群(自动分发证书)
- 启动参数解析
- certificate-key
- ETCD相关参数
- Kubernetes端口汇总
- 安装IPv4-IPv6双栈集群
- 下载二进制文件
- 使用Kata容器
- 快速安装shell脚本
- 存储
- 实践
- Ceph-RBD实践
- CephFS实践
- 对象存储
- 阿里云CSI
- CSI
- 安全
- 认证与授权
- 认证
- 认证-实践
- 授权
- ServiceAccount
- NodeAuthorizor
- TLS bootstrapping
- Kubelet的认证
- 准入控制
- 准入控制示例
- Pod安全上下文
- Selinux-Seccomp-Capabilities
- 给容器配置安全上下文
- PodSecurityPolicy
- K8S-1.8手动开启认证与授权
- Helm
- Helm命令
- Chart
- 快速入门
- 内置对象
- 模板函数与管道
- 模板函数列表
- 流程控制
- Chart依赖
- Repository
- 开源的Chart包
- CRD
- CRD入门
- 工作负载
- Pod
- Pod的重启策略
- Container
- 探针
- 工作负载的状态
- 有状态服务
- 网络插件
- Multus
- Calico+Flannel
- 容器网络限速
- 自研网络插件
- 设计文档
- Cilium
- 安装Cilium
- Calico
- Calico-FAQ
- IPAM
- Whereabouts
- 控制平面与Pod网络分开
- 重新编译
- 编译kubeadm
- 编译kubeadm-1.23
- 资源预留
- 资源预留简介
- imagefs与nodefs
- 资源预留 vs 驱逐 vs OOM
- 负载均衡
- 灰度与蓝绿
- Ingress的TLS
- 多个NginxIngressController实例
- Service的会话亲和
- CNI实践
- CNI规范
- 使用cnitool模拟调用
- CNI快速入门
- 性能测试
- 性能测试简介
- 制作kubemark镜像
- 使用clusterloader2进行性能测试
- 编译clusterloader2二进制文件
- 搭建性能测试环境
- 运行density测试
- 运行load测试
- 参数调优
- Measurement
- TestMetrics
- EtcdMetrics
- SLOMeasurement
- PrometheusMeasurement
- APIResponsivenessPrometheus
- PodStartupLatency
- FAQ
- 调度
- 亲和性与反亲和性
- GPU
- HPA
- 命名规范
- 可信云认证
- 磁盘限速
- Virtual-kubelet
- VK思路整理
- Kubebuilder
- FAQ
- 阿里云日志服务SLS