argoproj-labs / argocd-vault-plugin

An Argo CD plugin to retrieve secrets from Secret Management tools and inject them into Kubernetes secrets
https://argocd-vault-plugin.readthedocs.io
Apache License 2.0
831 stars 192 forks source link

Support decryption values.yaml #124

Closed lcc3108 closed 3 years ago

lcc3108 commented 3 years ago

My English is not so fluent Is your feature request related to a problem? Please describe. argocd-vault-plugin don't support decryption values.yaml

Describe the solution you'd like I think support decryption values.yaml more easier to use

Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.

Additional context

situation

values.yaml

password: <path:secret/data/harbor#password> 

templates/secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: {{ .Values.name }}
type: Opaque
data:
  PASSWORD: {{ .Values.password | b64enc | quote }}

key : "secret/data/harbor#password"
value: "password-at-vault"

key and value set at vault

if support values.yaml decryption

values.yaml decrypt by argocd-vault-plugin

password: "password-at-vault"

templates/secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: {{ .Values.name }}
type: Opaque
data:
  PASSWORD: "cGFzc3dvcmQtYXQtdmF1bHQ="
  #cGFzc3dvcmQtYXQtdmF1bHQ= equal base64 -d "password-at-vault"

but now release values.yaml

password: <path:secret/data/harbor#password>

templates/secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: {{ .Values.name }}
type: Opaque
data:
  PASSWORD: PHBhdGg6c2VjcmV0L2RhdGEvaGFyYm9yI3Bhc3N3b3JkPiA=
  #PHBhdGg6c2VjcmV0L2RhdGEvaGFyYm9yI3Bhc3N3b3JkPiA= equal base64 -d "<path:secret/data/harbor#password> "

It is difficult to change many files under the above circumstances.

werne2j commented 3 years ago

apiVersion: v1 kind: Secret metadata: name: {{ .Values.name }} type: Opaque data: PASSWORD: {{ .Values.password | b64enc | quote }}

Do you have control of this template? If so, you can just remove the | b64enc | quote and either use the base64encode modifier we provide or just input a bas64d value in vault.

password: <path:secret/data/harbor#password | base64encode>

lcc3108 commented 3 years ago

It is also possible to change the Helm template.

image but, I have many Helm Charts Changing multiple Helm templates can also cause human error. In my humble opinion, it would be good if you could support the method with fewer side effects and changes.

llavaud commented 3 years ago

I am facing the same problem and it would be great to have this feature. We use lots of upstream Helm charts and we can't control how they write their charts and often they take the secret value and base64 it... Before trying your plugin we have used the Banzai mutating webhook and they do something similar for Secret, they decode the value and search for the interpolation pattern. This is the last feature we are missing before we can migrate to this plugin ! ;)

teejaded commented 3 years ago

I'll take a look today and see if I can get something together. I made a tool that lets you use helm applications with this tool, and it would be useful to have this feature. Hopefully we can get it into 1.1.0

teejaded commented 3 years ago

Oops I found an issue with the feature I implemented while I was converting some apps over to use it.

Consider the following secret:

apiVersion: v1
kind: Secret
metadata:
  name: aws-credentials
type: Opaque
data:
  credentials: W2RlZmF1bHRdCmF3c19hY2Nlc3Nfa2V5X2lkPTxwYXRoOnNlY3JldC9hd3MjYWNjZXNzX2tleV9pZD4KYXdzX3NlY3JldF9hY2Nlc3Nfa2V5PTxwYXRoOnNlY3JldC9hd3Mjc2VjcmV0X2FjY2Vzc19rZXlfaWQ+

If we base64 decode the credentials we get this:

[default]
aws_access_key_id=<path:secret/aws#access_key_id>
aws_secret_access_key=<path:secret/aws#secret_access_key_id>

Adding modifiers to the placeholders won't let us base64 the entire thing again. I think the secret replacement needs to implicitly re-base64 a value that it has decoded.

werne2j commented 3 years ago

@teejaded Yeah, it seems like the modifiers are no longer working in this scenario..

apiVersion: v1
kind: Secret
metadata:
  name: example
  annotations:
    avp.kubernetes.io/path: some/path
