OpenShift 4 - 了解Secret

OpenShift 4.x HOL教程汇总

关于Secret对象

和ConfigMap对象用来保存明文格式的参数不同,Kubernetes 的 Secret 对象类型是用来保存敏感信息的,这些敏感信息包括:密码、登录凭证、OAuth 令牌和ssh key等。

三种途径创建Secret对象

执行以下命令查看创建secret的三种方法(子命令)。

$ oc create secret --help
Create a secret using specified subcommand.
 
Usage:
  oc create secret [flags]
 
Available Commands:
  docker-registry Create a secret for use with a Docker registry
  generic         Create a secret from a local file, directory or literal value
  tls             Create a TLS secret
 
Use "oc <command> --help" for more information about a given command.
Use "oc options" for a list of global command-line options (applies to all commands).

从说明可以看出这三种不同子命令适用不同情况:

  1. generic:使用命令参数或文件创建secret。OpenShift支持的文件有以下类型:key-value键值对文件、docker或podman登录Registry的身份凭证文件、git客户端登录git服务器的身份凭证文件等。
  2. docker-registry:使用docker或podman登录Registry,然后用生成的身份凭证创建secret。注意,当还没有身份凭证文件的时候使用该命令,如果本地已经有了访问Registry的身份凭证文件,则还是使用“generic”子命令生成secret对象(在后面有例子)。
  3. tls:使用公钥/私钥证书对创建secret。

Secret对象的结构

我们在Secret对象中可以使用type指定key和value的结构。当使用以下特定类型secret的时候服务器会验证其结构是否有效:

  • kubernetes.io/service-account-token:使用serviceaccount令牌的secret。
  • kubernetes.io/basic-auth. 使用基本(用户名/密码)认证的secret
  • kubernetes.io/ssh-auth. 使用SSH Key认证的secret
  • kubernetes.io/tls. 使用TLS 证书的secret
  • kubernetes.io/dockercfg. 使用docker的 .dockercfg 文件required Docker credentials.
  • kubernetes.io/dockerconfigjson. 使用docker的 .docker/config.json 文件 for required Docker credentials.

在Secret中可以指定“type=Opaque”,这样secret就会使用通用结构保存key-value对,而不验证其结构的有效性。

执行以下命令,查看一个新建项目的secret对象。OpenShift缺省为每个项目创建如下几个secret,注意它们的类型。

$ oc new-project my-secret
$ oc get secret -n my-secret
NAME                       TYPE                                  DATA   AGE
builder-dockercfg-cjng2    kubernetes.io/dockercfg               1      30h
builder-token-s28sk        kubernetes.io/service-account-token   4      30h
builder-token-tx7fv        kubernetes.io/service-account-token   4      30h
default-dockercfg-2cqn5    kubernetes.io/dockercfg               1      30h
default-token-4k7vk        kubernetes.io/service-account-token   4      30h
default-token-ntgp2        kubernetes.io/service-account-token   4      30h
deployer-dockercfg-khptz   kubernetes.io/dockercfg               1      30h
deployer-token-h76xc       kubernetes.io/service-account-token   4      30h
deployer-token-mdlcl       kubernetes.io/service-account-token   4      30h

创建Secret对象

一般结构Secret

通过命令创建Secret

  1. 执行命令,创建记录username和password的generic类型的secret对象。
$ echo -n 'admin' > ./username.txt
$ echo -n '1f2d1e2e67df' > ./password.txt
$ kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt
secret/db-user-pass created
  1. 查看生成的secret对象。注意此时Type类型是Opaque,另外Data的长度分别是12 bytes和5 bytes,这是没有base64编码之前原文的长度。
$ oc describe secrets/db-user-pass
Name:         db-user-pass
Namespace:    my-secret
Labels:       <none>
Annotations:  <none>
 
Type:  Opaque
 
Data
====
password.txt:  12 bytes
username.txt:  5 bytes
  1. 执行命令查看secrets/db-user-pass对象,确认在secret对象的data中保存的变量值为base64后的字符串。
$ oc get secrets/db-user-pass -oyaml
apiVersion: v1
data:
  password.txt: MWYyZDFlMmU2N2Rm
  username.txt: YWRtaW4=
kind: Secret
metadata:
  creationTimestamp: "2020-09-28T00:40:58Z"
  name: db-user-pass
  namespace: my-secret
  resourceVersion: "406667"
  selfLink: /api/v1/namespaces/my-secret/secrets/db-user-pass
  uid: 17f96d35-b753-4062-9518-a505fb04ec3f
 
