Python
Django

Djangoで環境変数?ならdjango-environを使おうか。

バックエンドを開発していると、秘密にしたい値がどうしてもでてきますよね。
AWSのシークレットキー・APIキー・DBの接続情報等…
ただ、それをsettings.pyでハードコードしてGitで管理というのは楽ですが正直セキュリティ的によろしくありません。

となると、「環境変数で管理しよう」となってくる事が多いと思いますが、
単純に環境変数にすると開発環境での管理が面倒になる場合もあります。

とりあえず環境変数にした場合の罠

開発環境はMac。
IDEはPythonista御用達のPyCharmを使います。

環境変数設定ファイルを作成

.env
# MySQL
DB_NAME=db_name
DB_PASSWORD=hogepass
DB_USER=hogehoge
DB_HOST=127.0.0.1
DB_PORT=3306
DB_ENGINE=django.db.backends.mysql

# AWS Settings
DJANGO_AWS_S3_BUCKET_NAME=huga-storage
DJANGO_AWS_ACCESS_KEY=xxxxxxxxxxxxxxxxxx
DJANGO_AWS_SECRET_KEY=xxxxxxxxxxxxxxxxxx

settings.pyを編集

settings.py
import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))

・・・

AWS_S3_BUCKET_NAME=os.environ['DJANGO_AWS_S3_BUCKET_NAME']
AWS_ACCESS_KEY=os.environ['DJANGO_AWS_ACCESS_KEY']
AWS_SECRET_KEY=os.environ['DJANGO_AWS_SECRET_KEY']

DATABASES = {
    'default': {
        'ENGINE': os.environ['POSTGRES_ENGINE'],
        'NAME': os.environ['POSTGRES_NAME'],
        'USER': os.environ['POSTGRES_USER'],
        'PASSWORD': os.environ['POSTGRES_PASSWORD'],
        'HOST': os.environ['POSTGRES_HOST'],
        'PORT': os.environ['POSTGRES_PORT'],
    }
}

・・・

と、こんな感じでしょうか。

問題点

  • コマンドラインから行う時はMacの環境変数にセットしなければならない。
  • Macの環境変数にセットしてなかったらPycharmRun/Debug Configrationsで環境変数をいちいち指定しないといけない。

たかが2点されど2点。
まずLinux運用想定で.envを作成したとしても、Macだとexportしないと環境変数に登録できないし…
↓のようなシェルスクリプト作成して環境変数修正するたびに実行してなんてしたくない。

env.sh
#!/bin/sh
# ファイルを1行ずつ読み込んで表示

TESTFILE=./.env
while read line; do
    export $line
done < $TESTFILE

という事で、こんな無駄をなくしましょう。

django-environを使用する

Github
https://github.com/joke2k/django-environ
ありがたや(-人-)

導入

$ pip install django-environ

環境変数設定ファイルを修正

.env
# MySQL
DATABASE_URL=mysql://hogehoge:hogepass@127.0.0.1:3306/db_name

# AWS Settings
DJANGO_AWS_S3_BUCKET_NAME=huga-storage
DJANGO_AWS_ACCESS_KEY=xxxxxxxxxxxxxxxxxx
DJANGO_AWS_SECRET_KEY=xxxxxxxxxxxxxxxxxx

settings.pyを改善

settings.py
import environ

# settings.pyの位置を起点として3つ上の親ディレクトリを参照。
BASE_DIR = environ.Path(__file__) - 3

env = environ.Env()

# 環境変数でDJANGO_READ_ENV_FILEをTrueにしておくと.envを読んでくれる。
READ_ENV_FILE = env.bool('DJANGO_READ_ENV_FILE', default=False)
if READ_ENV_FILE:
    env_file = str(BASE_DIR.path('.env'))
    env.read_env(env_file)

・・・

AWS_S3_BUCKET_NAME=env('DJANGO_AWS_S3_BUCKET_NAME')
AWS_ACCESS_KEY=env('DJANGO_AWS_ACCESS_KEY')
AWS_SECRET_KEY=env('DJANGO_AWS_SECRET_KEY')

DATABASES = {
    'default': env.db() # デフォルトでDATABASE_URLの環境変数を分解してくれる
}

・・・

ポイント

  • Macに環境変数を設定しなくても、1つ環境変数をTrueにしておけば .env を読んでくれる。
  • DATABASE_URLという環境変数で一行書くことでDBの定義ができる
  • ディレクトリのベースディレクトリ定義などがスッキリする。

ちなみに、DB以外にもキャッシュとかもワンラインで定義できます。
DJANGO_READ_ENV_FILEをTrueにしておけば.envを修正しても毎回読み直してくれるのでかなり便利です。

まとめ

使用したメソッドは一例ですが、これだけでもスッキリしたコードになりました。
環境変数にする事によりセキュリティ対策にもなるし、開発と本番とかでsettingsファイルを切り替える必要もなくなります。
OSSは日に日に追加・改善等が進められているので、いつのまにか痒い所に手が届くライブラリが作成されているという事が無いようにしていく事が大切ですね。
そして人様が開発したライブラリに頼りきるのではなく、自らも積極的にOSSに貢献していきましょう!

Let's OSS Life!!!