Github actions using secret

I’m trying to create a secret in k8s using github actions like following (I’ve pre step which install lightweight k8s - k3s)

  - name: example tests
    shell: bash
    env:
      SUPER_SECRET: ${{ secrets.KUBECONFIG }}
   run: |
       kubectl create secret generic mysec --from-literal="$SUPER_SECRET" -n default

But I got error, any idea how to do it using github actions?

I use the settings->secrets and create a KUBECONFIG value and put the file content

in my local env I created a secret successfully with a kubeconfig file like:

 kubectl create secret generic mysec --from-file=./kubeconfig -n default

But in the CI I want to use it from the secret env in github …

The error is: Error: Error: The process '/usr/local/bin/kubectl' failed with exit code 1

Error: ENAMETOOLONG: name too long, open '/home/runner/work/_temp/*** *** *** *** *** ***

What am I missing here?

I tried also with

kubectl create secret generic mysec --from-literal kubeconfig=$SUPER_SECRET -n default

if there is other way to make it work please let me know.

1 Like

HI, any idea or some hint/ workaround as we are currently stuck :frowning: thanks

Can you post a link to the workflow run that contains this error? Or, if it’s in a private repo, it’d be helpful if you could post the full log output for this step.

HI,

create a git secret and call it KUBECONFIG
use the following workflow

name: Example action

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - uses: actions/checkout@v2
      - name: install k8s
        run: |
          curl -sfL https://get.k3s.io | K3S_KUBECONFIG_MODE=777 sh -
          cat /etc/rancher/k3s/k3s.yaml
          mkdir -p ~/.kube
          cp /etc/rancher/k3s/k3s.yaml ~/.kube/config

      - uses: azure/k8s-set-context@v1
        with:
          method: kubeconfig
          kubeconfig: ~/.kube/config # Use secret (https://developer.github.com/actions/managing-workflows/storing-secrets/)
#          context: <context name>  #If left unspecified, current-context from kubeconfig is used as defaults
        id: setcontext



      - run: 'echo "$KUBECONFIG" > ~/.tmpfile'
        shell: bash
        env:
          KUBECONFIG: ${{secrets.KUBECONFIG}}

      - name: example tests
        shell: bash
        run: |
          cat ~/.tmpfile
          kubectl create secret generic project-kubecfg --from-file=~/.tmpfile -n default

This is the output

what I need is a way to create a k8s secret from github secret ,

Btw,

to double check the file, when I try locally to provide the secret (on kind cluster or other cluster ) it works with exact the same command and the same file content that I put in github secrets using

kubectl create secret generic project-kubecfg --from-file=~/.tmpfile -n default

/.tmpfile - contain the kubeconfig value

Thanks

@thomasshaped - please let me now if something is missing or isnt clear.

Hmm, I’m afraid I’m out of my depth here as this is more of a Kubernetes problem than an Actions one, but from what I can understand from the answers elsewhere online this error is usually caused by a missing config file, or one that’s not formatted as valid YAML. I’d double check that YAML file you’re creating is valid and that all the content is what you expect.

@thomasshaped - well, im not sure its related to K8S as if I take the file as-is and put it in my mac and create it works, however if I put the exact same file content in github.action and use the same command I got error. how can I see the file value after creating it as its print only asterisks.

regard the missing config file could you please send reference i’ll open to try anything as my team stuck with it few days

@thomasshaped - you can use the workflow that I provided and just create the following dummy file with git secret calledKUBECONFIG and you will get the error

{
“apiVersion”: “v1”,
“clusters”: [
{
“cluster”: {
“certificate-authority”: “fake-ca-file”,
“server”: “https://1.2.3.4
},
“name”: “development”
}
],
“contexts”: [
{
“context”: {
“cluster”: “development”,
“namespace”: “frontend”,
“user”: “developer”
},
“name”: “dev-frontend”
}
],
“current-context”: “dev-frontend”,
“kind”: “Config”,
“preferences”: {},
“users”: [
{
“name”: “developer”,
“user”: {
“client-certificate”: “fake-cert-file”,
“client-key”: “fake-key-file”
}
}
]
}

If you have the whole JSON file in the secrets it’s likely that something gets messed up while running it through the shell in the echo "$KUBECONFIG" > ~/.tmpfile command. I see two options here that might work:

  1. Keep only the actually private data (e.g. client private key, maybe cluster details) in secrets, and have a template with the JSON structure in your repository. Substitute the secrets during the workflow. This is what I’d prefer.
  2. Shell-escape the JSON before storing it in the secret.

