はじめに

前の実験では、ロボットアシスタントが倉庫に自動的にログインしました。では、ロボットはパスワードをどこから取得したのでしょうか。

実際の自動化では、ワークフローが API キー、パスワード、トークンなどの機密データを必要とすることがよくあります。これらの値をリポジトリ内のファイルにハードコードしてはいけません。

GitHub は、ワークフローで使用する機密値を保護して保存する仕組みとして Secrets を提供しています。パイプラインでは権限のあるアクセスが必要になることが多いため、これは CI/CD における基本的なセキュリティ対策です。

これは、自動化のセキュリティにおける最も重要な境界の一つです。パイプラインには認証情報が必要ですが、その認証情報はバージョン管理にコミットするのではなく、保護されたストレージから実行時に注入するべきです。

この実験では、次のことを行います。

  • Vault に Secret のパスワードを作成する。
  • ロボットがそのパスワードを取得できるようにする。
  • ロボットがパスワードを表示しようとしても、GitHub がそれを検閲することを確認する。

前提条件

引き続き github-actions-basics リポジトリを使用します。

Secret を作成する

アプリケーションがデータベースへの接続を必要としているとします。データベースのパスワードを安全に保存する必要があります。

DB_PASSWORD という名前の Secret を作成します。

  1. GitHub で github-actions-basics リポジトリを開きます。
  2. Settings タブをクリックします。
  3. 左側のサイドバーで Secrets and variables メニューを探し、クリックして展開します。
  4. Actions を選択します。
  5. New repository secret と表示された緑色のボタンをクリックします。

New repository secret

次のような簡単なフォームが表示されます。

  • Name:DB_PASSWORD と入力します。(Secret 名には大文字を使用するのが一般的です)。
  • Secret:SuperSafePassword123! と入力します。

Add secret をクリックします。

これで DB_PASSWORD が一覧に表示されます。ただし、値はもう表示できません。Secret を保存すると、その値は永久に保護されます。更新または削除はできますが、あなたを含め、誰もその値を再び表示することはできません。

Secret を使用する

パスワードを安全に保存できたので、次はそれを使用するワークフローを作成します。

ここで重要なのは、間接参照というパターンです。ワークフローは名前で Secret を参照し、GitHub が実行中にその値を安全に解決します。

ワークフローの中では、${{ secrets.YOUR_SECRET_NAME }} という構文を使用して、任意の Secret にアクセスできます。

プロジェクトのディレクトリに移動します。

cd ~/project
git clone https://github.com/your-username/github-actions-basics.git
cd github-actions-basics

注:your-username は実際の GitHub ユーザー名に置き換えてください。

.github/workflows フォルダー内に、security-test.yml という新しいワークフローファイルを作成します。

touch .github/workflows/security-test.yml

nano で開きます。

nano .github/workflows/security-test.yml

次の内容を追加します。

name: Security Test

on: [push]

jobs:
  test-secret:
    runs-on: ubuntu-latest
    steps:
      - name: Try to print secret
        env:
          MY_PASSWORD: ${{ secrets.DB_PASSWORD }}
        run: echo "The password is $MY_PASSWORD"

ここでは、興味深い処理を行っています。GitHub Vault の Secret を、MY_PASSWORD という Environment Variable に移しています。その後、echo を使って表示しようとします。

待ってください! パスワードをログに出力するのは、ひどい方法ではありませんか。もちろん、ひどい方法です。しかし、これは GitHub Actions の強力なセキュリティ機能を実演するために行っています。

nano で保存して終了します。

マスキングを確認する

このワークフローを実行し、Secret を漏えいさせようとすると何が起こるかを確認します。

変更をコミットしてプッシュします。

git add .
git commit -m "Test secret masking"
git push

GitHub でリポジトリの Actions を開きます。

  1. 「Security Test」ワークフローの実行をクリックします。
  2. test-secret ジョブをクリックします。
  3. 「Try to print secret」ステップを展開します。

出力を確認します。次のような内容が表示されるはずです。

The password is ***

Secret masked

GitHub Actions は、$MY_PASSWORD の値が Secret に由来することを自動的に認識します。ログに何かを出力する前に、その機密値を検索し、*** に置き換えます。

マスキングによって、ログへの偶発的な情報漏えいによる被害を抑えられます。ただし、Secret を最初から出力しないことが、より適切な方法です。セキュリティ機能は安全網であり、不注意な取り扱いを正当化するものではありません。

この「Masking」機能があなたを保護します。誤って Secret を表示しようとした場合や、使用しているツールの出力が多すぎる場合でも、GitHub がそれを検知し、ログから機密データを削除します。

GITHUB_TOKEN について:前の実験で使用した ${{ secrets.GITHUB_TOKEN }} を覚えていますか。これはまったく同じ仕組みで動作します。GitHub が実行ごとに自動作成する Secret であり、その値もログ内でマスキングされます。

まとめ

この実験では、自動化におけるセキュリティの基本を学びました。

  • Vault:GitHub Secrets を使用して、パスワードなどの機密データを保存しました。
  • Access:${{ secrets.NAME }} を使用して、ロボットにそのデータへのキーカードによるアクセス権を与えました。
  • Masking:GitHub がログ内の Secret を自動的に伏せ字(***)にして、偶発的な漏えいを防ぐことを確認しました。

これで、安全な自動化パイプラインが完成しました。最後の実験では、DevOps の最終的な目標である Continuous Deployment に取り組みます。ロボットがコードを稼働中のサーバーへデプロイできるようにする方法を学びます。