GitHub Actionsの応用設定

この講座では、GitHub Actionsの応用的な設定について学びます。

  • 変数の利用(env・vars・secrets・Context)
  • ワークフロー制御(条件分岐・マトリックス戦略)
  • パーミッション設定
  • 外部サービスとの接続(ベーシック認証・OIDC連携)
  • 保護ブランチと必須チェック

1. 変数の利用

GitHub Actions では、設定値や情報を「変数のように扱う」ことができます。このセクションでは、GitHub Actionsで利用できるいくつかの変数の違いや使い分けについて順番に説明します。

1.1 env(Environment Variables)

Environment Variables は、GitHub Actions で一般的に使われる変数の仕組みであり、env: というブロックで定義した変数をワークフローやジョブの中で利用できます。

Environment Variablesの定義

Environment Variables を定義する場合は、ワークフロー、ジョブ、ステップなど「使いたい場所」の冒頭に env: ブロックを記載します。その中に、変数名と値を記述します。

env:
  APP_NAME: demo-app
  STAGE: deployment

この例では、APP_NAMEdemo-appSTAGEdeployment という値を設定しています。

Environment Variables の主な利用シーンとしては、同じワークフロー内やジョブ内で、同じ値を繰り返し利用したい場合に有効です。APP_NAMESTAGE のような値は、処理の中で複数箇所に登場することがあり、毎回直接記載すると入力誤りのリスクがあったり、値が変更になった際に修正箇所が増える可能性があります。これらの問題を防ぐために Environment Variables が役立ちます。

Environment Variables は、そのスコープ(利用範囲)に応じて定義できます。ワークフローの冒頭に記載すればワークフロー全体で利用でき、ジョブの冒頭に記載すればそのジョブ内のみ、ステップの冒頭に記載すればそのステップ内のみで利用できます。

Environment Variablesの利用方法

Environment Variables を利用したい場合は ${{ env.変数名 }} のように記載します。これにより、その部分が定義した値に展開されます。

steps:
  - name: 変数を表示
    run: echo "アプリ名は ${{ env.APP_NAME }}、ステージは ${{ env.STAGE }} です"

この例では、echo コマンドで APP_NAMESTAGE の値を表示しています。もちろん用途は表示に限らず、アクションのパラメータとして利用したり、変数の値に応じて処理を分岐したりするなど、幅広い活用が可能です。

1.2 vars(GitHub Variables)

GitHub VariablesはGitHubの画面上で定義できる設定値で、コードに直接値を記載したくない場合や、複数のワークフローで同じ値を使いたい場合などに有効です。

GitHub Variablesの定義

開発者がGitHubの画面上でGitHub Variablesを定義することで、ワークフローから使用できるようになります。設定値は変数名と値のセットで登録します。

主な利用シーンとしては、コード上に直接値を記載したくない場合や、複数のワークフローで同じ値を使いたい場合が該当します。例えば、設定値の例で挙げたAPP_NAMEAWS_REGIONなどは、ワークフローごとに変わるものではなく、GitHub全体で共通になることが多い値です。そのため、Environment Variablesとしてワークフロー内で定義するのではなく、GitHub VariablesとしてリポジトリまたはOrganization全体に定義することが有効になります。

GitHub Variablesの設定方法

GitHub Variablesは、GitHubの設定画面から、リポジトリ単位またはOrganization単位で設定ができます。下記は、APP_NAMEとAWS_REGIONというVariablesを設定した例です。

GitHub Variablesの利用方法

Variablesを利用する場合、${{ vars.変数名 }} の形式で参照できます。

steps:
  - name: GitHub Variablesを表示
    run: echo "アプリ名は ${{ vars.APP_NAME }}、リージョンは ${{ vars.AWS_REGION }} です"

この形式で参照すれば、GitHubの画面上で登録した値がそのまま出力されます。

GitHub Actions の variables・secrets の使い分けや書式の詳細は、GitHub公式ドキュメントのStore information in variablesに記載があります。

1.3 Secrets

