该篇文章已经被专栏《从零开始学k8s》收录
上一篇文章:kubectl深入理解 点击跳转
上面我们学习的 Configmap 一般是用来存放明文数据的,如配置文件,对于一些敏感数据,如密码、私钥等数据时,要用 secret 类型。
Secret 解决了密码、token、秘钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者 Pod Spec 中。Secret 可以以 Volume 或者环境变量的方式使用。
要使用 secret,pod 需要引用 secret。Pod 可以用两种方式使用 secret:作为 volume 中的文件被挂载到 pod 中的一个或者多个容器里,或者当 kubelet 为 pod 拉取镜像时使用。 (比如harbor拉取,里面存储了harbor的用户密码等)
secret 可选参数有三种:
generic: 通用类型,通常用于存储密码数据。
tls:此类型仅用于存储私钥和证书。
docker-registry: 若要保存 docker 仓库的认证信息的话,就必须使用此种类型来创建。
Secret 类型:
Service Account:用于被 serviceaccount 引用。serviceaccout 创建时 Kubernetes 会默认创建对应的 secret。Pod 如果使用了 serviceaccount,对应的 secret 会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中。
Opaque:base64 编码格式的 Secret,用来存储密码、秘钥等。可以通过 base64 – decode 解码获得原始数据,因此安全性弱
kubernetes.io/dockerconfigjson:用来存储私有 docker registry 的认证信息。
1、通过环境变量引入 Secret
把 mysql 的 root 用户的 password 创建成 secret
[root@k8smaster ~]# kubectl create secret generic mysql-password --from-literal=password=paopaopodshuaige66
secret/mysql-password created
[root@k8smaster secret]# kubectl get secrets
NAME TYPE DATA AGE
mysql-password Opaque 1 60s
[root@k8smaster secret]# kubectl describe secret mysql-password
Name: mysql-password
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password: 18 bytes
password 的值是加密的,但 secret 的加密是一种伪加密,它仅仅是将数据做了 base64 的编码,下面是解密,找到mysqlpassword里的加密密码。
[root@k8smaster secret]# kubectl get secret -o yaml
- apiVersion: v1
data:
password: eGlhbmNoYW9wb2QqKmx1Y2t5NjY=
[root@k8smaster secret]# echo 'eGlhbmNoYW9wb2QqKmx1Y2t5NjY=' | base64 --decode
paopaopodshuaige66
#创建 pod,引用 secret
[root@k8smaster secret]# vim pod-secret.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-secret
labels:
app: myapp
spec:
containers:
- name: myapp
image: nginx
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
env:
- name: MYSQL_ROOT_PASSWORD #它是 Pod 启动成功后,Pod 中容器的环境变量名.
valueFrom:
secretKeyRef:
name: mysql-password #这是 secret的对象名 把这个secret中的password这个key和对应的value值赋值给上面的变量
key: password #它是 secret 中的 key 名
[root@k8smaster secret]# kubectl apply -f pod-secret.yaml
pod/pod-secret created
[root@k8smaster secret]# kubectl exec -it pod-secret -- /bin/sh
/ # printenv
MYSQL_ROOT_PASSWORD=paopaopodshuaige66
通过 volume 挂载 Secret
创建 Secret,手动加密,基于 base64 加密
[root@k8smaster secret]# echo -n 'admin' | base64
YWRtaW4=
[root@k8smaster secret]# echo -n 'paopaoshuaige' | base64
cGFvcGFvc2h1YWlnZQ==
解码
[root@k8smaster secret]# echo cGFvcGFvc2h1YWlnZQ== | base64 -d
paopaoshuaige
创建 yaml 文件
[root@k8smaster secret]# vim secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: cGFvcGFvc2h1YWlnZQ==
[root@k8smaster secret]# kubectl apply -f secret.yaml
secret/mysecret created
[root@k8smaster secret]# kubectl describe secret mysecret
Name: mysecret
Namespace: default
Labels: <none>
Annotations:
Type: Opaque
Data
====
password: 13 bytes
username: 5 bytes
把 Secret 挂载到 Volume 中
[root@xianchaomaster1 ~]# vim pod_secret_volume.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-secret-volume
spec:
containers:
- name: myapp
image: registry.cn-beijing.aliyuncs.com/google_registry/myapp:v1
imagePullPolicy: IfNotPresent
volumeMounts:
- name: secret-volume
mountPath: /etc/secret
readOnly: true
volumes:
- name: secret-volume #把secret做成卷挂载到/etc/secret 只读权限
secret:
secretName: mysecret
[root@k8smaster secret]# kubectl apply -f pod_secret_volume.yaml
pod/pod-secret-volume created
[root@k8smaster secret]# kubectl exec -it pod-secret-volume -- /bin/sh
/ # ls /etc/secret
password username
/ # cat /etc/secret/username
admin
/ # cat /etc/secret/password
paopaoshuaige/ #
由上可见,挂载到 pod 中的 secret 信息实际已经被解密。
k8s 对我们整个系统的认证,授权,访问控制做了精密的设置;对于 k8s 集群来说,apiserver 是整个集群访问控制的唯一入口,我们在 k8s 集群之上部署应用程序的时候,也可以通过宿主机的 NodePort 暴露的端口访问里面的程序,用户访问 kubernetes 集群需要经历如下认证过程:认证 ->授权->准入控制(adminationcontroller)
1.认证(Authenticating)是对客户端的认证,通俗点就是用户名密码验证
2.授权(Authorization)是对资源的授权,k8s 中的资源无非是容器,最终其实就是容器的计算,网络,存储资源,当一个请求经过认证后,需要访问某一个资源(比如创建一个 pod),授权检查会根据授权规则判定该资源(比如某 namespace 下的 pod)是否是该客户可访问的。
3.准入(Admission Control)机制: 准入控制器(Admission Controller)位于 API Server 中,在对象被持久化之前,准入控制器拦截对 API Server 的请求,一般用来做身份验证和授权。其中包含两个特殊的控制器:
MutatingAdmissionWebhook 和 ValidatingAdmissionWebhook。分别作为配置的变异和验证准入控制 webhook。
变更(Mutating)准入控制:修改请求的对象
验证(Validating)准入控制:验证请求的对象
准入控制器是在 API Server 的启动参数配置的。一个准入控制器可能属于以上两者中的一种,也可能两者都属于。当请求到达 API Server 的时候首先执行变更准入控制,然后再执行验证准入控制。
我们在部署 Kubernetes 集群的时候都会默认开启一系列准入控制器,如果没有设置这些准入控制器的话可以说你的 Kubernetes 集群就是在裸奔,应该只有集群管理员可以修改集群的准入控制器。
例如我会默认开启如下的准入控制器。
–admission-control=ServiceAccount,NamespaceLifecycle,NamespaceExists,LimitRanger,ResourceQuota,MutatingAdmissionWebhook,ValidatingAdmissionWebhook
k8s 的整体架构也是一个微服务的架构,所有的请求都是通过一个 GateWay,也就是 kube-apiserver 这个组件(对外提供 REST 服务),k8s 中客户端有两类,一种是普通用户,一种是集群内的 Pod,这两种客户端的认证机制略有不同,但无论是哪一种,都需要依次经过认证,授权,准入这三个机制。
(1)令牌(token)认证:
双方有一个共享密钥,服务器上先创建一个密码下来,客户端登陆的时候拿这个密码登陆即可,这个就是对称密钥认证方式。k8s 提供了一个 restful 风格的接口,它的所有服务都是通过 http 协议提供的,因此认证信息只能经由 http 协议的认证首部进行传递,这种认证首部进行传递通常叫做令牌。
(2)ssl 认证:
对于 k8s 访问来讲,ssl 认证能让客户端确认服务器的认证身份,我们在跟服务器通信的时候,需要服务器发过来一个证书,我们需要确认这个证书是不是 ca 签署的,如果是我们认可的ca签署的, 里面的subj信息与我们访问的目标主机信息保持一致,没有问题,那么我们就认为服务器的身份得到认证了,k8s 中最重要的是服务器还需要认证客户端的信息,kubectl 也应该有一个证书,这个证书也是 server 所认可的 ca 签署的证书,双方需要互相认证,实现加密通信,这就是 ssl 认证。
客户端对 apiserver 发起请求,apiserver 要识别这个用户是否有请求的权限,要识别用户本身能否通过 apiserver 执行相应的操作,那么需要哪些信息才能识别用户信息来完成对用户的相关的访问控制呢?
kubectl explain pods.spec 可以看到有一个字段 serviceAccountName(服务账号名称),这个就是我们 pod 连接 apiserver 时使用的账号,因此整个 kubernetes 集群中的账号有两类, ServiceAccount(服务账号),User account(用户账号)
User account:实实在在现实中的人人可以登陆的账号,客户端想要对 apiserver 发起请求, apiserver 要识别这个客户端是否有请求的权限,那么不同的用户就会有不同的权限,靠用户账号表示,叫做 username
ServiceAccount:方便 Pod 里面的进程调用 Kubernetes API 或其他外部服务而设计的,是 kubernetes 中的一种资源
sa 账号:登陆 dashboard 使用的账号
user account:这个是登陆 k8s 物理机器的用户
执行kubectl指令的时候会加载文件
[root@k8smaster secret]# cat /root/.kube/config
文件里有一个user用户,做了rbac授权
user: kubernetes-admin
会基于这个用户去访问k8s
创作不易,如果觉得内容对你有帮助,麻烦给个三连关注支持一下我!如果有错误,请在评论区指出,我会及时更改!
目前正在更新的系列:从零开始学k8s
感谢各位的观看,文章掺杂个人理解,如有错误请联系我指出~