Docker でパーミッションをどう扱うか?

DockerDockerBeginner
オンラインで実践に進む

💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください

はじめに

Docker でのパーミッション管理は、コンテナ化されたアプリケーションを管理する上で重要な側面です。このチュートリアルでは、Docker ファイルのパーミッションを理解し、Docker コンテナ内でパーミッションを設定し、パーミッション管理のベストプラクティスを探る方法を案内します。最後まで学ぶことで、Docker ベースのプロジェクトでパーミッションを効果的に管理する知識を身につけることができます。

この実験では、Docker コンテナのパーミッションがどのように機能するか、コンテナ内で非 root ユーザーを作成して使用する方法、およびホストとコンテナ間でデータを共有する際のパーミッション管理方法を学びます。

Docker のデフォルトパーミッションの理解

Docker では、パーミッションがどのように機能するかを理解することは、セキュアなコンテナを維持するための基本です。まずは、Docker コンテナのデフォルトのパーミッション設定を調べてみましょう。

Docker のデフォルトユーザーの確認

デフォルトでは、Docker はコンテナ内のプロセスを root ユーザーとして実行します。これは、コンテナが侵害された場合に潜在的なセキュリティ問題を引き起こす可能性があります。この動作を確認するために、簡単なコンテナを作成して、どのユーザーがプロセスを実行しているかを確認しましょう。

まず、プロジェクトディレクトリにいることを確認します。

cd ~/project

次に、基本的な Ubuntu コンテナを実行して、現在のユーザーを確認します。

docker run -it --rm ubuntu:22.04 whoami

以下の出力が表示されるはずです。

root

これにより、Docker がデフォルトで root ユーザーを使用していることが確認できます。次に、ユーザー ID (UID) とグループ ID (GID) を確認しましょう。

docker run -it --rm ubuntu:22.04 id

出力は次のようになるはずです。

uid=0(root) gid=0(root) groups=0(root)

uid=0gid=0 は、コンテナが root ユーザーおよびグループとして実行されていることを示しており、これらはコンテナ内のすべてのリソースに完全なアクセス権を持っています。

コンテナ内のファイルパーミッションの調査

Docker コンテナ内でファイルパーミッションがどのように機能するかを調べてみましょう。コンテナ内に簡単なファイルを作成して、そのパーミッションを確認します。

まず、バックグラウンドで実行されるコンテナを作成します。

docker run -d --name permissions-demo ubuntu:22.04 sleep 3600

次に、このコンテナ内でコマンドを実行して、ファイルを作成し、そのパーミッションを確認します。

docker exec permissions-demo touch /test-file
docker exec permissions-demo ls -l /test-file

次のような出力が表示されるはずです。

-rw-r--r-- 1 root root 0 May 15 12:34 /test-file

ファイルが root ユーザーとグループによって所有されていることに注意してください。これは、Docker コンテナ内でデフォルトで作成されるすべてのファイルが root ユーザーによって所有されることを示しています。

ディレクトリを作成して、そのパーミッションも確認してみましょう。

docker exec permissions-demo mkdir /test-directory
docker exec permissions-demo ls -ld /test-directory

出力は次のようになるはずです。

drwxr-xr-x 2 root root 4096 May 15 12:35 /test-directory

再び、ディレクトリは root ユーザーとグループによって所有されています。

次のステップに進む前に、コンテナをクリーンアップしましょう。

docker stop permissions-demo
docker rm permissions-demo

これは、ユーザーパーミッションに関する Docker のデフォルトの動作を示しています。次のステップでは、Docker コンテナ内で非 root ユーザーを作成して使用する方法を学び、セキュリティを向上させます。

Docker での非 root ユーザーの作成と使用

Docker コンテナ内でアプリケーションを root ユーザーとして実行することは、セキュリティ上のリスクを伴います。攻撃者が root として実行されているコンテナを侵害した場合、ホストシステムでエスカレートされた特権を取得する可能性があります。このステップでは、Docker コンテナ内で非 root ユーザーを作成して使用する方法を学びます。

非 root ユーザーを定義した Dockerfile の作成

非 root ユーザーを定義し、コマンドを実行するためのデフォルトユーザーとして設定する Dockerfile を作成しましょう。