Secretsは、varsとは異なり、値を安全に扱うためのパラメータです。パスワードやAPIキー、認証情報など、外部に漏れてはいけない情報を扱う場合に利用します。

💡 ポイント
varsとSecretsの使い分けに迷ったら、「その値が他人に見られても問題ないか?」で判断してください。リージョン名やアプリ名はvarsで問題ありませんが、パスワードやAPIキーは必ずSecretsを使ってください。

Secretsの特徴

扱い方はvarsと同様にワークフローから参照できますが、GitHubに登録した時点で値は非表示となり、後から内容を確認することもできません。また、ワークフロー内で誤ってログに出力された場合でも、値は自動的にマスクされ、***のように伏せられます。この仕組みにより、安全に機密情報を扱うことができます。

設定値の例としては、PASSWORDACCESS_KEYのような、外部に漏れてはいけない情報が対象です。

Secretsの設定方法

Secretsも、GitHubの画面上から、リポジトリ単位またはOrganization単位で設定できます。

Secretsの利用方法

Secretsを利用する場合は、事前にGitHub上で登録しておき、ワークフロー内では ${{ secrets.変数名 }} の形式で参照します。以下は、Secretsに登録したアクセスキーとパスワードを使って外部サービスにアクセスする例です。

env:
  API_URL: https://api.example-service.com

steps:
  - name: 外部サービスにデプロイ
    run: |
      curl -X POST ${{ env.API_URL }}/deploy \
        -H "X-Access-Key: ${{ secrets.ACCESS_KEY }}" \
        -H "X-Password: ${{ secrets.PASSWORD }}"

ワークフローが実行されても値そのものは表示されず、必要に応じて安全に利用されます。このように、Secretsで登録した値はGitHub内で厳重に保護される仕組みになっています。

Secretsの登録方法・スコープ(リポジトリ/環境/Organization)・暗号化の仕組みなどの詳細は、GitHub公式ドキュメントのUsing secrets in GitHub Actionsに記載があります。

1.4 Context

コンテキストとは、GitHub Actions が自動的に提供している変数の集合で、ワークフローがどのような状況で実行されているのかを参照するための情報です。

代表的なContext

Contextは開発者が定義する必要はなく、GitHubから自動で提供されます。

代表的なものとして、github.refで実行されたブランチの完全な参照(例:refs/heads/main)、github.ref_nameでブランチ名、github.shaでコミットを識別するID、github.actorで実行したユーザ名などが取得できます。

Contextの利用方法

Contextの利用方法ですが、コンテキスト名.プロパティ名 の形式で参照できます。

steps:
  - name: 実行情報を表示
    run: |
      echo "ブランチ名: ${{ github.ref_name }}"
      echo "コミットID: ${{ github.sha }}"
      echo "実行者: ${{ github.actor }}"

この仕組みにより、どのブランチでワークフローが動いているのか、どのコミットを対象に実行されているのか、誰が実行したのかといった内容を、実行中のワークフローから簡単に取得できます。

2. ワークフローの制御

このセクションでは、ワークフローの実行を制御する流れを説明します。今までは処理を単純に直列で実行していましたが、条件によって特定のステップやジョブを実行したり、ジョブ同士の依存関係によって実行順序を制御するなど、さまざまな制御方法があります。

2.1 条件分岐(if)

条件分岐は、特定の条件に一致した場合にのみ処理を実行したいときに利用する記述です。ワークフローの中で、あるステップを実行するかどうかを条件によって切り替えるための仕組みです。

条件分岐のイメージ

まず、条件の例として「ブランチが main かどうか」を判定するケースがあります。処理が始まった後、現在実行されているブランチ名を確認し、それが main であれば処理を実行し、main でなければそのステップはスキップされます。このように、条件に適合したときだけ処理が進むという流れになります。

条件分岐の記載方法

GitHub Actions では、if という項目を使って条件を記述します。

steps:
  - name: mainブランチのみデプロイ
    if: github.ref == 'refs/heads/main'
    run: echo "mainブランチへのデプロイを実行します"

  - name: mainブランチ以外の処理
    if: github.ref != 'refs/heads/main'
    run: echo "このブランチではデプロイをスキップします"

