Secret概述

Secret解决了密码、token、秘钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者Pod Spec中。Secret可以以Volume或者环境变量的方式使用。

用户可以创建 secret,同时系统也创建了一些 secret。

要使用 secret,pod 需要引用 secret。Pod 可以用两种方式使用 secret:作为 volume 中的文件被挂载到 pod 中的一个或者多个容器里,或者当 kubelet 为 pod 拉取镜像时使用。

Secret类型

  • Service Account:用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的 /run/secrets/kubernetes.io/serviceaccount 目录中。
  • Opaque:base64编码格式的Secret,用来存储密码、秘钥等。
  • kubernetes.io/dockerconfigjson:用来存储私有docker registry的认证信息。

    Service Account

    通过kube-proxy查看
    1. [root@k8s-master01 ~]# kubectl get pod -A | grep "kube-proxy"
    2. kube-system kube-proxy-5jt9d 1/1 Running 6 22d
    3. kube-system kube-proxy-r4dx5 1/1 Running 6 22d
    4. [root@k8s-master01 ~]# kubectl exec -it -n kube-system kube-proxy-5jt9d -- /bin/sh
    5. # ls -l /run/secrets/kubernetes.io/serviceaccount
    6. total 0
    7. lrwxrwxrwx 1 root root 13 Apr 27 12:55 ca.crt -> ..data/ca.crt
    8. lrwxrwxrwx 1 root root 16 Apr 27 12:55 namespace -> ..data/namespace
    9. lrwxrwxrwx 1 root root 12 Apr 27 12:55 token -> ..data/token

    Opaque Secret

    创建secret

    手动加密,基于base64加密
    [root@k8s-master01 ~]# echo "admin" | base64
    YWRtaW4K
    [root@k8s-master01 ~]# echo -n '1f2d1e2e67df' | base64
    MWYyZDFlMmU2N2Rm
    
    yaml文件
    [root@k8s-master01 secret]# pwd
    /root/k8s_practice/secret
    [root@k8s-master01 secret]# cat secret.yaml 
    apiVersion: v1
    kind: Secret
    metadata:
    name: mysecret
    type: Opaque
    data:
    username: YWRtaW4K
    password: MWYyZDFlMmU2N2Rm
    
    或者通过如下命令行创建【secret名称故意设置不一样,以方便查看对比】,生成secret后会自动加密,而非明文存储。
    kubectl create secret generic db-user-pass --from-literal=username=admin --from-literal=password=1f2d1e2e67df
    
    生成secret,并查看状态 ```shell [root@k8s-master01 secret]# kubectl apply -f secret.yaml secret/mysecret created

[root@k8s-master01 secret]# kubectl get secret ### 查看默认名称空间的secret简要信息 NAME TYPE DATA AGE db-user-pass Opaque 2 53s default-token-k2f44 kubernetes.io/service-account-token 3 22d mysecret Opaque 2 21s

[root@k8s-master01 secret]# kubectl get secret mysecret -o yaml ### 查看mysecret详细信息 apiVersion: v1 data: password: MWYyZDFlMmU2N2Rm username: YWRtaW4K kind: Secret metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {“apiVersion”:”v1”,”data”:{“password”:”MWYyZDFlMmU2N2Rm”,”username”:”YWRtaW4K”},”kind”:”Secret”,”metadata”:{“annotations”:{},”name”:”mysecret”,”namespace”:”default”},”type”:”Opaque”} creationTimestamp: “2021-04-27T23:49:37Z” name: mysecret namespace: default resourceVersion: “149397” selfLink: /api/v1/namespaces/default/secrets/mysecret uid: 70cfe6e0-6347-4efd-9333-5f896d14e6b8 type: Opaque

[root@k8s-master01 secret]# kubectl describe secret mysecret ### 查看描述信息 Name: mysecret Namespace: default Labels: Annotations:
Type: Opaque

Data

password: 12 bytes username: 6 bytes

<a name="csEBW"></a>
## 将Secret挂载到Volume中
yaml文件
```shell
[root@k8s-master01 secret]# pwd
/root/k8s_practice/secret

[root@k8s-master01 secret]# cat 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
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/secret
      readOnly: true
  volumes:
  - name: secret-volume
    secret:
      secretName: mysecret

