skip to Main Content

The idea is to share token between jobs, in order to avoid duplicating
the step of the generated token,

  1. any risks on doing so ?
  2. Seems that I am losing the token
    value in the others jobs, any ideas?
name: My Workflow
 
 on:   push:
     branches:
       - main
 
 jobs: 
   generate-token:
     runs-on: ubuntu-latest
     outputs:
       token: ${{ steps.github-app-token.outputs.token }}
     steps:
       - name: Generate Github App access token
         id: github-app-token
         uses: tibdex/github-app-token@021a2405c7f990db57f5eae5397423dcc554159c
         with:
           app_id: ${{ secrets.APP_ID }}
           private_key: ${{ secrets.PRIVATE_KEY }}
           installation_id: ${{ secrets.INSTALLATION_ID }}
       - name: Print access token
         run: echo ${{ steps.github-app-token.outputs.token }} 

    my-job:
     runs-on: ubuntu-latest
     needs: generate-token
     env:
       APP_ACCESS_TOKEN: ${{ needs.generate-token.outputs.token }}
     steps:
       - name: Checkout code
         uses: actions/checkout@v2
       - name: Use Github API
         run: |
           curl -H "Authorization: Bearer $APP_ACCESS_TOKEN" https://api.github.com/user
 

Thank you for your help

3

Answers


  1. Chosen as BEST ANSWER

    What worked for me (but not sure if I will actually use it) a solution proposed in this article

    1. Create a secret with pass phrase is mandatory
    2. Adding a step on Job one as following
            - name: Set outputs
              id: set_outputs
              run: |
                  echo "token=$(gpg --symmetric --batch --passphrase "$SECRET" --output - <(echo "${{ steps.generate_token.outputs.token }}") | base64 -w0)" >> $GITHUB_OUTPUT
              env:
                SECRET: ${{ secrets.PGP_SECRET_SIGNING_PASSPHRASE }}
    
    1. and to use the token or secret on the second job
    $(gpg --decrypt --quiet --batch --passphrase "$SECRET" --output - <(echo "${{ needs.generate-token.outputs.token }}" | base64 --decode))
    

    PS, I had an issue with the expirationdate, but this is another problem


  2. Your job my-job is missing the needs keyword. In order to use the output from a previous job you need to specify that my-job depends on generate-token by using needs. Only then can you use ${{ needs.generate-token.outputs.token }}. Also I would suggest re-ordering your job in your workflows fail it will make it easier to understand.

    Login or Signup to reply.
  3. ⚠️ Be VERY careful when passing secrets between jobs. The secret value will be visible in a number of cases, even if you apply the `::add-mask“ command diligently. Even if you encrypt the value, it may not be easily accessible, but the encrypted value will be logged and can be intercepted.

    In a number of cases the runner will even fail to set the output variable altogether, it will log a warning, but won’t fail the build:

    build

    Skip output ‘protect-this’ since it may contain secret.

    When a job runs in debug mode, even the first step will list all of the variables passed to it. They are logged in the debug logs plaintext and won’t be retroactively scrubbed when you register the secret using ::add-mask in the script itself.

    Sample workflow:

    # ⚠️ BAD EXAMPLE. This workflow demonstrates you can't rely on output variables to pass secrets.
    on:
      workflow_dispatch:
    
    env:
      ACTIONS_RUNNER_DEBUG: true
    
    
    jobs:
      build:
        outputs:
          environment: ${{ steps.environment-selector.outputs.environment }}
    
        runs-on: ubuntu-latest
        steps:
          - name: Run a one-line script
            id: environment-selector
            run: |
              echo "environment=prod" >> $GITHUB_OUTPUT
              echo '::add-mask::prod'          
    
      deploy:
         runs-on: ubuntu-latest
         needs: build
         steps:
         - name: Run a multi-line script
           run: |
              echo '::add-mask::${{ needs.build.outputs.environment }}'
              echo ${{ needs.build.outputs.environment }}
    

    In the debug logs:

    ##[debug]Evaluating condition for step: 'Run a multi-line script'
    ##[debug]Evaluating: success()
    ##[debug]Evaluating success:
    ##[debug]=> true
    ##[debug]Result: true
    ##[debug]Starting: Run a multi-line script
    ##[debug]Loading inputs
    ##[debug]Evaluating: format('echo ''::add-mask::{0}''
    ##[debug]echo {1}
    ##[debug]', needs.build.outputs.environment, needs.build.outputs.environment)
    ##[debug]Evaluating format:
    ##[debug]..Evaluating String:
    ##[debug]..=> 'echo ''::add-mask::{0}''
    ##[debug]echo {1}
    ##[debug]'
    ##[debug]..Evaluating Index:
    ##[debug]....Evaluating Index:
    ##[debug]......Evaluating Index:
    ##[debug]........Evaluating needs:
    ##[debug]........=> Object
    ##[debug]........Evaluating String:
    ##[debug]........=> 'build'
    ##[debug]......=> Object
    ##[debug]......Evaluating String:
    ##[debug]......=> 'outputs'
    ##[debug]....=> Object
    ##[debug]....Evaluating String:
    ##[debug]....=> 'environment'
    ##[debug]..=> 'prod'                         <<<< SECRET LOGGED AS PLAINTEXT
    ##[debug]..Evaluating Index
    

    ⚠️ Even if you encrypt the secret using GPG or another tool, the encrypted text will be stored for anyone to see and could be reverse engineered. You can’t hide the text safely.

    ⚠️ Most auth-related actions will inject a post-job script which will revoke the token as soon as the job finishes. So you can’t rely on a token to survive the job.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search