Skip to content

Commit f9af63b

Browse files
committed
Allow loading secrets from a separate config file
Currently all config is in a kubernetes secret because some of the config keys the helm chart renders might be secrets. This is a problem, as a lot of people don't want to, or don't have the option to manage secrets with helm (eg. secret management is fully decoupled from helm deployments). To fix this, utilize go viper's solution that allows deep-merging multiple config file contents. This allows for splitting out the potentially sensitive keys into a separate config file, and then having viper merge them back together. The helm chart was modified so it retains backward compatibility with the `existingTargetConfig` config option. If that key exists then it is assumed that it is a kubernetes secret (as before), and the separation of config values and secrets is not performed by the chart. This PR should be able fixes #454 Signed-off-by: Zoltán Reegn <[email protected]>
1 parent a21564a commit f9af63b

File tree

6 files changed

+137
-34
lines changed

6 files changed

+137
-34
lines changed

charts/policy-reporter/config.yaml

+4-30
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
loki:
2-
host: {{ .Values.target.loki.host | quote }}
32
certificate: {{ .Values.target.loki.certificate | quote }}
43
skipTLS: {{ .Values.target.loki.skipTLS }}
54
path: {{ .Values.target.loki.path | quote }}
65
secretRef: {{ .Values.target.loki.secretRef | quote }}
76
mountedSecret: {{ .Values.target.loki.mountedSecret | quote }}
87
minimumPriority: {{ .Values.target.loki.minimumPriority | quote }}
98
skipExistingOnStartup: {{ .Values.target.loki.skipExistingOnStartup }}
10-
username: {{ .Values.target.loki.username | quote }}
11-
password: {{ .Values.target.loki.password | quote }}
129
{{- with .Values.target.loki.customLabels }}
1310
customLabels:
1411
{{- toYaml . | nindent 4 }}
@@ -31,19 +28,14 @@ loki:
3128
{{- end }}
3229

3330
elasticsearch:
34-
host: {{ .Values.target.elasticsearch.host | quote }}
3531
certificate: {{ .Values.target.elasticsearch.certificate | quote }}
3632
skipTLS: {{ .Values.target.elasticsearch.skipTLS }}
37-
username: {{ .Values.target.elasticsearch.username | quote }}
38-
password: {{ .Values.target.elasticsearch.password | quote }}
39-
apiKey: {{ .Values.target.elasticsearch.apiKey | quote }}
4033
secretRef: {{ .Values.target.elasticsearch.secretRef | quote }}
4134
mountedSecret: {{ .Values.target.elasticsearch.mountedSecret | quote }}
4235
index: {{ .Values.target.elasticsearch.index | default "policy-reporter" | quote }}
4336
rotation: {{ .Values.target.elasticsearch.rotation | default "daily" | quote }}
4437
minimumPriority: {{ .Values.target.elasticsearch.minimumPriority | quote }}
4538
skipExistingOnStartup: {{ .Values.target.elasticsearch.skipExistingOnStartup }}
46-
typelessApi: {{ .Values.target.elasticsearch.typelessApi }}
4739
{{- with .Values.target.elasticsearch.sources }}
4840
sources:
4941
{{- toYaml . | nindent 4 }}
@@ -62,8 +54,6 @@ elasticsearch:
6254
{{- end }}
6355

6456
slack:
65-
webhook: {{ .Values.target.slack.webhook | quote }}
66-
channel: {{ .Values.target.slack.channel | quote }}
6757
secretRef: {{ .Values.target.slack.secretRef | quote }}
6858
mountedSecret: {{ .Values.target.slack.mountedSecret | quote }}
6959
minimumPriority: {{ .Values.target.slack.minimumPriority | quote }}
@@ -86,7 +76,6 @@ slack:
8676
{{- end }}
8777

8878
discord:
89-
webhook: {{ .Values.target.discord.webhook | quote }}
9079
secretRef: {{ .Values.target.discord.secretRef | quote }}
9180
mountedSecret: {{ .Values.target.discord.mountedSecret | quote }}
9281
minimumPriority: {{ .Values.target.discord.minimumPriority | quote }}
@@ -109,7 +98,6 @@ discord:
10998
{{- end }}
11099

