Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SSM (or generic secrets plugin) support with Environment Variables #745

Closed
acaire opened this issue Jul 8, 2019 · 33 comments
Closed

SSM (or generic secrets plugin) support with Environment Variables #745

acaire opened this issue Jul 8, 2019 · 33 comments

Comments

@acaire
Copy link
Contributor

acaire commented Jul 8, 2019

I'd love to have the functionality of #662 but I wanted to throw my use-case in here while it's topical as what i'm suggesting is probably closer to #705.

We're deploying a bunch of apps, but one particular app has a helm vars file which expects over 150 config values (environment variables):

# example app.yaml.gotmpl
env:
  FOO1: {{ requiredEnv "FOO1" | quote }}  # fetched from /helm/$app/FOO1
  FOO2: {{ requiredEnv "FOO2" | quote }}  # fetched from /helm/$app/FOO2 etc.
  ....
  FOO150: ....

As we have a bunch of different apps across a range of languages and platforms, for us at least, it is best to leave the secret fetching and templating to helm/helmfile.

With the PR as it is, individual SSM fetches would likely be slow and prevent us from overriding values with ENV vars (not to mention our paths different between environments), and we'd likely go back to longer deploys and AWS rate limiting. It would be more useful for us to be able to inject entire SSM paths (i.e. /helm/$app/*) as environment variables for a helm run instead of what we're doing now which is using chamber. Chamber is great but means we have to iterate our helmfile.yaml anyway, read in the list of apps and whether or not they are to be installed, and then execute helmfile for each and every one.

It'd be great to have something like the following:

# helmfile.yaml
releases:
   - name: example which executes an app to inject values into the helm run
      envExec:
        - ["./my_script_that_exports_env_vars.sh", "{{MY_ENV}}", "{{$appName}}"]  # `$appName` resolved from name in YAML file, `MY_ENV` passed in via env var

# or

   - name: an integrated SSM plugin to inject values into the helm run
      ssm:
        paths:
         - /helm/{{MY_ENV}}/{{$appName}}/   # recursively pulling in every param due to a trailing slash
         - /helm/{{MY_ENV}}/{{$appName}}/or_individual_keys

Subsequently run with:

MY_ENV=test helmfile sync
or
MY_ENV=prod helmfile sync

In this example, the following keys:

/helm/test/app/FOO1
/helm/test/app/FOO2

Would be exported as:

FOO1=value_of_foo1_key
FOO2=value_of_foo2_key

Using env vars might simplify additional plugin development instead of using a custom resolver for each, as it makes it hard to template out the resolver.

@mumoshu
Copy link
Collaborator

mumoshu commented Jul 10, 2019

@acaire Hey! Thanks a lot for the detailed proposal.

I'm considering to enhance helmfile for this use-case but still figuring out how it should be done.

Would you mind reading my comment here #387 (comment) as the context - what if we added a mix of (1)a pluggable values provider interface and (2)a new configuration syntax that fits nicely with (1)?

The imaginary config would look like:

plugins:
  # This will normally load the executable binary `helmfile-ssm` in `$PATH` that serves the helmfile plugin. Implementation-wise we'd use hashicorp/go-plugin.
  # The plugin developer would implement the helmfile-ssm to advertise that it provides the `ssm` values provider that can be accessed with a `ssm` key under `releases[].valuesFrom`
  #
  # Perhaps we provide two flavors of helmfile binaries, one includes all the "standard" plugins like helmfile-ssm for easier onboarding experience, and a vanilla helmfile without any embedded plugins for people who doesn't use plugins and want to cut binary size
- name: ssm

