How to generate, mask, and output a token from one job in a workflow to the next #29880
-
I'm building a GH Actions workflow for running tests that needs an instance of the MS SQL Server database. So, in my unit-test job, I've defined a service to spawn the mssql db in a container. This service requires an initial password to be passed via Example code: name: Tests
on:
push
jobs:
gen-passwords:
runs-on: ubuntu-latest
outputs:
SAPW: ${{ steps.genpw.outputs.sapw }}
steps:
- name: install password generator
run: sudo apt install --quiet --assume-yes apg
- name: generate database passwords
id: genpw
run: |
RAND_PW=$(apg -a 1 -n 1 -m 32 -M SNCL -E \''@:;[]{}()\"')
printf "::add-mask::%s\n" "$RAND_PW"
printf "::set-output name=sapw::%s\n" "$RAND_PW"
echo "Generated password has character class distribution:"
printf '%s' "$RAND_PW" \
| sed -e 's/[[:lower:]]/a/g' \
-e 's/[[:upper:]]/A/g' \
-e 's/[[:digit:]]/0/g' \
-e 's/[^Aa0]/*/g' \
-e 's/./&\n/g' \
| sort | uniq -c
pw-test:
runs-on: ubuntu-latest
needs: gen-passwords
env:
SA_PW: ${{ needs.gen-passwords.outputs.SAPW }}
steps:
- name: check passing of generated passwords from a prior job
run: |
printf 'Got SA_PW length %s, distribution:\n' \
$(printf '%s' "$SA_PW" | wc -c)
printf '%s' "$SA_PW" \
| sed -e 's/[[:lower:]]/a/g' \
-e 's/[[:upper:]]/A/g' \
-e 's/[[:digit:]]/0/g' \
-e 's/[^Aa0]/*/g' \
-e 's/./&\n/g' \
| sort | uniq -c This fails with the second job, Am I doing something wrong? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
This isn't something currently supported 😞 https://github.com/orgs/community/discussions/13082 is a similar discussion and has an example workaround of encrypting and later decrypting the secrets instead of masking. You could also temporarily save the password as a repository secret, use it in the next job and then clean it up. Here's an example of doing that. Unfortunately it requires using a personal access token (PAT) to save the secret, so at that point you may prefer just encrypting and decrypting the secrets and not masking them at all.1 Footnotes
|
Beta Was this translation helpful? Give feedback.
-
BACKGROUND CONTEXTAlthough there are now docs on masking and passing secrets between jobs or workflows, it didn't meet requirements like:
PROBLEM STATEMENTSWith these factors in mind, the main blockers are:
PROPOSED SOLUTION
WORKING EXAMPLEThese methods are sourced from DevSecTop/TF-via-PR (permalink) repository, which hosts a reusable workflow to run Terraform commands via PR comments, like a CLI. As a bonus, any number of secrets can be securely passed into the reusable workflow to be used as environment variables, for example. The repository also contains recent GitHub Actions workflow runs to verify that the secrets remain masked throughout. # caller-workflow.yml
jobs:
credentials:
runs-on: ubuntu-latest
outputs:
CREDENTIAL1: ${{ steps.credentials.outputs.CREDENTIAL1 }}
CREDENTIAL2: ${{ steps.credentials.outputs.CREDENTIAL2 }}
steps:
- name: Output encoded credentials
id: credentials
env:
CREDENTIAL1: ${{ secrets.CREDENTIAL1 }}
CREDENTIAL2: ${{ secrets.CREDENTIAL2 }}
run: |
echo "CREDENTIAL1=$(echo $CREDENTIAL1 | base64 -w0 | base64 -w0)" >> $GITHUB_OUTPUT
echo "CREDENTIAL2=$(echo $CREDENTIAL2 | base64 -w0 | base64 -w0)" >> $GITHUB_OUTPUT
reusable-workflow:
needs: credentials
uses: reusable-workflow.yml
secrets:
env_vars: |
CREDENTIAL1=${{ needs.credentials.outputs.CREDENTIAL1 }}
CREDENTIAL2=${{ needs.credentials.outputs.CREDENTIAL2 }} # reusable-workflow.yml
on:
workflow_call:
secrets:
env_vars:
required: true
jobs:
parse-credentials:
runs-on: ubuntu-latest
env:
env_vars: ${{ secrets.env_vars }}
steps:
- name: Decode credentials as environment variables
run: |
for i in $env_vars; do
i=$(echo $i | sed 's/=.*//g')=$(echo ${i#*=} | base64 -di | base64 -di)
echo ::add-mask::${i#*=}
printf '%s\n' $i >> $GITHUB_ENV
done
- name: Validate credentials
run: |
# Secrets are now available as masked environment variable.
echo $CREDENTIAL1 # or ${{ env.CREDENTIAL1 }}
echo $CREDENTIAL2 # or ${{ env.CREDENTIAL2 }} Where:
|
Beta Was this translation helpful? Give feedback.
This isn't something currently supported 😞
https://github.com/orgs/community/discussions/13082 is a similar discussion and has an example workaround of encrypting and later decrypting the secrets instead of masking.
You could also temporarily save the password as a repository secret, use it in the next job and then clean it up. Here's an example of doing that. Unfortunately it requires using a personal access token (PAT) to save the secret, so at that point you may prefer just encrypting and decrypting the secrets and not masking them at all.1
Footnotes
This suggestion was made on my own, not as an employee of GitHub 🙂 ↩