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

k8s之secret(特殊存储卷)

云原生小记 2020-03-24
735


一、Secret介绍

在Kubernetes集群资源中,Secret对象与ConfigMap对象类似,但它主要是用于存储小片敏感的需要加密的数据,例如密码,token和SSH key密钥等等。这类数据当然也可以存放在Pod的定义中或者镜像中,但是放在Secret中是为了更方便的控制如何使用数据,更加安全和灵活,并减少信息暴露的风险。在secret中存储的数据都需要通过base64进行转换加密后存放。Secret解决了密码、token、密钥等敏感数据的配置问题,使用Secret可以避免把这些敏感数据以明文的形式暴露到镜像或者Pod Spec中。用户可以创建自己的secret,系统也会有自己的secret。

Secret从属于Service Account资源对象, 属于Service Account的一部分, 在一个Service Account对象里面可以包括多个不同的Secret对象, 分别用于不同目的的认证活动。

Secret一旦被创建,则可以通过以下三种方式来使用:

  • 在创建Pod时,通过为pod指定Service
  • Account来自动使用该Secret,主要用于API Server鉴权的过程;通过挂载Secret到Pod来使用它。即作为volume的一个域被一个或多个容器挂载;
  • Docker镜像下载时使用,通过指定Pod的spc.ImagePullSecret来引用。一般用于私有仓库登录拉取镜像。即在拉取镜像的时候被kubelet引用。

Kubernetes集群中有內建的Secrets:
由ServiceAccount创建的API证书附加的秘钥,Kubernetes会自动生成的用来访问apiserver的Secret,所有Pod会默认使用这个Secret与apiserver通信。这是Kubernetes 默认的行为,也可以通过自定义的方式禁用或者创建我们所需要的Secret。

二、Secret 类型和使用

  • Opaque:使用base64编码存储信息,可以通过base64 --decode解码获得原始数据,因此安全性弱。
  • kubernetes.io/dockerconfigjson:用于存储docker registry的认证信息.
  • kubernetes.io/service-account-token (即Service Account):用于被 serviceaccount引用。

serviceaccout 创建时,Kubernetes 会默认创建对应的 secret。Pod 如果使用了 serviceaccount,对应的 secret 会自动挂载到 Pod 的/run/secrets/kubernetes.io/serviceaccount 目录中。Service Account 是内置secret,使用 API 凭证自动创建和附加secret。Kubernetes自动创建包含访问API凭据的secret,并自动修改pod以使用此类型的secret。如果需要,可以禁用或覆盖自动创建和使用API凭据。但是,如果需要的只是安全地访问apiserver,则推荐这样的工作流程


查看secret

kubectl get secret

查看创建证书方法:

[root@k8s-master configmap]# kubectl create secret -h
Available Commands:
docker-registry Create a secret for use with a Docker registry
generic Create a secret from a local file, directory or literal value
tls Create a TLS secret

创建证书和私钥的必须指定secret是tls类型。如果是创建docker仓库的认证信息,需要指定类型为docker-registry。特别是使用私有仓库的时候,需要使用账号信息。使用kubelet来进行认证。剩下其他的一些认证就使用generic。

第一种类型:Opaque SecretOpaque类型的Secret,其value为base64编码后的值。

1)从文件新建secret:
分别创建两个名为username.txt和password.txt的文件

# 新建文件
[root@k8s-master ~]# echo "admin" >./username.txt
[root@k8s-master ~]# echo -n "Fw6se0c8q0SoPrBk" >./passwd.txt

# 用kubectl create secret创建secret
[root@k8s-master ~]# kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./passwd.txt
secret "db-user-pass" created

# 查看刚刚创建的secret
[root@k8s-master ~]# kubectl get secret db-user-pass -o yaml
apiVersion: v1
data:
passwd.txt: Rnc2c2UwYzhxMFNvUHJCaw==
username.txt: YWRtaW4=
kind: Secret
metadata:
creationTimestamp: "2019-08-26T12:34:16Z"
name: db-user-pass
namespace: default
resourceVersion: "4414"
selfLink: /api/v1/namespaces/default/secrets/db-user-pass
uid: 63ce4152-2d0f-450b-b018-7ffe35627629
type: Opaque

