個人開発をしていると、APIトークンの管理に悩むことがある。Netlify、Firebase、App Store Connect...サービスが増えるたびにトークンも増え、「このトークンどこに保存したっけ?」となりがちだ。
今回、iOS開発で使っている fastlane match の設計思想を参考に、APIトークン管理全般に使える仕組みを作ったので紹介する。
課題: 開発環境のAPIトークン管理の悩み
開発者なら一度は経験したことがあるはず:
- dotfilesにトークンを直書き → うっかりpublicリポにpushして漏洩
- macOS Keychainに保存 → マシン移行やKeychain再作成で全部消える
- .envファイルに書く → プロジェクトごとに散らばって管理しきれない
- ~/.zshrcにexport文 → 平文トークンがシェル設定ファイルに露出
特に困るのが「Keychainが消えたとき」。macOSのKeychainはマシン移行やクリーンインストール時にリセットされることがある。そうなると、各サービスのダッシュボードを回ってトークンを再発行する羽目になる。
発想: fastlane matchから学んだ「暗号化repoパターン」
iOS開発者にはおなじみの fastlane match。これはiOSアプリのコード署名証明書とプロビジョニングプロファイルを管理するツールだ。
matchの設計思想がシンプルで美しい:
- 証明書・プロファイルを MATCH_PASSWORD で暗号化
- 暗号化ファイルを GitHub private repo に保管
- 新しいマシンでは
fastlane matchを実行するだけで全て復元
「暗号化したファイルをGitリポに入れる」という発想。Gitの履歴管理、アクセス制御、バックアップが自動的に効く。
この設計思想を「APIトークン管理」全般に応用したのが今回の仕組みだ。しかもfastlane matchと同じMATCH_PASSWORDを使い回すので、覚えるパスワードは1つだけ。
アーキテクチャ: 3層構造
全体像はこうなっている:
certificates repo (private) ← 暗号化されたトークンを保管
↕ MATCH_PASSWORD(openssl enc で暗号化/復号)
プロジェクト repo ← setup_secrets.sh(復号+登録スクリプト)
↕ security コマンド
macOS Keychain ← ランタイムのトークン格納先
↕ security find-generic-password
~/.zshrc ← 環境変数として動的取得
ポイント:
- certificates repo: fastlane matchが既に使っているprivateリポ。ここにsecretsディレクトリを追加してトークンも保管
- プロジェクト repo: 復元スクリプトのみ。トークンの平文は一切含まない
- Keychain: macOSの標準的なシークレットストレージ。アプリからもCLIからもアクセス可能
- ~/.zshrc: Keychainから動的に値を取得する。平文は書かない
実装手順
Step 1: トークンを暗号化してcertificates repoに保管
まず、管理したいトークンをopenssl で暗号化する:
# 暗号化
echo "YOUR_TOKEN_VALUE" | openssl enc -aes-256-cbc -pbkdf2 -salt \
-pass pass:"YOUR_MATCH_PASSWORD" -out token_name.enc
# 復号(確認用)
openssl enc -aes-256-cbc -pbkdf2 -d \
-in token_name.enc -pass pass:"YOUR_MATCH_PASSWORD"
暗号化ファイル(.enc)をcertificates repoの secrets/ ディレクトリに配置する:
certificates/
├── certs/ ← fastlane match管理の証明書
├── profiles/ ← fastlane match管理のプロファイル
└── secrets/ ← APIトークン(暗号化済み)
├── README.md
└── netlify_token.enc
Step 2: 復元スクリプトを作る
プロジェクトリポのルートに setup_secrets.sh を置く:
#!/bin/bash
set -euo pipefail
CERT_REPO="git@github.com:yourname/certificates.git"
TMPDIR=$(mktemp -d)
trap "rm -rf $TMPDIR" EXIT
echo "=== Secrets Setup ==="
read -rsp "MATCH_PASSWORD: " MATCH_PASSWORD
echo ""
# certificates repoをclone(shallow)
git clone --depth 1 "$CERT_REPO" "$TMPDIR/certs" 2>/dev/null
# 各トークンを復号→Keychain登録
TOKEN=$(openssl enc -aes-256-cbc -pbkdf2 -d \
-in "$TMPDIR/certs/secrets/token_name.enc" \
-pass pass:"$MATCH_PASSWORD") || {
echo "復号失敗。パスワードを確認してください。"
exit 1
}
security add-generic-password -a service_name -s TOKEN_NAME -w "$TOKEN" -U
echo "TOKEN_NAME をKeychainに登録しました"
# zshrc用のexport文を案内
echo ""
echo "以下を ~/.zshrc に追加してください:"
echo 'export TOKEN_NAME=$(security find-generic-password -a service_name -s TOKEN_NAME -w 2>/dev/null)'
このスクリプトの流れ:
- MATCH_PASSWORDを対話的に入力
- certificates repoをtmpディレクトリにshallow clone
- 暗号化ファイルを復号
security add-generic-passwordでKeychainに登録- tmpディレクトリを自動削除(
trap EXIT)
Step 3: ~/.zshrcでKeychainから動的取得
~/.zshrcには平文トークンを書かない。代わりにKeychainから動的に取得する:
# NG: 平文を直書き
export TOKEN_NAME="actual_token_value_here"
# OK: Keychainから動的取得
export TOKEN_NAME=$(security find-generic-password -a service_name -s TOKEN_NAME -w 2>/dev/null)
2>/dev/null を付けているのは、Keychainにまだ登録されていない場合のエラーメッセージを抑制するため。
CI/CD連携
ローカル開発ではKeychainを使うが、CI/CD環境(GitHub Actions等)ではKeychainが使えない。ここではGitHub Secretsを活用する:
# .github/workflows/deploy.yml
env:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
NETLIFY_TOKEN: ${{ secrets.NETLIFY_PERSONAL_ACCESS_TOKEN }}
設計上のポイント:
- MATCH_PASSWORD をGitHub Secretsに登録しておく
- CI環境ではcertificates repoからの復号は不要(GitHub Secretsから直接取得)
- ローカルとCIで同じMATCH_PASSWORDを共有することで、一貫性を保つ
既存ツールとの比較
この方式が万能というわけではない。チームの規模や環境に応じて最適なツールは異なる:
| ツール | 特徴 | 向いているケース |
|---|---|---|
| この方式 | 依存ゼロ、macOS標準ツールのみ | 個人開発、macOS限定 |
| 1Password CLI | GUI連携、チーム管理、マルチOS | チーム開発、マルチOS環境 |
| doppler | SaaS、環境変数統合、ダッシュボード | 大規模、クラウドネイティブ |
| SOPS | クラウドKMS連携、YAML/JSON暗号化 | AWS/GCP環境 |
| git-crypt | リポ全体の透過的暗号化 | リポ内秘密ファイルが多い |
正直、チーム開発なら1Password CLIやdopplerの方が管理しやすい。この方式が活きるのは「個人開発 + macOS + fastlaneを既に使っている」というケース。依存が本当にゼロ(macOS標準のopenssl + security コマンドだけ)なのが最大の利点。
まとめ
メリット:
- 依存ゼロ: macOS標準ツール(openssl, security)だけで完結
- fastlane matchとパスワード共有: 覚えるパスワードは1つ
- Gitで履歴管理: いつ、何のトークンが変更されたか追跡可能
- シンプル: シェルスクリプト1つで全トークンを復元
デメリット:
- macOS限定: Linux/Windowsでは別の仕組みが必要
- GUI管理なし: 全てCLI操作
- パスワード漏洩リスク: MATCH_PASSWORDが漏れると全トークンが露出
- スケール限界: トークン数が数十を超えると管理が煩雑に
向いているケース:
- 個人開発者で、macOSメイン
- fastlane matchを既に使っている(MATCH_PASSWORDが存在する)
- 外部サービスへの依存を最小限にしたい
- 「新しいMacを買ったらスクリプト1つ叩くだけ」を実現したい
iOS開発者ならfastlane matchの恩恵を既に受けているはず。その設計思想をAPIトークン管理にも広げるだけで、「新しいマシンのセットアップが楽になる」という地味だけど確実なメリットが得られる。