if の条件が true であればステップは実行され、false の場合はスキップされます。

ここで押さえておきたい点として、GitHub Actions の if には elseelse if といった構文は存在しません。条件に合わない場合は、そのステップが実行されずにスキップされる、という動作になります。上記のように、複数の条件分岐を行いたい場合は、条件ごとにステップを分けて記述する形になります。

このように、if を使うことで、ブランチ名やイベントの種類など、さまざまな条件に応じて柔軟に処理を切り替えることができます。

2.2 concurrency(同時実行制御)

同時実行制御は、ワークフローが同じタイミングで重複して実行されないようにするための仕組みです。特に、本番環境へのデプロイのように「同時に複数実行されると問題になる処理」を安全に管理する場面で役立ちます。

同時実行制御のイメージ

同じグループ名を与えられたワークフローは、同時に二つ以上動くことがありません。すでに一つが実行中であれば、新しく起動されたワークフローは制御されるようになります。この仕組みにより、例えば「同じデプロイ処理が並列で走ってしまう」といった事故を防ぐことができます。

また、動作の違いとして cancel-in-progress の設定があります。

cancel-in-progresstrue にすると、すでに実行中のジョブを強制的にキャンセルし、新しくキューに入ったジョブが優先的に実行されます。コードが更新され続けるような環境では、この動きが適している場合があります。

一方で、cancel-in-progressfalse に設定すると、現在実行中のジョブが終わるまで新しいジョブは待機します。落ち着いた運用で、毎回の実行結果を確実に残したい場合には、この設定が向いています。

同時実行制御の記載方法

これらの制御は、concurrency というブロックで指定します。

concurrency:
  group: deploy-production
  cancel-in-progress: true

group には制御したいグループ名を、cancel-in-progress には先ほど説明した動作を設定します。この例では、deploy-production というグループで同時実行を制御し、新しいワークフローが起動された際には実行中のものをキャンセルする設定になっています。

2.3 needs(ジョブ間依存)

ジョブ間依存は、複数のジョブが存在するワークフローの中で、どのジョブを先に実行し、どのジョブを後から実行するかを明確にするための仕組みです。特定のジョブを、ほかのジョブが終わるまで待機させたい場合に利用します。

ジョブ間依存のイメージ

まず、needs を指定しない場合の動きを考えます。ジョブを複数並べて記述しただけでは、それぞれは独立して実行されるため、実行順序は保証されません。極端な例では、build がまだ終わっていないのに deploy が先に実行されるといった状況が起きる可能性があります。

これに対して、needs を指定すると、依存先のジョブが確実に完了するまで次のジョブは実行されません。例えば deploy のジョブに needs: build と記載すると、deploy は build というジョブが正常に終わるまで待機し、完了後に実行されます。

ジョブ間依存の記載方法

needs の後に「依存したいジョブ名」をそのまま書くことで、ジョブ間の依存関係を定義できます。

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: echo "テストを実行"

  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "ビルドを実行"

  deploy:
    needs: [test, build]
    runs-on: ubuntu-latest
    steps:
      - run: echo "デプロイを実行"

この例では、deploy ジョブに needs: [test, build] を指定しているため、testbuild の両方が正常に完了した後に deploy が実行されます。このように、複数のジョブの完了を待ち、それらがすべて成功したタイミングで次のジョブを動かすことが可能です。

ジョブ間の実行順序を制御したい場合や、特定のジョブの成功が次の処理の前提になるようなワークフローでは、needs が非常に重要な役割を果たします。

2.4 そのほかの制御構文

他にもいくつか制御構文がありますが、利用頻度は上記と比べると少し低くなります。ここでは、簡単な紹介に留めておきます。

matrix

同じジョブを複数のパターンで繰り返し実行するための設定です。[項目, 項目, ・・・]のようにリスト形式で定義します。

複数バージョンの言語でテストを行いたい場合や、複数 OS に対して同じジョブを実行する場合に利用します。

