Eli's Blog

1. 机制说明

API Server 是集群内部各个组件通讯的中介,也是外部控制的入口。k8s 使用认证(Authentication)、鉴权(Authorization)、准入控制(Admission Control) 三步来确保API Server的安全。

2. 认证 (Authentication)

  • HTTP Token:HTTP Request Header 的 Token字段

  • HTTP Base: 客户端通过base64 USERNAME:PASSWORD, 填充 HTTP Request Header 的 Authorization字段,服务端收到后解码获取用户名和密码

  • HTTPS: 基于CA根证书签名的客户端身份认证方式。(推荐)

2.1 HTTPS 证书认证

https

2.2 需要认证的节点

auth

两种类型:

  • Kubernetes组件对API Server的访问:kubectl、Controller Manager、Scheduler、kubelet、kube-proxy

  • Kubernetes管理的Pod对容器的访问:Pod(dashborad也是以Pod形式运行)

安全性说明:

  • Controller Manager、Scheduler与API Server在同一台机器,所以直接使用API Server的非安全端口访问--insecure-bind-address=127.0.0.1
  • kubectl、kubelet、kube-proxy访问API Server都需要证书进行HTTPS双向认证

证书颁发:

  • 手动签发:通过k8s集群的根 ca 进行签发 HTTPS 证书
  • 自动签发:kubelet 首次访问 API Server 时,使用 token 认证,通过后,Controller Manager 会为kubelet生成一个证书,以后的访问均使用该证书

2.3 kubeconfig

kubeconfig 文件包含集群参数(CA证书、API Server地址),客户端参数,集群context信息(集群名称、用户名)。k8s 组件通过启动时指定不同的 kubeconfig 文件可以切换到不同的集群

cat ~/.kube/config

2.4 ServiceAccount

Pod 中的容器访问API Server。因为Pod的创建和销毁是动态的,所以要为它手动生成证书是不可行的,k8s 使用 Service Account解决Pod访问API Server的认证问题

2.5 Secret 与 SA 的关系

Secret 分两类:

  • 用于ServiceAccount的 service-account-token
  • 用于保存用户自定义的保密信息的 Opaque

SA 中包含三个部分:

  • token:使用API Server私钥签名的 JWT
  • ca.crt: 根证书,用于Client端验证API Server发送的证书
  • namespace: 标识该service-account-token的作用域名空间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$ kubectl get secret --all-namespaces
NAMESPACE NAME TYPE DATA AGE
default default-token-rhw7k kubernetes.io/service-account-token 3 5d16h
ingress-nginx default-token-ftjf6 kubernetes.io/service-account-token 3 2d3h
kube-system kube-proxy-token-kcgcp kubernetes.io/service-account-token 3 5d16h

$ kubectl describe secret default-token-rhw7k
Name: default-token-rhw7k
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name: default
kubernetes.io/service-account.uid: 3fdb2906-e8c4-4bb1-9dc0-ac8aa15167b6

Type: kubernetes.io/service-account-token

Data
====
ca.crt: 1025 bytes
namespace: 7 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6Ikx5ZjJCcWJPandjZzl5czlkRHpZZWp0d2NtT2dSU0w3c2M5dXY2ZUQ0QkUifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tcmh3N2siLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjNmZGIyOTA2LWU4YzQtNGJiMS05ZGMwLWFjOGFhMTUxNjdiNiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.FkcID8mWCOXDQbZAZPJLWSSWngvt9R-69AEDVV_QQvyvP_BW1MwiANOM2cXkS-qDo4-hcDcRKGOZ-q7BxQC96YUsj41iiLBbsXyVI1_ovEgp58dwROJe-MTxkSlk8sic40QmW2y1CwREf-5EIxwLy1iGekbbMZb4W0m4oXa-BN7qzNzMwu4Bb6ScJbxljHpO33K80oKtWYN-fpow31FjMjZMEebUvf-pGw6O2FPLvzwC7A7_U-WRNrFWd2wZIRQf8GfQgUf5-phAnmyawcJ4gpQooRvHoyGyW366dEY-qAk4D-1xSj598X0Q_pq7PdT1WQkO3nozHL-w4mbSlb3Ytw

$ kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
kube-proxy-c5t62 1/1 Running 13 5d16h
kube-proxy-q7m2t 1/1 Running 13 5d16h
kube-proxy-t2tgb 1/1 Running 13 5d16h

$ kubectl exec kube-proxy-c5t62 -n kube-system -it -- ls -l /run/secrets/kubernetes.io/serviceaccount
total 0
lrwxrwxrwx 1 root root 13 Sep 13 06:40 ca.crt -> ..data/ca.crt
lrwxrwxrwx 1 root root 16 Sep 13 06:40 namespace -> ..data/namespace
lrwxrwxrwx 1 root root 12 Sep 13 06:40 token -> ..data/token

2.6 总结

auth

3. 鉴权 (Authorization)

认证 和鉴权:

  • 认证(authencation): 通过只代表通讯双方是可信的
  • 鉴权(authorization): 确定请求方有哪些资源权限

API Server的授权策略,启动参数--authorization-mode

  • AlwaysDeny: 拒绝所有请求,一般用于测试
  • AlwaysAllow: 接收所有请求。如果集群不需要授权流程,采用该策略
  • ABAC (Attribute-Based Access Control): 基于属性的访问控制,表示使用用户配置的授权规则对用户请求进行匹配和控制
  • Webbook: 通过调用外部REST服务对用户进行授权
  • RBAC (Role-Based Access Control): 基于角色的访问控制,默认规则

RBAC优势:

  • 对集群中的资源和非资源均拥有完整的覆盖
  • 整个RBAC完全由几个API对象完成,同其他API对象一样,可以用kubectl或API进行操作
  • 可在运行时调整,无需重启API Server

3.1 RBAC 的 API资源对象

  • Role
  • ClusterRole
  • RoleBinding
  • ClusterRoleBinding

auth

k8s 不会提供用户管理,User, Group, ServiceAccount指定的用户,需要通过证书请求文件指定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"CN": "admin", // User
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "HangZhou",
"L": "XS",
"O": "system:master", // Group
"OU": "Sytem"
}
]
}

3.2 Role & ClusterRole

3.2.1 Role

Role 表示一组规则权限,权限只会增加(累加权限),不存在一开始就开通很多权限而通过RBAC对其减少的操作。Role 必须定义在一个namespace中,跨namespace可以使用ClusterRole

1
2
3
4
5
6
7
8
9
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: pod-reader
namespace: default
rules:
- apiGroups: [""] # "" indicates the core API group
resources: [ pods ]
verbs: [get, watch, list]

3.2.2 ClusterRole

ClusterRole 是集群级别的,可用于:

  • 集群级别资源控制,例如node访问权限
  • 非资源型 endpoints,例如/healthz 访问
  • 所有命名空间资源控制,例如pod
1
2
3
4
5
6
7
8
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: secret-reader
rules:
- apiGroups: [""] # "" indicates the core API group
resources: [ secrets ]
verbs: [get, watch, list]

3.3 RoleBinding & ClusterRoleBinding

3.3.1 RoleBinding

RoleBinding 可以将角色中定义的权限赋予用户或组,它包含了一种权限列表(subjects),权限列表包含不同形式的待授予权限资源类型(users,groups,service accounts),同时它也包含被Bind的Role引用

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
- kind: User
name: jane
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io

RoleBinding引用ClusterRole:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# This role binding allows "dave" to read secrets in the "development" namespace
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: read-secrets
namespace: development
subjects:
- kind: User
name: dave
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io

3.3.2 ClusterRoleBinding

ClusterRoleBinding 可以对整个集群中的所有命名空间资源权限进行授权