启动pod并查看状态

[root@k8s-master01 secret]# kubectl apply -f pod_secret_volume.yaml
pod/pod-secret-volume created

[root@k8s-master01 secret]# kubectl get pod -o wide
NAME                      READY   STATUS    RESTARTS   AGE    IP               NODE         NOMINATED NODE   READINESS GATES
daemonset-example-5sjhf   1/1     Running   0          10h    192.168.85.244   k8s-node01   <none>           <none>
frontend-4crh5            1/1     Running   0          10h    192.168.85.239   k8s-node01   <none>           <none>
frontend-n4z6w            1/1     Running   0          10h    192.168.85.213   k8s-node01   <none>           <none>
frontend-pmcrm            1/1     Running   0          10h    192.168.85.235   k8s-node01   <none>           <none>
nginx-configmap           1/1     Running   0          119m   192.168.85.238   k8s-node01   <none>           <none>
pod-secret-volume         1/1     Running   0          41s    192.168.85.229   k8s-node01   <none>           <none>

查看secret信息

[root@k8s-master01 secret]#  kubectl exec -it pod-secret-volume -- /bin/sh
/ # cd /etc/secret/
/etc/secret # ls
password  username
/etc/secret # cat username 
admin
/etc/secret # cat password 
1f2d1e2e67df

由上可见,在pod中的secret信息实际已经被解密。

将Secret导入到环境变量中

yaml文件

[root@k8s-master01 secret]# pwd
/root/k8s_practice/secret

[root@k8s-master01 secret]# cat pod_secret_env.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-secret-env
spec:
  containers:
  - name: myapp
    image: registry.cn-beijing.aliyuncs.com/google_registry/myapp:v1
    env:
    - name: SECRET_USERNAME
      valueFrom:
        secretKeyRef:
          name: mysecret
          key: username
    - name: SECRET_PASSWORD
      valueFrom:
        secretKeyRef:
          name: mysecret
          key: password
  restartPolicy: Never

启动pod并查看状态

[root@k8s-master01 secret]# kubectl apply -f pod_secret_env.yaml
pod/pod-secret-env created
[root@k8s-master01 secret]# kubectl get pod -o wide
NAME                      READY   STATUS    RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATES
daemonset-example-5sjhf   1/1     Running   0          11h     192.168.85.244   k8s-node01   <none>           <none>
frontend-4crh5            1/1     Running   0          11h     192.168.85.239   k8s-node01   <none>           <none>
frontend-n4z6w            1/1     Running   0          11h     192.168.85.213   k8s-node01   <none>           <none>
frontend-pmcrm            1/1     Running   0          11h     192.168.85.235   k8s-node01   <none>           <none>
nginx-configmap           1/1     Running   0          126m    192.168.85.238   k8s-node01   <none>           <none>
pod-secret-env            1/1     Running   0          19s     192.168.85.240   k8s-node01   <none>           <none>

查看secret信息

[root@k8s-master01 secret]# kubectl exec -it pod-secret-env -- /bin/sh
/ # env
MYAPP_SVC_PORT_80_TCP_ADDR=10.98.57.156
MYAPP_SERVICE_PORT_HTTP=80
KUBERNETES_PORT=tcp://10.20.0.1:443
KUBERNETES_SERVICE_PORT=443
MYAPP_SVC_PORT_80_TCP_PORT=80
HOSTNAME=pod-secret-env
SHLVL=1
MYAPP_SVC_PORT_80_TCP_PROTO=tcp
HOME=/root
MYAPP_SERVICE_HOST=10.20.179.180
SECRET_PASSWORD=1f2d1e2e67df
MYAPP_SVC_PORT_80_TCP=tcp://10.98.57.156:80
MYAPP_SERVICE_PORT=80
MYAPP_PORT=tcp://10.20.179.180:80
TERM=xterm
NGINX_VERSION=1.12.2
KUBERNETES_PORT_443_TCP_ADDR=10.20.0.1
MYAPP_PORT_80_TCP_ADDR=10.20.179.180
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
MYAPP_PORT_80_TCP_PORT=80
MYAPP_PORT_80_TCP_PROTO=tcp
MYAPP_SVC_SERVICE_HOST=10.98.57.156
SECRET_USERNAME=admin

