陈同学
微服务
Accelerator
About
# K8s 安全抽象:Secret > [K8s Secret](https://kubernetes.io/zh/docs/concepts/configuration/secret/) > [为 Pod 配置服务账户](https://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-service-account/) Secret 是对敏感信息的抽象,例如:密码、token、SSH key,其他对象可引用Secret。 Pod 使用 Secret 有两种场景: * 作为 volume 中的文件被挂载到 Pod 中一个或多个容器中 * 拉取镜像时需要使用 secret 作为安全凭证 ## Secret 分类 Secret 可分为三类: * **docker-registry**: 创建一个给 Docker Registry 使用的 secret,实际是保存了账户密码。 * **generic**:从本地 file, directory 或者 literal value 创建一个 secret。 * **tls**:创建一个 TLS secret。 ## 创建 generic secret ### 通过 literal(字面量)创建 创建一个order数据库的secret,包含账户密码两个字段。 ```bash kubectl create secret generic db-order-secret --from-literal=username=admin --from-literal=password=123456 ``` > literal 中若包含特殊字符则需要进行转义,如"123456!" 需设置为 "123456\\!" 查看secret,`describe secret db-order-secret`,查看时隐藏了字段值,仅展示了字节数。 对应的API对象为 **Opaque([oʊˈpeɪk])**,译为"不透明物",等同于"敏感数据"。 ``` Name: db-order-secret Namespace: default Labels: <none> Annotations: <none> Type: Opaque Data ==== password: 6 bytes username: 5 bytes ``` 再看看其yaml形态: ```bash kubectl get secret db-order-secret -o yaml ``` 其中字段是base64编码后的值。 ```yaml apiVersion: v1 data: password: MTIzNDU2 username: YWRtaW4= kind: Secret metadata: creationTimestamp: "2020-03-14T04:21:29Z" name: db-order-secret namespace: default resourceVersion: "28023453" selfLink: /api/v1/namespaces/default/secrets/db-order-secret uid: 5c60f906-ec8e-4277-8b96-caa75ef6589a type: Opaque ``` 解码password字段,值为`123456`。 ```bash $ echo MTIzNDU2 | base64 --decode 123456 ``` ### 通过文件创建 在当前目录创建一个RSA 公私钥对作为例子。 ```bash $ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): ./id_rsa Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in ./id_rsa. Your public key has been saved in ./id_rsa.pub. ``` 将私钥创建为secret,公钥可分发给另一方。 ```bash kubectl create secret generic rsa-key-secret --from-file=./id_rsa ``` ### 通过yaml创建 通过yaml提供元数据以创建secret,字段需用base64先编码,如: `echo -n admin | base64`。 ```yaml apiVersion: v1 kind: Secret metadata: name: db-user-secret type: Opaque data: username: YWRtaW4= password: MTIzNDU2 ``` 然后创建Secret即可。 ```bash kubectl apply -f ./secret.yaml ``` ### Pod 中应用Secret 下面的例子演示了Secret 的三种应用方式。 * 作为volume直接挂载,在容器中可直接使用 * 在环境变量中使用secret * 向特定目录映射secret 下面是Pod yaml。 ```yaml apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx-container image: nginx env: - name: SECRET_USERNAME # 使用secret 做环境变量 valueFrom: secretKeyRef: name: db-user-secret key: username volumeMounts: # 将secret作为volume挂载 - name: volume1 mountPath: "/etc/foo1" readOnly: true # 向特定目录映射secret - name: volume2 mountPath: "/etc/foo2" readOnly: true volumes: - name: volume1 secret: secretName: db-user-secret - name: volume2 secret: secretName: db-user-secret items: - key: username path: usernameFile ``` 创建Pod,然后进入Pod验证效果。 * 做环境变量 ```yaml - name: SECRET_USERNAME valueFrom: secretKeyRef: name: db-user-secret key: username ``` 结果如下: ```bash $ env | grep SECRET_USERNAME SECRET_USERNAME=admin ``` * 挂载到容器 ```yaml volumeMounts: - name: volume1 mountPath: "/etc/foo1" readOnly: true ``` 效果如下: ```bash $ ls -l /etc/foo1 total 0 lrwxrwxrwx 1 root root 15 Mar 14 07:49 password -> ..data/password lrwxrwxrwx 1 root root 15 Mar 14 07:49 username -> ..data/username ``` * 向特定目录映射secret ```yaml spec: volumeMounts: - name: volume2 mountPath: "/etc/foo2" readOnly: true volumes: - name: volume2 secret: secretName: db-user-secret items: - key: username path: usernameFile ``` 将 username 字段映射到了 `/etc/foo2/usernameFile` 中 ```bash $ cat /etc/foo2/usernameFile admin ``` ## 创建 docker-registry secret 拉取镜像 构建、部署时需要拉取镜像,可以向Pod提供一个secret专门用于拉取镜像。 以腾讯云镜像仓库为例,`ccr.ccs.tencentyun.com/easyk8s/nginx` 是一个私有的demo镜像。 利用下面yaml跑一个简单Pod: ```yaml apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx-container image: ccr.ccs.tencentyun.com/easyk8s/nginx:1.17 ``` 运行后Pod Event如下,出现 `Error: ErrImagePull` 。  接下来创建一个secret专门用于拉取镜像。 ```bash kubectl create secret docker-registry registry-tecent-secret \ --docker-server=ccr.ccs.tencentyun.com \ --docker-username=name \ --docker-password=password ``` 在 Pod 中使用 secret。 ```yaml apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx-container image: ccr.ccs.tencentyun.com/easyk8s/nginx:1.17 imagePullSecrets: - name: registry-tecent-secret ``` 应用yaml后Pod成功创建。  通过`kubectl get secret registry-tecent-secret -o yaml` 拿到的 `registry-tecent-secret` 的yaml结构如下: ``` apiVersion: v1 data: .dockerconfigjson: eyJhdXR... kind: Secret metadata: creationTimestamp: "2020-03-14T05:01:04Z" name: registry-tecent-secret namespace: default resourceVersion: "28027921" selfLink: /api/v1/namespaces/default/secrets/registry-tecent-secret uid: a05ae3c0-b504-448b-bc78-8c540b2dda6c type: kubernetes.io/dockerconfigjson ``` 其中 **.dockerconfigjson** 通过base64解码后可以拿到docker-registry的账户密码。 ## 创建tls secret 存储用于SSL通讯的私钥文件和证书文件,下面以nginx为例子。 预先准备好nginx ssl 通讯所需的key和crt文件. ```bash kubectl create secret tls nginx-ssl-secret \ --key=nginx.key \ --cert=nginx.crt ``` 下面是 secret 的数据,其类型为:`kubernetes.io/tls` ```bash $ kubectl describe secret/nginx-ssl-secret Name: nginx-ssl-secret Namespace: default Labels: <none> Annotations: <none> Type: kubernetes.io/tls Data ==== tls.crt: 4241 bytes tls.key: 1679 bytes ``` 在nginx pod 中应用该secret,作为volume映射到容器中。 ```yaml apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx-container image: nginx volumeMounts: - name: nginx-crt mountPath: /etc/nginx/ssl readOnly: true volumes: - name: nginx-crt secret: secretName: nginx-ssl-secret ``` 运行Pod后进入Pod查看 `/etc/nginx/ssl` 目录,可看到映射的证书、私钥文件,不过名字从 `nginx.crt, nginx.key` 变为了 `tls.crt, tls.key`。 ```bash $ ls -l /etc/nginx/ssl/ total 0 lrwxrwxrwx 1 root root 14 Mar 14 08:42 tls.crt -> ..data/tls.crt lrwxrwxrwx 1 root root 14 Mar 14 08:42 tls.key -> ..data/tls.key ``` 接着可以在nginx配置中使用这两个文件完成ssl通讯配置。 ## 常用 Secret 示意图 
本文由
cyj
创作,可自由转载、引用,但需署名作者且注明文章出处。
文章标题:
K8s 安全抽象:Secret
文章链接:
https://chenyongjun.vip/articles/149
扫码或搜索 cyjrun 关注微信公众号, 结伴学习, 一起努力