下記は、actions/setup-python@v6のアクションを、3.10、3.11、3.12の複数パターンで実行したい場合のサンプルです。

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.10", "3.11", "3.12"]
    steps:
      - uses: actions/setup-python@v6
        with:
          python-version: ${{ matrix.python-version }}

matrix で指定できる項目数の上限や、includeexclude を使った組み合わせの絞り込みなどの仕様は、GitHub公式ドキュメントのRunning variations of jobs in a workflowに記載があります。

strategy

strategy は、matrix と組み合わせて複数のジョブを実行する際の動作を制御する設定です。

代表的なものに fail-fast があります。これは、どれか一つのパターンが失敗した時に、残りの並列実行を止めるかどうかを指定するものです。すべてのパターンを最後まで実行したい場合には false を指定します。

以下の例では、Ubuntu と macOS の2つの OS で並列テストを行うものの、どちらかが失敗しても残りは停止せず最後まで実行されます。

jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest]
    steps:
      - run: echo "テストを実行"

continue-on-error

continue-on-error は、ジョブやステップが失敗してもワークフロー全体を失敗扱いにしないための設定です。

テスト結果の比較や、特定の OS だけ一時的に問題がある時など、「失敗しても他の処理は続けたい」場合に使います。

以下の例では、一部のステップが失敗してもジョブ自体は成功した扱いとなり、後続の処理が続きます。

steps:
  - name: 実験的な処理
    run: exit 1
    continue-on-error: true

timeout-minutes

timeout-minutes は、ジョブやステップが無限に実行され続けることを防ぐための設定で、実行できる最大時間を指定します。外部 API の応答が遅い場合や、デプロイに時間がかかりすぎる可能性がある時に便利です。

以下の例では、このジョブは最大 10 分まで実行でき、時間を過ぎると強制的に停止します。

jobs:
  deploy:
    timeout-minutes: 10
    steps:
      - run: ./deploy.sh

defaults

defaults は、すべてのステップに共通する設定をまとめて記述するための仕組みです。特定のシェルを毎回書くのが面倒な場合や、すべての run ステップに共通オプションを付けたい場合に使います。以下の例では、すべての run ステップが bash を使うようになります。

defaults:
  run:
    shell: bash

jobs:
  sample:
    steps:
      - run: echo "このステップは bash で実行されます"

3. パーミッション

このセクションでは、GitHubのワークフローが行える権限を設定する「パーミッション」について説明します。

3.1 パーミッションとは

パーミッションは、ワークフローが GitHub のリソースにアクセスする際に、どこまでの権限を許可するかを制御する仕組みです。ワークフローの中で行われる操作が、GitHub 上のどのリソースにどのレベルでアクセスできるかを明確に指定します。

GitHub Actions からは、contentspull-requestsactions といった GitHub のリソースに対して操作を行うことができます。それぞれのリソースに対して、readwritenone のいずれかの権限を割り当てます。read は参照のみ、write は更新が可能、none は参照も更新もできないという意味です。権限を省略した場合は、基本的に read 権限が付与されますが、一部のリソースでは none が付与されるものもあります。

3.2 よくあるパーミッション

よくある権限として、contentswrite 権限を与えると、リポジトリへの push や release の作成、tags の作成や削除といった操作が許可されます。pull-requestswrite 権限を付与すると、プルリクエストへのコメント投稿や編集、ラベルの付与、マージなどが実行できます。actionswrite 権限では、ワークフローの再実行、別のワークフローの起動、アーティファクトの操作などが可能になります。

3.3 パーミッションの定義

パーミッションの定義は、permissions ブロックを使って記述します。

permissions:
  contents: write
  pull-requests: write
  actions: read

この例では、contentspull-requestswrite 権限を、actionsread 権限を付与しています。

また、パーミッションにはスコープがあり、ワークフロー全体に対して権限を指定する方法と、特定のジョブだけに対して権限を設定する方法があります。

jobs:
  deploy:
    permissions:
      contents: write
    steps:
      - run: echo "このジョブだけcontentsへのwrite権限を持つ"