releases:
- name: {{ . }}`
  chart: my-chart
  valuesFrom:
  - ssm:
       # All the values for the keys under `/helm/envname/appname/` will be fetched and imported as a flat hash of kvs
       path: /helm/{{MY_ENV}}/{{$appName}}/

And the new syntax valuesFrom plays nicely with other use-cases outlined in #387 (comment) as well...

Thoughts?

@acaire
Copy link
Contributor Author

acaire commented Jul 10, 2019

@mumoshu thanks for the quick response! I'm curious about the comment: will be fetched and imported as a flat hash of kvs - Will this be imported directly into .Values.FLAT_KEY as a 1:1 mapping with helm values, or available to be referenced as a helmfile value (i.e. like .Environment.Values?

I'd like to delve further into our current use of helmfile - Here's a templated values file for a postgresql chart (this is a custom fork of the chart, but the basic concept remains):

# example 1 - nested variables - We currently pull these down from ssm:/helm/prod/foo-postgres/* and import flat env vars
# prod is one example of an environment or parent path, we use ci, dev, test - And then we have individual developer paths with their names i.e. dev-ash.caire - So we supply base vars we think everyone will need, and allow devs to override according to their needs/branches.   This reigns true, even whether to install an app or not (i.e. `INSTALL_FOO_POSTGRES` in the `helmfile.yaml` example below)

image: postgres
imageTag: "10-alpine"

initdb:
  {{ if eq .Environment.Name "default" }}
  awsSecret: "aws-creds"
  {{ end }}
  enabled: true
  env:
    FOO_URL: https://{{ requiredEnv "FOO_SERVER_NAME" }}
  {{ if env "INITDB_S3PATH" }}
  s3path: {{ env "INITDB_S3PATH" }}
  {{ end }}

postgresUser: {{ requiredEnv "USERNAME" }}
postgresPassword: {{ requiredEnv "PASSWORD" }}
postgresDatabase: {{ requiredEnv "DATABASE" }}

{{ if ne .Environment.Name "default" }}
resources:
  limits:
    cpu: 20m
    memory: 100Mi
  requests:
    cpu: 10m
    memory: 100Mi
{{ end }}

and the related helmfile.yaml component:

  - name: foo-postgres
    namespace: {{ env "RELEASE_NAMESPACE" | default "foo-postgres" }} 
    chart: ./helm_charts/postgresql
    installed: {{ env "INSTALL_FOO_POSTGRES" | default "true" }}
    labels:
      app: foo
    values:
      - helm_vars/foo-postgres.yaml.gotmpl

Now if I wanted to set initdb.env.FOO_URL from SSM, would I have to do something like this?

# helmfile.yaml
releases:
  - name: foo-postgres
     plugins:
       - ssm:
            # side note: awesome if this was a list, because we do overrides (i.e. feature branches):
            - path: /helm/{{env "MY_ENV"}}/{{$appName}}/  # SSM key: /helm/prod/foo-postgres/FOO_URL, value: http://FOO
            - path: /helm/{{env "MY_ENV"}}/{{$appName}}-my-feature-branch/  # SSM key:  /helm/prod/foo-postgres-my-feature-branch/FOO_URL, value: http://BAR
     values:
        - helm_vars/foo-postgres.yaml.gotmpl

# values.yaml.gotmpl
initdb:
  env:
    FOO_URL: {{ .SsmValues.FOO_URL}}

Or would I have to store my values in SSM like this:

/helm/
  prod/
    foo-postgres/
      initdb/
        env/
          FOO_URL: http://FOO

I'd welcome any implementation to take away some of the sticky tape we've put around secrets management, but something that simply injects env vars to a helm run, seems far simpler than putting too much work into a plugin system, at least if we were going to maintain a fork of helmfile 😄 If we ever change our secrets provider, or logic - we don't have to change any of our values templates, just how the values are fetched.

@mumoshu
Copy link
Collaborator

mumoshu commented Jul 10, 2019

@acaire Hey!

Will this be imported directly into .Values.FLAT_KEY as a 1:1 mapping with helm values, or available to be referenced as a helmfile value (i.e. like .Environment.Values?

As the proposed valuesFrom resides under releases in my example above, it should be unable to mutate helmfile values(Neither .Environment.Values nor .Values) so the former seems correct if I didn't misread.

However looking into your foo-postgres.yaml.gotmpl, there is a bunch of env and requiredEnv scattered across multiple levels of the yaml hashes. a flat hash of kvs doesn't seem to help it.

Perhaps your use-case should be addressed in terms of helmfile values?

What if we enhanced the syntax to:

plugins:
  # This will normally load the executable binary `helmfile-ssm` in `$PATH` that serves the helmfile plugin. Implementation-wise we'd use hashicorp/go-plugin.
  # The plugin developer would implement the helmfile-ssm to advertise that it provides the `ssm` values provider that can be accessed with a `ssm` key under `releases[].valuesFrom`
  #
  # Perhaps we provide two flavors of helmfile binaries, one includes all the "standard" plugins like helmfile-ssm for easier onboarding experience, and a vanilla helmfile without any embedded plugins for people who doesn't use plugins and want to cut binary size
- name: ssm

valuesFrom:
- ssm:
     # All the values for the keys under `/helm/envname/appname/` will be fetched and imported as a flat hash of kvs
     path: /helm/{{MY_ENV}}/{{$appName}}/

releases:
- name: {{ . }}`
  chart: my-chart
  values:
  - helm_vars/foo-postgres.yaml.gotmpl
  # Or:
  #valuesFrom:
  #- template:
  #    path: helm_vars/foo-postgres.yaml.gotmpl

