如何创建和使用Kubernetes的秘密
当前文章将解决kubernetes最重要的功能之一,即秘密。
在开始深入研究此功能之前,我想提到的是,在本文中,我将交替使用术语Kubernetes和K8s。
好吧,本文的目的是介绍K8s Secrets背后的最重要概念,以及它如何处理集群中的敏感信息。
我将使用minikube演示这些概念,minikube是运行本地K8s集群的工具。
是的,所有K8的功能都可以在我的笔记本电脑中启动并运行,这是一件非常好的事情吗?
安装非常简单,如果我们卡在某个地方,请随时ping我。
因此,我们将学习:
- 探索K8s生态系统中的秘密
- 了解秘密背后的概念
- 与真实的用例一起玩秘密
好吧,本文的其余部分安排如下:
- 介绍
- 概述
- 秘密创造
- 秘密可用性
- 作为卷
- 作为环境变量
- 结论
介绍
机密旨在存储和处理内部或者外部资源可能需要的敏感信息,这些信息可能来自Pod,图像和容器的立足点。
例如,API,端点,服务器,数据库等需要/使用的凭据,密码,令牌,密钥,ssh证书等。
实际上,秘密不仅提供了一种管理敏感数据的灵活方式,而且最重要的是,秘密可以在服务器中管理此类信息。
比将其以纯文本形式包含在容器或者Pod中更安全的方式。
概述和概念图
粗略地说,“秘密”是一个包含少量敏感数据(例如密码,密钥和令牌等)的对象。
K8s生态系统内部的“秘密”的简要概念图可以绘制如下:
Pod主要是命名空间的一部分,而命名空间又是群集节点的一部分。
属于容器的容器可能共享已装载的卷,这些容器在Secrets对象上运行以与内部或者外部系统进行交互。
为了做到这一点,Pod必须引用所需的机密。
因此,主要有三种处理方式,第一种是使用卷,第二种是使用环境变量,最后一种是通过kubelet。
关于秘密对象本身,我们可以区分两种类型,即用户和系统的秘密,例如K8会自动创建自己的秘密以访问K8s API服务器(在K8s下管理闭门器的主要入口点),并且所有用户都创建了该秘密。
Pod位于幕后,因此无法使用内置机密。
让我们检查一下我的环境中是否存在任何系统机密,在创建任何机密对象之前,我们可以按照K8s的kubectl get命令API进行操作,这就是kubectl get secrets
>> ~ kubectl get secrets NAME TYPE DATA AGE default-token-xny9c kubernetes.io/service-account-token 3 13d tls-certs Opaque 4 13d
我可以看到已经创建了一个服务帐户:default-token-xny9c是秘密构建的。
秘密创造
假设Pod需要访问Redis数据库,主要是用户名和密码,它们存储在例如文件中。
/用户名。
txt和。
/密码。
文本文件。
请注意,为简单起见,本文的其余部分将在演示中使用相同的文件。
因此,让我们创建一些虚假数据并将其放入这两个文件中:
>> ~ echo -n 'zombie' > ./username.txt >> ~ echo -n '1f2d1e2e67df' > ./password.txt >> ~ cat username.txt zombie% >> ~ cat password.txt 1f2d1e2e67df
实际上,有两种方法可以在K8s中创建密钥,第一种方法是使用命令kubectl create secret,第二种方法是从spec文件手动创建。
允许JSON或者YAML数据序列化。
使用命令行创建秘密对象
为了创建一个秘密对象,我们使用如下命令:
>> ~ kubectl create secret generic db-zombie-pass --from-file=./username.txt --from-file=./password.txt secret "db-zombie-pass" created
再次检查创建机密:
>> ~ kubectl get secrets NAME TYPE DATA AGE db-zombie-pass Opaque 2 27m default-token-xny9c kubernetes.io/service-account-token 3 14d tls-certs Opaque 4 13d
现在我们已经创建了第一个秘密对象,让我们使用kubectl describe命令对其进行描述:
>> ~ kubectl describe secret db-zombie-pass Name: db-zombie-pass Namespace: default Labels: Annotations: Type: Opaque Data ==== password.txt: 12 bytes username.txt: 6 bytes
请注意,最后一个命令显示的是捆绑在我们的秘密对象中的文件,而不是内容本身,这非常重要,因为它可以防止秘密使用k8s环境向其他用户公开。
使用规格文件手动创建秘密对象
可以通过使用JSON或者YAML数据序列化的规范文件来手动创建秘密对象。
秘密值是用base64字符串编码的。
因此,首先,为了使用规范文件创建秘密对象,用户需要对秘密值进行编码,如下所示:
>> ~ echo -n 'zombie' | base64 em9tYmll >> ~ echo -n '1f2d1e2e67df' | base64 MWYyZDFlMmU2N2Rm
其次,打开我们喜欢的编辑器并按如下所示编辑秘密文件,我们将其称为“我的秘密”。
yaml
apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: username: em9tYmll password: MWYyZDFlMmU2N2Rm
然后,我们可以通过运行以下命令从规范文件中创建秘密对象:
>> ~ vim my-secrte.yaml >> ~ kubectl create -f ./my-secrte.yaml secret "mysecret" created
好吧,我看到kubectl describe不会显示秘密对象的内容,但是如果有人想要检查该内容,该怎么办?
好了,我们可以通过提供秘密对象名称来使用命令kubectl get secret,例如,对于我们第一个创建的秘密db-zombie-pass,我们可以像这样检查内容:
>> ~ kubectl get secret db-zombie-pass -o yaml apiVersion: v1 data: password.txt: MWYyZDFlMmU2N2Rm username.txt: em9tYmll kind: Secret metadata: creationTimestamp: 2015-11-30T17:07:17Z name: db-zombie-pass namespace: default resourceVersion: "364840" selfLink: /api/v1/namespaces/default/secrets/db-zombie-pass uid: 72b890fd-b71f-11e6-84fe-2aa787ee170e type: Opaque
我们可能还记得我使用“ zombie”作为用户名,但是却得到了“ em9tYmll”。
。
。
任何想法。
。
!如上所述的base64字符串编码。
因此,为了检查这些值,我们必须像之前对编码那样对这些值进行解码。
例如,让我们对用户名进行解码:
>> ~ echo 'em9tYmll' | base64 --decode zombie%
秘密可用性
好吧,如上所述,机密既可以用作已安装卷,也可以用作环境变量,这是我们将在本文中介绍的K8s生态系统中机密最常用的方式。
作为安装量:
- 首先,我们需要如上所述创建一个秘密。
- 其次,需要通过指定字段secret.secretName引用秘密对象的名称来修改pod spec,以在volumes数组下添加一个卷。
- 第三,我们必须影响容器[] .volumeMounts []下容器中每个容器的秘密卷,还必须同时指定两个容器[] .volumeMounts []。readOnly = true,以使卷可以处于只读模式以及容器中已安装卷的文件夹路径[] .volumeMounts []。mountPath
使用YAML规范进行此类设置的最终示例如下所示:
apiVersion: v1 kind: Pod metadata: name: "mypod" namespace: "production" spec: containers: - name: mypod image: "redis" volumeMounts: - name: foo mountPath: "/etc/baz" readOnly: true volumes: - name: foo secret: secretName: "mysecret"
说明:
- 如果有多个容器需要保密数据,则每个容器都必须指定volumeMounts
- 可以将多个文件捆绑在一个秘密对象中,也可以在一个pod规格文件中使用许多秘密
- 也可以在不同文件的路径中使用不同的键,此概念称为秘密的键投影。现在,用户名将存储在/etc/baz/specific-path/username下,而不是/etc/baz/username下(请参见下面的shell片段)。
- 请注意,不是密码不会被投射,然后就不能使用,因此,规则是,一旦指定了项目数组,则只能从密钥中指定的密钥可用于Pod及其底层容器
- 如果秘密对象中不存在指定的密钥,则将永远不会创建该卷
… volumes: - name: foo secret: secretName: “mysecret” items: - key: “username” path: “specific-path/username”
作为环境变量
像已装载的卷一样,我们必须对pods的spec文件做些改动,以便能够通过添加如下所示的env标签将pods用作pods及其底层容器内的env变量,让我们将此规范文件称为redis-pod. yaml:
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
创建Pod后,env变量SECRET_USERNAME和SECRET_PASSWORD将在Pod内可用并可以使用。
在下面的shell片段中,我将根据上面的spec文件创建pod,然后使用命令kubectl exec name_of_the_pods -i -t – sh SSH sh pod以检查两个env变量。
>> ~ kubectl create -f redis-pod.yaml pod "secret-env-pod" created >> ~ kubectl exec secret-env-pod -i -t -- sh # echo $SECRET_USERNAME zombie # echo $SECRET_PASSWORD 1f2d1e2e67df #
请注意,创建Pod可能会花费一些时间,因此,我们可能需要稍等片刻才能使ssh Pod,因此请耐心等待。
可以通过运行以下命令kubectl get来检查特定容器的状态:
>> ~ kubectl get pods secret-env-pod NAME READY STATUS RESTARTS AGE secret-env-pod 1/1 Running 0 5m
用例
在用例方面,我将主要在devops生态系统中提供两个常用的用例,它们使用ssh证书和即时凭证密钥。
ssh
在K8s生态系统中使用秘密的一个实际用例之一是处理ssh的公钥和私钥,为了说明这一点,我将为Gitlab生成一个ssh RSA密钥,比如说,然后创建一个存储私有密钥和公共密钥的秘密对象:
>> ~ ssh-keygen -t rsa -b 4096 -C “[email protected]” Generating public/private rsa key pair. Enter file in which to save the key (.ssh/id_rsa): gitlab_rsa Enter passphrase (empty for no passphrase): … >> ~ kubectl create secret generic ssh-key-secret --from-file=ssh-privatekey=gitlab_rsa --from-file=ssh-publickey=gitlab_rsa.pub secret "ssh-key-secret" created
然后可以在pod的spec文件中的volumes array下像下面的波纹管那样使用这个秘密:
spec: containers: - name: mypod image: "redis" volumeMounts: - name: foo mountPath: “/etc/ssh-secret-vol“ readOnly: true volumes: - name: foo secret: secretName: "ssh-key-secret"
一旦卷被挂载,文件夹“/etc/ssh-secret-vol/gitlab_rsa”和“/etc/ssh-secretvol/gitlab_rsa. pub”将可用。
即时凭证
有时,用户可能需要输入用户名和密码凭据才能执行某些任务,例如:调试,数据库检查等。
这可以使用--from-literal参数来实现,如下所示:
>> ~ kubectl create secret generic debugger-secret --from-literal=username=debugger --from-literal=password=super-strong-pwd secret "debugger-secret" created