K8S - Secret 的简介和使用

news/2024/11/9 16:45:31/

在这里插入图片描述





Secret 的定义

Kubernetes(k8s)中的 Secret 是一种用于存储敏感信息的 Kubernetes 资源对象,如密码、API 密钥、证书等。Secret 被设计为用于安全地存储和管理敏感数据,并且可以通过 Volume 或环境变量的方式将这些数据提供给 Pod 中的容器。

简单来讲, K8S 的secret 和 configmap 的作用都是存放configuration 配置数据
但是 configmap 不适合存放证书, 密码等敏感数据。
官方推荐把敏感配置 存放在 secret 中, 会更加安全, 虽然个人认为也不怎么安全





Secret 创建

跟configmap 类似
screct 也可以用如下kubeclt命令来查看创建的例子

gateman@MoreFine-S500:~/projects/coding/k8s-s/service-case/cloud-order$ kubectl create secret -h
Create a secret with specified type.A docker-registry type secret is for accessing a container registry.A generic type secret indicate an Opaque secret type.A tls type secret holds TLS certificate and its associated key.Available Commands:docker-registry   Create a secret for use with a Docker registrygeneric           Create a secret from a local file, directory, or literal valuetls               Create a TLS secretUsage:kubectl create secret (docker-registry | generic | tls) [options]Use "kubectl create secret <command> --help" for more information about a given command.
Use "kubectl options" for a list of global command-line options (applies to all commands).





Secret 的3个子类

由上面看出 secret 也分3个子类

  1. docker-repository 这个类别是存放docker 私服的验证token, 会保存为json 格式, 假如k8s deployment拉取的镜像是from docker 私服, 则很可能需要provide 这个 docker-repository 类别的secret
  2. tls 用于存放ssl 证书 和 passwork 等信息
  3. generic 正常的text , 密码等配置

本文主要详细介绍 generic 类型, 不会cover 其他两种





generic 类型 secret的创建

1. by kubectl command line

还是先看一下官方例子

gateman@MoreFine-S500:~/projects/coding/k8s-s/service-case/cloud-order$ kubectl create secret generic -h
Create a secret based on a file, directory, or specified literal value.A single secret may package one or more key/value pairs.When creating a secret based on a file, the key will default to the basename of the file, and the value will default to
the file content. If the basename is an invalid key or you wish to chose your own, you may specify an alternate key.When creating a secret based on a directory, each file whose basename is a valid key in the directory will be packaged
into the secret. Any directory entries except regular files are ignored (e.g. subdirectories, symlinks, devices, pipes,
etc).Examples:# Create a new secret named my-secret with keys for each file in folder barkubectl create secret generic my-secret --from-file=path/to/bar# Create a new secret named my-secret with specified keys instead of names on diskkubectl create secret generic my-secret --from-file=ssh-privatekey=path/to/id_rsa
--from-file=ssh-publickey=path/to/id_rsa.pub# Create a new secret named my-secret with key1=supersecret and key2=topsecretkubectl create secret generic my-secret --from-literal=key1=supersecret --from-literal=key2=topsecret# Create a new secret named my-secret using a combination of a file and a literalkubectl create secret generic my-secret --from-file=ssh-privatekey=path/to/id_rsa --from-literal=passphrase=topsecret# Create a new secret named my-secret from env fileskubectl create secret generic my-secret --from-env-file=path/to/foo.env --from-env-file=path/to/bar.env
...

这里就不一一作例子了, 选最常用那个

gateman@MoreFine-S500:~/projects/coding/k8s-s/service-case/cloud-order$ kubectl create secret generic test-sec1 --from-literal=username=u123 --from-literal=password=p123456
secret/test-sec1 created

这里的 test-sec1 是secret item的名字, 在这个item 其实里面创建了2个 secret 对象
分别是
username:u123
password:p12345

注意, 如果value 包含特殊字符, 则需要用引号包住, 否则base64 encode 会有gap

2. by yaml

格式

apiVersion: v1
kind: Secret
metadata:name: my-secret
type: Opaque
data:username: <base64-encoded-username>password: <base64-encoded-password>

注意的是, secret里的值都需要 base64 encoded之后才写入yaml文件, 但是base64 encoded 的text 是十分容易decoded, 所以建议密码还是要先加密再encoded 写入





Secret 的查看

gateman@MoreFine-S500:~/projects/coding/k8s-s/service-case/cloud-order$ kubectl get secret 
NAME                  TYPE                                  DATA   AGE
default-token-7khb9   kubernetes.io/service-account-token   3      175d
test-sec1             Opaque                                2      25m
gateman@MoreFine-S500:~/projects/coding/k8s-s/service-case/cloud-order$ 