2)使用描述文件创建Secret:

首先使用base64对数据进行编码用base64对数据进行编码

[root@k8s-master ~]# echo -n 'admin' | base64
YWRtaW4=
[root@k8s-master ~]# echo -n '123456' | base64
MTIzNDU2

创建一个类型为secret的描述文件

[root@k8s-master ~]# vim secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MTIzNDU2

应用资源清单创建secret

[root@k8s-master ~]# kubectl create -f secret.yaml
secret "mysecret" created

查看secret

[root@k8s-master ~]# kubectl get secret
NAME TYPE DATA AGE
default-token-lnftf kubernetes.io/service-account-token 3 1d
mysecret Opaque 2 9s
[root@k8s-master ~]# kubectl get secret mysecret -o yaml

注意:默认情况下,get 和 describe 命令都不会显示文件的内容。这是为了防止将secret中的内容被意外暴露给从终端日志记录中刻意寻找它们的人。

3)Secret的使用创建好Secret之后,可以通过两种方式使用:

  • 以Volume方式
  • 以环境变量方式

secret可以指定secret文件的权限,类似linux系统文件权限,如果不指定默认权限是0644,等同于linux文件的-rw-r--r--权限

Secret 可以作为数据卷被挂载,或作为环境变量暴露出来以供 pod 中的容器使用。它们也可以被系统的其他部分使用,而不直接暴露在 pod 内。例如,它们可以保存凭据,系统的其他部分应该用它来代表您与外部系统进行交互。

在 Pod 中的 volume 里使用 Secret:

创建一个 secret 或者使用已有的 secret。多个 pod 可以引用同一个 secret。

修改镜像或者命令行让程序从该目录下寻找文件。Secret的data映射中的每一个键都成为了mountPath下的一个文件名。

3.1   将Secret挂载到Volume中 (下面是一个在pod中使用volume挂载secret的例子)

apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: data
mountPath: "/etc/data"
readOnly: true
volumes:
- name: data
secret:
secretName: mysecret

进入Pod查看挂载的Secret:

# ls /etc/data
password.txt username.txt
# cat /etc/data/username.txt
kevin
# cat /etc/data/password.txt
kevin@123

想要用的每个secret都需要在spec.volumes 中指明。如果pod中有多个容器,每个容器都需要自己的volumeMounts配置块,但是每个secret只需要一个spec.volumes。还可以打包多个文件到一个secret中,或者使用的多个secret,怎样方便就怎样来。也可以向特性路径映射secret密钥。

还可以控制Secret key映射在 volume 中的路径,可以使用 spec.volumes[].secret.items字段修改每个key的目标路径。也就是说可以只挂载Secret中特定的key:

apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: data
mountPath: "/etc/data"
readOnly: true
volumes:
- name: data
secret:
secretName: mysecret
items:
- key: username
path: my-group/my-username

注意在这种情况下:

  • username 存储在 /etc/data/my-group/my-username中
  • password 未被挂载

如果使用了 spec.volumes[].secret.items,只有在 items 中指定的 key 被影射。要使用 secret 中所有的 key,所有这些都必须列在 items 字段中。所有列出的密钥必须存在于相应的 secret 中。否则,不会创建卷。

3.2   将Secret设置为环境变量

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
restartPolicy: Never

3.4 只挂载Secret中特定的key,并且用mode字段单独指定某个key的权限

apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
items:
- key: username
path: my-group/my-username
mode: 511

# 在这种情况下:
username 存储在/etc/foo/my-group/my-username中
password未被挂载


第二种类型:kubernetes.io/dockerconfigjson如何让k8s能够拉取私有仓库的镜像?在使用私有镜像时,需要创建一个docker registry secret,并在容器中引用。用于存储docker registry的认证信息,可以直接使用kubectl create secret命令创建

1. 登录docker镜像仓库

这里以阿里云docker镜像仓库为例

docker login --username=xxx@aliyun.com registry.cn-hangzhou.aliyuncs.com

