首页 > 解决方案 > 动态检索 GitHub Actions 机密

问题描述

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

假设我有两个 GitHub Secrets:

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

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

env:
  FRUIT_NAME: APPLES

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

env:
  FRUIT_SECRET: {{ 'SECRET_' + env.FRUIT_NAME }}

我尝试了以下方法,但没有成功:

secrets['SECRET_$FRUIT_NAME'] }}

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

secrets['$FRUIT_NAME'] }}

{{ secrets.$FRUIT_NAME }}

以上都没有奏效。

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

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

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

例如:

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"

标签: githubgithub-actions

解决方案


更新 - 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

更新 - 2020 年 8 月

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

  1. 秘密名称与环境名称和分支名称对齐-developmentstagingproduction
  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] }}

完整示例

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

在阅读了这篇 - 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"

这导致

SECRET_NAME = A_FRUIT_NAME
SECRET_NAME = A_FRUIT_NAME
SECRET_VALUE = ***

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

我学到的东西——

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

    env:
      SECRET_PREFIX: A
      SECRET_NAME: ${{ env.SECRET_PREFIX }}_FRUIT_NAME
    

    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步骤


推荐阅读