暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Kubernetes K8S中加密Secret的存储之道

IT运维大爆炸 2023-08-28
146

1、简介

在应用程序开发领域,诸如API密钥、数据库密码和认证令牌等敏感信息通常是必需的。在配置文件中硬编码或存储这些凭据可能会带来重大安全风险。Kubernetes Secrets通过提供一种安全且易于管理的方式来存储和分发敏感数据到集群内的pod,从而解决了这个问题。其中,敏感信息是采用 Base64 编码保存起来的。

2、Secret存储类型

Secret 可以用于存储不同类型的数据,包括字符串和二进制数据:

  • Opaque:这是默认的 Secret 类型,适用于任何类型的数据。它将数据存储为 Base64 编码的字符串。通常用于存储密码、密钥等。

  • kubernetes.io/service-account-token:这种类型的 Secret 用于存储与 Kubernetes 服务账户相关的令牌信息,这些令牌允许 pod 访问 Kubernetes API。

  • kubernetes.io/dockerconfigjson:用于存储与 Docker 镜像仓库身份验证相关的信息,允许 pod 在拉取私有镜像时进行身份验证。

  • kubernetes.io/tls:用于存储 TLS 证书和私钥,用于在应用程序之间或与外部服务之间进行加密通信。

3、使用Secrets的最佳实践

  • 限制访问:只授予需要访问Secrets的pod访问权限。使用Kubernetes的RBAC(基于角色的访问控制)来控制对Secrets的访问。

  • 避免硬编码:避免将敏感信息硬编码到应用程序代码或配置文件中。相反,从pod内部引用Secrets。

  • 加密:如果有特别敏感的数据,请考虑在将其存储到Secret之前进行加密。

  • 轮换:定期轮换Secrets,特别是如果存在可能造成泄漏的情况。Kubernetes 1.22引入了Secret轮换以自动化此过程。

4、注意事项

  • Secret和ConfigMap:都可以存储敏感信息、配置数据等,但在不同的命名空间内不能直接共享。

  • etcd存储:etcd是Kubernetes集群的分布式键值存储系统,用于存储集群的配置信息、状态等。Secret数据会被存储在etcd中,但由于etcd本身并没有提供加密功能,因此需要依赖其他手段来确保数据的安全性。

5、创建和使用Secrets

创建Secret涉及对敏感数据进行Base64 编码,并在Secret的定义中提供它。您可以使用kubectl
命令行工具以命令方式创建Secret,也可以通过YAML文件以声明方式创建。创建Secret后,可以在pod中以多种方式使用它:

  • 环境变量:Secrets可以作为环境变量注入到pod容器中,允许应用程序直接访问敏感信息。

  • 卷挂载:Secrets可以作为文件挂载到pod容器中,使应用程序能够从特定文件路径读取敏感数据。

注意:Base64只是一种编码,不含密钥的,并不安全。默认情况下,Kubernetes Secret 未加密地存储在 API 服务器的底层数据存储(etcd)中。任何拥有 API 访问权限的人都可以检索或修改 Secret,任何有权访问 etcd 的人也可以。此外,任何有权限在命名空间中创建 Pod 的人都可以使用该访问权限读取该命名空间中的任何 Secret。

6、查看创建类型

[root@node1 ~]# kubectl create secret --help
Available Commands:
docker-registry :docker仓库准备的秘钥
generic         :普通秘钥
tls             :tls

7、使用命令行的方式创建

#准备两个数据
[root@node1 ~]# echo -n 'admin' > ./username.txt
[root@node1 ~]# echo -n '123456' > ./password.txt

#1、使用文件方式创建(这种要转移文件中的特殊字符,$, \* 和 !)
[root@node1 ~]# kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt

#看不到明文
[root@node1 ~]# kubectl --kubeconfig=sit get secret db-user-pass -o yaml
apiVersion: v1
data:
password.txt: MTIzNDU2
username.txt: YWRtaW4=
kind: Secret
metadata:
creationTimestamp: "2023-08-24T10:01:08Z"
managedFields:
 - apiVersion: v1
  fieldsType: FieldsV1
  fieldsV1:
    f:data:
      .: {}
      f:password.txt: {}
      f:username.txt: {}
    f:type: {}
  manager: kubectl
  operation: Update
  time: "2023-08-24T10:01:08Z"
name: db-user-pass
namespace: default
resourceVersion: "279290207"
uid: 02774a21-fa20-4352-b98a-8caf27757ce5
type: Opaque

#2、使用字符串方式(这种直接写就可以,特殊字符不用提前转义)
[root@node1 ~]# kubectl --kubeconfig=sit create secret generic db-user-pass2 --from-literal=username=admin --from-literal=password=123456