Where your foo-postgres.yaml.gotmpl will be written as:

image: postgres
imageTag: "10-alpine"

initdb:
  {{ if eq .Environment.Name "default" }}
  awsSecret: "aws-creds"
  {{ end }}
  enabled: true
  env:
    FOO_URL: {{.Values.FOO_URL}}
  {{ if .Values.INITDB_S3PATH }}
  s3path: {{ .Values.INITDB_S3PATH }}
  {{ end }}

postgresUser: {{ .Values.USERNAME }}
postgresPassword: {{ .Values.PASSWORD }}
postgresDatabase: {{ .Values.DATABASE }}

{{ if ne .Environment.Name "default" }}
resources:
  limits:
    cpu: 20m
    memory: 100Mi
  requests:
    cpu: 10m
    memory: 100Mi
{{ end }}

And in SSM you have the following keys set to corresponding values:

  • /helm/prod/foo-postgres/FOO_URL
  • /helm/prod/foo-postgres/INITDB_S3PATH
  • /helm/prod/foo-postgres/USERNAME
  • /helm/prod/foo-postgres/PASSWORD
  • /helm/prod/foo-postgres/DATABASE

WDYT?

If we ever change our secrets provider, or logic - we don't have to change any of our values templates, just how the values are fetched.

This seems to help your goal, in an another way.

@acaire
Copy link
Contributor Author

acaire commented Jul 10, 2019

Ahh that clears it up perfectly, thanks! I'm guessing from your example we'd be able to do this per release, so this would be our final syntax:

3 apps with mock SSM values:

/helm/prod/postgres1/FOO = 1
/helm/prod/postgres1-overrides/FOO = one
/helm/prod/postgres2/FOO = 2
/helm/prod/postgres3/FOO = 3

With this helmfile.yaml:

plugins:
  - name: ssm

releases:
  - name: postgres1
    chart: stable/postgresql
    values:
      - helm_vars/foo-postgres.yaml.gotmpl
    valuesFrom:
      - ssm:
          path: /helm/prod/postgres1/    # is there a way to reference releases[0].name here?
      - ssm:
          path: /helm/prod/postgres1-overrides/  # I'm assuming this wold be possible?

  - name: postgres2
    chart: stable/postgresql
    values:
      - helm_vars/foo-postgres.yaml.gotmpl
    valuesFrom:
      - ssm:
          path: /helm/prod/postgres2/

  - name: postgres3
    chart: stable/postgresql
    values:
      - helm_vars/foo-postgres.yaml.gotmpl
    valuesFrom:
      - ssm:
          path: /helm/prod/postgres3/

So .Values.FOO with your gotmpl example as you've described would be evaluated as one, 2 or 3 matching the app name. 👍

My only concern is terminology - values: refers to values optionally rendered by a gotmpl file and passed to helm, but now valuesFrom: refers to values passed to a gotmpl file, which is then rendered and passed to helm. Complicated further by using the same .Values.FOO syntax as helm ❓

@mumoshu
Copy link
Collaborator

mumoshu commented Jul 10, 2019

