自由気ままに書いちゃおう

好きなことをつらつらと・・・

【Github】リポジトリ設定のEnvironmentsの使い方について

Githubのリポジトリ設定にて整理する機会があったので、備忘。

Environments 設定箇所

リポジトリ > Settings > Code and automation > Environments

Environments 利用シーン

Environments ワークフローとの連携以外 に用いられるケースはほぼありません。(Deployments REST API 経由での利用も可能)

ワークフロー内でjobs.<job_id>.environment: <env> を付けると、そのジョブが実行される前に環境保護ルール(Required reviewers、Wait timer)を必ず通過しないと先に進めなくなります。

さらに、Environment に定義したシークレット(Environmentsシークレット)・変数(Environments変数)は、そのジョブからしか読み込めません。

それ以外、たとえばプルリク上でのブランチ制御やコードレビュー、Packages/Codespaces/Dependabot など他の GitHub 機能で Environment を直接参照したり制御したりする仕組みは提供されていません。

Environments で何ができるのか

Environments を使うことで、リポジトリ全体のシークレット(Settings -> Security -> Secrets and variables)とは別に、より細かいアクセス制御や承認フローをシークレット利用時に挟むことができます。

主なメリットは以下のとおりです:

  1. 環境ごとのシークレット分離

    • 通常のリポジトリシークレットは、ワークフロー内のどのジョブからでも ${{ secrets.NAME }} で取得可能です。※ 重要
    • 一方、Environment に登録したシークレットは、その環境を参照したジョブ(environment: staging など)でしか読み込めません。
    • たとえば、本番用の AWS 認証情報を production 環境にのみ置き、それ以外のブランチ/ワークフローでは一切参照できないようにできます。
  2. デプロイ前の保護(承認)ルール適用

    • Environment には「Required reviewers」や「Wait timer」を設定でき、ジョブが実際に環境シークレットへアクセスする前に人による承認や一定時間の待機を挟めます。
    • たとえば、production 環境のシークレットを取得する前に必ず 2 名以上のレビュアー承認を通す、といった運用が可能です。
  3. ブランチやタグの制限

    • 環境保護ルールで、どのブランチ/タグからのジョブだけが環境を利用できるかを指定できます。
    • これにより、dev ブランチでは staging 環境のシークレットは使えても、staging 環境の承認を通したジョブだけが production のシークレットを読める、という段階的アクセスコントロールが実現できます。
  4. 監査ログとの連携

    • 環境を介して実行されたジョブは、誰がいつ承認したかを GitHub の監査ログで追跡できます。
    • 機密情報へのアクセス記録を残すことで、セキュリティ要件への対応やインシデント時の調査に役立ちます。

「Required reviewers」

Required reviewers(必須レビューアー)

  • 何をするか 環境(Environment)に対して「このジョブを実行する前に、特定のユーザー/チームの承認を必須にする」機能です。
  • 主な挙動

    1. ワークフロー上で jobs.<job_id>.environment: <env-name> を指定したジョブは、開始直後に“保護ゲート”に入ります。
    2. ジョブは「Waiting」ステータスとなり、実際のステップ(run: 等)は実行されません。
    3. 必須レビュアーとして設定したユーザーまたはチームのうち いずれか1名 が「Approve & deploy」を行うと、ジョブは保護ゲートを通過し、続きのステップを実行します。
    4. 承認が 30日以内 に行われない場合、自動的に失敗扱いとなります。
  • 設定のポイント

    • レビュアーは最大 6 名(ユーザー/チームの組み合わせ)まで指定可能。
    • レビュアーには少なくともリポジトリの「Read」権限が必要。
    • 必要に応じて「自己承認を防ぐ(prevent self-review)」オプションで、ジョブ実行者自身による承認を禁止できます。
  • プラン制限

    • パブリックリポジトリ:Free/Pro/Team でも利用可
    • プライベート/内部リポジトリ:GitHub Enterprise プランが必要

「Wait timer」

Wait timer(待機タイマー)

  • 何をするか ジョブ実行開始直後に指定分数だけ “一時停止” し、その後で次の保護ルール(Required reviewers など)へ進ませる機能です。
  • 主な挙動

    1. ジョブがトリガーされると即座にタイマーを開始し、指定分数の間ジョブ実体を保留(保護ゲート内)にします。
    2. タイマーが切れると、ジョブは「タイマー待機完了」となり、次の承認ステップや実際の処理へ移行します。
  • 設定のポイント

    • タイマーは 1 分~43,200 分(30 日) の整数で設定可能。
    • タイマー中の時間は 課金対象外 です。
  • プラン制限

    • パブリックリポジトリ:Free/Pro/Team でも利用可
    • プライベート/内部リポジトリ:GitHub Enterprise プランが必要