$ echo 'MWYyZDFlMmU2N2Rm' | base64 -d
1f2d1e2e67df
$ echo 'YWRtaW4=' | base64 -d
admin

通过YAML创建Secret

在定义secret对象的YAML中可以使用data和stringData定义需要记录的内容,它们的区别如下:

  1. 如果直接用YAML创建secret对象,可以先将字符串做base64编码。
$ echo -n 'admin' | base64
YWRtaW4=
$ echo -n '1f2d1e2e67df' | base64
MWYyZDFlMmU2N2Rm
  1. 创建内容如下的mysecret1.yaml文件,其中username和password是base64后的内容。
apiVersion: v1
kind: Secret
metadata:
  name: mysecret1
type: Opaque
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm
  1. 执行命令,创建secret对象。
$ oc apply -f ./mysecret1.yaml
secret/mysecret1 created
  1. 在YAML中除了在data中使用base64编码字符串外,还可以在stringData中直接使用明文,OpenShift会在创建secret的时候自动进行base64编码。
  2. 创建内容如下的mysecret2.yaml文件,注意config.yaml的key和后面的value都是明文,它们都属于stringData。
apiVersion: v1
kind: Secret
metadata:
  name: mysecret2
type: Opaque
stringData:
  config.yaml: |-
    apiUrl: "https://my.api.com/api/v1"
    username: "username"
    password: "password"
  1. 执行命令创建mysecret2,然后确认config.yaml后的value已经被自动base64编码了。
$ oc apply -f ./mysecret2.yaml
secret/mysecret2 created
$ oc get secret/mysecret2 -oyaml
apiVersion: v1
kind: Secret
type: Opaque
data:
  config.yaml: YXBpVXJsOiAiaHR0cHM6Ly9teS5hcGkuY29tL2FwaS92MSIKdXNlcm5hbWU6ICJ1c2VybmFtZSIKcGFzc3dvcmQ6ICJwYXNzd29yZCI=
metadata:
  name: mysecret2
  namespace: my-secret
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{},"name":"mysecret2","namespace":"my-secret"},"stringData":{"config.yaml":"apiUrl: \"https://my.api.com/api/v1\"\nusername: \"username\"\npassword: \"password\""},"type":"Opaque"}
  creationTimestamp: "2020-09-28T01:27:32Z"
  resourceVersion: "2092932"
  selfLink: /api/v1/namespaces/my-secret/secrets/mysecret2
  uid: 8db8a8c0-51c7-4904-9eb5-ff956282cf72
  1. 创建内容如下的mysecret3.yaml文件。确认username同时在data和stringData都有。
apiVersion: v1
kind: Secret
metadata:
  name: mysecret3
type: Opaque
data:
  username: YWRtaW4=
stringData:
  username: administrator
  1. 执行名创建mysecret3对象,然后确认此时username的内容是通过stringData定义的内容,这说明stringData的内容会覆盖data中相同key的内容。
$ oc get secret/mysecret3 -oyaml
apiVersion: v1
data:
  username: YWRtaW5pc3RyYXRvcg==
kind: Secret
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","data":{"username":"YWRtaW4="},"kind":"Secret","metadata":{"annotations":{},"name":"mysecret3","namespace":"my-secret"},"stringData":{"username":"administrator"},"type":"Opaque"}
  creationTimestamp: "2020-09-28T02:08:23Z"
。。。 

$ echo 'YWRtaW5pc3RyYXRvcg==' | base64 -d
administrator

属于dockerconfigjson或dockercfg类型的pull-secret

pull-secret是Kubernetes中专门用来访问Registry的secet。我们可以把pull-secret看成是一种“特定”类型的secret。pull-secret本身的类型有可能是kubernetes.io/dockerconfigjson或kubernetes.io/dockercfg(取决于secret对象是从本地的.docker/config.json文件还是.dockercfg生成的)。

我们可以使用以下三种方式创建pull-secret,其中第一种方法是用USERNAME和PASSWORD直接访问REGISTRY_SERVER,在此过程中会先在本地生成.docker/config.json文件并基于它生成pull-secret。而后两种方法是直接使用本地已有的身份凭证文件.docker/config.json或.dockercfg(当docker或podman在首次访问Registry的时候会将身份凭证保存在文件中)。

$ oc create secret docker-registry <PULL_SECRET_NAME> \
    --docker-server=<REGISTRY_SERVER> \
    --docker-username=<USERNAME> \
    --docker-password=<PASSWORD> \
    --docker-email=<EMAIL>

$ oc create secret generic <PULL_SECRET_NAME> \
    --from-file=.dockerconfigjson=<PATH/.docker/config.json> \
    --type=kubernetes.io/dockerconfigjson