My only concern is terminology - values: refers to values optionally rendered by a gotmpl file and passed to helm, but now valuesFrom: refers to values passed to a gotmpl file, which is then rendered and passed to helm

No, it isn't how things work!

valuesFrom under releases[] never refer to values passed to gotmpl files.

@acaire
Copy link
Contributor Author

acaire commented Jul 10, 2019

Sorry maybe I'm not explaining correctly.

Basically, you have a list of releases under releases::

- name:       # refers to the 'helm' release name used in a helm release
  chart:      # refers to the 'helm' chart name used in a helm release
  values:     # refers to the 'helm' values used in a helm release
  valuesFrom: # refers to retrieved values from helmfile plugins to be used in .gotmpl template rendering

I was just suggesting that re-using the term values in the valuesFrom: directive, may cause confusion.

@mumoshu
Copy link
Collaborator

mumoshu commented Jul 10, 2019

releases[].valuesFrom is an extensible alternative to releases[].values, so in my understanding the explanations can be rewritten as:

- name:       # refers to the 'helm' release name used in a helm release
  chart:      # refers to the 'helm' chart name used in a helm release
  values:     # refers to the 'helm' values used in a helm release
  valuesFrom: # refers to the 'helm' values used in a helm release. Values are retrieved from helmfile plugins

@mumoshu
Copy link
Collaborator

mumoshu commented Jul 10, 2019

And my hidden plan is deprecating values in favor of valuesFrom, as this:

releases:
- name: myapp
   valuesFrom:
   - template:
        path: values.yaml.gotmpl

is an equivalent of:

releases:
- name: myapp
   values:
   - values.yaml.gotmpl

@acaire
Copy link
Contributor Author

acaire commented Jul 10, 2019

ok, cool so the example you gave earlier:

initdb:
  {{ if eq .Environment.Name "default" }}
  awsSecret: "aws-creds"
  {{ end }}
  enabled: true
  env:
    FOO_URL: {{.Values.FOO_URL}}

Populates initdb.env.FOO_URL with {{.Values.FOO_URL}}; but also if the chart had a FOO_URL defined in values.yaml, it would set/overwrite that?

As a more simplistic example, would this invalidate itself?

initdb:
  env:
    INIT_DB: {{.Values.initdb}}

@mumoshu
Copy link
Collaborator

mumoshu commented Jul 10, 2019

would this invalidate itself?

Still trying to understand - What do you imagine to happen when it isn't invalidated?

@acaire
Copy link
Contributor Author

acaire commented Jul 10, 2019

With a given SSM path specified via valuesFrom, the returned parameters are flattened and available within a .gotmpl via {{.Values}}.

i.e. /helm/prod/postgres1/ with a child key initdb with a value of true becomes accessible via {{.Values.initdb}} in a .gotmpl file.

But you're saying that this is also passed verbatim into the helm install? So if I didn't have a .gotmpl file at all, helmfile would basically run --set initdb=true as a helm arg.?

And if I did have a .gotmpl file, and specified it like this:

initdb:
  env:
    INITDB: {{.Values.initdb}}

You'd pass helm --set initdb=true and --set initdb.env.INITDB=true?

@mumoshu
Copy link
Collaborator

mumoshu commented Jul 11, 2019

But you're saying that this is also passed verbatim into the helm install?

For the top level valuesFrom , no.

For valuesFrom under releases[], yes - only valuesFroms under releases[] are passed verbatim to helm.

@acaire
Copy link
Contributor Author

acaire commented Jul 11, 2019

ok thanks for clearing that up - It will mean we'll have to be careful about the naming choice of our SSM keys (so as not to cause clashes as describe above with strings/nested dicts), but otherwise that implementation will work for us 👍

@mumoshu
Copy link
Collaborator

mumoshu commented Jul 11, 2019

@acaire Thanks for confirming!

Yes. Naming SSM keys will be important.

I wanted to note one thing though - If we could enhance the syntax to specify where the KVs should be imported, you'll less likely encounter clashes.

Suppose we added under to specify where to import KVs:

    valuesFrom:
      - ssm:
          under: foo.bar # Any other name better than `under`??
          path: /helm/prod/postgres2/

