MetaPii 技術室

あなたの知恵と思いを検索するフラッシュメモアプリMetaPiiのエンジニアブログです。

Docker Laravel root以外のユーザーで起動する on Ubuntu

Dockerを運用し始めてから約半年、この問題の対処方法を紹介します。 ずっと放置していたんですが、サービスをリリースすることになったためセキュリティの観点から対応しました。

「Nginx + Laravel ( + Mysql ) 」の組み合わせについての方法です。(Mysqlはあんま関係ないかも、mysqlmysqlユーザーで開始すればOK) ローカルから編集もできるし、docker上で実行エラーも起きないそんな方法です。

前提条件

こんな感じのプロジェクトディレクトリで運用してます。 Laravelやってる人はぴんとくるものがあると思います。 今回関係あるのは下図の★のところだけです。

project
├── Dockerfile
├── compose_by_env
│   ├── docker-compose_cloud.yml
│   ├── docker-compose_local.yml
├── docker
│   ├── mysql
│   │   ├── Dockerfile
│   │   └── my.cnf
│   ├── nginx
│        ├── Dockerfile
│        ├── default.conf
│        ├── nginx.conf
├── docker-compose.yml -> ./compose_by_env/docker-compose_local.yml
├── logs ★
│   ├── access.log
│   └── error.log
└── src ★
    ├── README.md
    ├── app
    ├── artisan
    ├── bootstrap
    ├── composer.json
    ├── composer.lock
    ├── config
    ├── database
    ├── package.json
    ├── phpunit.xml
    ├── public
    ├── resources
    ├── routes
    ├── server.php
    ├── storage
    ├── tests
    ├── vendor
    ├── webpack.mix.js
    └── yarn.lock

対処

結論から言いますが、いくつか方針とステップがあります。

1.ユーザー作成
ホスト側にdocker の nginx , laravel app内のwww-dataユーザーと同じUID, GIDでユーザーとグループを作成する
2.グループ追加   ホスト側で作成した上記ユーザーグループにホスト側でいつも使っている開発ユーザーを加える
3.Dockerファイル編集
docker の nginx , laravel appをwww-data で立ち上げるようにする(その他もろもろ)
4.所有権変更
workディレクトリ(上図だとsrcフォルダ)以下をnginx , laravel app(docker)上のwww-dataと同じUID:GIDでchownする
5.権限変更
workディレクトリ(上図だとsrcフォルダ)以下のファイル権限を770にする

こうすることでDocker上からはwww-dataユーザーで関係するファイルがすべてwww-data権限で構成されるため実行上のエラーは起きません。
またホスト側においても、開発ユーザーはwww-dataユーザーグループに加わっており770で権限管理されているためローカル編集することができます。

では詳しく見ていきましょう。

1.ユーザー作成、及び 2.グループ追加

nginx及びLaravel app のwww-dataユーザーのUIDは82です。
なので、ホスト上でそのUIDでユーザーを作成します。 私は一身上の都合でユーザー名はdocにしました。(www-dataのほうがわかりやすいかも)

sudo useradd --shell /bin/bash -u 82 -o -m doc
sudo groupmod -g 82 doc
sudo gpasswd -a $USER doc
3.DockerFile(その他もろもろ)
nginx

・DockerFile

FROM nginx:1.17-alpine
WORKDIR /
# 【重要】ディレクトリオーナーを変更
RUN touch /var/run/nginx.pid && \
  chown -R 82:www-data /var/run/nginx.pid && \
  chown -R 82:www-data /var/cache/nginx
USER 82
RUN alias ll="ls -al"

USER www-data だと起動できないので、UIDで指定します。 もう一つ、nginxの場合root権限以外で80, 443番ポートを立ち上げることができないっぽいので、default.confで別ポートを指定します。

・default.conf

server {
    #listen 80;
    listen 8080;
    return 301 https://$host$request_uri;
}
server {
    #listen 443 ssl;
    listen 8443 ssl;
・・・以下略

あとnginx.confも今回編集したので貼っておきます。

#user  nginx www-data; これをコメントアウト
#worker_processes  auto; これをコメントアウト
worker_processes  1;  #これ追加

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}
・・・以下略
Laravel app

laravelのDockerFileも同様です。

FROM php:7.3-fpm-alpine
LABEL maintainer "ucan"

COPY ${PROJECT_PATH} /work
RUN chown -R www-data:www-data /work
RUN chmod +x /work/public

USER 82
RUN alias ll="ls -al"
4.所有権変更 及び 5.権限変更

最後にホスト側でこれ。 私の場合logsというフォルダーにnginxログファイルを吐いているので、そこも変えています。

cd project
sudo chown -R doc:doc src
sudo chown -R doc:doc logs
sudo chmod -R 770 src
sudo chmod -R 770 logs

あとは

docker-compose build 
docker-compose up -d

でおけ。

docker セキュリティ

rootで実行するとよくないので、今回のやり方はその対策にもなっています。

残された課題

ローカルで新規にファイルを作成した場合、所有権がローカルユーザーとなるため、

sudo chown -R doc:doc src

のコマンドをどこかに保存して、新規作成のたびに実行するような仕組みをつくりましょう。 暫定と呼ぶ所以はこの問題が残されているからです。。