$ oc create secret generic <PULL_SECRET_NAME> \
    --from-file=.dockercfg=<PATH/.dockercfg> \
    --type=kubernetes.io/dockercfg
  1. 执行命令创建一个访问registry.redhat.io的pull-secret。注意:用户名和密码是随意写的,这说明在创建secret的时候不会验证该用户名和密码是否有效。
$ oc create secret docker-registry registry-redhat-secret \
    --docker-server=registry.redhat.io \
    --docker-username=user1 \
    --docker-password=password1
  1. 查看registry-redhat-secret对象的内容,确认“.dockerconfigjson”后是经过base64编码的访问凭证。
$ oc get secret registry-redhat-secret -o yaml
apiVersion: v1
data:
  .dockerconfigjson: 4oCYe2F1dGhzOnt5b3VyLnJ........
kind: Secret
metadata:
  ...
  name: <PULL_SECRET_NAME>
  ...
type: kubernetes.io/dockerconfigjson
  1. 执行以下命令将“.dockerconfigjson”内容解析出来,确认内容就是前面生成secret所使用的访问Registry的相关信息。
$ oc get secret PULL_SECRET_NAME --output="jsonpath={.data.\.dockerconfigjson}" | base64 --decode
{"auths":{"your.registry.com":{"username":"user1","password":"password1","email":"","auth":"dXNlcjE6cGFzc3dvcmQxCg=="}}}
  1. 执行命令再将auth的内容解析出来,确认就是用户名和密码的组合。
$ echo "dXNlcjE6cGFzc3dvcmQxCg==" | base64 --decode
user1:password1

basic-auth类型secret

basic-auth类型secret是由username和password、或者token组成。

$ oc create secret generic <secret_name> \
    --from-literal=username=<user_name> \
    --from-literal=password=<password> \
    --type=kubernetes.io/basic-auth
 
$ oc create secret generic <secret_name> \
    --from-literal=password=<token> \
    --type=kubernetes.io/basic-auth

ssh-auth类型secret

ssh-auth使用ssh私钥生成secret。以下以访问git

  1. 执行以下命令,全部采用缺省内容生成ssh密钥对。
$ ssh-keygen -t rsa -C "your_email@example.com"
  1. 在打算用secret登录的目标环境中导入生成的公钥。
  2. 执行命令,基于私钥生成secret。
$ oc create secret generic <SECRET_NAME> \
    --from-file=ssh-privatekey=/path/to/.ssh/id_rsa \
    --from-file=ssh-publickey=/path/to/.ssh/id_rsa.pub 
    --type=kubernetes.io/ssh-auth
  1. 基于以下YAML创建Pod。其中将<SECRET_NAME>的内容挂载到“/etc/secret-volume”下。
apiVersion: v1
kind: Pod
metadata:
  name: secret-test-pod
  labels:
    name: secret-test
spec:
  volumes:
  - name: secret-volume
    secret:
      secretName: <SECRET_NAME>
  containers:
  - name: ssh-test-container
    image: mySshImage
    volumeMounts:
    - name: secret-volume
      readOnly: true
      mountPath: "/etc/secret-volume"
  1. 此后就可以在Pod中用/etc/secret-volume/ssh-privatekey建立SSH链接。

引用或使用Secret中内容

从Secret中解析出其内容

  1. 执行命令,将前面创建的secret/db-user-pass中的所有内容解析出来,输出到STOUT。
$ oc extract secret/db-user-pass --to=-
# password.txt
1f2d1e2e67df
# username.txt
admin
  1. 使用以下命令,将secret/db-user-pass中的所有内容解析出来,并保存到db-user-pass目录下。
$ mkdir db-user-pass && oc extract secret/db-user-pass --to=./db-user-pass
db-user-pass/password.txt
db-user-pass/username.txt

在Pod中通过挂载存储使用Secret

  1. 创建内容如下的my-redis.yaml文件。其中将mysecret挂载到pod中的/etc/foo下面的子目录中。
apiVersion: v1
kind: Pod
metadata:
  name: my-redis
spec:
  containers:
  - name: my-redis
    image: redis
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    secret:
      secretName: mysecret
      items:
      - key: username
        path: my-group/my-username
  1. 执行命令创建pod。然后进入该pod,并在相应目录中查看secret的内容。
$ oc apply -f my-redis.yaml
pod/my-redis created
 
$ oc rsh my-redis
# ls -l /etc/foo/my-group/my-username
-rw-r--r--. 1 root root 5 Sep 28 02:47 /etc/foo/my-group/my-username
# cat /etc/foo/my-group/my-username
admin

