动态检索 GitHub 操作密钥

Mar*_*Kim 11 github github-actions

我正在尝试在运行时使用 GitHub Actions 动态拉回 GitHub 机密:

假设我有两个 GitHub Secrets:

  1. SECRET_ORANGES : "这是一个橙色的秘密"
  2. SECRET_APPLES : "这是苹果的秘密"

在我的 GitHub Action 中,我有另一个 env 变量,它在分支之间会有所不同

env:
  FRUIT_NAME: APPLES
Run Code Online (Sandbox Code Playgroud)

本质上,我想找到一种方法来进行某种变量替换以获得正确的秘密。因此,在我的一项儿童工作中,我想做以下事情:

env:
  FRUIT_SECRET: {{ 'SECRET_' + env.FRUIT_NAME }}
Run Code Online (Sandbox Code Playgroud)

我尝试了以下方法但没有运气:

secrets['SECRET_$FRUIT_NAME'] }}
Run Code Online (Sandbox Code Playgroud)

我什至尝试了一种没有串联的更简单的方法,只是为了尝试让它工作

secrets['$FRUIT_NAME'] }}
Run Code Online (Sandbox Code Playgroud)

{{ secrets.$FRUIT_NAME }}

Run Code Online (Sandbox Code Playgroud)

以上都没有奏效。

如果我没有很好地解释这一点,请道歉。我试图让我的例子尽可能简单。

任何人都知道如何实现这一目标?

或者,我想做的是在每个分支的基础上存储秘密

例如:

customer1代码分支中: SECRET_CREDENTIAL="abc123"

customer2代码分支中: SECRET_CREDENTIAL="def456"

然后我可以SECRET_CREDENTIAL根据我所在的分支访问正确的值。

谢谢!

更新:我越来越接近我想要实现的目标:

name: Test

env:
  CUSTOMER: CUSTOMER1

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      AWS_ACCESS_KEY_ID: ${{ env.CUSTOMER }}_AWS_ACCESS_KEY_ID
    steps:
    - uses: actions/checkout@v2
    - run: |
        AWS_ACCESS_KEY_ID=${{ secrets[env.AWS_ACCESS_KEY_ID] }}
        echo "AWS_ACCESS_KEY_ID = $AWS_ACCESS_KEY_ID"
Run Code Online (Sandbox Code Playgroud)

Mei*_*bay 10

更新 - 2021 年 7 月

我找到了一种更好的方法来在作业中准备动态机密,然后在其他作业中将这些机密作为环境变量使用。

下面是它在GitHub Actions 中的样子。

我的假设是应该根据分支名称获取每个秘密。我通过这个动作rlespinasse/github-slug-action得到了分支的名称。

浏览内嵌注释以了解它们是如何协同工作的。

name: Dynamic Secret Names

# Assumption:
# You've created the following GitHub secrets in your repository:
# AWS_ACCESS_KEY_ID_master
# AWS_SECRET_ACCESS_KEY_master

on:
  push:

env:
  AWS_REGION: "eu-west-1"

jobs:
  prepare:
    name: Prepare
    runs-on: ubuntu-20.04
    steps:
      - uses: actions/checkout@v2
      - name: Inject slug/short variables
        uses: rlespinasse/github-slug-action@v3.x
      - name: Prepare Outputs
        id: prepare-step
        # Sets this step's outputs, that later on will be exported as the job's outputs
        run: |
          echo "::set-output name=aws_access_key_id_name::AWS_ACCESS_KEY_ID_${GITHUB_REF_SLUG}";
          echo "::set-output name=aws_secret_access_key_name::AWS_SECRET_ACCESS_KEY_${GITHUB_REF_SLUG}";
    # Sets this job's, that will be consumed by other jobs
    # https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idoutputs
    outputs:
      aws_access_key_id_name: ${{ steps.prepare-step.outputs.aws_access_key_id_name }}
      aws_secret_access_key_name: ${{ steps.prepare-step.outputs.aws_secret_access_key_name }}

  test:
    name: Test
    # Must wait for `prepare` to complete so it can use `${{ needs.prepare.outputs.{output_name} }}`
    # https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#needs-context
    needs:
      - prepare
    runs-on: ubuntu-20.04
    env:
      # Get secret names
      AWS_ACCESS_KEY_ID_NAME: ${{ needs.prepare.outputs.aws_access_key_id_name }}
      AWS_SECRET_ACCESS_KEY_NAME: ${{ needs.prepare.outputs.aws_secret_access_key_name }}
    steps:
      - uses: actions/checkout@v2
      - name: Test Application
        env:
          # Inject secret values to environment variables
          AWS_ACCESS_KEY_ID: ${{ secrets[env.AWS_ACCESS_KEY_ID_NAME] }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets[env.AWS_SECRET_ACCESS_KEY_NAME] }}
        run: |
          printenv | grep AWS_
          aws s3 ls