All the KVs under /helm/prod/postgres2 will be available under {{.Values.foo.bar.}} so that initdb could be accessed via {{.Values.foo.bar.initdb}}.

@acaire
Copy link
Contributor Author

acaire commented Jul 11, 2019

Great thanks! Yes that would work, assuming that Helm continues to ignore unused values data instead of erroring on it, which i'd hope is a pretty safe bet. Perhaps targetKey or destKey instead of under?

@mumoshu
Copy link
Collaborator

mumoshu commented Jul 11, 2019

Yes, I bet so too 😃

Also, I like targetKey, or maybe even simpler key!

@acaire
Copy link
Contributor Author

acaire commented Jul 11, 2019

Thanks! Let me know if there's anything I can do to assist :)

@rms1000watt
Copy link

rms1000watt commented Jul 11, 2019

@mumoshu I like the proposals above. Here's another twist on it:

plugins:
- type: ssm
  region: us-east-1
  path: /{{requiredEnv "env"}}/us-east-1/svc-1/

releases:
- name: 
  chart: my-chart
  values:
  - db:
    user: {{requiredEnv "DB_USER"}}
    pass: {{requiredEnv "DB_PASS"}}

When these exist in ssm:

  • /{{requiredEnv "env"}}/us-east-1/svc-1/DB_USER
  • /{{requiredEnv "env"}}/us-east-1/svc-1/DB_PASS

(My ❤️goes out to you @mumoshu. I'm guessing this is going to be a pain to implement since you have to render plugins first, then initialize plugins, then continue the rendering.. Maybe it's not too bad. Lol. But yeah, looking forward to this)


Edit:

Just to be more explicit, type can be ssm-env which means "Pull from ssm and populate my environment"

@aegershman
Copy link
Contributor

aegershman commented Jul 12, 2019

This is very interesting

  • Could a few non-SSM examples be included in these discussions as well (specifically sops)?
  • Would the secrets: key in helmfile.yaml be deprecated in favor of having sops become a plugin?

@mumoshu
Copy link
Collaborator

mumoshu commented Jul 12, 2019

@aegershman Hey! Thanks for chiming-in.

Could a few non-SSM examples be included in these discussions as well (specifically sops)?

Sure. Here it is:

plugins:
  # This will normally load the executable binary `helmfile-ssm` in `$PATH` that serves the helmfile plugin. Implementation-wise we'd use hashicorp/go-plugin.
  # The plugin developer would implement the helmfile-ssm to advertise that it provides the `ssm` values provider that can be accessed with a `ssm` key under `releases[].valuesFrom`
  #
  # Perhaps we provide two flavors of helmfile binaries, one includes all the "standard" plugins like helmfile-ssm for easier onboarding experience, and a vanilla helmfile without any embedded plugins for people who doesn't use plugins and want to cut binary size
- name: ssm

valuesFrom:
- ssm:
    # All the values for the keys under `/helm/envname/appname/` will be fetched and imported as a flat hash of kvs
    path: /helm/{{MY_ENV}}/{{$appName}}/