data:
  sample-secret: PHB1bGxfc2VjcmV0IHwgYmFzZTY0ZW5jb2RlPg==
type: Opaque

Where PHB1bGxfc2VjcmV0IHwgYmFzZTY0ZW5jb2RlPg== is <pull_secret | base64encode>

And the output is

apiVersion: v1
kind: Secret
metadata:
  name: example
  annotations:
    avp.kubernetes.io/path: some/path
data:
  sample-secret: plain-text-secret
type: Opaque

Do you want to work on a fix for this? I will reopen the issue

werne2j commented 3 years ago

@teejaded actually.. i take that back. The modifier is working. So i am a little confused on what you are referring to as not working? We decided that the plugin is not suppose to base64 a value unless the modifier is used. If someone wants a base64 value injected, they would put it into Vault that way

teejaded commented 3 years ago

It only works in the case where the placeholder makes up the entire value. If I take my example value and add modifiers:

apiVersion: v1
kind: Secret
metadata:
  name: aws-credentials
type: Opaque
data:
  credentials: W2RlZmF1bHRdCmF3c19hY2Nlc3Nfa2V5X2lkPTxwYXRoOnNlY3JldC9hd3MjYWNjZXNzX2tleV9pZCB8IGJhc2U2NGVuY29kZT4KYXdzX3NlY3JldF9hY2Nlc3Nfa2V5PTxwYXRoOnNlY3JldC9hd3Mjc2VjcmV0X2FjY2Vzc19rZXlfaWQgfCBiYXNlNjRlbmNvZGU+

When you decode data.credentials you get:

[default]
aws_access_key_id=<path:secret/aws#access_key_id | base64encode>
aws_secret_access_key=<path:secret/aws#secret_access_key_id | base64encode>

And after AVP you end up with this invalid secret:

apiVersion: v1
kind: Secret
metadata:
  name: aws-credentials
type: Opaque
data:
  credentials: |-
    [default]
    aws_access_key_id=dGVzdF9rZXk=
    aws_secret_access_key=dGVzdF9rZXlfc2VjcmV0
werne2j commented 3 years ago

@teejaded Is this a yaml that you own? Or can you point me to an upstream helm chart you use, so that we can get a better idea of the problem? If you own the helm chart, then you can just convert the secret to use stringData.

If we can see an upstream chart that actually has the scenario you are describing it would help.

teejaded commented 3 years ago

I don't think it's that uncommon of a pattern. The bitnami chart maintainers seem to make pretty heavy use of it. This is the specific example I ran into.

https://github.com/bitnami/charts/blob/master/bitnami/external-dns/templates/secret.yaml#L16 https://github.com/bitnami/charts/blob/master/bitnami/external-dns/templates/_helpers.tpl#L205-L209

If I search their chart repo I get a couple dozen hits. Granted, I didn't go through every one of these templates to check if they're doing anything more than a conditional.

rg 'include .* \| b64enc'
bitnami/postgresql-ha/templates/ldap-secrets.yaml
15:  bind-password: {{ (include "postgresql-ha.ldapPassword" .) | b64enc | quote }}

bitnami/postgresql-ha/templates/pgpool/secrets.yaml
16:  admin-password: {{ (include "postgresql-ha.pgpoolAdminPassword" .) | b64enc | quote }}

bitnami/postgresql-ha/templates/postgresql/secrets.yaml
17:  postgresql-postgres-password: {{ include "postgresql-ha.postgresqlPostgresPassword" . | b64enc | quote }}
19:  postgresql-password: {{ (include "postgresql-ha.postgresqlPassword" .) | b64enc | quote }}
20:  repmgr-password: {{ (include "postgresql-ha.postgresqlRepmgrPassword" .) | b64enc | quote }}

bitnami/thanos/templates/objstore-secret.yaml
9:    {{- include "common.tplvalues.render" (dict "value" .Values.objstoreConfig "context" $) | b64enc | nindent 4 }}
12:    {{- include "common.tplvalues.render" (dict "value" .Values.indexCacheConfig "context" $) | b64enc | nindent 4 }}
16:    {{- include "common.tplvalues.render" (dict "value" .Values.bucketCacheConfig "context" $) | b64enc | nindent 4 }}