Run Code Online (Sandbox Code Playgroud)

更新 - 2020 年 8 月

在对这个项目terraform-monorepo进行了一些实践经验之后,下面是我如何设法动态使用秘密名称的示例

  1. 秘密名称与环境名称和分支名称对齐 - developmentstaging以及production
  2. $GITHUB_REF_SLUG来自获取分支名称的Slug GitHub Action
  3. 执行解析的命令是
      - name: set-aws-credentials
        run: |
          echo "::set-env name=AWS_ACCESS_KEY_ID_SECRET_NAME::AWS_ACCESS_KEY_ID_${GITHUB_REF_SLUG}"
          echo "::set-env name=AWS_SECRET_ACCESS_KEY_SECRET_NAME::AWS_SECRET_ACCESS_KEY_${GITHUB_REF_SLUG}"
      - name: terraform-apply
        run: |
          export AWS_ACCESS_KEY_ID=${{ secrets[env.AWS_ACCESS_KEY_ID_SECRET_NAME] }}
          export AWS_SECRET_ACCESS_KEY=${{ secrets[env.AWS_SECRET_ACCESS_KEY_SECRET_NAME] }}
Run Code Online (Sandbox Code Playgroud)

完整示例

name: pipeline

on:
  push:
    branches: [development, staging, production]
    paths-ignore:
      - "README.md"

