【第3回】GitHub Actions × Python 自動化入門 — 自動デプロイとシークレット管理で本番運用に近づける

プログラミング

前回は GitHub Actions で Python スクリプトを定期実行する方法(スケジュール実行・手動トリガー)を紹介しました。今回はいよいよ「本番っぽい運用」に踏み込む回です。テーマは シークレット管理自動デプロイ。AWS の認証情報や API キーをどう安全に扱うか、というやつです。

正直、最初はこのあたりが一番よくわからなかった。ワークフローファイルは GitHub 上で丸見えなのに、どこに秘密情報を書けばいいのか…という混乱があって。調べていくうちにだいぶ整理できたので、まとめておきます。

  • GitHub Actions のシークレットの種類(Repository / Environment / Organization)と使い分け
  • Repository Secrets・Environment Secrets の具体的な設定手順
  • Python スクリプトでの環境変数の受け取り方
  • AWS Lambda への自動デプロイワークフローの実装例
  • シークレットを安全に扱うための注意点(echo 禁止・Variables との混同など)

GitHub Actions のシークレット管理、何が違う?

まず基本の整理から。GitHub Actions でシークレットを扱う方法は大きく3種類あります。

  • Repository Secrets:リポジトリ全体で使えるシークレット
  • Environment Secrets:特定の環境(production / staging など)に紐づいたシークレット
  • Organization Secrets:Organization 配下の複数リポジトリで共有できるシークレット

個人開発だと Repository Secrets だけで済むことが多いんですが、「本番環境には本番用の API キー、ステージングには別のキーを使いたい」みたいなケースが出てくると Environment Secrets が便利です。

シークレットは組織・リポジトリ・リポジトリ環境の単位で保存できます。GitHub Actions でシークレットを使うには、ワークフローファイル内で明示的に参照(環境変数やアクションの input に受け渡し)する必要があります。

Environment Secrets では、環境保護ルールとして「必須レビュアー(required reviewers)」を設定でき、承認が下りるまではその環境のシークレットにジョブがアクセスできない、という制御も可能になります。チームだとだいぶ助かるやつです。

Repository Secrets の設定手順

まずは Repository Secrets から。設定場所はリポジトリの Settings です。

「Settings」タブを開き、サイドバーの「Security」セクションから「Secrets and variables」→「Actions」を選択し、「Secrets」タブをクリックして登録できます。

ここで AWS_ACCESS_KEY_IDOPENAI_API_KEY などを登録しておきます。値は一度保存すると二度と見えません(本当に見えない)。

ワークフローから参照するには ${{ secrets.シークレット名 }} という構文を使います。

name: Deploy

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Install dependencies
        run: pip install -r requirements.txt

      - name: Run deploy script
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
        run: python deploy.py

Python 側では普通に os.environ で取得できます。

import os

api_key = os.environ["OPENAI_API_KEY"]
webhook_url = os.environ.get("SLACK_WEBHOOK_URL", "")

ちなみに env: ブロックはステップ単位で書くのが原則です。ジョブ全体に env: を設定することもできますが、スコープを絞った方が安全。最小権限の原則はワークフロー内でも意識したい。

Environment Secrets で dev / prod を切り替える

次に Environment Secrets のパターンです。たとえば「main ブランチへの push は production 環境にデプロイ、develop ブランチは staging に」という構成を作りたいとき。

まず GitHub 側で Environment を作成します。SettingsEnvironmentsNew environmentproductionstaging を作り、それぞれ別のシークレットを登録しておきます。

ワークフローでは environment: キーを指定するだけです。

jobs:
  deploy-prod:
    runs-on: ubuntu-latest
    environment: production   # ここで環境を指定
    steps:
      - uses: actions/checkout@v4
      - name: Deploy
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        run: python deploy.py

Environment Secrets にアクセスするには、設定された保護ルール(必須レビュアーなど)をすべてクリアする必要があります。

なお、Environment 自体や Environment Secrets は GitHub Pro / Team のプライベートリポジトリでも利用可能 です。一方で「必須レビュアー(required reviewers)」「wait timer」などの 一部のデプロイ保護ルールは、プライベートリポジトリでは Enterprise 以外だと使えないケースがあります(公開リポジトリだと無料で使えることもある)。プランとリポジトリ公開範囲で挙動が変わるので、ここだけは実際に Settings の画面で項目が出るか確認するのが確実です。