releases:
- name: myapp`
  chart: my-chart
  valuesFrom:
  - inline:
       foo: FOO
  - file:
      path: values/values.yaml
  - templateFile:
      path: values/values-file.yaml.gotmpl
      valuesFrom:
      # Instead of implicitly passing helmfile's Values to the values-file.yaml.gotmpl
      # Overrides it with `releaseName: myapp`
      - inlineTemplate:
          releaseName: `{{.Release.Name}}` #<- you'll need {{` `}} to defer rendering until the evaluation time of inlineTemplate. otherwise this fails due to that .Release.Name isn't available at loading-time of your helmfile.yaml :)
  - sops:
      # Path to the YAML file encrypted with sops or helm-secrets     
      path: secrets/secrets.yaml

Would the secrets: key in helmfile.yaml be deprecated in favor of having sops become a plugin?

That sounds like a good idea :)

@mumoshu
Copy link
Collaborator

mumoshu commented Jul 12, 2019

@rms1000watt Thanks!

Just to be more explicit, type can be ssm-env which means "Pull from ssm and populate my environment"

Understood. My idea was to make type defaults to the name of a plugin. That is:

- name: ssm

is equivalent to:

- type: ssm
  name: ssm

I like the distinction between type and name because it allows you to have different "plugin instances" with the same type but diversified configurations:

plugins:
- name: ssmUsEast1
   type: ssm
  region: us-east-1
  path: /{{requiredEnv "env"}}/us-east-1/
- name: ssmUsWest2
   type: ssm
  region: us-west-2
  path: /{{requiredEnv "env"}}/us-west-2/

releases:
- name: us-east-1-svc-1
  chart: my-chart
  valuesFrom:
  - ssmUsEast1:
      path: svc-1
- name: us-west-2-svc-1
  chart: my-chart
  valuesFrom:
  - ssmUsWest2:
      path: svc-1

I'd prefer pathPrefix over path under plugins[] so that it is clearer that it isn't the "default" path:

plugins:
- name: ssmUsEast1
   type: ssm
  region: us-east-1
  pathPrefix: /{{requiredEnv "env"}}/us-east-1/
- name: ssmUsWest2
   type: ssm
  region: us-west-2
  pathPrefix: /{{requiredEnv "env"}}/us-west-2/

@mumoshu
Copy link
Collaborator

mumoshu commented Jul 12, 2019

@acaire Can we consider an another syntax that plays nicely with the targetKey feature?

What we have so far is:

    # Import kv pairs
    valuesFrom:
      - ssm:
          targetKey: foo.bar # Any other name better than `under`??
          path: /helm/prod/postgres2/

But I want to suggest this as the alternative:

    # Import kv pairs
    setValues:
    - key: foo.bar
      valuesFrom:
      - ssm:
          path: /helm/prod/postgres2/

This also help smoothly extending the syntax for setting single kv:

    # Import a kv pair
    setValues:
    - key: foo.bar
      valueFrom:
      - ssm:
          path: /helm/prod/postgres2/bar

I'm not satisfied about that valuesFrom actually import not only values but also keys.

How about using keysAndValuesFrom for that, like:

    # Import kv pairs
    setValues:
    - keyPrefix: foo.bar
      keysAndValuesFrom:
      - ssm:
          path: /helm/prod/postgres2/

    # Import a kv pair
    setValues:
    - key: foo.bar
      valueFrom:
      - ssm:
          path: /helm/prod/postgres2/bar

@acaire
Copy link
Contributor Author

acaire commented Jul 12, 2019

@mumoshu Happy with either implementation, but I do like setValues - Could valueFrom just be source? keysAndValuesFrom seems overly verbose for what i'd consider to be an easy concept to follow - Ultimately IMHO, people care most about getting values to helm - The keys are important to reference of course but the values are crucial.

Also, Would there be a mechanism for recursion? (And while I think of it, caching previously fetched credentials across a helmfile execution?) I'd imagine some people would have a path like:

/helm/prod/postgres2/encrypted/ONE
/helm/prod/postgres2/decrypted/TWO

With:

    - key: foo.bar
      valueFrom:
      - ssm:
          path: /helm/prod/postgres2/

would they be available as .Values.foo.bar.encrypted.ONE and Values.foo.bar.decrypted.TWO? Also periods are valid path chars 😭

@mumoshu
Copy link
Collaborator

mumoshu commented Jul 12, 2019

Could valueFrom just be source?

Interesting idea. Perhaps you felt "value" in setValues and value(s)From redundant?

keysAndValuesFrom seems overly verbose for what i'd consider to be an easy concept to follow

I think so, too!

What if we extend the existing set to accept new things:

    # Import kv pairs
    set:
    - key: foo.bar
      valuesFrom:
      - ssm:
          path: /helm/prod/postgres2/

    # Import a kv pair
    set:
    - key: foo.bar
      valueFrom:
      - ssm:
          path: /helm/prod/postgres2/bar

vs

    # Import kv pairs
    setValues:
    - keyPrefix: foo.bar
      valuesFrom: # What could be a variant of `source` for `valuesFrom`?
      - ssm:
          path: /helm/prod/postgres2/

    # Import a kv pair
    setValues:
    - key: foo.bar
      source:
      - ssm:
          path: /helm/prod/postgres2/bar

@mumoshu
Copy link
Collaborator

mumoshu commented Jul 12, 2019

Would there be a mechanism for recursion?

I had not thought about that yet.

would they be available as .Values.foo.bar.encrypted.ONE and Values.foo.bar.decrypted.TWO? Also periods are valid path chars 😭

Good point!

Then maybe we'd use GetParametersByPath API and we'd better not recurse but import the path as-is.

For:

/helm/prod/postgres2/encrypted/ONE.one
/helm/prod/postgres2/decrypted/TWO.two

Helmfile will expose encrypted/ONE.one and decrypted/TWO.two under {{.Values.foo.bar}}.

It will be accessed like:

{{ index .Values.foo.bar "decrypted/ONE.one" }}
{{ index .Values.foo.bar "decrypted/TWO.two" }}

caching previously fetched credentials across a helmfile execution?

Probably it will be addressed in #444

@rms1000watt
Copy link

@mumoshu the other thing to consider is where to draw the line.

You could consider the only function of these plugins is to fill the environment. Then all usage of the plugins within the helmfile is just {{ requiredEnv "var" }}.


And blame it on 12-factor apps.. "Environment variables or nothing!" lololol jk 🤣

@mumoshu
Copy link
Collaborator

mumoshu commented Jul 13, 2019

@rms1000watt The fundamental problem I see there is that helmfile shouldn't mutate envvars. Otherwise multiple concurrent releases when --concurrency is set to some value greater than 1 will can end up data race on envvars :)

Helmfile can possibly be enhanced to internally translate requiredEnv "var" to .Values.var but then requiredEnv isn't really accessing any envvar so its name is quite confusing.

To me the point of 12-factor apps is that you should be able to use envvars to set/override any settings at runtime.

For that I believe you can already wire-up things to honor that today, writing a template expression like {{ default .Values.foo (env "FOO") }}.

But from your previous comments I didn't think it, honoring 12-facor apps rules, is your actual goal. Wouldn't your goal be no need to rewrite go templates and values.yaml files each time you switch the backend(SSM, values files, templates)?

If so, that's one of goals of the setValues/valuesFrom proposal 😃

@mumoshu
Copy link
Collaborator

mumoshu commented Jul 23, 2019

Related: #760 (comment)

@mumoshu
Copy link
Collaborator

mumoshu commented Sep 6, 2019

JFYI, this is the backend of this feature I've developed externally: https://github.com/mumoshu/values

It has support for:

  • Vault
  • AWS SSM Parameter Store
  • AWS Secrets Manager
  • Merge with Spruce (e.g. Append/Prepend Arrays In Hash)

@rms1000watt
Copy link

@mumoshu values looks beautiful. It looks like the perfect compliment to helmfile 🤣👍👍🙌🙌💙

Is it something you need help integrating with helmfile?

@mumoshu
Copy link
Collaborator

mumoshu commented Sep 6, 2019

@rms1000watt Yup, we need to integrate it into Helmfile 😃

@vladfr
Copy link

vladfr commented Sep 10, 2019

@mumoshu Hi! been following these threads for a while. values looks great, it's pluggable and generic enough, while keeping the yaml small. Kudos!

@mumoshu
Copy link
Collaborator

mumoshu commented Oct 25, 2019

@rms1000watt @acaire @vladfr I'm super excited about that SSM and also AWS Secrets Manager are finally supported via #906! Would you mind testing it out?


We've ended up with different syntax than what we've discussed in this thread.

But it turned out to provide more flexible configuration especially when combined with go templates.

Also, in near future, that syntax will allow us to keep references to secrets as-is, and defer the secrets retrieval to the time of kubectl apply when used with something like helmfile template --no-process-refs. Good fit for GitOps without SealedSecrets. See https://github.com/variantdev/vals#helm for more info on that.

@mumoshu mumoshu closed this as completed Oct 25, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants