現象
稼働中のシステムでDjangoのバージョンを上げたとたんに標題の現象が発生。具体的には、Djangoで構築したシステムからファイルをアップロードした後、システムからそのファイルを閲覧しようとした際に「403 Forbidden」が表示されてファイルが閲覧できない事象が発生した。
環境
- Ubuntu 16.04
- nginx
- uwsgi
- python 3.5
- Django 1.11.11
動作条件
- nginx workerプロセスはwww-data:www-data
- uwsgiプロセスはroot:root
- それぞれのプロセスはdockerコンテナ上で動作
経緯とかどうでもいいから結論を教えて!
Djangoのsettingsに下記の設定を追加しましょう。
FILE_UPLOAD_PERMISSIONS = 0o644
現象の調査
アップロードされたファイルの権限を確認してみると次のことがわかりました。
- 今まではアップロードされたファイルのowner:groupはwww-data:www-dataであったがDjangoのバージョンを上げるとroot:rootでアップロードされるようになった。
- ファイルサイズが小さい場合はファイルの権限が0644でアップロードされるが、サイズが大きい(数MB)場合にはファイル権限が0600でアップロードされてしまう。
つまり、サイズが大きいファイルだと権限がroot:rootの0600で保存されるので、当該ファイルにnginxからアクセスしようとするとwww-data権限でアクセスを試みて「403 Forbidden」となってしまうということでした。
対応策の調査
調べてみるとDjangoの設定でなんとかなりそうなことが分かりました。
DjangoのドキュメントによるとFILE_UPLOAD_MAX_MEMORY_SIZEのデフォルト値2.5MBを超えるファイルがアップロードされると、アップロード処理中はFILE_UPLOAD_TEMP_DIRで設定されたディレクトリ(私の環境の場合は/tmp/)へ一時的にファイルが保存される。この時にファイルの権限が0600(ここの振る舞いはOS依存)になってしまうとのことでした。つまり勝手に0600にならないようにアップロードファイルの権限をDjango側で指定すればよいということですね。
結論
ということで結論です。
Djangoのsettingsに下記の設定を追加しましょう。
FILE_UPLOAD_PERMISSIONS = 0o644
これでアップロードされたファイルにowner以外へのRead権限が与えられるのでファイル閲覧時に「403 Forbidden」とはなりません。
残る疑問
アップロードされるファイルのowner:groupがwww-data:www-dataからroot:rootに変わった原因は未だ不明です。