注意这里的Opaque 就是 generic的意思, Data 列2 是有连个子项(username , password)

用 Kubectl describe secret 只能看到size 信息

gateman@MoreFine-S500:~/projects/coding/k8s-s/service-case/cloud-order$ kubectl describe secret test-sec1
Name:         test-sec1
Namespace:    default
Labels:       <none>
Annotations:  <none>Type:  OpaqueData
====
password:  7 bytes
username:  4 bytes

用 kubectl get secret xxx -o yaml 可以查看encoded 后的值

gateman@MoreFine-S500:~/projects/coding/k8s-s/service-case/cloud-order$ kubectl get secret test-sec1 -o yaml
apiVersion: v1
data:password: cDEyMzQ1Ng==username: dTEyMw==
kind: Secret
metadata:creationTimestamp: "2024-08-17T13:47:38Z"name: test-sec1namespace: defaultresourceVersion: "6132863"uid: 2a027099-090b-478b-b460-e42991a50c62
type: Opaque

很方便地 decoded 出来真正的值

gateman@MoreFine-S500:~/projects/coding/k8s-s/service-case/cloud-order$ echo cDEyMzQ1Ng== | base64 --decode
p123456

所以说也不是很安全





Secret 的使用

例子介绍

这里我们用springboot 访问mysql的用户名和密码作例子

原本 cloud order service 的配置文件是这样的
application-prod.yml

...
spring:datasource:url: jdbc:mysql://192.168.0.42:3306/demo_cloud_order?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=trueusername: cloud_orderpassword: ENC(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)driver-class-name: com.mysql.cj.jdbc.Driver
...

我们增加1个yaml 文件作为例子
application-k8sprod

...
spring:datasource:url: jdbc:mysql://192.168.0.42:3306/demo_cloud_order?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=truedriver-class-name: com.mysql.cj.jdbc.Driver
...

吧user name 和 密码去掉了
那么怎么启动这个springboot service呢, 当然是在启动参数中传入



方法1, 吧secret map 到 环境变量

创建 secret 包含db 的username 和 password (加密后的)

这里用yaml方式

cloud-order-db-secret.yaml

apiVersion: v1
kind: Secret
metadata:name: cloud-order-db-secret
type: Opaque
data:# echo cloud-order | base64username: Y2xvdWQtb3JkZXIKpassword: RU5DKE9KaDRYVGFXejFixxxxxxxxxxxxx

执行

gateman@MoreFine-S500:~/projects/coding/k8s-s/service-case/cloud-order$ kubectl apply -f cloud-order-db-secret.yaml 
secret/cloud-order-db-secret created



修改deployment yaml

deployment-cloud-order-with-secret-command-notwork.yaml

apiVersion: apps/v1
kind: Deployment
metadata:labels: # label of this deploymentapp: cloud-order # custom definedauthor: nvd11name: deployment-cloud-order # name of this deploymentnamespace: default
spec:replicas: 3            # desired replica count, Please note that the replica Pods in a Deployment are typically distributed across multiple nodes.revisionHistoryLimit: 10 # The number of old ReplicaSets to retain to allow rollbackselector: # label of the Pod that the Deployment is managing,, it's mandatory, without it , we will get this error # error: error validating data: ValidationError(Deployment.spec.selector): missing required field "matchLabels" in io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector ..matchLabels:app: cloud-orderstrategy: # Strategy of upodatetype: RollingUpdate # RollingUpdate or RecreaterollingUpdate:maxSurge: 25% # The maximum number of Pods that can be created over the desired number of Pods during the updatemaxUnavailable: 25% # The maximum number of Pods that can be unavailable during the updatetemplate: # Pod templatemetadata:labels:app: cloud-order # label of the Pod that the Deployment is managing. must match the selector, otherwise, will get the error Invalid value: map[string]string{"app":"bq-api-xxx"}: `selector` does not match template `labels`spec: # specification of the Podcontainers:- image: europe-west2-docker.pkg.dev/jason-hsbc/my-docker-repo/cloud-order:1.0.2 # image of the containerimagePullPolicy: Alwaysname: container-cloud-ordercommand: ["bash"]# does not work, as the password format is ENV(xxxxx) , and the java -jar command could not handle (),  after I added double quotes "ENV(xxxx)", service failed to start due to db password error# unless I set the plain text password to secret , but I don't think it's secure enoughargs: - "-c"- |java -jar -Dserver.port=8080 app.jar --spring.profiles.active=$APP_ENVIRONMENT --spring.datasource.username=$DB_USER --spring.datasource.password=$DB_PASSWORD env: # set env varaibles- name: APP_ENVIRONMENT # name of the environment variablevalue: k8sprod # value of the environment variable- name: APP_TAG valueFrom: # value from config mapconfigMapKeyRef: name: cloud-order-app-tag-config # name of the configMap itemkey: APP_TAG # key from the config map item- name: DB_USERvalueFrom: # value from secretsecretKeyRef:name: cloud-order-db-secretkey: username- name: DB_PASSWORDvalueFrom: # value from secretsecretKeyRef:name: cloud-order-db-secretkey: passwordrestartPolicy: Always # Restart policy for all containers within the PodterminationGracePeriodSeconds: 10 # The period of time in seconds given to the Pod to terminate gracefully