両者を同時に使う場合の流れ

  1. ジョブがトリガー → Wait timer が動き出し、指定時間だけ保留
  2. タイマー切れ → 「承認待ち(Required reviewers)」の状態に移行
  3. 必須レビュアーのいずれかが承認 → ジョブ本体ステップが実行
  4. 未承認状態が 30日 継続すると失敗扱い

つまり、 * まず「最低限の待機時間」を確保し、 * その後「人による承認」を通過させて * 初めてデプロイ用スクリプトや機密シークレットへのアクセスを許可

ということができます。

Github契約プランによるEnvironments設定の違いについて

  • プライベートリポジトリでは Required reviewersWait timer といったデプロイ保護ルールは使えません

  • GitHub Free/Pro/Team プランでは、環境 (Environments) 自体や「環境シークレット」「デプロイ対象ブランチ制限」はプライベートリポジトリでも利用できますが、 Required reviewersWait timer をはじめとする「その他のデプロイ保護ルール」は パブリックリポジトリでのみ 有効です 。

  • プライベートリポジトリでこれらを利用するには、GitHub Enterprise プランへのアップグレードが必要になります 。

ワークフローでenvironmentsを指定した際に、Environmentsシークレット/変数が見つからなかったとき

GitHub Actions の secrets および vars(変数)コンテキストは、ジョブがアクセス可能な全レベルの値をまとめて提供します。つまり、ジョブで environment: production を指定すると、

  1. Environment シークレット
  2. Repository シークレット
  3. Organization シークレット

のすべてが secrets コンテキストにロードされ、同一キー名があれば Environment シークレットが優先 されます。

  • もし production 環境側に API_KEY が定義されていなくても、リポジトリ側に同じキー (API_KEY) があれば secrets.API_KEY で取得できます 。
  • どちらにも定義がなく参照しようとすると、戻り値は空文字列になります 。

同様に、変数 (vars)

  1. Environment 変数
  2. Repository 変数
  3. Organization 変数 をまとめて読み込み、同名キーは Environment 側が上書きします。定義がなければ Repository 側の変数が使われます 。

まとめ

  • environment: production を指定したジョブでは、Environment→Repository→Organization の順でシークレット/変数を参照。
  • Environment に値がなければ、リポジトリの値をそのまま利用。
  • どこにも存在しないキーを参照すると、空文字列が返ります。

ワークフローでenvironmentsを指定した際に、各箇所で同一名のEnvironmentsシークレット/変数を登録していた場合

Environment に secret1: A  
Repository に secret1: B  
Organization に secret1: C

であれば、最終的にはEnvironmentsのAが採用されます。

つまり優先順位は、Environments > Repository > Organizations。(範囲が狭いほうが優先されます。)

Environmentsを使ったワークフロー例

environmentワークフローのトップレベルステップレベルではなく、必ず各ジョブ (jobs.<job_id>) の中に定義する必要があります。

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production   # ← ここでのみ指定可能

    steps:
      - uses: actions/checkout@v4
      - name: Deploy
        run: ./deploy.sh
  • ジョブ外 (workflow ルート) に書くと構文エラー になります。
  • ステップ毎に environment を切り替えることもできず、あくまでジョブ単位で “このジョブはどの Environment の保護ルール・シークレットを使うか” を指定する用途です。

したがって、環境ゲートを使いたいジョブごとに必ず environment: <env-name> を書いてください。

サンプルコード

  • Environmentsにproductionとして登録済みとする。
name: Deploy with Environment Secrets

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    name: Deploy to Production
    runs-on: ubuntu-latest
    environment: production   # production 環境を参照

    defaults:
      run:
        working-directory: ./deploy-scripts  # デプロイスクリプトの場所

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Use production secrets
        # production 環境のシークレットを読み込む
        run: echo "ACCESS_KEY=${{ secrets.PROD_ACCESS_KEY }}" && \
             echo "SECRET=${{ secrets.PROD_SECRET_KEY }}"

      - name: Run deployment script
        run: ./deploy.sh
# environment設定値を手動ワークフロー実行時に指定するパターン
name: Terraform CI/CD

on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Deployment environment'
        required: true
        default: 'production'

jobs:
  terraform:
    runs-on: ubuntu-latest
    environment: ${{ github.event.inputs.environment }}   # 実行時に指定された environment を参照
    defaults:
      run:
        working-directory: ./infra  # 必要に応じてパスを調整してください

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Configure AWS Credentials (Assume Role)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}    # Assume Role 用の ARN
          aws-region: ${{ secrets.AWS_REGION }}
          role-session-name: github-actions-session      # 任意のセッション名

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: 1.7.2  # お好みのバージョンを指定可能

      - name: Terraform Init
        run: terraform init

      - name: Terraform Validate
        run: terraform validate

      - name: Terraform Format Check
        run: terraform fmt -check

      - name: Terraform Plan
        run: terraform plan -out=tfplan

以上です。