bitnami/kube-prometheus/templates/prometheus/additionalScrapeJobs.yaml
9:  scrape-jobs.yaml: {{ include "common.tplvalues.render" ( dict "value" .Values.prometheus.additionalScrapeConfigs.internal.jobList "context" $ ) | b64enc | quote }}

bitnami/jupyterhub/templates/hub/secret.yaml
17:  values.yaml: {{ include "common.tplvalues.render" ( dict "value" .Values.hub.configuration "context" $ ) | b64enc | quote }}

bitnami/airflow/templates/config/secret-external-db.yaml
15:  {{ include "airflow.database.existingsecret.key" . }}: {{ .Values.externalDatabase.password | b64enc | quote }}

bitnami/zookeeper/templates/secrets.yaml
16:  client-password: {{ include "zookeeper.clientPassword" . | b64enc | quote }}
17:  server-password: {{ include "zookeeper.serverPasswords" . | b64enc | quote }}

bitnami/minio/templates/secrets.yaml
16:  access-key: {{ include "minio.secret.userValue" . | b64enc | quote }}
17:  secret-key: {{ include "minio.secret.passwordValue" . | b64enc | quote }}

bitnami/redis-cluster/templates/secret.yaml
15:  redis-password: {{ include "redis-cluster.password" . | b64enc | quote }}

bitnami/external-dns/templates/secret.yaml
13:  alibaba-cloud.json: {{ include "external-dns.alibabacloud-credentials" . | b64enc | quote }}
16:  credentials: {{ include "external-dns.aws-credentials" . | b64enc | quote }}
18:  config: {{ include "external-dns.aws-config" . | b64enc | quote }}
22:  azure.json: {{ include "external-dns.azure-credentials" . | b64enc | quote }}

bitnami/redis/templates/secret.yaml
16:  redis-password: {{ include "redis.password" . | b64enc | quote }}

bitnami/harbor/templates/_helpers.tpl
394:  {{- include "harbor.database.rawPassword" . | b64enc | quote -}}
398:  {{- include "harbor.database.clairRawPassword" . | b64enc | quote -}}

bitnami/harbor/templates/core/core-secret-envvars.yaml
15:  _REDIS_URL_CORE: {{ include "harbor.redisForCore" . | b64enc | quote }}
16:  _REDIS_URL_REG: {{ include "harbor.redisForGC" . | b64enc | quote }}

bitnami/harbor/templates/registry/registry-secret.yaml
16:  REGISTRY_REDIS_PASSWORD: {{ (include "harbor.redis.rawPassword" .) | b64enc | quote }}

bitnami/harbor/templates/trivy/trivy-secret-envvars.yaml
17:  SCANNER_REDIS_URL: {{ include "harbor.redisForTrivyAdapter" . | b64enc }}
18:  SCANNER_STORE_REDIS_URL: {{ include "harbor.redisForTrivyAdapter" . | b64enc }}
19:  SCANNER_JOB_QUEUE_REDIS_URL: {{ include "harbor.redisForTrivyAdapter" . | b64enc }}

bitnami/harbor/templates/clair/clair-secret.yaml
16:  redis: {{ include "harbor.redisForClairAdapter" . | b64enc }}
17:  database: {{ include "harbor.database.clair" . | b64enc }}

bitnami/harbor/templates/chartmuseum/chartmuseum-secret.yaml
17:  CACHE_REDIS_PASSWORD: {{ include "harbor.redis.rawPassword" . | b64enc | quote }}

bitnami/harbor/templates/notary/notary-secret-envvars.yaml
16:  server_db_url: {{ include "harbor.database.notaryServer" . | b64enc | quote }}
17:  signer_db_url: {{ include "harbor.database.notarySigner" . | b64enc | quote }}

bitnami/postgresql/templates/secrets.yaml
15:  postgresql-postgres-password: {{ include "postgresql.postgres.password" . | b64enc | quote }}
17:  postgresql-password: {{ include "postgresql.password" . | b64enc | quote }}
19:  postgresql-replication-password: {{ include "postgresql.replication.password" . | b64enc | quote }}
werne2j commented 3 years ago

Fix available in https://github.com/IBM/argocd-vault-plugin/releases/tag/v1.1.0