まず、プロジェクト用の新しいディレクトリを作成します。

mkdir -p ~/project/non-root-user
cd ~/project/non-root-user

次に、nano テキストエディタを使用して Dockerfile を作成します。

nano Dockerfile

Dockerfile に以下の内容を追加します。

FROM ubuntu:22.04

## ユーザー ID 1000 で 'appuser' という新しいユーザーを作成する
RUN useradd -m -u 1000 appuser

## アプリケーション用のディレクトリを作成し、所有権を設定する
RUN mkdir -p /app && chown -R appuser:appuser /app

## 作業ディレクトリを /app に設定する
WORKDIR /app

## 非 root ユーザーに切り替える
USER appuser

## テストファイルを作成する
RUN touch test-file.txt

## コンテナが起動したときに実行するコマンド
CMD ["bash", "-c", "echo 'Running as user:' && whoami && echo 'File ownership:' && ls -l test-file.txt && tail -f /dev/null"]

Ctrl+O を押してから Enter でファイルを保存し、Ctrl+X でエディタを終了します。

この Dockerfile は以下のことを行います。

  1. UID 1000 で appuser という新しいユーザーを作成する
  2. アプリケーション用のディレクトリを作成し、所有権を appuser に与える
  3. 作業ディレクトリを /app に設定する
  4. 以降のコマンドを非 root ユーザーとして実行するように切り替える
  5. appuser が所有するテストファイルを作成する
  6. ユーザーとファイルの所有権情報を表示するコマンドを設定する

非 root ユーザーコンテナのビルドと実行

次に、Dockerfile から Docker イメージをビルドしましょう。

docker build -t non-root-image .

Docker がイメージをビルドしていることを示す出力が表示されるはずです。ビルドが完了したら、このイメージからコンテナを実行します。

docker run --name non-root-container -d non-root-image

次に、コンテナからの出力を確認しましょう。

docker logs non-root-container

次のような出力が表示されるはずです。

Running as user:
appuser
File ownership:
-rw-r--r-- 1 appuser appuser 0 May 15 12:45 test-file.txt

これにより、コンテナが appuser ユーザーとして実行されており、テストファイルが appuser によって所有されていることが確認できます。

非 root ユーザーのパーミッションのテスト

実行中のコンテナに接続し、非 root ユーザーのパーミッションを調べてみましょう。

docker exec -it non-root-container bash

これで、appuser としてコンテナ内に入っているはずです。これを確認しましょう。

whoami

次のように表示されるはずです。

appuser

ユーザー ID とグループ ID を確認します。

id

出力は次のようになるはずです。

uid=1000(appuser) gid=1000(appuser) groups=1000(appuser)

次に、ルートディレクトリにファイルを作成してみましょう。

touch /root-test-file

パーミッション拒否エラーが表示されるはずです。

touch: cannot touch '/root-test-file': Permission denied

これは、非 root ユーザーにはルートディレクトリへの書き込み権限がないためです。ただし、ユーザーは /app ディレクトリに書き込むことができます。

touch /app/user-test-file
ls -l /app/user-test-file

新しいファイルが appuser によって所有されていることがわかるはずです。

-rw-r--r-- 1 appuser appuser 0 May 15 12:50 /app/user-test-file

コンテナのシェルを終了します。

exit

次のステップに進む前に、コンテナをクリーンアップしましょう。

docker stop non-root-container
docker rm non-root-container

このステップでは、Docker コンテナ内で非 root ユーザーを作成して使用する方法を示しました。非 root ユーザーを使用することで、アプリケーションに利用可能なパーミッションを制限し、コンテナ化されたアプリケーションのセキュリティを向上させることができます。

ボリュームマウントのパーミッション管理

Docker ボリュームを使用すると、ホストとコンテナ間でデータを共有できます。ただし、ボリュームを使用する際にパーミッションを正しく管理することは、問題を回避するために重要です。このステップでは、ボリュームマウントを使用する際のパーミッションの扱い方を学びます。

ボリュームマウントのパーミッション問題の理解

Docker ボリュームマウントに関する主な問題は、コンテナ内のユーザー ID がホストシステムのユーザー ID と一致しない場合があることです。これにより、マウントされたボリューム内のファイルにアクセスする際にパーミッション問題が発生する可能性があります。