リポジトリシークレットはワークフロー横断で共有したい値に、Environment Secrets はデプロイ先ごとに異なるシークレット(例:dev/prod で別の API トークン)に使い分けるのが基本的な考え方です。

AWS デプロイの実装例(Lambda へのデプロイ)

具体例として、Python スクリプトを AWS Lambda にデプロイするワークフローを書いてみます。第1回・第2回でスケジュール実行や通知の仕組みを作ってきたので、その延長です。

AWS 認証には aws-actions/configure-aws-credentials を使います。

name: Deploy to Lambda

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Install dependencies
        run: |
          pip install -r requirements.txt -t ./package
          cp lambda_function.py ./package/

      - name: Zip package
        run: cd package && zip -r ../deploy.zip .

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1

      - name: Deploy to Lambda
        run: |
          aws lambda update-function-code \
            --function-name my-function \
            --zip-file fileb://deploy.zip

依存ライブラリを -t ./package で同じディレクトリに展開して zip にまとめるのが Lambda デプロイのお作法です。最初これがわからなくてけっこうハマりました。

OIDC 認証という選択肢も

余談ですが、最近は AWS 認証を長期的なアクセスキー(AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY)ではなく、OIDC トークンで行う方法も広まっています。

OIDC を使うと、GitHub Actions ワークフローから AWS リソースにアクセスする際に、長期間有効な AWS クレデンシャルを GitHub Secrets に保存する必要がなくなります。「長期の AWS アクセスキーを GitHub Secrets に置かなくて済む」というのが主なメリットで、クレデンシャルを長期間有効な状態で複製し続けなくていい、という考え方です。

ワークフロー側では permissions: id-token: write を追加して、configure-aws-credentials アクションに role-to-assume を渡す形になります。セキュリティ的にはこちらが理想なんですが、IAM Role(+ OIDC Provider)の設定が必要で少し手間があります。個人的にはまだアクセスキー方式で運用していて、OIDC への移行は「次のリファクタリングでやろう」と思い続けてそれなりの時間が経っています。

シークレットを安全に扱うための注意点

最後に、やらかしがちなポイントをいくつか。

echo でシークレットをログに出さない

GitHub Actions はシークレットの値をログにマスクしてくれますが、マスクは万能ではないです。たとえば、値を加工(base64 化したり、一部だけ切り出したり、JSON から取り出した値にしたり)すると、マスク対象から外れて漏れることがあります。なので echo ${{ secrets.SOMETHING }} は書かないのが原則です。

# NG
- run: echo "KEY=${{ secrets.API_KEY }}"

# OK: env 経由で渡してスクリプト内で使う
- run: python check.py
  env:
    API_KEY: ${{ secrets.API_KEY }}

Secrets と Variables を混同しない

シークレットとは別に「Variables」(vars.xxx)という機能もあります。こちらは秘匿性のない設定値(リージョン名・関数名など)を管理するためのもので、ログにも普通に表示されます。API キーを Variables に入れてしまうとそれだけで終わりなので、絶対に間違えないようにしましょう(見た目が似てるので油断すると混同します)。

フォークされたリポジトリからのアクセス

フォークされた PR からのワークフロー実行では、デフォルトでシークレットが渡されません。これは意図的な仕様で、悪意ある PR でシークレットを抜かれないようにするためです。オープンソースプロジェクトで CI を組む場合は特に意識しておいた方がいいです。

※この記事にはプロモーションが含まれます

ちなみに、お名前.com レンタルサーバー(WordPressに特化した高速レンタルサーバー。月額990円〜、独自ドメイン実質0円)も気になっています。お名前.com レンタルサーバー

まとめ

シークレット管理は「とりあえず Repository Secrets に入れておけば動く」というレベルから始めて、デプロイ先が複数になってきたら Environment Secrets を活用する、という流れが自然だと思います。OIDC は理想的ではあるけど、個人開発のうちはアクセスキー方式でも十分かなと(ちゃんとローテーションするという前提で)。

  • Repository Secrets:まず覚えるべき基本。個人開発はほぼこれで完結
  • Environment Secrets:dev / prod で異なるキーを使いたくなったら導入
  • OIDC 認証:セキュリティを突き詰めたいなら検討。ただし IAM 設定が必要
  • Variables との混同:API キーを Variables に入れない。これだけは絶対

そういえば最近、Actions の設定画面がちょいちょい変わってて「昨日と同じ場所に無い…」みたいなことが起きがちです。こういうの、地味に体力削られます。

タイトルとURLをコピーしました