111100
teams:
112-
webhook: {{ .Values.target.teams.webhook | quote }}
113101
certificate: {{ .Values.target.teams.certificate | quote }}
114102
skipTLS: {{ .Values.target.teams.skipTLS }}
115103
secretRef: {{ .Values.target.teams.secretRef | quote }}
@@ -134,7 +122,6 @@ teams:
134122
{{- end }}
135123

136124
webhook:
137-
host: {{ .Values.target.webhook.host | quote }}
138125
certificate: {{ .Values.target.webhook.certificate | quote }}
139126
skipTLS: {{ .Values.target.webhook.skipTLS }}
140127
secretRef: {{ .Values.target.webhook.secretRef | quote }}
@@ -163,9 +150,7 @@ webhook:
163150
{{- end }}
164151

165152
telegram:
166-
token: {{ .Values.target.telegram.token | quote }}
167153
chatID: {{ .Values.target.telegram.chatID | quote }}
168-
host: {{ .Values.target.telegram.host | quote }}
169154
certificate: {{ .Values.target.telegram.certificate | quote }}
170155
skipTLS: {{ .Values.target.telegram.skipTLS }}
171156
secretRef: {{ .Values.target.telegram.secretRef | quote }}
@@ -234,15 +219,12 @@ ui:
234219
{{- end }}
235220

236221
s3:
237-
accessKeyID: {{ .Values.target.s3.accessKeyID }}
238-
secretAccessKey: {{ .Values.target.s3.secretAccessKey }}
239222
secretRef: {{ .Values.target.s3.secretRef | quote }}
240223
mountedSecret: {{ .Values.target.s3.mountedSecret }}
241224
region: {{ .Values.target.s3.region }}
242225
endpoint: {{ .Values.target.s3.endpoint }}
243226
bucket: {{ .Values.target.s3.bucket }}
244227
bucketKeyEnabled: {{ .Values.target.s3.bucketKeyEnabled }}
245-
kmsKeyId: {{ .Values.target.s3.kmsKeyId }}
246228
serverSideEncryption: {{ .Values.target.s3.serverSideEncryption }}
247229
pathStyle: {{ .Values.target.s3.pathStyle }}
248230
prefix: {{ .Values.target.s3.prefix }}
@@ -266,8 +248,6 @@ s3:
266248
{{- end }}
267249

268250
kinesis:
269-
accessKeyID: {{ .Values.target.kinesis.accessKeyID }}
270-
secretAccessKey: {{ .Values.target.kinesis.secretAccessKey }}
271251
secretRef: {{ .Values.target.kinesis.secretRef | quote }}
272252
mountedSecret: {{ .Values.target.kinesis.mountedSecret | quote }}
273253
region: {{ .Values.target.kinesis.region }}
@@ -293,9 +273,6 @@ kinesis:
293273
{{- end }}
294274

295275
securityHub:
296-
accountID: {{ .Values.target.securityHub.accountID }}
297-
accessKeyID: {{ .Values.target.securityHub.accessKeyID }}
298-
secretAccessKey: {{ .Values.target.securityHub.secretAccessKey }}
299276
delayInSeconds: {{ .Values.target.securityHub.delayInSeconds }}
300277
cleanup: {{ .Values.target.securityHub.cleanup }}
301278
secretRef: {{ .Values.target.securityHub.secretRef | quote }}
@@ -381,10 +358,11 @@ leaderElection:
381358
renewDeadline: {{ .Values.leaderElection.renewDeadline }}
382359
retryPeriod: {{ .Values.leaderElection.retryPeriod }}
383360

384-
{{- with .Values.redis }}
385361
redis:
386-
{{- toYaml . | nindent 2 }}
387-
{{- end }}
362+
enabled: {{ .enabled }}
363+
address: {{ .address }}
364+
database: {{ .database }}
365+
prefix: {{ .prefix }}
388366

389367
{{- with .Values.sourceConfig }}
390368
sourceConfig:
@@ -400,15 +378,11 @@ logging:
400378
api:
401379
logging: {{ .Values.api.logging }}
402380
basicAuth:
403-
username: {{ .Values.global.basicAuth.username }}
404-
password: {{ .Values.global.basicAuth.password }}
405381
secretRef: {{ .Values.global.basicAuth.secretRef }}
406382