Note that the documentation advises against storing structured data in secrets: :warning:

To help ensure that GitHub redacts your secret in logs, avoid using structured data as the values of secrets. For example, avoid creating secrets that contain JSON or encoded Git blobs.

@airtower-luna - thanks, I believe im not the first one which need such things, is there any example/reference which I can use as reference for the first suggestion? as im not sure how to do it…:frowning:

I tried option 2 to the following file (the file that I need to use in prod) using Escape Shell Characters - Online Linux Tools and got the same error, you can try reproduce (very simple) it with my workflow (just copy the workflow as-is) in previous post and take this file and put it as github secret as-is…

apiVersion: v1
kind: Config
clusters:
  - name: brf
    cluster:
      certificate-authority-data: >-
        LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURTakNDQWpLZ0F3SUJBZ0lVWjRTUWRmUEVUdmRnRmVQTVh0dE41RnJVaDFJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0t6RXBNQ2NHQTFVRUF4TWdkbWx5ZE2bUljTlRtakFWCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
      server: 'https://vfg.canary.k8s.ondemand.com'
users:
  - name: robot
    user:
      token: >-
        eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJnYXJkZW4tZGV2eC1raW5nIiwia3ViZXJuZXRlcyGWyljXldfIpa7UYYMg1ZQ2b0xqHX57C8RNTzXC4r13ch7MW4T7Yvww__xolvU7sxwxnftPsAACwHhEr0uPBxECAnp2exDwzCrNxPj5rPhA96kBg7EB0BGa-G3hiZTb0p-ozB97IfhupHrlBDkusP7uxtib82eflmtBWjOZpQJ8a5aPuNWhjYGoUg
contexts:
  - name: g-root
    context:
      cluster: garden
      user: robot
      namespace: gking
current-context: gaot

Let’s say you have a secret TEST_SECRET and want to have it in the secret attribute of this JSON object, which contains a placeholder:

{
    "secret": "@TEST_SECRET@",
    "number": 42
}

Let’s assume that JSON is in test.json.in, and we want to write the result to test.json.

Option one (only for secrets that won’t mess with the shell): Search and replace the placeholder, sed is the traditional tool to do that:

- name: replace placeholder using sed
  run: |
    sed -e 's,@TEST_SECRET@,${{ secrets.TEST_SECRET }},' test.json.in >test.json

Option two: Parse the JSON input, set the field to the value you want, and write JSON. This doesn’t use the placeholder, instead I have a script that writes a certain environment variable to a certain field:

- name: set field in JSON
  env:
    TEST_SECRET: ${{ secrets.TEST_SECRET }}
  shell: python3 {0}
  run: |
    import json
    import os
    with open('test.json.in') as fh:
      data = json.load(fh)
    data['secret'] = os.environ['TEST_SECRET']
    with open('test-field.json', 'w') as fh:
      json.dump(data, fh)

The second option is a bit more complex but also more flexible. You can use any language with JSON support, Python is just my preference.

You can see both variants in action here:

I just saw your edit, did you mean to publish that token? You might want to revoke and replace it. :open_mouth:

One thing that might have gone wrong: You need to use echo -e to turn \n back into line breaks.

HI,

Thank you very much!!!, for option 2 (the token is not complete :slight_smile: ) ,

I tried also with echo - e and it doesnt works either, does it works for you?

in addition I’ve tried

- name: replace placeholder using sed
  run: |
    sed -e 's,@TEST_SECRET@,${{ secrets.TEST_SECRET }},' test.json.in >test.json

and I got error
image

That output looks like the secret still contains multiple lines, which is not going to work unfortunately. Or at least not without escaping, and the result wouldn’t be valid JSON unless you still have JSON syntax in the secret. I don’t see any single value in your examples that’d need multiple lines, try avoiding that.

HI,

First of all thanks for you time!
ahh bit confused.

I think what would be really helpful if you take the following file
and demonstrate how it should look like, or how should I store it in the git secret to make it work.

apiVersion: v1
kind: Config
clusters:
  - name: brf
    cluster:
      certificate-authority-data: >-
        LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURTakNDQWpLZ0F3SUJBZ0lVWjRTUWRmUEVUdmRnRmVQTVh0dE41RnJVaDFJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0t6RXBNQ2NHQTFVRUF4TWdkbWx5ZE2bUljTlRtakFWCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
      server: 'https://vfg.canary.k8s.ondemand.com'
