Skip to content

Commit

Permalink
Allow loading secrets from a separate config file
Browse files Browse the repository at this point in the history
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
  • Loading branch information
reegnz committed Jun 14, 2024
1 parent a21564a commit 6340b67
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 34 deletions.
34 changes: 4 additions & 30 deletions charts/policy-reporter/config.yaml
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
loki:
host: {{ .Values.target.loki.host | quote }}
certificate: {{ .Values.target.loki.certificate | quote }}
skipTLS: {{ .Values.target.loki.skipTLS }}
path: {{ .Values.target.loki.path | quote }}
secretRef: {{ .Values.target.loki.secretRef | quote }}
mountedSecret: {{ .Values.target.loki.mountedSecret | quote }}
minimumPriority: {{ .Values.target.loki.minimumPriority | quote }}
skipExistingOnStartup: {{ .Values.target.loki.skipExistingOnStartup }}
username: {{ .Values.target.loki.username | quote }}
password: {{ .Values.target.loki.password | quote }}
{{- with .Values.target.loki.customLabels }}
customLabels:
{{- toYaml . | nindent 4 }}
Expand All @@ -31,19 +28,14 @@ loki:
{{- end }}

elasticsearch:
host: {{ .Values.target.elasticsearch.host | quote }}
certificate: {{ .Values.target.elasticsearch.certificate | quote }}
skipTLS: {{ .Values.target.elasticsearch.skipTLS }}
username: {{ .Values.target.elasticsearch.username | quote }}
password: {{ .Values.target.elasticsearch.password | quote }}
apiKey: {{ .Values.target.elasticsearch.apiKey | quote }}
secretRef: {{ .Values.target.elasticsearch.secretRef | quote }}
mountedSecret: {{ .Values.target.elasticsearch.mountedSecret | quote }}
index: {{ .Values.target.elasticsearch.index | default "policy-reporter" | quote }}
rotation: {{ .Values.target.elasticsearch.rotation | default "daily" | quote }}
minimumPriority: {{ .Values.target.elasticsearch.minimumPriority | quote }}
skipExistingOnStartup: {{ .Values.target.elasticsearch.skipExistingOnStartup }}
typelessApi: {{ .Values.target.elasticsearch.typelessApi }}
{{- with .Values.target.elasticsearch.sources }}
sources:
{{- toYaml . | nindent 4 }}
Expand All @@ -62,8 +54,6 @@ elasticsearch:
{{- end }}

slack:
webhook: {{ .Values.target.slack.webhook | quote }}
channel: {{ .Values.target.slack.channel | quote }}
secretRef: {{ .Values.target.slack.secretRef | quote }}
mountedSecret: {{ .Values.target.slack.mountedSecret | quote }}
minimumPriority: {{ .Values.target.slack.minimumPriority | quote }}
Expand All @@ -86,7 +76,6 @@ slack:
{{- end }}

discord:
webhook: {{ .Values.target.discord.webhook | quote }}
secretRef: {{ .Values.target.discord.secretRef | quote }}
mountedSecret: {{ .Values.target.discord.mountedSecret | quote }}
minimumPriority: {{ .Values.target.discord.minimumPriority | quote }}
Expand All @@ -109,7 +98,6 @@ discord:
{{- end }}

teams:
webhook: {{ .Values.target.teams.webhook | quote }}
certificate: {{ .Values.target.teams.certificate | quote }}
skipTLS: {{ .Values.target.teams.skipTLS }}
secretRef: {{ .Values.target.teams.secretRef | quote }}
Expand All @@ -134,7 +122,6 @@ teams:
{{- end }}

webhook:
host: {{ .Values.target.webhook.host | quote }}
certificate: {{ .Values.target.webhook.certificate | quote }}
skipTLS: {{ .Values.target.webhook.skipTLS }}
secretRef: {{ .Values.target.webhook.secretRef | quote }}
Expand Down Expand Up @@ -163,9 +150,7 @@ webhook:
{{- end }}

telegram:
token: {{ .Values.target.telegram.token | quote }}
chatID: {{ .Values.target.telegram.chatID | quote }}
host: {{ .Values.target.telegram.host | quote }}
certificate: {{ .Values.target.telegram.certificate | quote }}
skipTLS: {{ .Values.target.telegram.skipTLS }}
secretRef: {{ .Values.target.telegram.secretRef | quote }}
Expand Down Expand Up @@ -234,15 +219,12 @@ ui:
{{- end }}