必要な操作が限定されている場合は、このようにジョブ単位で権限を細かく調整することで、より安全な構成にできます。

このように、パーミッションは GitHub Actions のセキュリティや制御性を高めるために欠かせない仕組みです。必要な権限だけを適切に付与し、最小権限の原則に沿って設定していくことが重要になります。

4. 外部サービスとの接続

このセクションでは、GitHub Actionsから、AWSなどの外部サービスと接続する方法について説明します。

4.1 ベーシック認証

ベーシック認証は、外部サービスが発行する ID やパスワード、あるいはアクセスキーなどの固定された認証情報を直接送信して接続する、最もシンプルな認証方式です。仕組みは非常に直感的で、発行された資格情報をそのまま使って外部サービスにアクセスします。

ベーシック認証の特徴

まず、ベーシック認証で使用する資格情報には、パスワードやアクセスキーといった種類があります。これらは外部サービスが発行し、認証の際に利用します。

GitHub Actions では、こうした認証情報は Secrets に登録して管理します。Secrets に登録することで、パスワードやアクセスキーを安全に保持でき、ログなどにも値が表示されない仕組みになっています。

一方で、ベーシック認証には流出のリスクがあります。認証文字列が一度でも漏れてしまうと、本人になりすまして外部サービスにそのままアクセスされてしまう危険があります。このため、認証情報の取り扱いには細心の注意が必要です。

AWSを使ったベーシック認証の例

AWS を例にとると、まず開発者が IAMユーザに対してAWS のアクセスキーを発行します。次に、そのアクセスキーを GitHub の Secrets に登録します。そして、GitHub Actions 内で AWS CLI を使い、登録されたアクセスキーをもとに AWS へアクセスする、という流れになります。

steps:
  - name: AWS認証(ベーシック認証)
    uses: aws-actions/configure-aws-credentials@v5
    with:
      aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
      aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      aws-region: ap-northeast-1

この例では、Secretsに登録したアクセスキーを使ってAWSに接続しています。

このように、ベーシック認証は仕組みがシンプルな分、扱いやすさとリスクが表裏一体になっています。正しく管理すれば便利に利用できますが、運用には注意が欠かせない認証方式です。

4.2 OIDCプロバイダ

OIDCプロバイダを利用すると、GitHub が発行する ID トークンを外部サービス側で検証し、許可されたリポジトリやブランチからのアクセスだけを認証できるようになります。固定された資格情報を使わずに、安全にアクセス権を管理できる仕組みです。

イメージ

まず、GitHub Actions が外部サービスへ接続する際、GitHub は ID トークンを生成します。このトークンには、実行したアカウント、リポジトリ、ブランチなどの情報が含まれており、署名と発行元によって正当性が保証されています。

外部サービスは、この ID トークンを検証することで、「どのリポジトリから実行されたワークフローなのか」「どのブランチからの実行なのか」といった情報を正しく判断できます。そして、事前に許可しているリポジトリやブランチに一致する場合のみ、アクセスを許可します。これにより、不正なトークンを使ったアクセスや、未許可のブランチからの接続を防ぐことができます。

特徴

OIDC を利用する大きな特徴は、固定の資格情報、つまりアクセスキーのような長期間利用される認証情報が不要になることです。ID トークンは短い有効期限を持っており、毎回新しいものが発行されるため、セキュリティリスクが大きく減ります。また、どのリポジトリやブランチから実行されたかを外部サービス側で正確に判断できるため、アクセス制御も柔軟に行えます。

注意点

一方で注意点もあります。外部サービス側が OIDC に対応している必要があります。現時点では対応していないサービスも多いため、利用前に確認が必要です。また、GitHub Actions を経由した場合にのみトークンが信頼されるため、ローカル環境などから同じ方法では接続できません。この動作は、不正アクセスを防ぐための仕組みでもあります。

AWSとのOIDC連携の場合、ワークフローでは以下のように記述します。

permissions:
  id-token: write
  contents: read

steps:
  - name: AWS認証(OIDC)
    uses: aws-actions/configure-aws-credentials@v5
    with:
      role-to-assume: arn:aws:iam::123456789012:role/github-actions-role
      aws-region: ap-northeast-1