この問題を簡単な例で説明しましょう。

まず、コンテナにマウントするホスト上の新しいディレクトリを作成します。

mkdir -p ~/project/host-data
cd ~/project/host-data

このディレクトリにテストファイルを作成します。

echo "This is a test file created on the host" > host-file.txt

このファイルの所有権を確認します。

ls -l host-file.txt

ファイルが labex ユーザー(ホスト上の現在のユーザー)によって所有されていることがわかるはずです。

-rw-r--r-- 1 labex labex 39 May 15 13:00 host-file.txt

次に、このディレクトリをマウントするコンテナを実行し、ファイルを変更してみましょう。

docker run -it --rm -v ~/project/host-data:/container-data ubuntu:22.04 bash

これでコンテナ内に入りました。マウントされたファイルの所有権を確認しましょう。

ls -l /container-data/host-file.txt

次のような出力が表示されることがあります。

-rw-r--r-- 1 1000 1000 39 May 15 13:00 /container-data/host-file.txt

コンテナはホストの labex ユーザーについて知らないため、ファイルはユーザー名ではなく数値 ID で表示されていることに注意してください。

マウントされたディレクトリに新しいファイルを作成してみましょう。

echo "This is a test file created in the container" > /container-data/container-file.txt

この新しいファイルの所有権を確認します。

ls -l /container-data/container-file.txt

次のように表示されるはずです。

-rw-r--r-- 1 root root 47 May 15 13:05 /container-data/container-file.txt

ファイルはコンテナ内の root ユーザーによって所有されています(デフォルトで root として実行されているため)。

コンテナを終了します。

exit

次に、ホスト上の両方のファイルの所有権を確認します。

ls -l ~/project/host-data/

コンテナ内から作成されたファイルがホスト上で root によって所有されていることがわかります。

-rw-r--r-- 1 root  root  47 May 15 13:05 container-file.txt
-rw-r--r-- 1 labex labex 39 May 15 13:00 host-file.txt

ホスト上の非 root ユーザーがこれらのファイルにアクセスまたは変更する必要がある場合、これによりパーミッション問題が発生する可能性があります。

ボリュームのパーミッション問題の解決方法

ボリュームのパーミッション問題を解決する方法はいくつかあります。いくつかの一般的なアプローチを見てみましょう。

アプローチ 1: Dockerfile でユーザーをホストユーザーに一致させる

この例用の新しいディレクトリを作成します。

mkdir -p ~/project/volume-permissions
cd ~/project/volume-permissions

新しい Dockerfile を作成します。

nano Dockerfile

以下の内容を追加します。

FROM ubuntu:22.04

## ホストユーザーと同じ UID のユーザーを作成する
RUN useradd -m -u 1000 appuser

## アプリケーションディレクトリを作成し、所有権を設定する
RUN mkdir -p /app/data && chown -R appuser:appuser /app

## 作業ディレクトリを設定する
WORKDIR /app

## appuser に切り替える
USER appuser

## 実行するコマンド
CMD ["bash", "-c", "echo 'I can write to the mounted volume' > /app/data/test.txt && tail -f /dev/null"]

エディタを保存して終了します。

イメージをビルドします。

docker build -t volume-permissions-image .

テスト用のホストディレクトリを作成します。

mkdir -p ~/project/volume-permissions/host-data

ボリュームをマウントしたコンテナを実行します。

docker run -d --name volume-test -v ~/project/volume-permissions/host-data:/app/data volume-permissions-image

しばらくしてから、ホスト上で作成されたファイルの所有権を確認します。

ls -l ~/project/volume-permissions/host-data/

ファイルが UID 1000 のユーザーによって所有されていることがわかるはずです。これはホストユーザーの UID と一致するはずです。

-rw-r--r-- 1 labex labex 35 May 15 13:15 test.txt

このアプローチが機能するのは、コンテナ内にホストユーザーと同じ UID のユーザーを作成したからです。

アプローチ 2: --user フラグを使用する

もう 1 つのアプローチは、コンテナを実行する際に使用するユーザー ID を指定するために --user フラグを使用することです。