s3:
accessKeyID: {{ .Values.target.s3.accessKeyID }}
secretAccessKey: {{ .Values.target.s3.secretAccessKey }}
secretRef: {{ .Values.target.s3.secretRef | quote }}
mountedSecret: {{ .Values.target.s3.mountedSecret }}
region: {{ .Values.target.s3.region }}
endpoint: {{ .Values.target.s3.endpoint }}
bucket: {{ .Values.target.s3.bucket }}
bucketKeyEnabled: {{ .Values.target.s3.bucketKeyEnabled }}
kmsKeyId: {{ .Values.target.s3.kmsKeyId }}
serverSideEncryption: {{ .Values.target.s3.serverSideEncryption }}
pathStyle: {{ .Values.target.s3.pathStyle }}
prefix: {{ .Values.target.s3.prefix }}
Expand All @@ -266,8 +248,6 @@ s3:
{{- end }}

kinesis:
accessKeyID: {{ .Values.target.kinesis.accessKeyID }}
secretAccessKey: {{ .Values.target.kinesis.secretAccessKey }}
secretRef: {{ .Values.target.kinesis.secretRef | quote }}
mountedSecret: {{ .Values.target.kinesis.mountedSecret | quote }}
region: {{ .Values.target.kinesis.region }}
Expand All @@ -293,9 +273,6 @@ kinesis:
{{- end }}

securityHub:
accountID: {{ .Values.target.securityHub.accountID }}
accessKeyID: {{ .Values.target.securityHub.accessKeyID }}
secretAccessKey: {{ .Values.target.securityHub.secretAccessKey }}
delayInSeconds: {{ .Values.target.securityHub.delayInSeconds }}
cleanup: {{ .Values.target.securityHub.cleanup }}
secretRef: {{ .Values.target.securityHub.secretRef | quote }}
Expand Down Expand Up @@ -381,10 +358,11 @@ leaderElection:
renewDeadline: {{ .Values.leaderElection.renewDeadline }}
retryPeriod: {{ .Values.leaderElection.retryPeriod }}

{{- with .Values.redis }}
redis:
{{- toYaml . | nindent 2 }}
{{- end }}
enabled: {{ .enabled }}
address: {{ .address }}
database: {{ .database }}
prefix: {{ .prefix }}

{{- with .Values.sourceConfig }}
sourceConfig:
Expand All @@ -400,15 +378,11 @@ logging:
api:
logging: {{ .Values.api.logging }}
basicAuth:
username: {{ .Values.global.basicAuth.username }}
password: {{ .Values.global.basicAuth.password }}
secretRef: {{ .Values.global.basicAuth.secretRef }}

database:
type: {{ .Values.database.type }}
database: {{ .Values.database.database }}
username: {{ .Values.database.username }}
password: {{ .Values.database.password }}
host: {{ .Values.database.host }}
enableSSL: {{ .Values.database.enableSSL }}
dsn: {{ .Values.database.dsn }}
Expand Down
63 changes: 63 additions & 0 deletions charts/policy-reporter/secrets.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
loki:
host: {{ .Values.target.loki.host | quote }}
username: {{ .Values.target.loki.username | quote }}
password: {{ .Values.target.loki.password | quote }}

elasticsearch:
host: {{ .Values.target.elasticsearch.host | quote }}
username: {{ .Values.target.elasticsearch.username | quote }}
password: {{ .Values.target.elasticsearch.password | quote }}
apiKey: {{ .Values.target.elasticsearch.apiKey | quote }}
typelessApi: {{ .Values.target.elasticsearch.typelessApi }}

slack:
webhook: {{ .Values.target.slack.webhook | quote }}
channel: {{ .Values.target.slack.channel | quote }}

discord:
webhook: {{ .Values.target.discord.webhook | quote }}

teams:
webhook: {{ .Values.target.teams.webhook | quote }}

webhook:
host: {{ .Values.target.webhook.host | quote }}
token: {{ .Values.target.webhook.token| quote }}

telegram:
token: {{ .Values.target.telegram.token | quote }}
host: {{ .Values.target.telegram.host | quote }}

googleChat:
webhook: {{ .Values.target.googleChat.webhook | quote }}

s3:
accessKeyID: {{ .Values.target.s3.accessKeyID }}
secretAccessKey: {{ .Values.target.s3.secretAccessKey }}
kmsKeyId: {{ .Values.target.s3.kmsKeyId }}

kinesis:
accessKeyID: {{ .Values.target.kinesis.accessKeyID }}
secretAccessKey: {{ .Values.target.kinesis.secretAccessKey }}

securityHub:
accountID: {{ .Values.target.securityHub.accountID }}
accessKeyID: {{ .Values.target.securityHub.accessKeyID }}
secretAccessKey: {{ .Values.target.securityHub.secretAccessKey }}

gcs:
credentials: {{ .Values.target.gcs.credentials }}

api:
basicAuth:
username: {{ .Values.global.basicAuth.username }}
password: {{ .Values.global.basicAuth.password }}