ベーシック認証と異なり、アクセスキーを指定する必要がなく、role-to-assume でAWS側に作成したIAMロールを指定するだけで接続できます。permissionsid-token: write を設定することで、GitHub ActionsがIDトークンを発行できるようになります。

OIDC を利用することで、固定された秘密情報を扱わずに安全に認証でき、より細かいアクセス制御が可能になります。特にクラウドサービスとの連携では、現代的で安全な方法として広く採用されつつある仕組みです。

GitHub ActionsからAWSへOIDCで接続する仕組みは、OIDC federation(AWS公式ドキュメント)でも解説されています。原文(英語表示時)には以下のような記述があります。

OIDC federation is a method for applications to request temporary AWS security credentials dynamically without the need to store long-term AWS credentials.

「アプリケーションがAWSの長期クレデンシャルを保存せずに、一時的なAWSセキュリティクレデンシャルを動的に要求するための仕組みである」と読み取れます。GitHub Actions側の発行・受け渡しの仕様については、GitHub公式ドキュメントのAbout security hardening with OpenID Connectに記載があります。なお、AWSドキュメントは画面右上の言語セレクタから日本語表示に切り替えられます。

5. 保護ブランチ

このセクションでは、GitHubへのマージ条件を制御する「保護ブランチ」について解説します。

5.1 保護ブランチとは

保護ブランチは、指定したブランチに対して一定の条件を満たさないとマージできないようにする、GitHub の保護機能です。誤った変更がデプロイ用のブランチに直接入ってしまうことを防ぎ、安全に開発を進めるための仕組みです。

Pull Requestを必須にする

まず、保護ブランチの設定として代表的なものが「Pull Request を必須にする」という項目です。これは、対象のブランチに対して直接 push させず、必ず Pull Request を通すように強制する仕組みです。開発者が誤って直接 push してしまっても、その操作は拒否され、必ず Pull Request を経由した変更だけが反映されるようになります。

レビューを必須にする

次に、「レビューを必須にする」という設定があります。これは、特定のメンバー、もしくは特定人数のレビューが approve されていないと、Pull Request をマージできないようにするものです。コードレビューを必ず通すことで、品質や安全性を保ちながら変更を取り込むことができます。

特定のアクションを必須にする

さらに「特定のアクションを必須にする」という制御も有効です。たとえば、自動テストや静的解析など、Actions のジョブをステータスチェックとして設定しておき、そのチェックがすべて成功しない限りマージできないようにします。この設定により、不具合が含まれたコードが誤って本番ブランチに入ることを防ぐことができます。

このように保護ブランチは、直接 push を禁止したり、レビューを強制したり、自動テストを必須にするなど、複数の観点から変更の安全性を確保する効果があります。チーム開発での事故防止や品質向上において、非常に重要な役割を果たす機能です。

5.2 そのほかのルール

その他にも、保護ブランチには多数のルールがあります。

公式ドキュメントにルールの説明が記載されているため、必要に応じて参考にしてみてください。

保護されたブランチについて - GitHub Docs

6. まとめ

この講座では、GitHub Actionsの応用設定について学びました。

  • envはワークフロー内で使用する環境変数を定義し、${{ env.変数名 }}で参照する
  • varsはGitHub画面上で定義する変数で、${{ vars.変数名 }}で参照する
  • Secretsは機密情報を安全に管理し、ログでは自動的にマスクされる
  • ContextはGitHubが自動提供する情報(ブランチ名、コミットID、実行者など)
  • ifによる条件分岐で、特定の条件でのみステップを実行できる
  • concurrencyで同時実行を制御し、重複実行を防止できる
  • needsでジョブ間の依存関係を定義し、実行順序を制御できる
  • permissionsでワークフローがアクセスできるGitHubリソースの権限を制御する
  • OIDCを使うと、固定の認証情報なしで外部サービスと安全に接続できる
  • 保護ブランチでPull Request必須、レビュー必須、ステータスチェック必須などを設定できる