argo-workflows icon indicating copy to clipboard operation
argo-workflows copied to clipboard

Passing k8s secret to a workflow as input

Open roitalpaz opened this issue 3 years ago • 19 comments

Summary

I know it is possible to pass a secret to a container via ENV or FILE. but it is not possible to pass it as an argument of a workflow.

Use Cases

I have a few tools which accept values as command line args. These args are values which I'm not convenient in putting in YAMLs as plaintext and would like to store as k8s secrets.


Message from the maintainers:

Impacted by this bug? Give it a 👍. We prioritize the issues with the most 👍.

roitalpaz avatar Mar 25 '21 08:03 roitalpaz

Could you propose the syntax? Where would the secrets be? In the user namespace? The controller would need RBAC access. Might not pass security audit for some users.

alexec avatar Mar 25 '21 15:03 alexec

Thanks for the quick comment!

Syntax

Regarding the syntax I though something along the lines:

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: arguments-parameters-
spec:
  entrypoint: whalesay
  arguments:
    parameters:
    - name: message
      valueFrom:
         secretKeyRef:
           name: my-secret
           key: mypassword


  templates:
  - name: whalesay
    inputs:
      parameters:
      - name: message
    container:
      image: docker/whalesay:latest
      command: [cowsay]
      args: ["{{inputs.parameters.message}}"]

The valueFrom idea is taken from here: https://argoproj.github.io/argo-workflows/examples/#secrets

Secrets location

regarding the location of the secrets, I think placing the secret in the user namespace and giving permissions to the controller to this specific secret only will pass most security audits.

using the resourceNames https://kubernetes.io/docs/reference/access-authn-authz/rbac/#referring-to-resources

roitalpaz avatar Mar 29 '21 08:03 roitalpaz

That looks good. Would you like to submit a PR?

alexec avatar Mar 29 '21 15:03 alexec

Hi, may I work on this issue if no one does right now?

shuheiktgw avatar Jul 23 '21 06:07 shuheiktgw

@shuheiktgw hi, do you have any progress regarding this?

StepanKuksenko avatar Oct 17 '21 15:10 StepanKuksenko

We've recently added support for loading parameters from ConfigMaps in https://github.com/argoproj/argo-workflows/pull/6662 so it should be pretty straightforward to support secret as well following that reference implementation.

terrytangyuan avatar Oct 19 '21 01:10 terrytangyuan

If anyone would like to commit the changes, the core team will provide support.

alexec avatar Oct 19 '21 14:10 alexec

So for functionality is this basically a clone of #6982 @alexec @terrytangyuan ?

Should we also sanitize the display of such parameters as 'secret' ?

Should you be able to mark a parameter as secret at all?

- name: my-pass
  value: "{{some-output-val}}"
  secret: "true"

Which could subsequently not display the raw value anywhere? Same with outputs I guess... or is this overkill?

ArgoCD displays secrets like this: image

I'm having an issue right now where I'm using the http template and I have an API key. Right now it is passed in as a param but it renders in the UI. The alternative is to make a container running curl and pass it as an env value.... but I felt that was a little too much.

shadiramadan avatar Feb 02 '22 23:02 shadiramadan

I think you mean it is a clone of #6662. I think it might be more difficult. I think we store parameters in the workflows status. But, we should not do this with secrets. I might be wrong. Could you investigate?

alexec avatar Feb 03 '22 16:02 alexec

@roitalpaz you can mount the secret on pods. this is a more secure way to access the secret in container

sarabala1979 avatar May 04 '22 06:05 sarabala1979

any update on this?

panakour avatar May 21 '22 13:05 panakour

I'm unsure the reason Argo can't load secrets like this, but I suspect it was an intentional decision to limit Argo from accessing secrets directly. I just load the secret name into my workflows and pass it down to the container that needs it, and have it be "responsible" for getting the value from the secret.

jamesgoodhouse avatar Aug 17 '22 05:08 jamesgoodhouse

Related to OP:

When using Templates directly (e.g., the HTTP Template), it isn't possible to read a k8s secret into it.

beejiujitsu avatar Aug 26 '22 19:08 beejiujitsu