database:
username: {{ .Values.global.basicAuth.username }}
password: {{ .Values.global.basicAuth.password }}

redis:
username: {{ .Values.redis.username }}
password: {{ .Values.redis.password }}
8 changes: 5 additions & 3 deletions charts/policy-reporter/templates/config-secret.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{{- if not .Values.existingTargetConfig.enabled }}
{{- if not .Values.existingSecret.enabled }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "policyreporter.fullname" . }}-config
name: {{ include "policyreporter.fullname" . }}-secrets
namespace: {{ include "policyreporter.namespace" . }}
{{- if .Values.annotations }}
annotations:
Expand All @@ -12,5 +13,6 @@ metadata:
{{- include "policyreporter.labels" . | nindent 4 }}
type: Opaque
data:
config.yaml: {{ tpl (.Files.Get "config.yaml") . | b64enc }}
{{- end }}
secrets.yaml: {{ tpl (.Files.Get "secret.yaml") . | b65enc }}
{{- end }}
{{- end }}
15 changes: 15 additions & 0 deletions charts/policy-reporter/templates/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{{- if not .Values.existingTargetConfig.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "policyreporter.fullname" . }}-config
namespace: {{ include "policyreporter.namespace" . }}
{{- if .Values.annotations }}
annotations:
{{- toYaml .Values.annotations | nindent 4 }}
{{- end }}
labels:
{{- include "policyreporter.labels" . | nindent 4 }}
data:
config.yaml: {{ tpl (.Files.Get "config.yaml") . }}
{{- end }}
29 changes: 28 additions & 1 deletion charts/policy-reporter/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ spec:
{{- toYaml . | nindent 8 }}
{{- end }}
annotations:
checksum/secret: {{ include (print .Template.BasePath "/config-secret.yaml") . | sha256sum | quote }}
{{- if not .Values.existingTargetConfig.enabled }}
checksum/config: {{ include (print .Template.BasePath "/config.yaml") . | sha256sum | quote }}
{{- end }}
{{- with .Values.annotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
Expand Down Expand Up @@ -89,6 +91,16 @@ spec:
subPath: config.yaml
{{- end }}
readOnly: true
{{- if not .Values.existingTargetConfig.enabled }}
- name: config-secrets
mountPath: /app/secrets.yaml
{{- if and .Values.existingSecret.enabled .Values.existingSecret.subPath }}
subPath: {{ .Values.existingSecret.subPath }}
{{- else }}
subPath: secrets.yaml
{{- end }}
readOnly: true
{{- end }}
- name: tmp
mountPath: /tmp
{{- with .Values.extraVolumes.volumeMounts }}
Expand Down Expand Up @@ -116,13 +128,28 @@ spec:
emptyDir: {}
{{- end }}
- name: config-file
{{- /* keep existingTargetConfig a secret for backward compatibility */}}
{{- if .Values.existingTargetConfig.enabled }}
secret:
{{- if and .Values.existingTargetConfig.enabled .Values.existingTargetConfig.name }}
secretName: {{ .Values.existingTargetConfig.name }}
{{- else }}
secretName: {{ include "policyreporter.fullname" . }}-config
{{- end }}
{{- else}}
configMap:
name: {{ include "policyreporter.fullname" . }}-config
{{- end }}
optional: true
{{- if not .Values.existingTargetConfig.enabled }}
- name: config-secrets
secret:
{{- if and .Values.existingSecret.enabled .Values.existingSecret.name }}
secretName: {{ .Values.existingSecret.name }}
{{- else }}
name: {{ include "policyreporter.fullname" . }}-secrets
{{- end }}
{{- end }}
- name: tmp
{{- if .Values.tmpVolume }}
{{- toYaml .Values.tmpVolume | nindent 8 }}
Expand Down
22 changes: 22 additions & 0 deletions pkg/config/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,28 @@ func Load(cmd *cobra.Command) (*Config, error) {
log.Printf("[INFO] No configuration file found: %v\n", err)
}

// Load secrets from a dedicated secrets.yaml file
//
secretsFile := ""
secretsFlag := cmd.Flags().Lookup("secrets")
if secretsFlag != nil {
secretsFile = secretsFlag.Value.String()
}
if cfgFile != "" {
v.SetConfigFile(secretsFile)
} else {
v.AddConfigPath(".")
v.SetConfigName("secrets")
}

if err := v.MergeInConfig(); err != nil {
log.Printf("[INFO] No configuration file found: %v\n", err)
}

if err := v.MergeInConfig(); err != nil {
log.Printf("[INFO] No configuration file found: %v\n", err)
}

if flag := cmd.Flags().Lookup("worker"); flag != nil {
v.BindPFlag("worker", flag)
}
Expand Down

0 comments on commit 6340b67

Please sign in to comment.