jobs:
  terraform:
    runs-on: ubuntu-latest

    env:
      ### -----------------------
      ### Available in all steps, change app_name to your app_name
      TF_VAR_app_name: tfmonorepo
      ### -----------------------

    steps:
      - uses: actions/checkout@v2
      - name: Inject slug/short variables
        uses: rlespinasse/github-slug-action@v2.x
      - name: prepare-files-folders
        run: |
          mkdir -p ${GITHUB_REF_SLUG}/
          cp live/*.${GITHUB_REF_SLUG} ${GITHUB_REF_SLUG}/
          cp live/*.tf ${GITHUB_REF_SLUG}/
          cp live/*.tpl ${GITHUB_REF_SLUG}/ 2>/dev/null || true
          mv ${GITHUB_REF_SLUG}/backend.tf.${GITHUB_REF_SLUG} ${GITHUB_REF_SLUG}/backend.tf
      - name: install-terraform
        uses: little-core-labs/install-terraform@v1
        with:
          version: 0.12.28
      - name: set-aws-credentials
        run: |
          echo "::set-env name=AWS_ACCESS_KEY_ID_SECRET_NAME::AWS_ACCESS_KEY_ID_${GITHUB_REF_SLUG}"
          echo "::set-env name=AWS_SECRET_ACCESS_KEY_SECRET_NAME::AWS_SECRET_ACCESS_KEY_${GITHUB_REF_SLUG}"
      - name: terraform-apply
        run: |
          export AWS_ACCESS_KEY_ID=${{ secrets[env.AWS_ACCESS_KEY_ID_SECRET_NAME] }}
          export AWS_SECRET_ACCESS_KEY=${{ secrets[env.AWS_SECRET_ACCESS_KEY_SECRET_NAME] }}
          cd ${GITHUB_REF_SLUG}/
          terraform version
          rm -rf .terraform
          terraform init -input=false
          terraform get
          terraform validate
          terraform plan -out=plan.tfout -var environment=${GITHUB_REF_SLUG}
          terraform apply -auto-approve plan.tfout 
          rm -rf .terraform
Run Code Online (Sandbox Code Playgroud)

阅读本文后 - GitHub Actions 的上下文和表达式语法 ,重点关注 env object,我发现:

作为表达式的一部分,您可以使用两种语法之一访问上下文信息。

索引语法:github['sha']

属性解引用语法:github.sha

所以同样的行为适用于secrets,你可以做secrets[secret_name],所以你可以做以下

    - name: Run a multi-line script
      env:
        SECRET_NAME: A_FRUIT_NAME
      run: |
        echo "SECRET_NAME = $SECRET_NAME"
        echo "SECRET_NAME = ${{ env.SECRET_NAME }}"
        SECRET_VALUE=${{ secrets[env.SECRET_NAME] }}
        echo "SECRET_VALUE = $SECRET_VALUE"
Run Code Online (Sandbox Code Playgroud)

这导致

SECRET_NAME = A_FRUIT_NAME
SECRET_NAME = A_FRUIT_NAME
SECRET_VALUE = ***
Run Code Online (Sandbox Code Playgroud)

由于 SECRET_VALUE 被编辑,我们可以假设获取了真正的秘密。

我学到的东西——

  1. 你不能env从另一个引用env所以这行不通

    env:
      SECRET_PREFIX: A
      SECRET_NAME: ${{ env.SECRET_PREFIX }}_FRUIT_NAME
    
    Run Code Online (Sandbox Code Playgroud)

    SECRET_NAME 的结果是_FRUIT_NAME,不好

  2. 您可以在代码中使用上下文表达式,不仅是 in env,您还可以看到 in SECRET_VALUE=${{ secrets[env.SECRET_NAME] }},这很酷

当然 - 这是我测试的工作流程 - https://github.com/unfor19/gha-play/runs/595345435?check_suite_focus=true - 检查Run a multi-line script步骤


Ssa*_*der 8

使用format函数有一个更简洁的选项来实现这一点。

给定设置机密 DEV_A 和 TEST_A,以下两个作业将使用这两个机密:

name: Secrets

on: [push]

jobs:

  dev:
    name: dev
    runs-on: ubuntu-18.04
    env:
      ENVIRONMENT: DEV
    steps:
      - run: echo ${{ secrets[format('{0}_A', env.ENVIRONMENT)] }}

  test:
    name: test
    runs-on: ubuntu-18.04
    env:
      ENVIRONMENT: TEST
    steps:
      - run: echo ${{ secrets[format('{0}_A', env.ENVIRONMENT)] }}
Run Code Online (Sandbox Code Playgroud)

这也适用于通过手动工作流(workflow_dispatch事件)提供的输入:

name: Secrets

on:
  workflow_dispatch:
    inputs:
      env:
        description: "Environment to deploy to"
        required: true

jobs:
  secrets:
    name: secrets
    runs-on: ubuntu-18.04
    steps:
      - run: echo ${{ secrets[format('{0}_A', github.event.inputs.env)] }}
Run Code Online (Sandbox Code Playgroud)


Nic*_*Dao 6

如果这有帮助,在阅读了真正有帮助的上述答案后,我决定使用的策略包括按如下方式存储我的秘密:

  • DB_USER_MASTER
  • DB_PASSWORD_MASTER
  • DB_USER_TEST
  • DB_PASSWORD_TEST

其中 MASTER 是 prod 环境的 master 分支,TEST 是测试环境的 test 分支。

然后,使用该线程中建议的解决方案,关键是动态生成secrets变量的键。这些密钥是通过中间步骤(vars在下面的示例中称为)使用以下方法生成的outputs

name: Pulumi up
on:
  push:
    branches:
      - master
      - test
jobs:
  up:
    name: Update
    runs-on: ubuntu-latest
    steps:
      - name: Create variables
        id: vars 
        run: |
          branch=${GITHUB_REF##*/} 
          echo "::set-output name=DB_USER::DB_USER_${branch^^}"
          echo "::set-output name=DB_PASSWORD::DB_PASSWORD_${branch^^}"
      - uses: actions/checkout@v2
        with:
          fetch-depth: 1
      - uses: docker://pulumi/actions
        with:
          args: up -s ${GITHUB_REF##*/} -y
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
          PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}  
          DB_USER: ${{ secrets[steps.vars.outputs.DB_USER] }}  
          DB_PASSWORD: ${{ secrets[steps.vars.outputs.DB_PASSWORD] }}  
Run Code Online (Sandbox Code Playgroud)

注意获取大写分支的技巧:${branch^^}。这是必需的,因为 GitHub 强制机密为大写。


Mar*_*Kim 4

我能够使用工作流程名称作为分支特定变量来实现此目的。

对于我创建的每个分支,我只需更新 YML 文件顶部的单个值,然后添加 GitHub Secrets 以匹配工作流程名称:

name: CUSTOMER1

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      AWS_ACCESS_KEY_ID: ${{ github.workflow }}_AWS_ACCESS_KEY_ID
    steps:
    - uses: actions/checkout@v2
    - run: echo "::set-env name=AWS_ACCESS_KEY_ID::${{ secrets[env.AWS_ACCESS_KEY_ID] }}"
    - run: echo $AWS_ACCESS_KEY_ID

Run Code Online (Sandbox Code Playgroud)