users:
  - name: robot
    user:
      token: >-
        eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJnYXJkZW4tZGV2eC1raW5nIiwia3ViZXJuZXRlcyGWyljXldfIpa7UYYMg1ZQ2b0xqHX57C8RNTzXC4r13ch7MW4T7Yvww__xolvU7sxwxnftPsAACwHhEr0uPBxECAnp2exDwzCrNxPj5rPhA96kBg7EB0BGa-G3hiZTb0p-ozB97IfhupHrlBDkusP7uxtib82eflmtBWjOZpQJ8a5aPuNWhjYGoUg
contexts:
  - name: g-root
    context:
      cluster: garden
      user: robot
      namespace: gking
current-context: gaot

Regards,
Jenny

Assuming you want to keep the address of your server and the token private, you’d need two secrets:

  • CLUSTER_SERVER, value https://vfg.canary.k8s.ondemand.com
  • ROBOT_TOKEN, value eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9…

Template would look like this:

apiVersion: v1
kind: Config
clusters:
  - name: brf
    cluster:
      certificate-authority-data: >-
        LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURTakNDQWpLZ0F3SUJBZ0lVWjRTUWRmUEVUdmRnRmVQTVh0dE41RnJVaDFJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0t6RXBNQ2NHQTFVRUF4TWdkbWx5ZE2bUljTlRtakFWCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
      server: '@CLUSTER_SERVER@'
users:
  - name: robot
    user:
      token: >-
        @ROBOT_TOKEN@
contexts:
  - name: g-root
    context:
      cluster: garden
      user: robot
      namespace: gking
current-context: gaot

Matching the placeholder names with the secret names isn’t necessary, but hopefully makes clear what goes where. And then you need something like this in your workflow to replace the placeholders:

- name: replace placeholder using sed
  run: |
    sed -e 's,@CLUSTER_SERVER@,${{ secrets.CLUSTER_SERVER }},' -e 's,@ROBOT_TOKEN@,${{ secrets.ROBOT_TOKEN }},' config.yaml.in >config.yaml

One secret per value.

Hey,

I think this is the miss understanding , I didnt explain my self well .
I need to keep all the file as a secret as-is and from it build k8s secret.
How can I do it, as I have to store multi files?

Thanks,
Jenny

@airtower-luna - according to your suggestions, does it make sense to do it like

{
    "secret": "{\r\n  \"apiVersion\": \"v1\",\r\n  \"kind\": \"Config\",\r\n  \"clusters\": [\r\n    {\r\n      \"name\": \"brf\",\r\n      \"cluster\": {\r\n        \"certificate-authority-data\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURTakNDQWpLZ0F3SUJBZ0lVWjRTUWRmUEVUdmRnRmVQTVh0dE41RnJVaDFJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0t6RXBNQ2NHQTFVRUF4TWdkbWx5ZE2bUljTlRtakFWCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=\",\r\n        \"server\": \"https:\/\/vfg.canary.k8s.ondemand.com\"\r\n      }\r\n    }\r\n  ],\r\n  \"users\": [\r\n    {\r\n      \"name\": \"robot\",\r\n      \"user\": {\r\n        \"token\": \"eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJnYXJkZW4tZGV2eC1raW5nIiwia3ViZXJuZXRlcyGWyljXldfIpa7UYYMg1ZQ2b0xqHX57C8RNTzXC4r13ch7MW4T7Yvww__xolvU7sxwxnftPsAACwHhEr0uPBxECAnp2exDwzCrNxPj5rPhA96kBg7EB0BGa-G3hiZTb0p-ozB97IfhupHrlBDkusP7uxtib82eflmtBWjOZpQJ8a5aPuNWhjYGoUg\"\r\n      }\r\n    }\r\n  ],\r\n  \"contexts\": [\r\n    {\r\n      \"name\": \"g-root\",\r\n      \"context\": {\r\n        \"cluster\": \"garden\",\r\n        \"user\": \"robot\",\r\n        \"namespace\": \"gking\"\r\n      }\r\n    }\r\n  ],\r\n  \"current-context\": \"gaot\"\r\n}",
    "number": 42
}

No. The point is specifically not to have JSON, YAML, or other syntax in the secret. Both because those can get messed up by running them through the shell (where ", braces, and brackets have special meaning), and because it’s possible it might mess with redacting secrets.