why not just pass the secret name in and have the container load the secret? there's no need for argo to load the secret, nor do i think it should.

jamesgoodhouse avatar Aug 26 '22 19:08 jamesgoodhouse

why not just pass the secret name in and have the container load the secret? there's no need for argo to load the secret, nor do i think it should.

The HTTP Template is a built-in template that doesn't offer container parameters, so what you're suggesting isn't possible.

https://argoproj.github.io/argo-workflows/http-template/

beejiujitsu avatar Aug 26 '22 19:08 beejiujitsu

I too am attempting to use http template, and would like to set the authorization header using a value from a secret.

kevinpauli avatar Aug 31 '22 04:08 kevinpauli

I too am attempting to use http template, and would like to set the authorization header using a value from a secret.

I wrote this workflow to work-around the httpTemplate secrets limitation.

You're welcome to modify this WorkFlowTemplate to suit your needs.

---
 apiVersion: argoproj.io/v1alpha1
 kind: WorkflowTemplate
 metadata:
   annotations:
     workflows.argoproj.io/description: 'Forked subgraph: notify Discord'
     workflows.argoproj.io/maintainer: '@beejiujitsu'
     workflows.argoproj.io/version: '>= v3.3.6'
   name: forked-subgraph-notify-discord
 spec:
   activeDeadlineSeconds: 172800
   arguments:
     parameters:
       - name: content_prefix
       - name: forked_subgraph_name
       - name: forked_subgraph_url
   entrypoint: main
   podGC:
     strategy: OnWorkflowSuccess
   podMetadata:
     labels:
       app: forked-subgraph
   templates:
     - container:
         args:
           - $(WEBHOOK_URL)
           - '--include'
           - '--json'
           - '{"content": "{{inputs.parameters.content_prefix}} {{inputs.parameters.forked_subgraph_name}}: {{inputs.parameters.forked_subgraph_url}}"}'
         command:
           - curl
         env:
           - name: WEBHOOK_URL
             valueFrom:
               secretKeyRef:
                 key: forked-subgraph
                 name: discord-webhooks
         image: curlimages/curl:7.84.0
         name: curl
         resources:
           limits:
             memory: 100Mi
           requests:
             memory: 50Mi
         securityContext:
           allowPrivilegeEscalation: false
           runAsGroup: 1000
           runAsUser: 1000
       inputs:
         parameters:
           - name: content_prefix
           - name: forked_subgraph_name
           - name: forked_subgraph_url
       name: main 

beejiujitsu avatar Aug 31 '22 18:08 beejiujitsu

Hi, I created a workaround for the secret parameter: a template that extracts secret as a output parameter.

apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
  name: secret-extractor
spec:
  templates:
    - name: main
      inputs:
        parameters:
          - name: secretName
          - name: secretKey
      outputs:
        parameters:
          - name: secretValue
            valueFrom:
              path: /tmp/secret-value
      container:
        image: docker-registry.netbase.com/alpine:latest
        command:
          - sh
          - '-c'
        args:
          - echo -n "$SECRET_VALUE" > /tmp/secret-value
        env:
          - name: SECRET_VALUE
            valueFrom:
              secretKeyRef:
                name: "{{inputs.parameters.secretName}}"
                key: "{{inputs.parameters.secretKey}}"
  entrypoint: main

One can use it in steps, for example:

apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
  name: demo
spec:
  templates:
    - name: main
      steps:
        - - name: extract-secret
            templateRef:
              name: secret-extractor
              template: main
            arguments:
              parameters:
                - name: secretName
                  value: demo-secret
                - name: secretKey
                  value: password
        - - name: print-msg
            template: msg-printer
            arguments:
              parameters:
                - name: msg
                  value: "{{steps.extract-secret.outputs.parameters.secretValue}}"
    - name: msg-printer
      inputs:
        parameters:
          - name: msg
      container:
        image: docker-registry.netbase.com/alpine:latest
        command:
          - echo
          - "{{inputs.parameters.msg}}"
  entrypoint: main

johnlinp avatar Oct 04 '22 05:10 johnlinp

@johnlinp Thanks for this, works perfectly! 👍🏼

Igor992 avatar Oct 17 '22 08:10 Igor992