#看不到明文
[root@node1 ~]# kubectl --kubeconfig=sit get secret db-user-pass2 -o yaml
apiVersion: v1
data:
password: MTIzNDU2
username: YWRtaW4=
kind: Secret
metadata:
creationTimestamp: "2023-08-25T03:20:58Z"
managedFields:
 - apiVersion: v1
  fieldsType: FieldsV1
  fieldsV1:
    f:data:
      .: {}
      f:password: {}
      f:username: {}
    f:type: {}
  manager: kubectl
  operation: Update
  time: "2023-08-25T03:20:58Z"
name: db-user-pass2
namespace: default
resourceVersion: "279744032"
uid: 8c444952-2d28-4649-b35c-13c76015042b
type: Opaque

8、使用yaml的方式创建

#这种要提前把内容使用base64编码好。
[root@node1 ~]# echo -n 'admin' | base64 #不加-n会得到admin+换行的编码结果; 使用-n进行不换行输出
[root@node1 ~]# echo -n '123456' | base64 #不加-n会得到admin+换行的编码结果; 使用-n进行不换行输出

#1、用文件方式创建的
[root@node1 ~]# vim mysql-secret.yaml
apiVersion: v1
data:
password.txt: MTIzNDU2
username.txt: YWRtaW4=
kind: Secret
metadata:
name: mysql-secret
namespace: default
type: Opaque

#2、用字符串k=v创建的
[root@node1 ~]# vim mysql-secret-02.yaml
apiVersion: v1
data:
pwd: NjY2Ng==  # 通过base64编码的
un: aGFoYQ==   # 通过base64编码的
kind: Secret
metadata:
name: mysql-secret-02
namespace: default
type: Opaque

9、环境变量中使用

[root@node1 ~]# vim mysql-secret.yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod-secret-1
spec:
containers:
 - name: nginx
  image: nginx
  env:
     - name: SECRET_USERNAME
      valueFrom:
        secretKeyRef:
          name: mysql-secret
          key: username.txt
     - name: SECRET_PASSWORD
      valueFrom:
        secretKeyRef:
          name: mysql-secret
          key: password.txt

#进入创建好的Pod中进行验证
[root@node1 ~]# kubectl --kubeconfig=sit exec -it mypod-secret-1 bash
root@mypod-secret-1:/# echo $SECRET_USERNAME
admin

#即使修改mysql-secret值,pod里面现有的值也不会改变
root@mypod-secret-1:/# echo $SECRET_PASSWORD
123456

10、以volume的形式挂载到pod的某个目录下

[root@node1 ~]# vim mypod-secret-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod-secret-2
spec:
containers:
 - name: nginx
  image: nginx
  volumeMounts:
   - name: foo
    mountPath: "/etc/foo" #容器内挂载路径
    readOnly: true
volumes:
 - name: foo
  secret:
    secretName: mysecret
     
#进入容器验证测试
[root@mypod-secret-2 ]# cd etc/foo
[root@mypod-secret-2 foo]# ls
password.txt username.txt
[root@mypod-secret-2 foo]# cat password.txt
45678
[root@mypod-secret-2 foo]# cat username.txt
admin

#修改secret
[root@node1 ~]# kubectl --kubeconfig=sit edit secrets mysql-secret
secret/mysql-secret edited
[root@node1 ~]# kubectl --kubeconfig=sit exec -it mypod-secret-2 bash
[root@mypod-secret-2 ]# cd etc/foo

#即使修改mysql-secret值,pod里面现有的值也不会改变
[root@mypod-secret-2 foo]# cat password.txt
45678

11、实战(创建一个 Docker 镜像注册表凭据)

#docker secret的使用
[root@node1 ~]# kubectl create secret --help

[root@node1 ~]# kubectl create secret docker-registry my-secret --docker-server=registry.cn-zhangjiakou.aliyuncs.com --docker-username=lyt_goodtogread@163.com --docker-password=

#在下载镜像的时候声明使用即可
[root@node1 ~]# vim aliyun-app.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
  app: aliyun-app
name: aliyun-app
spec:
imagePullSecrets:
  name: my-secret  #之前创建的secret的名字
containers:
 - image: registry.cn-zhangjiakou.aliyuncs.com/icodingdocker/icoding-java-img:v1.0
  imagePullPolicy: Always
  name: aliyun-app
  ports:
   - containerPort: 8080
    name: http80
    protocol: TCP

欢迎大家扫码关注:

本公众号只写原创,不接广告、不接广告、不接广告。下期小伙伴想学习什么技术,可以私信发我吆。


文章转载自IT运维大爆炸,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论