まず、前のコンテナをクリーンアップします。

docker stop volume-test
docker rm volume-test

次に、--user フラグを使用してコンテナを実行します。

docker run -d --name user-flag-test --user "$(id -u):$(id -g)" -v ~/project/volume-permissions/host-data:/data ubuntu:22.04 bash -c "echo 'Created with --user flag' > /data/user-flag-test.txt && sleep 3600"

このコマンドは、現在のユーザー ID とグループ ID でコンテナを実行します。

新しいファイルの所有権を確認します。

ls -l ~/project/volume-permissions/host-data/user-flag-test.txt

ファイルがホストユーザーによって所有されていることがわかるはずです。

-rw-r--r-- 1 labex labex 23 May 15 13:20 user-flag-test.txt

次のステップに進む前にクリーンアップしましょう。

docker stop user-flag-test
docker rm user-flag-test

これらのアプローチは、Docker ボリュームを使用する際のパーミッションの管理方法を示しています。コンテナとホスト間のユーザー ID を一致させることで、データを共有する際のパーミッション問題を回避できます。

パーミッションのベストプラクティスの実装

これまで学んだことをすべて活用して、パーミッションのベストプラクティスに沿った Docker コンテナのより現実的な例を作成しましょう。パーミッションに関するセキュリティのベストプラクティスに沿ったシンプルな Web アプリケーションコンテナを作成します。

セキュアな Web アプリケーションコンテナの作成

まず、この例用の新しいディレクトリを作成します。

mkdir -p ~/project/secure-app
cd ~/project/secure-app

シンプルな Web アプリケーションを作成しましょう。まず、app.py ファイルを作成します。

nano app.py

シンプルな Flask Web サーバーを作成するために、以下の Python コードを追加します。

from flask import Flask
import os

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello from a secure container!'

@app.route('/whoami')
def whoami():
    return os.popen('id').read()

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

エディタを保存して終了します。

次に、Python の依存関係用の requirements.txt ファイルを作成します。

nano requirements.txt

以下の内容を追加します。

flask==2.0.1

エディタを保存して終了します。

次に、パーミッションのベストプラクティスに沿った Dockerfile を作成します。

nano Dockerfile

以下の内容を追加します。

FROM python:3.10-slim

## アプリケーションを実行する非 root ユーザーを作成する
RUN groupadd -g 1000 appgroup \
  && useradd -u 1000 -g appgroup -s /bin/bash -m appuser

## 作業ディレクトリを設定し、必要なディレクトリを作成する
WORKDIR /app

## Docker キャッシュを活用するために、最初に requirements をコピーする
COPY requirements.txt .

## root として依存関係をインストールする
RUN pip install --no-cache-dir -r requirements.txt

## アプリケーションコードをコピーする
COPY app.py .

## アプリケーションが書き込み可能なデータディレクトリを作成する
RUN mkdir -p /app/data \
  && chown -R appuser:appgroup /app

## 適切なパーミッションを設定する
RUN chmod -R 755 /app

## 非 root ユーザーに切り替える
USER appuser

## アプリケーションが実行されるポートを公開する
EXPOSE 8080

## アプリケーションを実行するコマンド
CMD ["python", "app.py"]

エディタを保存して終了します。

Docker イメージをビルドしましょう。

docker build -t secure-web-app .

次に、コンテナを実行します。

docker run -d --name secure-app -p 8080:8080 secure-web-app

アプリケーションをテストしましょう。まず、コンテナが実行されているか確認します。

docker ps

リストに secure-app コンテナが表示されるはずです。次に、curl を使用してアプリケーションをテストします。

curl http://localhost:8080/

次のように表示されるはずです。

Hello from a secure container!

アプリケーションがどのユーザーとして実行されているかを確認しましょう。

curl http://localhost:8080/whoami

次のような出力が表示されるはずです。

uid=1000(appuser) gid=1000(appgroup) groups=1000(appgroup)

これにより、アプリケーションが非 root の appuser として実行されていることが確認できます。

セキュリティ分析