KUBERNETES_PORT_443_TCP=tcp://10.20.0.1:443
KUBERNETES_SERVICE_PORT_HTTPS=443
PWD=/
MYAPP_PORT_80_TCP=tcp://10.20.179.180:80
KUBERNETES_SERVICE_HOST=10.20.0.1
MYAPP_SVC_SERVICE_PORT=80
MYAPP_SVC_PORT=tcp://10.98.57.156:80

由上可见,在pod中的secret信息实际已经被解密。

docker-registry Secret

harbor镜像仓库

首先使用harbor搭建镜像仓库,搭建部署过程参考:「Harbor企业级私有Docker镜像仓库部署

harbor部分配置文件信息

[root@linux harbor]# pwd
/root/harbor/harbor
[root@linux harbor]# cat harbor.yml
# Configuration file of Harbor

# The IP address or hostname to access admin UI and registry service.
# DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients.
hostname: 192.168.18.131

# http related config
http:
  # port for http, default is 80. If https enabled, this port will redirect to https port
  port: 5000

# https related config
https:
  # https port for harbor, default is 443
  port: 443
  # The path of cert and key files for nginx
  certificate: /etc/harbor/cert/httpd.crt
  private_key: /etc/harbor/cert/httpd.key

# # Uncomment following will enable tls communication between all harbor components
# internal_tls:
#   # set enabled to true means internal tls is enabled
#   enabled: true
#   # put your cert and key files on dir
#   dir: /etc/harbor/tls/internal

# Uncomment external_url if you want to enable external proxy
# And when it enabled the hostname will no longer used
# external_url: https://reg.mydomain.com:8433

# The initial password of Harbor admin
# It only works in first time to install harbor
# Remember Change the admin password from UI after launching Harbor.
harbor_admin_password: Harbor12345

# Harbor DB configuration
database:
  # The password for the root user of Harbor DB. Change this before any production use.
  password: root123
  # The maximum number of connections in the idle connection pool. If it <=0, no idle connections are retained.
  max_idle_conns: 50
  # The maximum number of open connections to the database. If it <= 0, then there is no limit on the number of open connections.
  # Note: the default number of connections is 1024 for postgres of harbor.
  max_open_conns: 1000

# The default data volume
data_volume: /data

启动harbor后客户端http设置
集群所有机器都要操作

所有客户端都需要添加这个配置,然后重启 docker 服务。

[root@k8s-master01 ~]# vim /etc/docker/daemon.json
{
    "exec-opts": ["native.cgroupdriver=systemd"],
    "log-driver": "json-file",
    "log-opts": {
    "max-size": "100m"
    },
    "storage-driver": "overlay2",
    "registry-mirrors":[
        "https://kfwkfulq.mirror.aliyuncs.com",
        "https://2lqq34jg.mirror.aliyuncs.com",
        "https://pee6w651.mirror.aliyuncs.com",
        "http://hub-mirror.c.163.com",
        "https://docker.mirrors.ustc.edu.cn",
        "https://registry.docker-cn.com"
    ],
    "insecure-registries": ["192.168.18.131:5000"]
}

添加了 “insecure-registries”: [“192.168.18.131:5000”] 这行,其中192.168.18.131为内网IP地址。该文件必须符合 json 规范,否则 Docker 将不能启动。

systemctl daemon-reload
systemctl restart docker

如果在Harbor所在的机器重启了docker服务,记得要重新启动Harbor。

创建「私有」仓库
image.png
镜像上传

docker pull registry.cn-beijing.aliyuncs.com/google_registry/myapp:v1
docker tag registry.cn-beijing.aliyuncs.com/google_registry/myapp:v1 192.168.18.131:5000/k8s-secret/myapp:v1
# 登录
docker login 192.168.18.131:5000 -u admin -p Harbor12345
# 上传
docker push 192.168.18.131:5000/k8s-secret/myapp:v1

image.png

退出登录
之后在操作机上退出harbor登录,便于后面演示

### 退出harbor登录
[root@k8s-node02 ~]# docker logout 192.168.18.131:5000  
Removing login credentials for 192.168.18.131:5000

