Z.S.K.'s Records

Kubernetes学习(在configmap中引用secret)

使用kubernetes做为底层平台, 对于配置文件的部署形式, 如果没有统一的配置管理, 使用最多的就是configmap及secret

但有时候只会将敏感的信息放在secret中,而大多数的配置会放在configmap, 这就造成要么把secret以env的形式存在于容器中,要么就以volumn的形式挂载到容器中, 需要从两个源来引用配置, 从本质上, configmap与secret是一个东西, 有时候会觉得这种场景其实可以优化到一个配置中, 官方到目前为止并不打算支持在configmap中引用secret, 这是在github上讨论的issue

某天随便逛github时,发现一个可以实现该功能的开源库configmapsecrets,它能够在configmap中引用secret中的变量, 最后生成一个完整的secret. 这样, 应用直接把这个secret挂载到指定路径即可, 同时,支持热更新.

经过一番研究后,发现用在GitOps流程中还是非常方便的, 结合SealedSecrets对secret的加密, 两者结合更好的支持了配置安全,方便统一管理

原理

原理非常简单,通过CRD来监控集群中特定资源(configmapSecret), 分析该资源引用的secret, 填充变量生成secret.

同时为了支持多个实例,多实例之间的竞争关系, 使用了sync.RWMutex

使用

安装CRD

按照github上的说明, 先生成CRD, 这里需要注意的是, 如果只想监视特定的ns中有效, 修改deployment.yaml中的容器的启动参数,

添加all-namespaces=false,这样,configmapsecret只会处理这个ns中的对象

kubectl apply -f manifest

secret

1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Secret
metadata:
name: alertmanager-keys
namespace: monitoring
labels:
app: alertmanager
stringData: # 使用stringData,不需要事先使用base64加密
opsgenieKey: 9eccf784-bbad-11e9-9cb5-2a2ae2dbcce4xxxxyyyyyyzzzzz
slackURL: https://hooks.slack.com/services/EFNPN1/EVU44X/J51NVTYSKwuPtCz3yyyy
type: Opaque

ConfigmapSecret

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
apiVersion: secrets.mz.com/v1alpha1
kind: ConfigMapSecret
metadata:
name: alertmanager-config
namespace: monitoring
labels:
app: alertmanager
spec:
template:
metadata:
name: alertmanager-config
labels:
app: alertmanager
data:
alertmanager.yaml: |
global:
resolve_timeout: 5m
opsgenie_api_key: $(OPSGENIE_API_KEY) # 在 Var中定义
slack_api_url: $(SLACK_API_URL)
special_how: $(CONFIGMAP_HOW)
special_type: $(CONFIGMAP_TYPE)
route:
receiver: default
group_by: ["alertname", "job", "team"]
group_wait: 30s
group_interval: 5m
repeat_interval: 12h
routes:
- receiver: foobar-sre
match:
team: foobar-sre
- receiver: widget-sre
match:
team: widget-sre
receivers:
- name: default
slack_configs:
- channel: unrouted-alerts
- name: foobar-sre
opsgenie_configs:
- responders:
- name: foobar-sre
type: team
slack_configs:
- channel: foobar-sre-alerts
- name: widget-sre
opsgenie_configs:
- responders:
- name: widget-sre
type: team
slack_configs:
- channel: widget-sre
vars:
- name: OPSGENIE_API_KEY
secretValue: # 引用secret
name: alertmanager-keys # secret 名字
key: opsgenieKey # secret key
- name: SLACK_API_URL
secretValue:
name: alertmanager-keys
key: slackURL
- name: CONFIGMAP_HOW # 引用configmap
configMapValue:
name: special-config
key: special.how
- name: CONFIGMAP_TYPE
configMapValue:
name: special-config
key: special.type

vars中内容即是引用的变量, 上面引用的是secret, 当然也可以引用configmap.

注意: 引用的必须是同一ns中secret/configmap

使用命令生成以上2个对象

1
2
kubectl apply -f secret.yaml
kubectl apply -f confsec.yaml

最终会在同一ns中生成一个secret,名字跟ConfigMapSecret对象的名字相同, 当然secret的data数据是被base64加密的

其它测试

  1. 如果修改引用的secret,会提示以下日志
1
{"level":"INFO","time":"2020-06-28T03:52:57.386Z","source":"controllers.controller.ConfigMapSecret","caller":"controllers/configmapsecret_controller.go:271","msg":"Updating Secret","configmapsecret":"monitoring/alertmanager-config","secret":"monitoring/alertmanager-config"}
  1. 修改configmapsecret本身,会提示以下错误, 但并不影响
1
{"level":"ERROR","time":"2020-06-28T03:50:08.555Z","source":"controllers.controller.ConfigMapSecret","caller":"controllers/configmapsecret_controller.go:462","msg":"Unable to update status","configmapsecret":"monitoring/alertmanager-config","error":"Operation cannot be fulfilled on configmapsecrets.secrets.mz.com \"alertmanager-config\": the object has been modified; please apply your changes to the latest version and try again"

1、2两种情况最终的secret会跟着被修改

  1. 而如果直接修改最终生成的secret,修改完之后会立即被复原.
1
{"level":"INFO","time":"2020-06-28T04:23:43.699Z","source":"controllers.controller.ConfigMapSecret","caller":"controllers/configmapsecret_controller.go:271","msg":"Updating Secret","configmapsecret":"monitoring/alertmanager-config","secret":"monitoring/alertmanager-config"}
  1. 删除configmapsecret, 则最终生成的secret也会被删除, 引用的secret则不会.

源码分析

关键代码在/pkg/controllers/configmapsecret_controller.go

首先通过SetupWithManager启动manager, 该manager用于监控configmapsecret及secret

关键函数sync用于同步相关资源的变更,通过对比OwnerReferences的UID来判断是否有变更,它调用renderSecret根据configmapsecret及引用的secret/configmap来渲染生成最终的secret

而处理引用变量的逻辑则是在makeVariables函数

不足

如果使用容器平台,如rancher, UI上不支持显示crd, 因此configmapsecret无法显示在页面上.

如果最终生成的形式为secret, 被base64编码,不能够直观地显示配置, 如果能够直接生成configmap,我觉得更合理

但生成的secret也不影响这个库用于GitOps中,结合SealedSecrets对secret的加密处理, 至此可以实现整个资源端到端的闭环.

参考文章:

转载请注明出处https://izsk.me

Z.S.K. wechat
Scan Me To Read on Phone
I know you won't do this,but what if you did?