Dockerfile のセキュリティ向上点を分析しましょう。

  1. 非 root ユーザー:アプリケーションを実行するための専用ユーザー (appuser) を作成し、コンテナが侵害された場合のリスクを低減します。
  2. 最小限のパーミッション:アプリケーションが機能するために必要な最小限のパーミッションのみを設定します。
  3. 明確な所有権:コンテナ内のすべてのファイルとディレクトリには、明確に定義された所有権があります。
  4. 適切なディレクトリ構造:アプリケーションとそのデータ用の専用のディレクトリ構造を作成します。

これらの実践により、攻撃者がアプリケーションの脆弱性を悪用した場合でも、コンテナとホストシステムへのアクセスが制限されます。

セキュアなアプリでのボリュームパーミッションの実装

セキュアなアプリケーションにボリュームを追加して、ボリュームのパーミッションを適切に扱う方法を示しましょう。

まず、既存のコンテナを停止して削除します。

docker stop secure-app
docker rm secure-app

ホスト上にデータディレクトリを作成します。

mkdir -p ~/project/secure-app/host-data

ホストディレクトリに正しいパーミッションを設定します。

sudo chown 1000:1000 ~/project/secure-app/host-data

次に、ボリュームをマウントしてコンテナを実行します。

docker run -d --name secure-app-with-volume \
  -p 8080:8080 \
  -v ~/project/secure-app/host-data:/app/data \
  secure-web-app

コンテナに接続し、マウントされたボリュームにファイルを作成しましょう。

docker exec -it secure-app-with-volume bash

コンテナ内で、マウントされたボリュームにテストファイルを作成します。

echo "Test file created from inside the container" > /app/data/container-file.txt

ファイルの所有権を確認します。

ls -l /app/data/container-file.txt

ファイルが appuser によって所有されていることがわかるはずです。

-rw-r--r-- 1 appuser appgroup 43 May 15 13:30 /app/data/container-file.txt

コンテナを終了します。

exit

次に、ホスト上でファイルの所有権を確認します。

ls -l ~/project/secure-app/host-data/container-file.txt

ファイルが UID 1000(ホストユーザーに対応)によって所有されていることがわかるはずです。

-rw-r--r-- 1 labex labex 43 May 15 13:30 container-file.txt

これは、適切なパーミッション設定により、コンテナ内でマウントされたボリュームに作成されたファイルがホスト上で正しい所有権を持つことを示しています。

最後にクリーンアップしましょう。

docker stop secure-app-with-volume
docker rm secure-app-with-volume

これらの Docker パーミッションのベストプラクティスに従うことで、コンテナ内およびホストシステムとのデータ共有時にファイルパーミッションを適切に管理する、セキュアで信頼性の高いコンテナ化アプリケーションを作成できます。

まとめ

この実験では、Docker コンテナのパーミッションを管理するための重要な技術を学びました。

  1. Docker のデフォルトパーミッションの理解:Docker コンテナがデフォルトで root として実行される仕組みと、これが潜在的なセキュリティリスクにつながる可能性を調べました。
  2. 非 root ユーザーの作成と使用:Docker コンテナ内でカスタムの非 root ユーザーを作成する方法を学びました。これは重要なセキュリティのベストプラクティスです。
  3. ボリュームマウントのパーミッション管理:ボリュームを使用してホストとコンテナ間でデータを共有する際のパーミッションの扱い方を学び、一般的なパーミッション問題に対処しました。
  4. パーミッションのベストプラクティスの実装:これらの概念をすべて適用して、Docker のパーミッションのベストプラクティスに沿ったセキュアな Web アプリケーションコンテナを作成しました。

これらの技術を Docker プロジェクトに適用することで、コンテナ化されたアプリケーションのセキュリティと信頼性を大幅に向上させることができます。コンテナを必要最小限の権限で実行することは、常に守るべき基本的なセキュリティ原則であることを忘れないでください。

いくつかの重要なポイントをまとめます。

  • コンテナでは常に非 root ユーザーを使用する
  • ボリュームを使用する際には、ホストとコンテナ間のユーザー ID を一致させる
  • 適切なファイルとディレクトリのパーミッションを設定する
  • 最小権限の原則に従う

これらの実践により、よりセキュアな Docker コンテナを構築し、一般的なパーミッション関連の問題を回避するのに役立ちます。