但是实际上这个方法对这个case 不work

因为java -jar 无法处理 ENV(XXX)
例如

gateman@MoreFine-S500:~/tmp$ java -jar -Dserver.port=8085 app.jar --spring.profiles.active=k8sprod --spring.datasource.username=cloud-order --spring.datasource.password=ENC(OJh4XTaWz1beLRY/1cMxxxx)
bash: syntax error near unexpected token `('

不能正确地转义括号

当我加上"" 双引号包住ENV()
则启动失败, 报错db 密码错误
我暂时无法解决这个问题, 除非我把明文密码放入secret , 不使用ENV() , 但是上面说过了, 把明文密码放入secret 我认为不够安全, 很容易decoded 出来




方法2, 吧secret 保存到文件

前提是其实
java 启动spring boot 命令有1个特性, 可以额外指定包含另1个配置文件

java -jar -Dserver.port=8085 -Dspring.config.additional-location=db-config.yaml app.jar --spring.profiles.active=k8sprod

注意这里的 spring.config.additional-location 必须用 -D 作为VM 参数传入, 而不是 --spring.boot 参数传入

所以我们的方向是吧username 和 password 的配置写入到1个卷中




创建 secret 包含db 的username 和 password (加密后的)

cloud-order-db-secret-file.yaml

apiVersion: v1
kind: Secret
metadata:name: cloud-order-db-secret-file
type: Opaque
data:# atasource:#   username: cloud_order#   password: ENC(OJh4XTaWz1beLRY/1cM4Xaxxx)dbconfig: c3ByaW5nOgogIGRhdGFzb3VyY2U6Cxxxx

注意这里的encoded 码是 原本的格式 , 必须符合spring 的配置




修改 deployment yaml
apiVersion: apps/v1
kind: Deployment
metadata:labels: # label of this deploymentapp: cloud-order # custom definedauthor: nvd11name: deployment-cloud-order # name of this deploymentnamespace: default
spec:replicas: 3            # desired replica count, Please note that the replica Pods in a Deployment are typically distributed across multiple nodes.revisionHistoryLimit: 10 # The number of old ReplicaSets to retain to allow rollbackselector: # label of the Pod that the Deployment is managing,, it's mandatory, without it , we will get this error # error: error validating data: ValidationError(Deployment.spec.selector): missing required field "matchLabels" in io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector ..matchLabels:app: cloud-orderstrategy: # Strategy of upodatetype: RollingUpdate # RollingUpdate or RecreaterollingUpdate:maxSurge: 25% # The maximum number of Pods that can be created over the desired number of Pods during the updatemaxUnavailable: 25% # The maximum number of Pods that can be unavailable during the updatetemplate: # Pod templatemetadata:labels:app: cloud-order # label of the Pod that the Deployment is managing. must match the selector, otherwise, will get the error Invalid value: map[string]string{"app":"bq-api-xxx"}: `selector` does not match template `labels`spec: # specification of the Podcontainers:- image: europe-west2-docker.pkg.dev/jason-hsbc/my-docker-repo/cloud-order:1.0.2 # image of the containerimagePullPolicy: Alwaysname: container-cloud-ordercommand: ["bash"]args: - "-c"- |java -jar -Dserver.port=8080 -Dspring.config.additional-location=/app/config/db-config.yaml app.jar --spring.profiles.active=$APP_ENVIRONMENTenv: # set env varaibles- name: APP_ENVIRONMENT # name of the environment variablevalue: k8sprod # value of the environment variable- name: APP_TAG valueFrom: # value from config mapconfigMapKeyRef: name: cloud-order-app-tag-config # name of the configMap itemkey: APP_TAG # key from the config map item- name: DB_USERvalueFrom: # value from secretsecretKeyRef:name: cloud-order-db-secretkey: username- name: DB_PASSWORDvalueFrom: # value from secretsecretKeyRef:name: cloud-order-db-secretkey: passwordvolumeMounts: # volume mount- name: db-configmountPath: /app/configvolumes:- name: db-configsecret:secretName: cloud-order-db-secret-file  items:- key: dbconfigpath: db-config.yamlrestartPolicy: Always # Restart policy for all containers within the PodterminationGracePeriodSeconds: 10 # The period of time in seconds given to the Pod to terminate gracefully

注意上面有几点

  1. command 容器启动命令被改成 java -jar -Dserver.port=8080 -Dspring.config.additional-location=/app/config/db-config.yaml app.jar --spring.profiles.active=$APP_ENVIRONMENT
  2. 把 secret的内容写入 到/app/config/db-config




检查和测试
gateman@MoreFine-S500:~/projects/coding/k8s-s/service-case/cloud-order$ kubectl apply -f deployment-cloud-order-with-secret.yaml 
deployment.apps/deployment-cloud-order created

首先部署

再进入容器, 查看/app/config/db-config.yaml 是否被生成

gateman@MoreFine-S500:~/projects/coding/k8s-s/service-case/cloud-order$ kubectl exec -it deployment-cloud-order-588c9444dc-7cphs /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
bash-4.4# cat /app/config/db-config.yaml 
spring:datasource:username: cloud_orderpassword: ENC(OJh4XTaWz1beLRY/1cM4Xa6IP/mrxxxxxx)

正确生成

测试接口:

gateman@MoreFine-S500:~/projects/coding/k8s-s/service-case/cloud-order$ curl http://www.jp-gcp-vms.cloud:8085/cloud-order/actuator/info | jq .% Total    % Received % Xferd  Average Speed   Time    Time     Time  CurrentDload  Upload   Total   Spent    Left  Speed
100  1922    0  1922    0     0   3616      0 --:--:-- --:--:-- --:--:--  3612
{"app": "Cloud Order Service","appEnvProfile": "k8sprod","version": "1.0.2","hostname": "deployment-cloud-order-588c9444dc-cjtkv","dbUrl": "jdbc:mysql://192.168.0.42:3306/demo_cloud_order?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true","description": "This is a simple Spring Boot application to for cloud order...","SystemVariables": {"PATH": "/usr/java/openjdk-17/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","CLUSTERIP_CLOUD_ORDER_SERVICE_HOST": "10.98.117.97","CLUSTERIP_BQ_API_SERVICE_SERVICE_PORT": "8080","KUBERNETES_PORT": "tcp://10.96.0.1:443","DB_USER": "cloud-order\n","JAVA_HOME": "/usr/java/openjdk-17","KUBERNETES_SERVICE_HOST": "10.96.0.1","LANG": "C.UTF-8","CLUSTERIP_CLOUD_ORDER_PORT": "tcp://10.98.117.97:8080","CLUSTERIP_BQ_API_SERVICE_PORT_8080_TCP": "tcp://10.100.68.154:8080","CLUSTERIP_CLOUD_ORDER_PORT_8080_TCP": "tcp://10.98.117.97:8080","CLUSTERIP_BQ_API_SERVICE_PORT_8080_TCP_PROTO": "tcp","PWD": "/app","JAVA_VERSION": "17.0.2","_": "/usr/java/openjdk-17/bin/java","CLUSTERIP_CLOUD_ORDER_PORT_8080_TCP_ADDR": "10.98.117.97","KUBERNETES_PORT_443_TCP": "tcp://10.96.0.1:443","KUBERNETES_PORT_443_TCP_ADDR": "10.96.0.1","CLUSTERIP_CLOUD_ORDER_PORT_8080_TCP_PORT": "8080","CLUSTERIP_BQ_API_SERVICE_PORT": "tcp://10.100.68.154:8080","CLUSTERIP_BQ_API_SERVICE_PORT_8080_TCP_PORT": "8080","KUBERNETES_PORT_443_TCP_PROTO": "tcp","APP_ENVIRONMENT": "k8sprod","KUBERNETES_SERVICE_PORT": "443","CLUSTERIP_CLOUD_ORDER_SERVICE_PORT": "8080","CLUSTERIP_BQ_API_SERVICE_PORT_8080_TCP_ADDR": "10.100.68.154","APP_TAG": "cloud-order-app-tag","HOSTNAME": "deployment-cloud-order-588c9444dc-cjtkv","CLUSTERIP_CLOUD_ORDER_PORT_8080_TCP_PROTO": "tcp","CLUSTERIP_BQ_API_SERVICE_SERVICE_HOST": "10.100.68.154","KUBERNETES_PORT_443_TCP_PORT": "443","KUBERNETES_SERVICE_PORT_HTTPS": "443","SHLVL": "1","HOME": "/root","DB_PASSWORD": "ENC(OJh4XTaWz1beLRY/1cM4Xa6IP/mrKgx2CdVRysJl+BZ/+7eHswcEzQWFF1PR/Hhl)"}
}
gateman@MoreFine-S500:~/projects/coding/k8s-s/service-case/cloud-order$ curl http://www.jp-gcp-vms.cloud:8085/cloud-order/actuator/health | jq .% Total    % Received % Xferd  Average Speed   Time    Time     Time  CurrentDload  Upload   Total   Spent    Left  Speed
100   364    0   364    0     0    735      0 --:--:-- --:--:-- --:--:--   736
{"status": "UP","components": {"db": {"status": "UP","details": {"database": "MySQL","validationQuery": "isValid()"}},"diskSpace": {"status": "UP","details": {"total": 20891439104,"free": 12675047424,"threshold": 10485760,"path": "/app/.","exists": true}},"livenessState": {"status": "UP"},"ping": {"status": "UP"},"readinessState": {"status": "UP"}},"groups": ["liveness","readiness"]
}

测试通过!


http://www.ppmy.cn/news/1514553.html

相关文章

云微客短视频矩阵到底能给企业带来什么呢?

目前&#xff0c;短视频平台如抖音、快手等已经成为了亿万用户的选择&#xff0c;这些平台的日活跃用户量以亿计&#xff0c;这就为企业品牌宣传提供了一个巨大的市场空间&#xff0c;众多企业老板也意识到&#xff0c;短视频营销可能是他们在激烈市场竞争中脱颖而出的关键。那…

python数据处理库——Pandas

文章目录 数据结构概览常用数据创建函数创建DataFrame创建Series 数据操作函数选择数据修改数据删除数据 数据清洗函数处理缺失值 数据转换函数数据类型转换数据排序 数据聚合函数描述性统计聚合函数 数据合并函数纵向合并横向合并 数据分组函数分组和聚合 时间序列函数时间序列…

鸿蒙HarmonyOS之使用ArkTs语言实现层级树状目录选择UI

一、实现效果 二、实现步骤 代码示例中用到的颜色、图片等资源可以自行替换设置 1、Index.ets 里面调用 import { CategoryView} from ./CategoryView;//主页面 Entry Component struct Index {State tabsIndex: number 0;build() {...//层级目录ViewCategoryView()...} …

R 2火灾温度预测

火灾温度预测 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 使用LSTM进行时间序列预测 这周学习如何使用长短期记忆网络&#xff08;LSTM&#xff09;进行时间序列预测。使用PyTorch框架来构建和训练模型&…

登录 k8s-Dashboard 显示 Your connection is not private

文章目录 一、背景二、解决方案 一、背景 部署好 kubernetes-Dashboard 后使用 master节点的 ipport 登录 Dashboard 显示 Your connection is not private 无论是 Edge 还是 Google Chrome 都是这样的情况 二、解决方案 点击网页空白处&#xff0c;英文输入法输入&#xf…

数字(智)化采购系统优点_亮点_应用场景

郑州信源数字化采购系统研发商&#xff0c;系统融合云原生、微服务、大数据、人工智能、物联网等先进技术&#xff0c;构建业务中台、数据中台、AI中台三大核心基座&#xff0c;以采购为切入点&#xff0c;结合供应链管理理念&#xff0c;为招采供应链提供交易、监管、数据、服…

Linux:CentOS配置

一&#xff0c;安装VMware 这个可以通过官网获取 vmware下载 也可以联系我&#xff0c;我发给你 二&#xff0c;安装CentOS Centos官网找要下载的版本&#xff1a; https://vault.centos.org/ 阿里云镜像&#xff1a;https://mirrors.aliyun.com/centos-vault/?spma2c6h.13…

深度学习--常用的调整张量形状的方法总结

在深度学习中&#xff0c;调整张量的形状是一个常见且重要的操作。它使我们能够调整数据的形式以适应模型的输入要求或进行其他处理。以下是一些常用的调整张量形状的方法&#xff0c;以及这些方法的详细解释和应用场景。 1. reshape() 功能&#xff1a;reshape() 方法用于将…