📑 この章の目次
title: 環境変数・シークレット管理 icon: 🔐 card_desc: パスワードやAPIキーをコードに直接書かない仕組み — .env・環境変数の基本・本番秘匿情報の守り方 slug: 04-env-secrets
04 環境変数・シークレット管理 — パスワードやAPIキーをコードに直接書かない仕組み
コードにAPIキーを直接書き込んでGitHubに公開してしまい、不正利用されて巨额請求が来た——。こういう事故は後にも先にも「シークレット管理」の失敗が原因です。この章では、パスワード・APIキー・本番秘匿情報を安全に扱う作法を根本から理解します。
一言でいうと
環境変数(environment variable) は、プログラムの外側にある設定値を差し込む仕組みです。シークレットは、その中でも他人に見られてはいけない秘密の値(APIキー・パスワード・トークン等)。基本原則は「コードに書かない・Gitに入れない・本番では専用の保管場所を使う」の3点に尽きます。
1. なぜ「コードに直接書いたらダメ」なのか
たとえば、こんなコードを書いてGitHubにpushしたとしましょう:
# ❌ 絶対やってはいけない例
API_KEY = "sk-1234567890abcdef" # あなたのAPIキー
DB_PASSWORD = "my_secret_password" # 本番DBのパスワード
STRIPE_SECRET = "sk_live_xxxxx" # 本番決済キー
数分以内に起きること:
- GitHubの自動ボットがAPIキーをスキャンし、アラートが届く
- 不正アクセスされ、キーを悪用される
- あなたのアカウントに高額な不正請求が来る
- 場合によっては法的責任を問われる
⚠ 現実の事故例: AWS のアクセスキーをGitHubに push して、暗号通貨のマイニングに悪用され数百万ドルの請求が来た事例は珍しくありません。一度公開したキーは「漏れた」と同じ。撤回できない情報です。
2. 環境変数 —— コードの外側で設定を差し込む
基本概念
環境変数は、プログラムの実行時にOSから渡される「外側の設定値」です。コードの中身を書き換えずに、振る舞いを変えられるのが最大の利点。
┌──────────────────────┐
│ OS / 実行環境 │
│ DATABASE_URL=... │ ← ここに設定値がある
└──────────┬───────────┘
│ 起動時に読み込まれる
↓
┌──────────────────────┐
│ あなたのプログラム │
│ DB_URL = os.environ │ ← コードは「キー名」だけ知っている
│ ["DB_URL"]│ 「値」は外側にある
└──────────────────────┘
なぜこの仕組みが必要か
| 理由 | 説明 |
|---|---|
| コードと設定を分離 | 同じコードで開発・本番を切り替えられる |
| Gitに入れない | 設定値はリポジトリの外に置くので漏洩リスク激減 |
| 人ごとに違う | 開発者A・B・Cが同じコードを動かしても、設定値は別々に持てる |
| 本番で上書き | 本番環境だけ別の値(本番DB接続情報等)を渡せる |
💡 **「コードと設定の分離」**は12-Factor App(Heroku創業者のAdam Wigginsらが2011年に提唱した、WebアプリをSaaSとして正しく運用するための12原則)の中核アイデアです。「設定は環境変数に」「コードと設定は別々に管理」が鉄則。
3. .env ファイル —— ローカル開発での「設定メモ」
実際の開発現場では、.env ファイルがよく使われます。これは「環境変数をまとめた設定ファイル」で、Gitには入れない前提です。
.env ファイルの例
# .env (ローカル開発用・絶対にGitに入れない)
DATABASE_URL=postgresql://localhost/mydb
STRIPE_API_KEY=sk_test_xxxxxxxx
JWT_SECRET=development-only-secret
NODE_ENV=development
.gitignore の設定
# .gitignore
.env
.env.local
.env.*.local
*.pem
*.key
.env 系のファイルをGit追跡から完全除外します。
.env.example —— 「雛形だけGitに置く」
# .env.example (雛形・Git OK・値は空欄)
DATABASE_URL=
STRIPE_API_KEY=
JWT_SECRET=
NODE_ENV=development
「こんな変数が必要ですよ」という目印だけを共有し、値は各自で埋める運用。
プログラムからの読み込み
# Python の例(python-dotenv ライブラリ)
from dotenv import load_dotenv
import os
load_dotenv() # .env を読み込む
db_url = os.environ["DATABASE_URL"] # 必須(未設定なら KeyError)
api_key = os.environ.get("STRIPE_API_KEY", "") # デフォルト値あり
// Node.js の例(CommonJS)
require('dotenv').config();
const dbUrl = process.env.DATABASE_URL;
const apiKey = process.env.STRIPE_API_KEY;
// Node.js の例(ESM・現行主流)
import dotenv from 'dotenv';
dotenv.config();
const dbUrl = process.env.DATABASE_URL;
const apiKey = process.env.STRIPE_API_KEY;
💡 「キー名」はコードに書いてOK。値は外側(環境変数・.env)に置く。コードレビューで「キー名が書かれている」のは問題なし、「値が直書きされている」のはNG。
4. 🔑 本番環境でのシークレット管理
ローカル開発は .env で十分ですが、本番環境はもっとしっかりした仕組みが必要です。
本番での典型的な保管場所
| サービス | 保管場所 |
|---|---|
| AWS | Secrets Manager / Systems Manager Parameter Store |
| GCP | Secret Manager / Cloud KMS |
| Azure | Key Vault |
| Vercel / Netlify | ダッシュボードの「Environment Variables」設定 |
| GitHub Actions | Secrets(リポジトリ設定) |
| Docker / Kubernetes | Docker Secrets / Kubernetes Secrets |
| Heroku | Config Vars |
💡 選定基準: 小規模・個人開発 → ホスティングサービスのダッシュボード(Vercel等)/中〜大規模・コンプライアンス要件あり → AWS Secrets Manager等の専用サービス。
なぜ「.env を本番に置かない」のか
| 理由 | 詳細 |
|---|---|
| 平文で保存される | .env は単なるテキストファイル。サーバーに侵入されたら全部読まれる |
| アクセス制御がない | 誰でもファイルを cat できる |
| 監査ログがない | 「いつ・誰が・何を読んだか」が残らない |
| ローテーションが難しい | 鍵を定期変更するのが大変 |
| 本番事故時の影響範囲 | 一つの漏洩がサービス全体に波及 |
本番シークレットマネージャーは、暗号化・アクセス制御・監査ログ・自動ローテーションを備えています。「ちゃんと保管する」とはこのレベルを指します。
5. やってはいけない・やっておくべき
❌ やってはいけない
| 行動 | なぜダメか |
|---|---|
| コードに直書き | Gitに永久に残る・漏洩リスク最大 |
| Gitにpush | 一度公開したら「漏れた」のと同じ |
| チャットツールで共有 | 履歴に残る・参加者にずっと見える |
| スクリーンショットで共有 | 履歴・バックアップに永久に残る・OCRで文字列復元可能 |
| フロントエンド(JS)に入れる | ブラウザで丸見え・サーバーキーには絶対使えない |
| 環境変数名を「HARDCODED_PASSWORD」等にする | 名前から「重要そう」と分かるだけで中身は守られない |
✅ やっておくべき
| 行動 | なぜ有効か |
|---|---|
| .env + .gitignore を最初に設定 | 予防が一番効果的 |
| APIキーにスコープ・権限を最小限 | 漏洩時の被害を限定 |
| 本番キーは環境別(dev/staging/prod)に分ける | 開発漏洩が本番被害に直結しない |
| ローテーション(定期変更) | 漏洩しても気づいた時に無効化できる |
| 使用量モニタリング・アラート | 不正利用を早期発見 |
| 漏洩検知サービス(GitHub Secret Scanning・TruffleHog 等) | 早期発見と自動失効 |
6. 🔑 環境変数で「うっかり上書き」する設計の落とし穴
環境変数は便利ですが、落とし穴も理解しておく必要があります。
「設定値が反映されない」三大パターン
| パターン | 症状 | 原因 |
|---|---|---|
| 変数名の typo | 設定値が読まれない | DATABASE_URL を DATBASE_URL と書いていた |
| .env が読み込まれていない | 値が無い | カレントディレクトリが違う・load_dotenv() を呼んでいない |
| 本番環境で設定漏れ | ローカルでは動くが本番で動かない | 本番サーバーに環境変数を設定し忘れた |
💡 「ローカルでは動くのに本番で動かない」のは、設定値の反映ミスが一番多い原因です。デプロイ時のチェックリストに「環境変数の確認」を必ず入れましょう。
12-Factor App の「設定の厳格な分離」
設定値の扱いを3種類に分けて考えます:
| 種類 | 例 | 保管場所 |
|---|---|---|
| コード(不変) | ビジネスロジック・アルゴリズム | Git |
| 設定(環境ごと) | DB接続先・APIエンドポイントURL | 環境変数 |
| シークレット(秘匿) | パスワード・APIキー | シークレットマネージャー |
「.env はローカル専用」「本番は専用シークレットマネージャー」を鉄則にすると、漏洩リスクが激減します。
7. 面接・実務での意味
「APIキーの管理、どうしてますか?」
この質問は、単に「どこに保存しているか」を聞いているのではありません。**「漏洩リスクを理解し、適切な手段で守っているか」**を聞いています。
- .gitignore で除外しているか
- 本番は専用シークレットマネージャーを使っているか
- キーにはスコープ・権限制限があるか
- ローテーション・モニタリングの運用があるか
- 漏洩検知・緊急対応の手順があるか
これらを自觉して運用できることが、「シークレットを理解している」エンジニアの証です。
まとめ
- 環境変数はコードの外側で設定値を差し込む仕組み。コードと設定の分離が目的
- シークレットは環境変数の中でも秘匿すべき値(APIキー・パスワード)
- 基本原則: コードに書かない・Gitに入れない・本番は専用シークレットマネージャー
- .env ファイルはローカル開発の道具。.gitignore で除外・.env.example で雛形共有
- 本番: AWS Secrets Manager / GCP Secret Manager / Vercel Env Vars など、暗号化・アクセス制御・監査ログ付きの保管場所を使う
- 漏洩リスク対策: スコープ最小化・ローテーション・モニタリング・漏洩検知
- .env は本番に置かない。本番は専用マネージャーで安全保管
💡 次のステップ: APIキーの保管場所を理解したところで、次は**「誰がアクセスしていいか」**の話になります。第5章では、認証・認可(ログイン・セッション・JWT・OAuth)の仕組みを扱い、シークレットが「誰に渡ってよいか」のルールを学びます。