在Pod中通过环境变量使用Secret

  1. 创建内容如下的my-redis-env.yaml文件,其中在pod中通过SECRET_USERNAME和SECRET_PASSWORD环境变量分别引用了前面创建的mysecret对象中的username和password。
apiVersion: v1
kind: Pod
metadata:
  name: secret-env-pod
spec:
  containers:
  - name: mycontainer
    image: redis
    env:
      - name: SECRET_USERNAME
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: username
      - name: SECRET_PASSWORD
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: password
  1. 执行命令,根据my-redis-env.yaml创建pod对象。然后进入这个pod,并查看SECRET_USERNAME和SECRET_PASSWORD两个环境变量应该已经有内容了。
$ oc apply -f my-redis-env.yaml
pod/secret-env-pod created
 
$ oc rsh secret-env-pod
# echo $SECRET_USERNAME
admin
# echo $SECRET_PASSWORD
1f2d1e2e67df

在Pod中使用pull_secret

通过以下方式可以在pod中引用名为“PULL_SECRET_NAME”的pull_secret。

apiVersion: v1
kind: Pod
metadata:
  name: foo
spec:
  containers:
    - name: foo
      image: your.registry.com/REPOSITORY/IMAGE:TAG
  imagePullSecrets:
    - name: <PULL_SECRET_NAME>

在ServiceAccount中使用secret和pull-secret

  1. 执行命令,查看项目中名为default的SerivceAccount的配置,确认其引用了2个secret和一个“imagePullSecrets”。
$ oc get sa default -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: "2020-09-28T01:05:49Z"
  name: default
  namespace: my-secret
  resourceVersion: "2077534"
  selfLink: /api/v1/namespaces/my-secret/serviceaccounts/default
  uid: c3f4429b-56be-4414-9e7c-1782d3d9ad2a
secrets:
-- name: default-dockercfg-2cqn5
-- name: default-token-ntgp2
imagePullSecrets:
-- name: default-dockercfg-2cqn5
  1. 执行命令查看前面创建的名为my-redis的Pod的配置。然后确认“volumes”部分除了有主动声明挂载的mysecret对象(只包含username),OpenShift还自动挂载了名为default-token-ntgp2的secret对象。
$ oc get pod my-redis -oyaml
。。。
  volumes:
  - name: foo
    secret:
      defaultMode: 420
      items:
      - key: username
        path: my-group/my-username
      secretName: mysecret
  - name: default-token-ntgp2
    secret:
      defaultMode: 420
      secretName: default-token-ntgp2
。。。
  1. 执行命令,进入在前面创建的名为my-redis的Pod,然后查看“/var/run/secrets/kubernetes.io/serviceaccount/”目录,确认有名为“ca.crt”、“namespace”、“service-ca.crt”和“token”的4个文件和对应的link。这4个就是OpenShift自动将项目中名为default的ServiceAccount中的secret注入到新建的Pod里面的键值对。
$ oc rsh my-redis
# ls -al /var/run/secrets/kubernetes.io/serviceaccount/
total 0
drwxrwxrwt. 3 root root 160 Sep 29 06:26 .
drwxr-xr-x. 3 root root  60 Sep 29 06:26 ..
drwxr-xr-x. 2 root root 120 Sep 29 06:26 ..2020_09_29_06_26_16.707525435
lrwxrwxrwx. 1 root root  31 Sep 29 06:26 ..data -> ..2020_09_29_06_26_16.707525435
lrwxrwxrwx. 1 root root  13 Sep 29 06:26 ca.crt -> ..data/ca.crt
lrwxrwxrwx. 1 root root  16 Sep 29 06:26 namespace -> ..data/namespace
lrwxrwxrwx. 1 root root  21 Sep 29 06:26 service-ca.crt -> ..data/service-ca.crt
lrwxrwxrwx. 1 root root  12 Sep 29 06:26 token -> ..data/token
  1. 执行命令,查看名为default的ServiceAccount所用到的名为“default-token-XXXX”的secret。确认其中包含的键值对即为上一步被my-redis Pod所引用的4个键值对。
$ oc get secret default-token-ntgp2 -oyaml

参考

https://kubernetes.io/zh/docs/concepts/configuration/secret/
https://docs.openshift.com/container-platform/4.5/openshift_images/managing_images/using-image-pull-secrets.html
https://docs.openshift.com/container-platform/4.4/builds/creating-build-inputs.html#builds-secrets-overview_creating-build-inputs
https://www.qikqiak.com/k8strain/config/serviceaccount/

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值