输入密码就可以了, 这个时候我们可以在配置文件中查看登录情况

cat ~/.docker/config.json

这个时候我们虽然可以通过docker pull命令拉取镜像, 但无法通过k8s创建pod方式拉取

2. 生成密钥secret
kubernetes.io/dockerconfigjson用于存储docker registry的认证信息 通过命令行create方式创建

[root@k8s-master yaml]# kubectl create secret -h #查看创建secret帮助
kubectl create secret docker-registry regsecret \
--namespace=regress \
--docker-server=registry.cn-hangzhou.aliyuncs.com \
--docker-username=allenjol@1040992050142591 \ # 阿里云镜像仓库中的docke-username
--docker-password=xxxxxx \
--docker-email=xx@aliyun.com

关键字解释:

  • regsecret:  secret名字。指定密钥的键名称, 可自行定义
  • --docker-server:  指定docker私有仓库地址
  • --docker-username:  指定docker私有仓库用户名
  • --docker-password:  指定docker私有仓库密码
  • --docker-email:  指定邮件地址(可选)
  • --namespace:指定命名空间(可选)。如果不指定,默认就生成在default命名空间下

查看创建的secret内容

[root@k8s-master yaml]# kubectl get secret secret -o yaml

通过base64对secret中的内容进行解码操作

echo "xxxx" | base64 -d

直接一条命令查看 -n指定命名空间可选

kubectl get secrets secret_name <-n namespace> --output="jsonpath={.data.\.dockerconfigjson}" | base64 -d

如果已经进行过docker login 的机器则会生成一个~/.dockercfg的文件,可根据该文件中的内容来创建

[root@k8s-master yaml]# kubectl create secret docker-registry secret --from-file="~/.dockercfg"

创建pod的时候yml文件中通过imagePullSecrets引用刚才创建的secret

---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: basic-server-delpoy
namespace: regress
spec:
replicas: 1
selector:
matchLabels:
app: basic-server
template:
metadata:
labels:
app: basic-server
spec:
imagePullSecrets:
- name: ali-registry
containers:
- name: basic-server
image: registry-vpc.cn-hangzhou.aliyuncs.com/allenjol/basic-server:20190425131211
ports:
- name: server-port
containerPort: 11010

加入密钥参数如下,name必须和kubectl create secret时候在docker-registry后面指定的名字一样:

imagePullSecrets:
- name: regsecret

其中imagePullSecrets是声明拉取镜像时需要指定密钥, regsecret 必须和上面生成密钥的键名一致, 另外检查一下pod和密钥是否在同一个namespace, 之后k8s便可以拉取镜像

注意:deployment.yaml文件里面,创建pod的时候namespace必须是要和secret指定同一个namespace。否则就发现kubectl apply -f deploy.yaml以后,死活拉不下来镜像,describe某个pod会发现提示没有权限或者没登录私有仓库。

查看secret

kubectl get secret
kubectl get secret regsecret -n regsecret -o yaml

可以看到当前除了默认的密钥, 还有我们刚才生成的. 另外要注意的是, 该密钥只能在对应namespace使用, 也就是这里的default, 如果需要用到其他namespace, 比如说regsecret, 就需要在生成的时候指定参数 --namespace regsecret


第三种类型:kubernetes.io/service-account-token用于被 serviceaccount 引用。serviceaccout 创建时 Kubernetes 会默认创建对应的 secret。Pod 如果使用了 serviceaccount,对应的 secret 会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中。

# kubectl run nginx --image nginx
deployment "nginx" created
# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-3137573019-md1u2 1/1 Running 0 13s
# kubectl exec nginx-3137573019-md1u2 ls /run/secrets/kubernetes.io/serviceaccount
ca.crt
namespace
token




------------------------------------------------------

公众号:竹下侯小姜运维

个人博客:https://www.ayunw.cn

重要的事情认真做,普通的事情规范做!

------------------------------------------------------

不定期更新优质内容,技术干货!如果觉得对你有帮助,请扫描下方二维码关注!

温馨提示

如果你喜欢本文,请分享到朋友圈,想要获得更多信息,请关注我



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

评论