1
2
3
4
5
6
7
8
9
10
11
12
13
# This cluster role binding allows anyone in the "manager" group to read secrets in any namespace.
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: read-secrets-global
subjects:
- kind: Group
name: manager
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io

3.4 Resources

访问子资源:

1
GET /api/v1/namespaces/{namespace}/pods/{name}/log
1
2
3
4
5
6
7
8
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: pod-and-pod-logs-reader
rules:
- apiGroups: [""] # "" indicates the core API group
resources: [ pods, "pods/log" ]
verbs: [get, list]

3.5 to Subjects

RoleBinding & ClusterRoleBinding 可以将Role绑定到Subjects, Subjects 可以是groups, users, 或SA

3.6 示例

3.6.1 创建Linux账号

1
2
3
4
5
6
useradd devuser
passwd devuser

su - devuser
$ kubectl get pod # 无权限
The connection to the server localhost:8080 was refused - did you specify the right host or port?

3.6.2 安装证书工具

1
2
3
4
5
6
7
8
# 下载证书生成工具
$ wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
$ wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
$ wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
$ chmod +x cfssl*
$ mv cfssl_linux-amd64 /usr/local/bin/cfssl
$ mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
$ mv cfssl-certinfo_linux-amd64 /usr/local/bin/cfssl-certinfo

3.6.3 生成证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ mkdir -p ~/cert/devuser

# 证书请求文件
$ cat > ~/cert/devuser/user-csr.json <<EOF
{
"CN": "devuser",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "JS",
"L": "NJ",
"O": "k8s",
"OU": "Sytem"
}
]
}
EOF

# 生成证书
$ cd /etc/kubernetes/pki
$ cfssl gencert -ca=ca.crt -ca-key=ca.key -profile=kubernetes ~/cert/devuser/user-csr.json | cfssljson -bare devuser

3.6.4 设置集群参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 设置集群参数
cd ~/cert/devuser
export KUBE_APISERVER="https://192.168.31.40:6443"

kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=devuser.kubeconfig

# 设置客户端认证参数
kubectl config set-credentials devuser \
--client-certificate=/etc/kubernetes/pki/devuser.pem \
--client-key=/etc/kubernetes/pki/devuser-key.pem \
--embed-certs=true \
--kubeconfig=devuser.kubeconfig

# 设置上下文
kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=devuser \
--namespace=dev \
--kubeconfig=devuser.kubeconfig

3.6.5 角色绑定

1
2
3
# rolebinding
kubectl create ns dev
kubectl create rolebinding devuser-admin-binding --clusterrole=admin --user=devuser --namespace=dev

3.6.6 用户管理配置

1
2
3
mkdir -p /home/devuser/.kube
cp devuser.kubeconfig /home/devuser/.kube/config
chown -R devuser:devuser /home/devuser/.kube

3.6.7 设置默认上下 和 验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 设置默认上下文
su - devuser
$ kubectl config use-context kubernetes --kubeconfig=.kube/config
Switched to context "kubernetes".

# devuser 用户下创建 pod
$ kubectl get pod
No resources found in dev namespace.

$ kubectl run nginx --image=hub.elihe.io/test/nginx:v1
pod/nginx created

$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 4s

$ kubectl get pod -n default
Error from server (Forbidden): pods is forbidden: User "devuser" cannot list resource "pods" in API group "" in the namespace "default"

4. 准入控制

准入控制是 API Server 的插件集合,通过添加不同的插件,实现额外的准入控制规则

常见准入控制插件:

  • NamespaceLifecycle: 防止在不存在的namespace上创建对象;防止删除系统预置的namespace;删除namespace时,连带删除它下面的所有资源
  • LimitRanger: 确保请求的资源不会超过资源所在Namespace的LimitRange的限制
  • ServiceAccount: 实现自动化添加SA
  • ResourceQuota: 确保请求的资源不会超过资源的ResourceQuota限制