文章目录
关于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).
从说明可以看出这三种不同子命令适用不同情况:
- generic:使用命令参数或文件创建secret。OpenShift支持的文件有以下类型:key-value键值对文件、docker或podman登录Registry的身份凭证文件、git客户端登录git服务器的身份凭证文件等。
- docker-registry:使用docker或podman登录Registry,然后用生成的身份凭证创建secret。注意,当还没有身份凭证文件的时候使用该命令,如果本地已经有了访问Registry的身份凭证文件,则还是使用“generic”子命令生成secret对象(在后面有例子)。
- 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
- 执行命令,创建记录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
- 查看生成的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
- 执行命令查看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定义需要记录的内容,它们的区别如下:
- 如果直接用YAML创建secret对象,可以先将字符串做base64编码。
$ echo -n 'admin' | base64
YWRtaW4=
$ echo -n '1f2d1e2e67df' | base64
MWYyZDFlMmU2N2Rm
- 创建内容如下的mysecret1.yaml文件,其中username和password是base64后的内容。
apiVersion: v1
kind: Secret
metadata:
name: mysecret1
type: Opaque
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
- 执行命令,创建secret对象。
$ oc apply -f ./mysecret1.yaml
secret/mysecret1 created
- 在YAML中除了在data中使用base64编码字符串外,还可以在stringData中直接使用明文,OpenShift会在创建secret的时候自动进行base64编码。
- 创建内容如下的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"
- 执行命令创建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
- 创建内容如下的mysecret3.yaml文件。确认username同时在data和stringData都有。
apiVersion: v1
kind: Secret
metadata:
name: mysecret3
type: Opaque
data:
username: YWRtaW4=
stringData:
username: administrator
- 执行名创建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
- 执行命令创建一个访问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
- 查看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
- 执行以下命令将“.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=="}}}
- 执行命令再将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
- 执行以下命令,全部采用缺省内容生成ssh密钥对。
$ ssh-keygen -t rsa -C "your_email@example.com"
- 在打算用secret登录的目标环境中导入生成的公钥。
- 执行命令,基于私钥生成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
- 基于以下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"
- 此后就可以在Pod中用/etc/secret-volume/ssh-privatekey建立SSH链接。
引用或使用Secret中内容
从Secret中解析出其内容
- 执行命令,将前面创建的secret/db-user-pass中的所有内容解析出来,输出到STOUT。
$ oc extract secret/db-user-pass --to=-
# password.txt
1f2d1e2e67df
# username.txt
admin
- 使用以下命令,将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
- 创建内容如下的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
- 执行命令创建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
- 创建内容如下的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
- 执行命令,根据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
- 执行命令,查看项目中名为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
- 执行命令查看前面创建的名为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
。。。
- 执行命令,进入在前面创建的名为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
- 执行命令,查看名为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/