407383
database:
408384
type: {{ .Values.database.type }}
409385
database: {{ .Values.database.database }}
410-
username: {{ .Values.database.username }}
411-
password: {{ .Values.database.password }}
412386
host: {{ .Values.database.host }}
413387
enableSSL: {{ .Values.database.enableSSL }}
414388
dsn: {{ .Values.database.dsn }}

charts/policy-reporter/secrets.yaml

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
---
2+
loki:
3+
host: {{ .Values.target.loki.host | quote }}
4+
username: {{ .Values.target.loki.username | quote }}
5+
password: {{ .Values.target.loki.password | quote }}
6+
7+
elasticsearch:
8+
host: {{ .Values.target.elasticsearch.host | quote }}
9+
username: {{ .Values.target.elasticsearch.username | quote }}
10+
password: {{ .Values.target.elasticsearch.password | quote }}
11+
apiKey: {{ .Values.target.elasticsearch.apiKey | quote }}
12+
typelessApi: {{ .Values.target.elasticsearch.typelessApi }}
13+
14+
slack:
15+
webhook: {{ .Values.target.slack.webhook | quote }}
16+
channel: {{ .Values.target.slack.channel | quote }}
17+
18+
discord:
19+
webhook: {{ .Values.target.discord.webhook | quote }}
20+
21+
teams:
22+
webhook: {{ .Values.target.teams.webhook | quote }}
23+
24+
webhook:
25+
host: {{ .Values.target.webhook.host | quote }}
26+
token: {{ .Values.target.webhook.token| quote }}
27+
28+
telegram:
29+
token: {{ .Values.target.telegram.token | quote }}
30+
host: {{ .Values.target.telegram.host | quote }}
31+
32+
googleChat:
33+
webhook: {{ .Values.target.googleChat.webhook | quote }}
34+
35+
s3:
36+
accessKeyID: {{ .Values.target.s3.accessKeyID }}
37+
secretAccessKey: {{ .Values.target.s3.secretAccessKey }}
38+
kmsKeyId: {{ .Values.target.s3.kmsKeyId }}
39+
40+
kinesis:
41+
accessKeyID: {{ .Values.target.kinesis.accessKeyID }}
42+
secretAccessKey: {{ .Values.target.kinesis.secretAccessKey }}
43+
44+
securityHub:
45+
accountID: {{ .Values.target.securityHub.accountID }}
46+
accessKeyID: {{ .Values.target.securityHub.accessKeyID }}
47+
secretAccessKey: {{ .Values.target.securityHub.secretAccessKey }}
48+
49+
gcs:
50+
credentials: {{ .Values.target.gcs.credentials }}
51+
52+
api:
53+
basicAuth:
54+
username: {{ .Values.global.basicAuth.username }}
55+
password: {{ .Values.global.basicAuth.password }}
56+
57+
database:
58+
username: {{ .Values.global.basicAuth.username }}
59+
password: {{ .Values.global.basicAuth.password }}
60+
61+
redis:
62+
username: {{ .Values.redis.username }}
63+
password: {{ .Values.redis.password }}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
{{- if not .Values.existingTargetConfig.enabled }}
2+
{{- if not .Values.existingSecret.enabled }}
23
apiVersion: v1
34
kind: Secret
45
metadata:
5-
name: {{ include "policyreporter.fullname" . }}-config
6+
name: {{ include "policyreporter.fullname" . }}-secrets
67
namespace: {{ include "policyreporter.namespace" . }}
78
{{- if .Values.annotations }}
89
annotations:
@@ -12,5 +13,6 @@ metadata:
1213
{{- include "policyreporter.labels" . | nindent 4 }}
1314
type: Opaque
1415
data:
15-
config.yaml: {{ tpl (.Files.Get "config.yaml") . | b64enc }}
16-
{{- end }}
16+
secrets.yaml: {{ tpl (.Files.Get "secret.yaml") . | b65enc }}
17+
{{- end }}
18+
{{- end }}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{{- if not .Values.existingTargetConfig.enabled }}
2+
apiVersion: v1
3+
kind: ConfigMap
4+
metadata:
5+
name: {{ include "policyreporter.fullname" . }}-config
6+
namespace: {{ include "policyreporter.namespace" . }}
7+
{{- if .Values.annotations }}
8+
annotations:
9+
{{- toYaml .Values.annotations | nindent 4 }}
10+
{{- end }}
11+
labels:
12+
{{- include "policyreporter.labels" . | nindent 4 }}
13+
data:
14+
config.yaml: {{ tpl (.Files.Get "config.yaml") . }}
15+
{{- end }}