### 拉取失败,需要先登录。表明完成准备工作
[root@k8s-master secret]# docker pull 192.168.18.131:5000/k8s-secret/myapp:v1
Error response from daemon: unauthorized: unauthorized to access repository: k8s-secret/myapp, action: pull: unauthorized to access repository: k8s-secret/myapp, action: pull

pod直接下载镜像

在yaml文件中指定image后,直接启动pod

[root@k8s-master01 secret]# pwd
/root/k8s_practice/secret
[root@k8s-master01 secret]# cat pod_secret_registry.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-secret-registry
spec:
  containers:
  - name: myapp
    image: 192.168.18.131:5000/k8s-secret/myapp:v1

启动pod并查看状态

[root@k8s-master01 secret]# kubectl apply -f pod_secret_registry.yaml 
pod/pod-secret-registry created

[root@k8s-master01 secret]# kubectl get pod -o wide     ### 可见镜像下载失败
NAME                      READY   STATUS             RESTARTS   AGE    IP               NODE         NOMINATED NODE   READINESS GATES
daemonset-example-5sjhf   1/1     Running            1          11h    192.168.85.233   k8s-node01   <none>           <none>
frontend-4crh5            1/1     Running            1          11h    192.168.85.216   k8s-node01   <none>           <none>
frontend-n4z6w            1/1     Running            1          11h    192.168.85.227   k8s-node01   <none>           <none>
frontend-pmcrm            1/1     Running            1          11h    192.168.85.236   k8s-node01   <none>           <none>
nginx-configmap           1/1     Running            1          147m   192.168.85.247   k8s-node01   <none>           <none>
pod-secret-env            0/1     Completed          0          21m    192.168.85.240   k8s-node01   <none>           <none>
pod-secret-registry       0/1     ImagePullBackOff   0          12s    192.168.85.245   k8s-node01   <none>           <none>
pod-secret-volume         1/1     Running            1          28m    192.168.85.237   k8s-node01   <none>           <none>

