こんにちは、かつコーチです。
Djangoでアプリを作っていると、settings.pyにSECRET_KEYやデータベースのパスワードを直接書いてしまいがちです。
ですがこのままGitHubにpushしてしまうと、秘密情報が世界中に公開されてしまいます。
筆者は駆け出しの頃、個人開発のリポジトリを公開設定のままpushしてしまい、数時間後にGitHubから「秘密情報が検出されました」という警告メールが届いて青ざめた経験があります。
この記事では、そうした事故を防ぐための環境変数の管理方法を、django-environというライブラリを使って解説します。
なぜ環境変数で管理する必要があるのか
秘密情報をコードに書くリスク
環境変数とは、OSやサーバー側で管理する設定値のことです。settings.pyのようなコードファイルに直接書く代わりに、コードの外側から値を渡す仕組みだとイメージしてください。
SECRET_KEYやDB接続情報をコードに直書きすると、以下のようなリスクがあります。
- Gitリポジトリに履歴として残り、後から削除しても完全には消えない
- 本番用と開発用で値を切り替えるたびにコードを書き換える必要がある
- チームで開発する際、各自の環境差分がコードに紛れ込む
12 Factor Appの考え方
この問題を解決する考え方として有名なのがTwelve-Factor Appの「設定をコードから分離する」という原則です。
設定値(環境変数)とコードを分けておけば、開発環境・本番環境で同じコードを使い回しつつ、値だけを差し替えられます。
Djangoでこれを実現する定番ライブラリがdjango-environです。
django-environの導入と基本の書き方
インストールと.envファイルの作成
まずはライブラリをインストールします。
pip install django-environ
プロジェクトのルート(manage.pyと同じ階層)に.envファイルを作成します。
# .env
SECRET_KEY=django-insecure-xxxxxxxxxxxxxxxxxxxxxxxx
DEBUG=True
DATABASE_URL=postgres://user:password@localhost:5432/mydb
ALLOWED_HOSTS=localhost,127.0.0.1
settings.pyでの読み込み方
settings.pyでenvironを初期化し、.envを読み込みます。
# settings.py
import os
import environ
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
env = environ.Env(
DEBUG=(bool, False),
)
# .envファイルを読み込む
environ.Env.read_env(os.path.join(BASE_DIR, ".env"))
SECRET_KEY = env("SECRET_KEY")
DEBUG = env("DEBUG")
ALLOWED_HOSTS = env.list("ALLOWED_HOSTS")
DATABASES = {
"default": env.db(), # DATABASE_URLを自動でパースしてくれる
}
env.db()を使うと、DATABASE_URLの文字列を自動的にENGINEやNAMEなどに分解してくれるので、DB設定を手動で書く手間が省けます。
.gitignoreへの追加を忘れない
.envは絶対にGitの管理下に置いてはいけません。.gitignoreに以下を追記しておきましょう。
.env
よくあるつまずきポイント・エラー対処
.envを読み込んでいるのに値が反映されない
❌Before
# .envをread_envせずにenv()だけ呼んでいる
env = environ.Env()
SECRET_KEY = env("SECRET_KEY")
このまま実行すると、次のようなエラーが出ます。
environ.errors.ImproperlyConfigured: Set the SECRET_KEY environment variable
筆者はこのエラーに遭遇したとき、「.envファイルは作ったのに、なぜ読み込まれないのか」としばらく悩みました。
原因はenviron.Env.read_env()を呼び忘れていたことでした。Env()のインスタンス化と.envファイルの読み込みは別の処理だと覚えておく必要があります。
✅After
env = environ.Env()
environ.Env.read_env(os.path.join(BASE_DIR, ".env")) # これを忘れずに呼ぶ
SECRET_KEY = env("SECRET_KEY")
本番環境で環境変数が反映されない
RenderやHerokuのようなPaaSにデプロイする場合、.envファイル自体をサーバーに置く必要はありません。
そうしたサービスの管理画面上で環境変数を直接設定すれば、django-environは.envファイルがなくてもOS側の環境変数を読みにいってくれます。
「本番でも.envファイルをアップロードしなければ動かない」と誤解して、間違って.envをリポジトリに含めてしまうケースが初心者にはよくあるので注意しましょう。
応用・一歩先の使い方
環境ごとに.envファイルを分ける
開発・ステージング・本番で設定を切り替えたい場合、.env.developmentや.env.productionのようにファイルを分け、起動時に読み込むファイルを切り替える運用も可能です。
env_file = os.environ.get("ENV_FILE", ".env")
environ.Env.read_env(os.path.join(BASE_DIR, env_file))
DEBUGの値は必ずFalseをデフォルトにする
environ.Env(DEBUG=(bool, False))のように、デフォルト値をFalseにしておくのがセキュリティ上のベストプラクティスです。
環境変数の設定漏れがあっても、本番でDEBUG=Trueのまま公開されてしまう事故を防げます。
まとめ
この記事のポイント
- 秘密情報を
settings.pyに直書きすると、Git履歴に残り漏えいリスクがある django-environを使えば.envファイルから設定値を読み込めるenviron.Env.read_env()の呼び忘れが典型的なつまずきポイント.envは必ず.gitignoreに追加する- PaaSデプロイ時は管理画面側の環境変数設定で代用できる
次に読むべき記事
環境変数の管理ができたら、実際にRenderへデプロイする手順もあわせて確認しておきましょう。
「DjangoアプリをRenderにデプロイする方法」の記事で、具体的な手順を解説しています。
タグ: Django, 中級者向け, デプロイ