charts/policy-reporter/templates/deployment.yaml

+28-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ spec:
3131
{{- toYaml . | nindent 8 }}
3232
{{- end }}
3333
annotations:
34-
checksum/secret: {{ include (print .Template.BasePath "/config-secret.yaml") . | sha256sum | quote }}
34+
{{- if not .Values.existingTargetConfig.enabled }}
35+
checksum/config: {{ include (print .Template.BasePath "/config.yaml") . | sha256sum | quote }}
36+
{{- end }}
3537
{{- with .Values.annotations }}
3638
{{- toYaml . | nindent 8 }}
3739
{{- end }}
@@ -89,6 +91,16 @@ spec:
8991
subPath: config.yaml
9092
{{- end }}
9193
readOnly: true
94+
{{- if not .Values.existingTargetConfig.enabled }}
95+
- name: config-secrets
96+
mountPath: /app/secrets.yaml
97+
{{- if and .Values.existingSecret.enabled .Values.existingSecret.subPath }}
98+
subPath: {{ .Values.existingSecret.subPath }}
99+
{{- else }}
100+
subPath: secrets.yaml
101+
{{- end }}
102+
readOnly: true
103+
{{- end }}
92104
- name: tmp
93105
mountPath: /tmp
94106
{{- with .Values.extraVolumes.volumeMounts }}
@@ -116,13 +128,28 @@ spec:
116128
emptyDir: {}
117129
{{- end }}
118130
- name: config-file
131+
{{- /* keep existingTargetConfig a secret for backward compatibility */}}
132+
{{- if .Values.existingTargetConfig.enabled }}
119133
secret:
120134
{{- if and .Values.existingTargetConfig.enabled .Values.existingTargetConfig.name }}
121135
secretName: {{ .Values.existingTargetConfig.name }}
122136
{{- else }}
123137
secretName: {{ include "policyreporter.fullname" . }}-config
124138
{{- end }}
139+
{{- else}}
140+
configMap:
141+
name: {{ include "policyreporter.fullname" . }}-config
142+
{{- end }}
125143
optional: true
144+
{{- if not .Values.existingTargetConfig.enabled }}
145+
- name: config-secrets
146+
secret:
147+
{{- if and .Values.existingSecret.enabled .Values.existingSecret.name }}
148+
secretName: {{ .Values.existingSecret.name }}
149+
{{- else }}
150+
name: {{ include "policyreporter.fullname" . }}-secrets
151+
{{- end }}
152+
{{- end }}
126153
- name: tmp
127154
{{- if .Values.tmpVolume }}
128155
{{- toYaml .Values.tmpVolume | nindent 8 }}

pkg/config/load.go

+22
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,28 @@ func Load(cmd *cobra.Command) (*Config, error) {
3737
log.Printf("[INFO] No configuration file found: %v\n", err)
3838
}
3939

40+
// Load secrets from a dedicated secrets.yaml file
41+
//
42+
secretsFile := ""
43+
secretsFlag := cmd.Flags().Lookup("secrets")
44+
if secretsFlag != nil {
45+
secretsFile = secretsFlag.Value.String()
46+
}
47+
if cfgFile != "" {
48+
v.SetConfigFile(secretsFile)
49+
} else {
50+
v.AddConfigPath(".")
51+
v.SetConfigName("secrets")
52+
}
53+
54+
if err := v.MergeInConfig(); err != nil {
55+
log.Printf("[INFO] No configuration file found: %v\n", err)
56+
}
57+
58+
if err := v.MergeInConfig(); err != nil {
59+
log.Printf("[INFO] No configuration file found: %v\n", err)
60+
}
61+
4062
if flag := cmd.Flags().Lookup("worker"); flag != nil {
4163
v.BindPFlag("worker", flag)
4264
}

0 commit comments

Comments
 (0)