はじめに
Fargate で Laravel や WordPress を構築後、セキュリティを高める方法として、読み取り専用(readonlyRootFilesystem)
を有効にする方法があります。
この設定を行なうと、コンテナ内のファイルやディレクトリが読み取り専用となり、マルウェア等に対してセキュリティーが高めることができます。
ただし、全てを読み取りにはできず、一時的に書き込みが必要なディレクトリがサーバー内にありますので、一部のディレクトリを読み書き可能なボリュームとしてマウントし、残りは読み込み専用にすることが必要です。
今回は、Fargate で構築した Laravel と WordPress を読み取り専用にする方法について方法を記載します。
ちなみに、読み取り専用(readonlyRootFilesystem)
を有効にすると、Fargate Execが使用できないデメリットがあります。
事前構築
- 下記の記事でwordpressをfargateで構築
- ソースはDockerfileのみ
FROM wordpress:6.0.0-php8.1-apache
RUN set -ex; \
apt-get update && apt-get install -y --no-install-recommends \
unzip \
wget \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# /usr/src/wordpress/wp-content/plugin にプラグインを置いておくと、ビルド時、ドキュメントルートに設置する
WORKDIR /usr/src/wordpress/wp-content/plugins
# プラグイン[WP Offload Media Lite for Amazon S3]をインストール
RUN set -ex; \
wget -q -O amazon-s3-and-cloudfront.zip https://downloads.wordpress.org/plugin/amazon-s3-and-cloudfront.1.4.3.zip \
&& unzip -q -o '*.zip' -d /usr/src/wordpress/wp-content/plugins \
&& chown -R www-data:www-data /usr/src/wordpress/wp-content/plugins \
&& rm -f *.zip
# 所有者の変更
RUN chown -R www-data:www-data /var/www/html
WORKDIR /var/www/html
- 下記の記事でlaravelをfargateで構築
- ソースも添付(ブランチは、mainを使用してください)
マウントタイプ
読み取り専用にするにあたり、/var/runなどの一時的に書き込みが必要なディレクトリがあるため、その部分のみ書き込みを許可する必要があります。
Dockerでよく用いられるマウント
を行い、一部書き込みを許可します。
Fargateでマウントする方法は、3つあります
-
Volume
をDockerfileに記載し、マウントする - タスク定義の
Bind mount
でマウントする - EFSを利用して、マウントする
- EFSは、新たにリソースを作成する手間がある、EFSだと永続的に一時ファイルが保存される、という理由で今回は利用しません。
それぞれ説明します。
VolumeとBind mountの違い
-
Bind mount
はホストマシン OS のディレクトリ構造に依存しますが、Volume
は完全に Docker によって管理されます。 -
Volume
を作成しマウントすると、書き込まれるファイルシステムはDockerで管理され、ホストマシンからは見えません。- ホストマシンのディレクトリ構成を実行中のコンテナから分離することができます。
調べたところセキュリティー的には、Volume
でマウントする方がよいようです。
wordpressのコンテナを読み取り専用
DockerfileにVolume
を追加、タスク定義のreadonlyRootFilesystem
をtrue
にします。
Dockerfileの一部のディレクトリにVolumeでマウント
ソースは、Dockerfileのみです。
wordpress (fargate) では、下記の2つのディレクトリ内に一時ファイルが作成されるため、Volumeでマウントします
- /var/run/apache2
- /tmp
FROM wordpress:6.0.0-php8.1-apache
RUN set -ex; \
apt-get update && apt-get install -y --no-install-recommends \
unzip \
wget \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# /usr/src/wordpress/wp-content/plugin にプラグインを置いておくと、ビルド時、ドキュメントルートに設置する
WORKDIR /usr/src/wordpress/wp-content/plugins
# プラグイン[WP Offload Media Lite for Amazon S3]をインストール
RUN set -ex; \
wget -q -O amazon-s3-and-cloudfront.zip https://downloads.wordpress.org/plugin/amazon-s3-and-cloudfront.1.4.3.zip \
&& unzip -q -o '*.zip' -d /usr/src/wordpress/wp-content/plugins \
&& chown -R www-data:www-data /usr/src/wordpress/wp-content/plugins \
&& rm -f *.zip
# 所有者の変更
RUN chown -R www-data:www-data /var/www/html
WORKDIR /var/www/html
+ VOLUME ["/var/run/apache2", "/tmp"]
タスク定義のreadonlyRootFilesystem
をtrue
に修正
タスク定義の読み取り専用ルートファイルシステム
にチェックマークをつけるだけです。
これでデプロイすると、/var/run/apache2
と/tmp
を除いて、読み取り専用になりました。
laravelのコンテナを読み取り専用
DockerfileにVolumeを追加、タスク定義のreadonlyRootFilesystem
をtrue
にします。
また、タスク定義のコマンドを変更します。
ソースは、以下のmainブランチを使用します。
Dockerfileの一部のディレクトリにVolumeでマウント
phpのDockerfile修正
phpのDockerfileでは、下記の4つのディレクトリを、Volumeでマウントします
- /var/www/html/bootstrap/cache
- /var/www/html/storage/framework
- /var/www/html/storage/logs
- /tmp
FROM php:8.1-fpm-bullseye
# timezone environment
ENV TZ=Asia/Tokyo \
# locale
LANG=ja_JP.UTF-8 \
LANGUAGE=ja_JP:ja \
LC_ALL=ja_JP.UTF-8 \
# composer environment
COMPOSER_ALLOW_SUPERUSER=1 \
COMPOSER_HOME=/composer
COPY --from=composer:2.3 /usr/bin/composer /usr/bin/composer
RUN apt-get update \
&& apt-get -y install --no-install-recommends \
git \
libzip-dev \
libicu-dev \
libonig-dev \
locales \
unzip \
vim \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
&& locale-gen ja_JP.UTF-8 \
&& localedef -f UTF-8 -i ja_JP ja_JP.UTF-8 \
&& docker-php-ext-install \
bcmath \
intl \
pdo_mysql \
zip \
&& composer config -g process-timeout 3600 \
&& composer config -g repos.packagist composer https://packagist.org
COPY ./src /var/www/html
COPY ./docker/php/php.ini /usr/local/etc/php/php.ini
+ VOLUME ["/var/www/html/bootstrap/cache", "/var/www/html/storage/framework", "/var/www/html/storage/logs", "/tmp"]
RUN composer install -q -n --no-ansi --no-dev --no-scripts --no-progress --prefer-dist \
+ && chown -R www-data:www-data /var/www/html \
&& chmod -R 775 storage bootstrap/cache \
&& php artisan optimize:clear \
&& php artisan optimize \
&& php artisan cache:clear \
&& php artisan config:clear \
&& php artisan route:clear \
&& php artisan view:clear
Volumeを使用すると、所有者がrootになったため、&& chown -R www-data:www-data /var/www/html
も追加しています。
phpのDockerfile修正
phpのDockerfileでは、下記の3つのディレクトリを、Volumeでマウントします
- /var/cache/nginx
- /var/run
- /etc/nginx/conf.d
FROM nginx:1.20-alpine
COPY ./docker/nginx/default.conf /etc/nginx/conf.d/default.conf
COPY ./docker/nginx/nginx.conf /etc/nginx/nginx.conf
COPY ./src /var/www/html
ENV TZ=Asia/Tokyo
EXPOSE 80
+ VOLUME ["/var/cache/nginx", "/var/run", "/etc/nginx/conf.d"]
タスク定義のコマンドを修正
コマンドは、以下の記事に記載しておりました。
- 変更前
php artisan config:cache && php artisan view:cache && php artisan route:cache && php artisan migrate --force && chmod -R 777 storage/* && php-fpm && composer install --optimize-autoloader --no-dev
↓
- 変更後
php artisan config:cache && php artisan view:cache && php artisan route:cache && php artisan migrate --force && php-fpm && composer install --optimize-autoloader --no-dev
読み取り専用にすると、権限変更がエラーになりましたので、chmod -R 777 storage/*
を削除しました。
必要であれば、Dockerfileに追記するとよいです。
タスク定義のreadonlyRootFilesystem
をtrue
に修正
先程と同様に、タスク定義の読み取り専用ルートファイルシステム
にチェックマークをつけるだけです。
これでデプロイすると、4つのディレクトリを除いて、読み取り専用となります。
laravelの/tmpのパスを変更してみる
phpコンテナでは、/tmp
をVolumeでマウントしましたが、/tmp
は予想がつきマルウェア等に狙われやすいため、/fuga/tmp
パスを変更してみたいと思います。
やることは以下の2点です。
- phpのDockerfileを修正
- タスク定義の環境変数にTMPDIRを追加
phpのDockerfileを修正
FROM php:8.1-fpm-bullseye
# timezone environment
ENV TZ=Asia/Tokyo \
# locale
LANG=ja_JP.UTF-8 \
LANGUAGE=ja_JP:ja \
LC_ALL=ja_JP.UTF-8 \
# composer environment
COMPOSER_ALLOW_SUPERUSER=1 \
COMPOSER_HOME=/composer
COPY --from=composer:2.3 /usr/bin/composer /usr/bin/composer
RUN apt-get update \
&& apt-get -y install --no-install-recommends \
git \
libzip-dev \
libicu-dev \
libonig-dev \
locales \
unzip \
vim \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
&& locale-gen ja_JP.UTF-8 \
&& localedef -f UTF-8 -i ja_JP ja_JP.UTF-8 \
&& docker-php-ext-install \
bcmath \
intl \
pdo_mysql \
zip \
&& composer config -g process-timeout 3600 \
&& composer config -g repos.packagist composer https://packagist.org
COPY ./src /var/www/html
COPY ./docker/php/php.ini /usr/local/etc/php/php.ini
+ WORKDIR /fuga/tmp
+ VOLUME ["/var/www/html/bootstrap/cache", "/var/www/html/storage/framework", "/var/www/html/storage/logs", "/fuga/tmp"]
RUN composer install -q -n --no-ansi --no-dev --no-scripts --no-progress --prefer-dist \
&& chown -R www-data:www-data /var/www/html \
&& chmod -R 775 storage bootstrap/cache \
&& php artisan optimize:clear \
&& php artisan optimize \
&& php artisan cache:clear \
&& php artisan config:clear \
&& php artisan route:clear \
&& php artisan view:clear
/fuga/tmp
ディレクトリを作成し、Volumeにもマウントさせます。
タスク定義の環境変数にTMPDIRを追加
envファイル、もしくは、タスク定義に以下を追記します。
TMPDIR=/fuga/tmp
/tmp
ではなく、/fuga/tmp
に一時ファイルが保存されるようになりました。
Codebuildでビルドする場合
Codebuildでビルドする場合、DockerfileにVolume
や権限変更
のコマンドが効かなかったため、タスク定義のコマンドに追加しました。
タスク定義のコマンドを追加
- 変更前
php artisan config:cache && php artisan view:cache && php artisan route:cache && php artisan migrate --force && php-fpm && composer install --optimize-autoloader --no-dev
↓
- 変更後
php artisan config:cache && php artisan view:cache && php artisan route:cache && php artisan migrate --force && chown -hR www-data:www-data /var/www/html/bootstrap/cache /var/www/html/storage/framework /var/www/html/storage/logs /fuga/tmp && php-fpm && composer install --optimize-autoloader --no-dev
その他のfargateに関するtips
その他のfargateに関するtipsを記事としてまとめていますので、こちらを参考にしてください。
参考記事