3.6. 输入 secret 和配置映射
要防止输入 secret 和配置映射的内容出现在构建输出容器镜像中,请使用 Docker 构建和源至镜像构建策略中的构建 卷。
有时候,构建操作需要凭证或其他配置数据才能访问依赖的资源,但又不希望将这些信息放在源代码控制中。您可以定义输入 secret 和输入配置映射。
例如,在使用 Maven 构建 Java 应用程序时,可以设置通过私钥访问的 Maven Central 或 JCenter 的私有镜像。要从该私有镜像下载库,您必须提供以下内容:
-
配置了镜像的 URL 和连接设置的
settings.xml
文件。 -
设置文件中引用的私钥,例如
~/.ssh/id_rsa
。
为安全起见,不应在应用程序镜像中公开您的凭证。
示例中描述的是 Java 应用程序,但您可以使用相同的方法将 SSL 证书添加到 /etc/ssl/certs
目录,以及添加 API 密钥或令牌、许可证文件等。
3.6.1. 什么是 secret?
Secret
对象类型提供了一种机制来保存敏感信息,如密码、OpenShift Container Platform 客户端配置文件、dockercfg
文件和私有源存储库凭证等。secret 将敏感内容与 Pod 分离。您可以使用卷插件将 secret 信息挂载到容器中,系统也可以使用 secret 代表 Pod 执行操作。
YAML Secret 对象定义
apiVersion: v1 kind: Secret metadata: name: test-secret namespace: my-namespace type: Opaque 1 data: 2 username: <username> 3 password: <password> stringData: 4 hostname: myapp.mydomain.com 5
3.6.1.1. secret 的属性
主要属性包括:
- Secret 数据可以独立于其定义来引用。
- Secret 数据卷由临时文件工具 (tmpfs) 支持,永远不会停留在节点上。
- secret 数据可以在命名空间内共享。
3.6.1.2. secret 的类型
type
字段中的值指明 secret 的键名称和值的结构。此类型可用于强制使 secret 对象中存在用户名和密钥。如果您不想进行验证,请使用 opaque
类型,这也是默认类型。
指定以下一种类型来触发最小服务器端验证,确保 secret 数据中存在特定的键名称:
-
kubernetes.io/service-account-token
。使用服务帐户令牌。 -
kubernetes.io/dockercfg
。将.dockercfg
文件用于所需的 Docker 凭证。 -
kubernetes.io/dockerconfigjson
。将.docker/config.json
文件用于所需的 Docker 凭证。 -
kubernetes.io/basic-auth
。与基本身份验证搭配使用。 -
kubernetes.io/ssh-auth
。搭配 SSH 密钥身份验证使用。 -
kubernetes.io/tls
。搭配 TLS 证书颁发机构使用。
如果不想进行验证,设置 type= Opaque
。这意味着,secret 不声明符合键名称或值的任何约定。opaque
secret 允许使用无结构 key:value
对,可以包含任意值。
您可以指定其他任意类型,如 example.com/my-secret-type
。这些类型不在服务器端强制执行,但代表 secret 的创建者意在符合该类型的键/值要求。
3.6.1.3. 更新 secret
当修改 secret 的值时,已在被运行的 Pod 使用的 secret 值不会被动态更新。要更改 secret,必须删除原始 pod 并创建一个新 pod,在某些情况下,具有相同的 PodSpec
。
更新 secret 遵循与部署新容器镜像相同的工作流。您可以使用 kubectl rolling-update
命令。
secret 中的 resourceVersion
值不在引用时指定。因此,如果在 pod 启动的同时更新 secret,则将不能定义用于 pod 的 secret 版本。
目前,无法检查 Pod 创建时使用的 secret 对象的资源版本。按照计划 Pod 将报告此信息,以便控制器可以重启使用旧 resourceVersion
的 Pod。在此期间,请勿更新现有 secret 的数据,而应创建具有不同名称的新数据。
3.6.2. 创建 secret
您必须先创建 secret,然后创建依赖于此 secret 的 Pod。
在创建 secret 时:
- 使用 secret 数据创建 secret 对象。
- 更新 pod 的服务帐户以允许引用该 secret。
-
创建以环境变量或文件(使用
secret
卷)形式消耗 secret 的 pod。
流程
要从 JSON 或 YAML 文件创建 secret 对象,请输入以下命令:
$ oc create -f <filename>
例如,您可以从本地的
.docker/config.json
文件创建一个 secret:$ oc create secret generic dockerhub \ --from-file=.dockerconfigjson=<path/to/.docker/config.json> \ --type=kubernetes.io/dockerconfigjson
此命令将生成名为
dockerhub
的 secret JSON 规格并创建该对象。YAML Opaque Secret 对象定义
apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque 1 data: username: <username> password: <password>
- 1
- 指定一个 opaque secret。
Docker 配置 JSON 文件对象定义
apiVersion: v1 kind: Secret metadata: name: aregistrykey namespace: myapps type: kubernetes.io/dockerconfigjson 1 data: .dockerconfigjson:bm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg== 2
3.6.3. 使用 secret
创建 secret 后,可以创建一个 Pod 来引用您的 secret,再获取日志,然后删除 Pod。
流程
输入以下命令创建 pod 来引用您的 secret:
$ oc create -f <your_yaml_file>.yaml
输入以下命令来获取日志:
$ oc logs secret-example-pod
输入以下命令删除 pod:
$ oc delete pod secret-example-pod
其他资源
带有 secret 数据的 YAML 文件示例:
将创建四个文件的 secret 的 YAML 文件
apiVersion: v1 kind: Secret metadata: name: test-secret data: username: <username> 1 password: <password> 2 stringData: hostname: myapp.mydomain.com 3 secret.properties: |- 4 property1=valueA property2=valueB
pod 的 YAML 文件使用 secret 数据填充卷中的文件
apiVersion: v1 kind: Pod metadata: name: secret-example-pod spec: containers: - name: secret-test-container image: busybox command: [ "/bin/sh", "-c", "cat /etc/secret-volume/*" ] volumeMounts: # name must match the volume name below - name: secret-volume mountPath: /etc/secret-volume readOnly: true volumes: - name: secret-volume secret: secretName: test-secret restartPolicy: Never
pod 的 YAML 文件使用 secret 数据填充环境变量
apiVersion: v1 kind: Pod metadata: name: secret-example-pod spec: containers: - name: secret-test-container image: busybox command: [ "/bin/sh", "-c", "export" ] env: - name: TEST_SECRET_USERNAME_ENV_VAR valueFrom: secretKeyRef: name: test-secret key: username restartPolicy: Never
BuildConfig
对象的 YAML 文件,用于在环境变量中填充 secret 数据apiVersion: build.openshift.io/v1 kind: BuildConfig metadata: name: secret-example-bc spec: strategy: sourceStrategy: env: - name: TEST_SECRET_USERNAME_ENV_VAR valueFrom: secretKeyRef: name: test-secret key: username
3.6.4. 添加输入 secret 和配置映射
要向构建提供凭证和其他配置数据,而不将其放在源控制中,您可以定义输入 secret 和输入配置映射。
在某些情况下,构建操作需要凭证或其他配置数据才能访问依赖的资源。要使该信息在不置于源控制中的情况下可用,您可以定义输入 secret 和输入配置映射。
流程
将输入 secret 和配置映射添加到现有的 BuildConfig
对象中:
如果
ConfigMap
对象不存在,请输入以下命令来创建它:$ oc create configmap settings-mvn \ --from-file=settings.xml=<path/to/settings.xml>
这会创建一个名为
settings-mvn
的新配置映射,其中包含settings.xml
文件的纯文本内容。提示您还可以应用以下 YAML 来创建配置映射:
apiVersion: core/v1 kind: ConfigMap metadata: name: settings-mvn data: settings.xml: | <settings> … # Insert maven settings here </settings>
如果
Secret
对象不存在,请输入以下命令来创建它:$ oc create secret generic secret-mvn \ --from-file=ssh-privatekey=<path/to/.ssh/id_rsa> \ --type=kubernetes.io/ssh-auth
这会创建一个名为
secret-mvn
的新 secret,其包含id_rsa
私钥的 base64 编码内容。提示您还可以应用以下 YAML 来创建输入 secret:
apiVersion: core/v1 kind: Secret metadata: name: secret-mvn type: kubernetes.io/ssh-auth data: ssh-privatekey: | # Insert ssh private key, base64 encoded
将配置映射和 secret 添加到现有
BuildConfig
对象的source
部分中:source: git: uri: https://github.com/wildfly/quickstart.git contextDir: helloworld configMaps: - configMap: name: settings-mvn secrets: - secret: name: secret-mvn
要在新
BuildConfig
对象中包含 secret 和配置映射,请输入以下命令:$ oc new-build \ openshift/wildfly-101-centos7~https://github.com/wildfly/quickstart.git \ --context-dir helloworld --build-secret “secret-mvn” \ --build-config-map "settings-mvn"
在构建期间,构建过程将
settings.xml
和id_rsa
文件复制到源代码所在的目录中。在 OpenShift Container Platform S2I 构建器镜像中,这是镜像的工作目录,使用Dockerfile
中的WORKDIR
指令设置。如果要指定其他目录,请在定义中添加destinationDir
:source: git: uri: https://github.com/wildfly/quickstart.git contextDir: helloworld configMaps: - configMap: name: settings-mvn destinationDir: ".m2" secrets: - secret: name: secret-mvn destinationDir: ".ssh"
您还可以输入以下命令在创建新
BuildConfig
对象时指定目标目录:$ oc new-build \ openshift/wildfly-101-centos7~https://github.com/wildfly/quickstart.git \ --context-dir helloworld --build-secret “secret-mvn:.ssh” \ --build-config-map "settings-mvn:.m2"
在这两种情况下,
settings.xml
文件都添加到构建环境的./.m2
目录中,而id_rsa
密钥则添加到./.ssh
目录中。
3.6.5. Source-to-Image 策略
采用 Source
策略时,所有定义的输入 secret 都复制到对应的 destinationDir
中。如果 destinationDir
留空,则 secret 会放置到构建器镜像的工作目录中。
当 destinationDir
是一个相对路径时,使用相同的规则。secret 放置在相对于镜像工作目录的路径中。如果构建器镜像中不存在 destinationDir
路径中的最终目录,则会创建该目录。destinationDir
中的所有上述目录都必须存在,否则会发生错误。
输入 secret 将以全局可写(具有 0666
权限)形式添加,并且在执行 assemble
脚本后其大小会被截断为零。也就是说,生成的镜像中会包括这些 secret 文件,但出于安全原因,它们将为空。
assemble
脚本完成后不会截断输入配置映射。
3.6.6. Docker 策略
采用 docker 策略时,您可以使用 Dockerfile 中的 ADD
和 COPY
指令,将所有定义的输入 secret 添加到容器镜像中。
如果没有为 secret 指定 destinationDir
,则文件将复制到 Dockerfile 所在的同一目录中。如果将一个相对路径指定为 destinationDir
,则 secret 复制到相对于 Dockerfile 位置的该目录中。这样,secret 文件可供 Docker 构建操作使用,作为构建期间使用的上下文目录的一部分。
引用 secret 和配置映射数据的 Dockerfile 示例
FROM centos/ruby-22-centos7 USER root COPY ./secret-dir /secrets COPY ./config / # Create a shell script that will output secrets and ConfigMaps when the image is run RUN echo '#!/bin/sh' > /input_report.sh RUN echo '(test -f /secrets/secret1 && echo -n "secret1=" && cat /secrets/secret1)' >> /input_report.sh RUN echo '(test -f /config && echo -n "relative-configMap=" && cat /config)' >> /input_report.sh RUN chmod 755 /input_report.sh CMD ["/bin/sh", "-c", "/input_report.sh"]
用户应该从最终的应用程序镜像中移除输入 secret,以便从该镜像运行的容器中不会存在这些 secret。但是,secret 仍然存在于它们添加到的层中的镜像本身内。这一移除是 Dockerfile 本身的一部分。
为防止输入 secret 和配置映射的内容出现在构建输出容器镜像中并完全避免此移除过程,请在 Docker 构建策略中使用构建卷。
3.6.7. Custom 策略
使用 Custom 策略时,所有定义的输入 secret 和配置映射都位于 /var/run/secrets/openshift.io/build
目录中的构建器容器中。自定义构建镜像必须正确使用这些 secret 和配置映射。使用 Custom 策略时,您可以按照 Custom 策略选项中所述定义 secret。
现有策略 secret 与输入 secret 之间没有技术差异。但是,构建器镜像可以区分它们并以不同的方式加以使用,具体取决于您的构建用例。
输入 secret 始终挂载到 /var/run/secrets/openshift.io/build
目录中,或您的构建器可以解析 $BUILD
环境变量(包含完整构建对象)。
如果命名空间和节点上存在 registry 的 pull secret,构建会默认使用命名空间中的 pull secret。