GitHub で晒すとヤバい変数を django-environ と環境変数の設定で隠蔽する

# 動作環境とこれまでの経緯

## 動作環境
- ホスト環境
    - macOS Catalina 10.15.7
    - VirtualBox 6.1.14
- ゲスト環境
    - Ubuntu Server 20.04.1 LTS
    - Docker 19.03.13
    - Docker Compose 1.27.3
- パッケージ
    - Django 3.1.4
    - uwsgi 2.0.18
    - mysqlclient 1.4.6
    - django-environ 0.4.5

## これまでの経緯

1. [ローカルに Ubuntu Server を用意した](https://qiita.com/hajime-f/items/5d3373e98985776b4240)
2. [そこに Docker Compose をインストールした](https://qiita.com/hajime-f/items/2bd1cad93d3ae4a62be8)
3. [Django＋MySQL＋nginx の開発環境を Docker Compose で構築した](https://qiita.com/hajime-f/items/c40571647135df327aa7)
4. [Django を AWS Fargate で動作させようとした → 失敗した](https://qiita.com/hajime-f/items/4511f2aa036380249a3f)
5. [AbstractBaseUser を継承したカスタムユーザーで E-mail ログインができるようにした](https://qiita.com/hajime-f/items/c2f02306556c1ea16e5c)

（そろそろ目次ページを作る方がいいかもしれんな……）

# それは Git で晒すとヤベェだろ

Qiita で公開している個人開発のプロジェクトに「octave」という名前を付けて GitHub で晒し始めました。
https://github.com/hajime-f/octave

当然、パブリックにするとヤベェ内容がいろいろと含まれています。
- ```Makefile```：AWS のアカウントID
- ```settings.py```：SECRET_KEY と DATABASE の設定
- ```init.sql```：MySQL のパスワード
- ```docker-compose.dev.yml```：MySQL のパスワード

これらの内容がレポジトリに入っていると**「俺でなきゃ見逃しちゃうね😏 」という斜め上からのお便り**が、[GitGuardian](https://www.gitguardian.com/) から届きます。

そこで、今回はこれらを隠蔽して安全に公開できるようにしていきます。

# 手順

1. ```.env``` に環境変数を設定し、```init.sql``` と ```docker-compose.dev.yml``` を書き換える
2. 「django-environ」をインストールする
3. ```src/.env``` に変数を設定し、```settings.py``` を書き換える
4. ```.gitignore``` を確認する

## 1. 環境変数の設定と Docker 関連ファイルの書き換え

プロジェクトディレクトリ直下に ```.env``` という名前のファイルを作り、次のように編集します。なお、「プロジェクトディレクトリ」は ```docker-compose.dev.yml``` があるディレクトリです。以下同様に、パスはこのディレクトリからの相対パスです。

```shell:.env
AWS_ACCOUNT_ID=**********
OCTAVE_DB_PASSWORD=********
OCTAVE_DB_USER=*******
```

次に、```docker-compose.dev.yml``` の MySQL の設定箇所を書き換えます。

```yaml:docker-compose.dev.yml（抜粋）
environment:
  MYSQL_ROOT_PASSWORD: ${OCTAVE_DB_PASSWORD:-default}
  TZ: "Asia/Tokyo"
```

また、```init.sql``` のパスワードの設定箇所も書き換えます。

```sql:./mysql/init.d/init.sql（抜粋）
CREATE USER IF NOT EXISTS ${OCTAVE_DB_USER}@'%' IDENTIFIED BY ${OCTAVE_DB_PASSWORD}
```

AWS のアカウントIDは、```Makefile``` で使います。
設定ファイルの全部は、[GitHub のレポジトリ](https://github.com/hajime-f/octave)を見てね。

## 2. django-environ のインストール

Django を動かすコンテナに「django-environ」をインストールします。次のように ```requirements.txt``` に追記しましょう。

```:./python/requirements.txt
Django==3.1.4
uwsgi==2.0.18
mysqlclient==1.4.6
django-environ==0.4.5  # 追加
```

コンテナを再ビルドしてパッケージのインストールを反映させます。

```bash
$ docker-compose -f docker-compose.dev.yml build
```

ちなみに、[以前の記事](https://qiita.com/hajime-f/items/4511f2aa036380249a3f)に書いたとおり、このビルドコマンドは ```Makefile``` に定義しており、```$ make dev``` で実行できるようにしています。

```bash:Makefile（抜粋）
dev:
    docker-compose -f docker-compose.dev.yml build
```

## 3. 変数の設定と settings.py の書き換え

```./src/.env``` という名前のファイルを作成し、各変数の値を次のように設定します。

```bash:./src/.env
SECRET_KEY=**********
ENGINE=django.db.backends.mysql
NAME=*******
USER=*******
PASSWORD=*******
PORT=3306
HOST=*****
```

隠語だらけで怪しいですが、「*****」の部分は各自の値に置き換えましょう。

次に、```./src/.env``` で設定した各変数を ```settings.py``` に設定していきます。

```python:./src/octave/settings.py
import os, environ

BASE_DIR = Path(__file__).resolve().parent.parent

env = environ.Env()  # 追加
env.read_env(os.path.join(BASE_DIR, '.env'))  # 追加

SECRET_KEY = env('SECRET_KEY')  # 編集

・・・

DATABASES = {
    'default': {
        'ENGINE': env('ENGINE'),      # 編集
        'NAME': env('NAME'),          # 編集
        'USER': env('USER'),          # 編集
        'PASSWORD': env('PASSWORD'),  # 編集
        'PORT': env('PORT'),          # 編集
        'HOST': env('HOST'),          # 編集
    }
}
```

## 4. .gitignore を確認する

```.gitignore``` に　```.env``` が含まれていることを確認します。push したときにこのファイルまで GitHub にアップされちゃうと、ここまでの設定に意味がなくなるからね。

# 今回のバグ

毎回そうなのですが、今回のような簡単な設定でもバグにハマりました。

```bash
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/environ/environ.py", line 273, in get_value
    value = self.ENVIRON[var]
  File "/usr/local/lib/python3.9/os.py", line 679, in __getitem__
    raise KeyError(key) from None
KeyError: 'SECRET_KEY'
・・・
During handling of the above exception, another exception occurred:
django.core.exceptions.ImproperlyConfigured: Set the SECRET_KEY environment variable
```

```settings.py``` の「SECRET_KEY」を ```.env``` で設定しようとして遭遇したエラー。要するに**「SECRET_KEY なんて変数どこにもねーよ！」**とのこと。

「おかしい……パスを間違えてるのか…？」と思って ```BASE_DIR``` の値を確認したところ、```/code/``` であることが分かりました。

そういえば…```docker-compose.dev.yml``` で、次のとおりに設定していたことを思い出しました。

```yaml:docker-compose.dev.yml（抜粋）
volumes:
  - ./src:/code
  - ./static:/static
```

つまり、Django は ```./src``` 以下で動作しているのに、```.env``` ファイルを間違ってプロジェクトディレクトリに置いていたのです。```./src/.env``` に修正して解決。

django-environ は、Django のベースディレクトリ（BASE_DIR）を参照していることに注意が必要です。当たり前なんですが、docker-compose を使っていると、プロジェクトディレクトリと取り違えて、意外とミスるかもなと思いました（私だけ？）

# 参考
- [現場で使える Django の教科書《実践編》](https://www.amazon.co.jp/gp/product/B07L3DRGBT/)