整个 k8s 集群的 APIserver 是访问控制的唯一入口,但不会限制应用程序,任何用户试图操作资源对象时,要经历三个环节
- 认证: 访问 k8s 的账号和安全认证
- 授权: 是否有操作资源对象的权限
- 准入控制: 级联的其他资源是否有权限
用户可以通过多种插件来选择通过何种逻辑方式完成认证和准入控制如: token、SSL 等,其中 SSL 认证客户端需要验证服务端的 CA 证书同时,服务端也要认证 kubectl 的 CA 证书.如果环境中存在多个认证插件则不会串行认证,授权来说也可以通过插件来完成用户的授权间检查,k8s 1.6 之后开始支持基于 RBAC 认证,此前支持诸如 ABAC 的认证等,RBAC 与 LINUX 权限认证相思,默认拒绝所有请求只允许某些权限,所以可以细致到普通用户的各种独立权限.准入控制逻辑本身只是用来定义授权检查通过后的其他权限
同时也需要注意 k8s 集群上的证书一般是自签证书,任何这个自签机构颁发的证书都可以被 k8s 完成认证
用户账号权限
API server 识别用户的权限通过以下几种协议来识别
- 用户账号 user:username,uid
- 用户组 group:用户所属的组,权限指派和继承
- 附加权限 extra: 键值数据的字符串,用于提供认证时需要提供额外信息
更重要的是用户会请求具体某个特定的 API 资源,而 k8s 的 API server 是分组的,则用户会通过在 HTTP 协议当中的 URL 来标识的,如 http://${MasterIP}:6443/apis/apps/v1/namespaces/default/deployments/myapp-deploy
/apis/<GROUP>/<VERSION>/namespace/<NAMESPACE_NAME>/<KIND>[/OBJECT_ID]/
[root@master-0 ~]# kubectl proxy --port=8080
Starting to serve on 127.0.0.1:8080
[root@master-0 ~]# curl http://localhost:8080/api/v1/namespaces
... ...
与 API server 打交道的有两种身份
- 集群外部: 每次访问 apiserver 时,都是请求其所在的节点进行访问
- 集群内部: apiserver 有一个名为 kubernetes 的 svc,作为给集群内部 pod 访问的 ip 地址
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1JrBNGfM-1624627871200)(https://raw.githubusercontent.com/ma823956028/image/master/picgo/20200914103824.png)]
[root@master-0 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.208.0.1 <none> 443/TCP 165d
myapp ClusterIP 10.208.208.208 <none> 80/TCP 12d
myapp-svc ClusterIP None <none> 80/TCP 97d
[root@master-0 ~]# kubectl describe svc kubernetes
Name: kubernetes
Namespace: default
Labels: component=apiserver
provider=kubernetes
Annotations: <none>
Selector: <none>
Type: ClusterIP
IP: 10.208.0.1
Port: https 443/TCP
TargetPort: 6443/TCP
Endpoints: 10.211.55.35:6443
Session Affinity: None
Events: <none>
由于这种特殊的集群内部 apiserver 的机制,做证书时需要指明 apiserver 本身 ip 和 kubernetes svc 的 ip,同时由于双向认证的关系,容器内的服务如果要访问 apiserver 也需要进行认证,这个认证是 pod 的 spec.serviceAccountName
提供的
[root@master-0 ~]# kubectl explain pod.spec.serviceAccountName
KIND: Pod
VERSION: v1
FIELD: serviceAccountName <string>
DESCRIPTION:
ServiceAccountName is the name of the ServiceAccount to use to run this
pod. More info:
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
而各个 pod 多少都会与 apiserver 交互,所以每个名称空间下都会有一个和 apiserver 交互时的 token,但默认这个 token 只能管理 pod 自身
[root@master-0 ~]# kubectl get secret
NAME TYPE DATA AGE
default-token-lbf5s kubernetes.io/service-account-token 3 165d
[root@master-0 ~]# kubectl get secret -ningress-nginx
NAME TYPE DATA AGE
default-token-hfbph kubernetes.io/service-account-token 3 12d
serviceAccount
-
创建的 serviceAccount 只是账号,后需要通过 RBAC 来赋予真正的权限
[root@master-0 ~]# kubectl create serviceaccount mysa -o yaml --dry-run # dry-run 可以输出框架,同时对于运行的 pod 也可以使用 --export 来导出 yaml 文件 W0912 01:25:59.806447 11484 helpers.go:535] --dry-run is deprecated and can be replaced with --dry-run=client. apiVersion: v1 kind: ServiceAccount metadata: creationTimestamp: null name: mysa [root@master-0 ~]# kubectl get sa NAME SECRETS AGE default 1 165d [root@master-0 ~]# kubectl create serviceaccount admin serviceaccount/admin created [root@master-0 ~]# kubectl describe sa admin Name: admin Namespace: default Labels: <none> Annotations: <none> Image pull secrets: <none> # pod 拉取镜像时连接私有仓库的认证信息,比 secret 安全 Mountable secrets: admin-token-zr6cw Tokens: admin-token-zr6cw Events: <none> [root@master-0 ~]# kubectl get secret NAME TYPE DATA AGE admin-token-zr6cw kubernetes.io/service-account-token 3 16s ... ...
-
让 pod 挂载使用这个 sa
[root@master-0 ~]# cat pod-sa-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-sa-demo
namespace: default
labels:
app: myapp
tier: frontend
spec:
containers:
- name: myapp
image: nginx
ports:
- name: http
containerPort: 80
imagePullPolicy: IfNotPresent
serviceAccountName: admin
[root@master-0 ~]# kubectl apply -f pod-sa-demo.yaml
pod/pod-sa-demo created
认证信息的配置文件
-
除了 apiserver 自己本身,其他所有组件几乎都需要与其进行认证,而每个组件的认证信息配置文件被称为
kubeconfig
,显示 kubeconfig 设置命令为kubectl config view
[root@master-0 ~]# kubectl config view apiVersion: v1 clusters: # 集群列表 - cluster: certificate-authority-data: DATA+OMITTED # 服务器认证这个集群的认证方式,私密数据 server: https://10.211.55.35:6443 # 访问集群的 apiserver 路径 name: kubernetes contexts: - context: # 上下文列表,这个配置文件不单单可以访问一个 k8s 集群,context 则注明哪个账号可以访问那个集群 cluster: kubernetes # 集群名 user: kubernetes-admin # 访问这个集群用的用户信息 name: kubernetes-admin@kubernetes # context 的名字 current-context: kubernetes-admin@kubernetes # 当前上下文 kind: Config preferences: {} users: # 用户列表 - name: kubernetes-admin user: client-certificate-data: REDACTED # 被集群认证的信息 client-key-data: REDACTED
-
在配置文件中增加新的账号信息
[root@master-0 ~]# cd /etc/kubernetes/ [root@master-0 kubernetes]# cd pki/ [root@master-0 pki]# ls apiserver.crt apiserver.key ca.crt front-proxy-ca.crt front-proxy-client.key apiserver-etcd-client.crt apiserver-kubelet-client.crt ca.key front-proxy-ca.key sa.key apiserver-etcd-client.key apiserver-kubelet-client.key etcd front-proxy-client.crt sa.pub [root@master-0 pki]# (umask 077 ; openssl genrsa -out test.key 2048) # 生成私钥 Generating RSA private key, 2048 bit long modulus .......................................................................................................+++ ...+++ e is 65537 (0x10001) [root@master-0 pki]# openssl req -new -key test.key -out test.cr -subj "/CN=test" # CN 就是用户账号的名字 [root@master-0 pki]# openssl x509 -req -in test.cr -CA ca.crt -CAkey ca.key -CAcreateserial -out test.crt -days 365 # 签署证书 Signature ok subject=/CN=test Getting CA Private Key [root@master-0 pki]# openssl x509 -in test.crt -text -noout Certificate: Data: Version: 1 (0x0) Serial Number: 17177463334185398281 (0xee629be4706af009) Signature Algorithm: sha1WithRSAEncryption Issuer: CN=kubernetes Validity Not Before: Sep 12 06:28:32 2020 GMT Not After : Sep 12 06:28:32 2021 GMT Subject: CN=test ... ... [root@master-0 pki]# kubectl config set-credentials Usage: kubectl config set-credentials NAME [--client-certificate=path/to/certfile] [--client-key=path/to/keyfile] [--token=bearer_token] [--username=basic_user] [--password=basic_password] [--auth-provider=provider_name] [--auth-provider-arg=key=value] [--exec-command=exec_command] [--exec-api-version=exec_api_version] [--exec-arg=arg] [--exec-env=key=value] [options] [root@master-0 pki]# kubectl config set-credentials testadmin --client-certificate=./test.crt --client-key=./test.key --embed-certs=true User "testadmin" set. [root@master-0 pki]# kubectl config set-context --help Usage: kubectl config set-context [NAME | --current] [--cluster=cluster_nickname] [--user=user_nickname] [--namespace=namespace] [options] [root@master-0 pki]# kubectl config set-context testadmin@kubernetes --cluster=kubernetes --user=test Context "testadmin@kubernetes" created. [root@master-0 pki]# kubectl config view apiVersion: v1 clusters: - cluster: certificate-authority-data: DATA+OMITTED server: https://10.211.55.35:6443 name: kubernetes contexts: - context: cluster: kubernetes user: kubernetes-admin name: kubernetes-admin@kubernetes - context: cluster: kubernetes user: test name: testadmin@kubernetes current-context: kubernetes-admin@kubernetes kind: Config preferences: {} users: - name: kubernetes-admin user: client-certificate-data: REDACTED client-key-data: REDACTED - name: testadmin user: client-certificate-data: REDACTED client-key-data: REDACTED [root@master-0 pki]# kubectl config use-context testadmin@kubernetes Switched to context "testadmin@kubernetes". [root@master-0 pki]# kubectl config use-context kubernetes-admin@kubernetes
准入控制
一般不会手动操作