[root@k8s-master01 secret]# kubectl describe pod pod-secret-registry     ### 查看pod详情
Name:         pod-secret-registry
Namespace:    default
Priority:     0
Node:         k8s-node01/192.168.18.130
Start Time:   Wed, 28 Apr 2021 08:21:36 +0800
Labels:       <none>
Annotations:  cni.projectcalico.org/podIP: 192.168.85.245/32
              kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"pod-secret-registry","namespace":"default"},"spec":{"containers":[{"i...
Status:       Pending
IP:           192.168.85.245
IPs:
  IP:  192.168.85.245
Containers:
  myapp:
    Container ID:   
    Image:          192.168.18.131:5000/k8s-secret/myapp:v1
    Image ID:       
    Port:           <none>
    Host Port:      <none>
    State:          Waiting
      Reason:       ImagePullBackOff
    Ready:          False
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-k2f44 (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             False 
  ContainersReady   False 
  PodScheduled      True 
Volumes:
  default-token-k2f44:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-k2f44
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type     Reason     Age                From                 Message
  ----     ------     ----               ----                 -------
  Normal   Scheduled  <unknown>          default-scheduler    Successfully assigned default/pod-secret-registry to k8s-node01
  Normal   BackOff    21s (x2 over 22s)  kubelet, k8s-node01  Back-off pulling image "192.168.18.131:5000/k8s-secret/myapp:v1"
  Warning  Failed     21s (x2 over 22s)  kubelet, k8s-node01  Error: ImagePullBackOff
  Normal   Pulling    5s (x2 over 22s)   kubelet, k8s-node01  Pulling image "192.168.18.131:5000/k8s-secret/myapp:v1"
  Warning  Failed     5s (x2 over 22s)   kubelet, k8s-node01  Failed to pull image "192.168.18.131:5000/k8s-secret/myapp:v1": rpc error: code = Unknown desc = Error response from daemon: unauthorized: unauthorized to access repository: k8s-secret/myapp, action: pull: unauthorized to access repository: k8s-secret/myapp, action: pull
  Warning  Failed     5s (x2 over 22s)   kubelet, k8s-node01  Error: ErrImagePul

可见拉取私有镜像失败。

pod通过Secret下载镜像

通过命令行创建Secret,并查看其描述信息

[root@k8s-master01 secret]# kubectl create secret docker-registry myregistrysecret --docker-server='192.168.18.131:5000' --docker-username='admin' --docker-password='Harbor12345' 
secret/myregistrysecret created

[root@k8s-master01 secret]# kubectl get secret 
NAME                  TYPE                                  DATA   AGE
db-user-pass          Opaque                                2      35m
default-token-k2f44   kubernetes.io/service-account-token   3      22d
myregistrysecret      kubernetes.io/dockerconfigjson        1      25s
mysecret              Opaque                                2      34m

[root@k8s-master01 secret]# kubectl get secret myregistrysecret -o yaml     ### 查看详细信息
apiVersion: v1
data:
  .dockerconfigjson: eyJhdXRocyI6eyIxOTIuMTY4LjE4LjEzMTo1MDAwIjp7InVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6IkhhcmJvcjEyMzQ1IiwiYXV0aCI6IllXUnRhVzQ2U0dGeVltOXlNVEl6TkRVPSJ9fX0=
kind: Secret
metadata:
  creationTimestamp: "2021-04-28T00:24:03Z"
  name: myregistrysecret
  namespace: default
  resourceVersion: "154358"
  selfLink: /api/v1/namespaces/default/secrets/myregistrysecret
  uid: 317d6799-337e-4eda-9002-23707c13f8e4
type: kubernetes.io/dockerconfigjson


[root@k8s-master01 secret]# kubectl describe secret myregistrysecret     ### 查看描述信息
Name:         myregistrysecret
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  kubernetes.io/dockerconfigjson

Data
====
.dockerconfigjson:  113 bytes

修改之前的yaml文件

[root@k8s-master01 secret]# cat pod_secret_registry.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-secret-registry
spec:
  containers:
  - name: myapp
    image: 192.168.18.131:5000/k8s-secret/myapp:v1
  imagePullSecrets:
    - name: myregistrysecret

启动pod并查看状态

[root@k8s-master01 secret]# kubectl get pod -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
daemonset-example-mvptr   1/1     Running   0          79s   192.168.85.255   k8s-node01   <none>           <none>
frontend-6jpsr            1/1     Running   0          97s   192.168.85.200   k8s-node01   <none>           <none>
frontend-6tzs6            1/1     Running   0          97s   192.168.85.250   k8s-node01   <none>           <none>
frontend-lvsdl            1/1     Running   0          97s   192.168.85.253   k8s-node01   <none>           <none>
pod-secret-registry       1/1     Running   0          31s   192.168.85.202   k8s-node01   <none>           <none>


[root@k8s-master01 secret]# kubectl describe pod pod-secret-registry
Name:         pod-secret-registry
Namespace:    default
Priority:     0
Node:         k8s-node01/192.168.18.130
Start Time:   Wed, 28 Apr 2021 08:29:06 +0800
Labels:       <none>
Annotations:  cni.projectcalico.org/podIP: 192.168.85.202/32
              kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"pod-secret-registry","namespace":"default"},"spec":{"containers":[{"i...
Status:       Running
IP:           192.168.85.202
IPs:
  IP:  192.168.85.202
Containers:
  myapp:
    Container ID:   docker://a86ddde7e21a47110ae8117c5f359ab160de9fd67cea5cc4e9254c7355ef7efa
    Image:          192.168.18.131:5000/k8s-secret/myapp:v1
    Image ID:       docker-pullable://192.168.18.131:5000/k8s-secret/myapp@sha256:9eeca44ba2d410e54fccc54cbe9c021802aa8b9836a0bcf3d3229354e4c8870e
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Wed, 28 Apr 2021 08:29:07 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-k2f44 (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  default-token-k2f44:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-k2f44
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age        From                 Message
  ----    ------     ----       ----                 -------
  Normal  Scheduled  <unknown>  default-scheduler    Successfully assigned default/pod-secret-registry to k8s-node01
  Normal  Pulling    40s        kubelet, k8s-node01  Pulling image "192.168.18.131:5000/k8s-secret/myapp:v1"
  Normal  Pulled     40s        kubelet, k8s-node01  Successfully pulled image "192.168.18.131:5000/k8s-secret/myapp:v1"
  Normal  Created    40s        kubelet, k8s-node01  Created container myapp
  Normal  Started    40s        kubelet, k8s-node01  Started container myapp

由上可见,通过secret认证后pod拉取私有镜像是可以的。