【Docker】ApacheのSSL証明書せって「mkcert」 「Let’s Encrypt」

Dockerで始めるセキュアな開発環境:HTTPS/SSL設定

Docker環境でのSSL接続設定について詳しく解説します。

HTTPSとSSL/TLSの関係って?

  • HTTPS(Hypertext Transfer Protocol Secure)は、Webブラウザとサーバー間の通信を安全に行うためのプロトコルです。
  • SSL/TLSは、HTTPSの中で使われている暗号化技術です(SSLは古い呼び方で、現在はTLSが主流です)。
HTTP (アプリケーション層) SSL/TLS (セキュリティ層) TCP (トランスポート層) HTTPSは「HTTP over SSL/TLS」 (SSL/TLSで暗号化されたHTTP通信)
ブラウザ Webサーバー HTTPS (暗号化通信) SSL/TLS: 通信を暗号化するプロトコル HTTPS = HTTP + SSL/TLS による暗号化 HTTP (暗号化なし)

Dockerを使用した開発環境でも、SSL接続を適切に設定することで、より本番環境に近い安全な環境を構築できます。

➡️ 本番環境との一貫性

まずはdocker-compose.ymlで設定

まずdocker-compose.ymlでポート443のマッピングを設定

ホストマシン Dockerコンテナ 443 443 ports: – “443:443”
services:
  app:
    ports:
      - "0.0.0.0:8080:80"
      - "443:443"

SSL証明書設定

SSL証明書設定には主に3つの選択肢

自己署名証明書 ・無料 ・簡単に作成可能 ・ブラウザに警告表示 openssl コマンド使用 mkcert ・無料 ・警告表示なし ・開発用に最適 ・簡単なコマンド Let’s Encrypt ・無料 ・本番環境向け ・ドメイン名必須 ・定期的な更新必要

自己署名証明書を使用する場合

https://localhostとしてブラウザで確認すると警告がでます

警告ページで「詳細」や「続行」などのオプションを探します。 リスクを理解した上で、「Webサイトへ進む」などのオプションを選択します。 ブラウザは警告を表示しつつも、ページの表示を許可します。

注意点:この方法は開発環境でのみ推奨されます。

この設定により、ホストマシンのポート443がDockerコンテナ内のポート443にマッピングされます。これにより、外部からのHTTPS接続(ポート443)をコンテナ内のApacheサーバーで受け付けることができます。

Dockerfileでの設定

次に、Dockerfileで以下のようなSSL関連の設定を行います:

1)SSLモジュールの有効化:

RUN a2enmod ssl

2)デフォルトのSSLサイト設定の有効化:

RUN a2ensite default-ssl

3)自己署名SSL証明書の生成:

RUN echo '#!/bin/bash
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/ssl/private/apache-selfsigned.key \
-out /etc/ssl/certs/apache-selfsigned.crt \
-subj "/CN=localhost"
sed -i "s|SSLCertificateFile.*|SSLCertificateFile /etc/ssl/certs/apache-selfsigned.crt|" /etc/apache2/sites-available/default-ssl.conf
sed -i "s|SSLCertificateKeyFile.*|SSLCertificateKeyFile /etc/ssl/private/apache-selfsigned.key|" /etc/apache2/sites-available/default-ssl.conf' > /usr/local/bin/generate_ssl_cert.sh

RUN chmod +x /usr/local/bin/generate_ssl_cert.sh && /usr/local/bin/generate_ssl_cert.sh
  • opensslコマンドを使用して自己署名証明書を生成しています。
  • -x509:自己署名証明書を生成することを指定します。
  • -nodes:秘密鍵をパスワードで保護しないことを指定します。
  • -days 365:証明書の有効期間を1年に設定します。
  • -newkey rsa:2048:2048ビットのRSA鍵を新しく生成します。
  • -keyout-out:鍵と証明書の出力先を指定します。
  • -subj "/CN=localhost":証明書のサブジェクト(ここではCommon Name)を設定します。…証明書が保護するドメイン名または IP アドレスを指定します
  • sed は “stream editor” の略で、テキストの変換や置換に使用
    • 置換パターン:s|旧パターン|新パターン| の形式で、| はデリミタ(区切り文字)として機能

4)ポート443の公開:

EXPOSE 80 443

Let’s Encryptは開発環境では難しい

Let’s Encryptが開発環境で難しい主な理由は:

  1. ドメイン名が必要
    • localhostでは使えない
    • IPアドレスでも使えない
  2. 外部からのアクセスが必要
    • 証明書発行時に外部からの認証が必要
    • ローカル環境では実現が難しい
  3. 更新の手間
    • 90日ごとに更新が必要
    • 開発環境では更新管理が面倒

ローカルDocker開発環境では難しい、、、?

Let’s Encryptの環境比較 開発環境 ✖ localhostやIPアドレスは使えない ✖ 外部からアクセス不可 ✖ 90日ごとの更新が面倒 ✖ 独自ドメインが必要 本番環境 〇 実際のドメインで使用可能 〇 インターネットからアクセス可能 〇 自動更新の設定が可能 〇 無料で信頼された証明書

mkcertを使用したSSL接続の設定

mkcertを使用することで、自己署名証明書の警告なしに安全な開発環境を構築できます。

Chocolateyがインストールされていない場合は、まずChocolateyをインストール

Chocolateyは、Windowsのためのパッケージマネージャーです。

Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
Chocolatey(チョコレーティー)とは? Windowsのパッケージマネージャー(ソフトウェアインストーラー) 通常のインストール方法 1. Webサイトを探す 2. インストーラーをダウンロード 3. exeファイルを実行 4. Next, Next… と進める Chocolateyの場合 1. PowerShellで1行を実行 例:choco install mkcert 自動でインストール完了!

Chocolatey現在のインストール状態を確認してみましょう

cd ~
PS C:\Users\ida-t> choco --version
choco : 用語 'choco' は、コマンドレット、関数、スクリプト ファイル、または操作可能なプログラムの名前として認識されません。
名前が正しく記述されていることを確認し、パスが含まれている場合はそのパスが正しいこと 
を確認してから、再試行してください。

// chocoコマンドは認識されない(PATHが通っていない)

\Users\name\AppData\Local> ls

..
d-----        2024/09/13      9:48                mkcert
..

// AppData\Localにmkcertフォルダがある
// chocolateyフォルダは見当たらない

管理者権限が必要

事前準備

インストール時の権限による違い 管理者権限で入れた場合 C:\ProgramData\… ✓ 全員が使える ✓ パスが自動で通る ✓ コマンドがすぐ使える ✓ 正しいインストール方法 一般権限で入れた場合 C:\Users\名前\AppData\… × 自分しか使えない × パスが通らない × コマンドが使えない × 中途半端な状態になる
chocolatey(チョコレーティー)の状態:

C:\Windows配下に複数のchocolateyInstall.ps1が残存(2019年と2024年のタイムスタンプ)
本来のインストール場所(C:\ProgramData\chocolateyまたはAppData\Local\chocolatey)にはない
コマンド(choco)は認識されない
→ 完全にインストールされていない、かつ古い痕跡が残っている状態

mkcert(エムケイサート)の状態:

C:\Users\[ユーザー名]\AppData\Local\mkcertフォルダが存在
コマンド(mkcert)は認識されない可能性が高い
→ 不完全なインストール状態

パスが通るとは

パスが通るとは? C:\Users\名前> choco Windowsの動き: 1. システムフォルダを探す 2. ProgramDataのフォルダを探す 3. Path(パス)に登録された場所を探す 見つからない場合 →「コマンドが見つかりません」

AppDataフォルダとは

ユーザーごとの設定を保存する隠しフォルダ
C:\Users\名前\AppData\Localにある
一般権限でインストールすると、ここに入ってしまう

AppDataフォルダって何? C:\Users\名前\AppData\ Local ・このPCだけで使う ・設定やデータ ・隠しフォルダ ※ 普段は見えない場所に  アプリの設定を保存する  特別なフォルダです

既存の不完全なmkcertのアンインストール
場所:C:\Users[ユーザー名]\AppData\Local\mkcertの削除

依頼タイトル:
開発環境のHTTPS化に必要なツール(Chocolatey、mkcert)の管理者権限インストール依頼
依頼理由:

ローカル開発環境でのHTTPS通信テストが必要
現状、HTTPSの証明書管理ツール(mkcert)が中途半端にインストールされている状態

必要な作業:

パッケージマネージャー(Chocolatey)の管理者権限でのインストール

インストール先:C:\ProgramData\chocolatey
理由:システム環境変数の設定が必要なため


mkcertの管理者権限でのインストール

コマンド:choco install mkcert
理由:ローカル認証局の設定に管理者権限が必要なため



期待される結果:

開発環境でのHTTPS通信のテストが可能になる
証明書の警告なしでローカル開発が行える

一般権限でパスを通す場合もしくはパスを通さずにしようすると、、(非推奨?)

mkcertの場合は残念ながら管理者権限が必須です。理由は:

  1. 証明書の信頼設定にシステムレベルのアクセスが必要
  2. ブラウザに信頼させるには管理者権限が必要
  3. ローカル認証局の作成に管理者権限が必要

そのため、パスを通すだけや、フルパスでの実行だけでは目的を達成できません。HTTPSの警告なし開発環境を作るには、管理者権限でのインストールが必要になります。

mkcertを管理者権限なしで使う場合の制限 方法1: パスを通す ユーザー環境変数のPATHに追加: \AppData\Local\mkcert × 証明書の信頼設定ができない × ブラウザが警告を出す × 結局管理者権限が必要 方法2: フルパスで実行 フルパスで実行: \AppData\Local\mkcert\mkcert.exe × 同じく証明書の信頼設定不可 × 警告が出る × 管理者権限が必要 結論: mkcertは証明書を信頼させる必要があるため、管理者権限が必須 → パスを通すだけでは解決できない

Chocolateyは一般権限でも一部機能は使える
しかし、mkcertのような管理者権限が必要なツールはインストールできても正常に動作しない

Chocolateyを一般ユーザーで使う場合 できること ✓ パッケージの検索 ✓ パッケージ情報の表示 ✓ ユーザーフォルダへの インストール できないこと × システムへの登録 × 管理者権限が必要な ツールのインストール × システム環境変数の変更

mkcert「エムケイサート」のインストールと使用

Windows PowerShell”を右クリックし、“管理者として実行”を選択します。

mkcertをインストール:

choco install mkcert

インストールの確認

mkcert --version

ローカル認証局のインストール

mkcert -install

インストールの確認

mkcert -CAROOT

証明書の生成

プロジェクトディレクトリに移動し、以下のコマンドを実行:

mkdir certs
cd certs
mkcert localhost 127.0.0.1 ::1

→ファイル生成
・証明書ファイル: [最初のドメイン名]+[追加エントリ数].pem (公開鍵を含む)
・秘密鍵ファイル: [最初のドメイン名]+[追加エントリ数]-key.pem

mkcert localhost 127.0.0.1 ::1 生成 証明書ファイル(公開可) localhost+2.pem ・ドメイン情報 ・有効期限 ・公開鍵 共有しても安全 秘密鍵ファイル(厳重管理) localhost+2-key.pem ・秘密鍵 ⚠ 絶対に共有しない! ⚠ Gitにコミットしない! ファイル名の規則: [ドメイン名]+[追加ドメイン数].pem / [ドメイン名]+[追加ドメイン数]-key.pem
— 証明書 –> localhost+2.pem 証明書 (公開情報) 公開鍵 localhost+2-key.pem 秘密鍵 対応 秘密 – 共有しないこと!

各ファイルを編集

鍵ファイルを作成したら下記を実施します

  • Apache設定ファイルでは、SSLエンジンを有効にし、証明書と秘密鍵のパスを正しく指定しています。
  • Dockerfileでは、Apacheの SSL モジュールを有効化しています。
  • docker-compose.ymlでは、443ポートをホストにマッピングし、必要なボリュームをマウントしています。
DockerPHP開発環境でのSSL設定(mkcert使用) ホストマシン Dockerコンテナ mkcert SSL証明書 Apache PHP 証明書のコピー 1. mkcertインストール 2. 証明書生成 3. Dockerfile設定 4. docker-compose.yml設定 5. Apache SSL設定 6. PHP設定(必要に応じて) 7. アプリケーション開発 HTTPSアクセス
project_root/
│
├── local-mysite/
│   ├── certs/
│   │   ├── localhost+2.pem
│   │   └── localhost+2-key.pem
│   ├── env_vars/
│   │   └── localhost
│   ├── sites-available/
│   │   └── 000-default.conf
│   ├── .htaccess
│   ├── docker-compose.yml
│   ├── Dockerfile
│   ├── php.ini
│   └── ssl_cert_gen.sh
│
└── mysite/
    └── (PHPアプリケーションファイル)

▼docker-compose.yml

version: "3.4"
services:
  app:
    # Dockerfileからイメージをビルド
    build:
      context: .
      dockerfile: Dockerfile
    
    # ボリュームマウントの設定
    volumes:
      # 環境変数ファイルをマウント
      - ./env_vars:/var/www/env_vars
      # PHPアプリケーションのソースコードをマウント
      - ../0824_mysite:/var/www/html
      # SSL証明書をマウント(読み取り専用)
      - ./certs/localhost+2.pem:/etc/ssl/certs/localhost+2.pem:ro
      # SSL秘密鍵をマウント(読み取り専用)
      - ./certs/localhost+2-key.pem:/etc/ssl/private/localhost+2-key.pem:ro
      # Apache設定ファイルをマウント
      - ./sites-available:/etc/apache2/sites-available

    # ポートマッピングの設定
    ports:
      # HTTP: ホストの8082ポートをコンテナの80ポートにマッピング
      - "0.0.0.0:8082:80"
      # HTTPS: ホストの443ポートをコンテナの443ポートにマッピング
      - "443:443"

    # 環境変数の設定(必要に応じて追加)
    environment:
      - APACHE_DOCUMENT_ROOT=/var/www/html

▼Dockerfile

# SSL対応PHP開発環境のDockerfile

# PHP 8.1とApacheをベースとした公式イメージを使用
FROM php:8.1-apache

# カスタムApache設定ファイルをコンテナ内の指定された場所にコピー
COPY ./sites-available/000-default.conf /etc/apache2/sites-available/000-default.conf

# PDO_MySQL拡張をインストールし、Apacheのrewrite、proxy、proxy_httpモジュールを有効化
RUN docker-php-ext-install pdo_mysql && a2enmod rewrite proxy proxy_http

# SSLモジュールを有効化
RUN a2enmod ssl

# デフォルトのSSLサイト設定を有効化
RUN a2ensite default-ssl

# 必要なパッケージをインストール
RUN apt-get update && apt-get install -y \
    curl \
    gnupg \
    git \
    unzip \
    openssl \
    # Node.jsのセットアップスクリプトを取得して実行
    && curl -sL https://deb.nodesource.com/setup_18.x | bash - \
    # Node.jsをインストール
    && apt-get install -y nodejs \
    # パッケージリストを削除してイメージサイズを削減
    && rm -rf /var/lib/apt/lists/*

# Composerをコンテナ内にコピー
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# コンテナ内の作業ディレクトリを設定
WORKDIR /var/www/html

# Composerの設定
ENV COMPOSER_HOME /var/www/.composer
RUN mkdir -p $COMPOSER_HOME && chown -R www-data:www-data $COMPOSER_HOME

# Apache実行ユーザーの設定
ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data

# Apacheの設定を変更し、.htaccessが機能するようにAllowOverrideをAllに設定
RUN sed -i '/<Directory \/var\/www\/>/,/<\/Directory>/ s/AllowOverride None/AllowOverride All/' /etc/apache2/apache2.conf

# コンテナのポート80(HTTP)と443(HTTPS)を公開
EXPOSE 80 443

# .htaccessファイルをコンテナ内にコピー
COPY .htaccess /var/www/html/.htaccess

# .htaccessファイルの所有権と権限を設定
RUN chown www-data:www-data /var/www/html/.htaccess && chmod 644 /var/www/html/.htaccess

# カスタムphp.iniをコンテナ内にコピー
COPY ./php.ini /usr/local/etc/php/php.ini

# PHPエラーログファイルを作成し、適切な権限を設定
RUN touch /var/log/php_errors.log && chmod 666 /var/log/php_errors.log

# mkcertで生成した証明書をコンテナ内にコピー
COPY ./certs/localhost+2.pem /etc/ssl/certs/localhost.crt
COPY ./certs/localhost+2-key.pem /etc/ssl/private/localhost.key

# 証明書のパーミッションを適切に設定
RUN chmod 644 /etc/ssl/certs/localhost.crt && \
    chmod 600 /etc/ssl/private/localhost.key

# Apacheをフォアグラウンドで実行
CMD ["apache2-foreground"]

▼000-default.conf

<VirtualHost *:80>
    ServerName localhost
    DocumentRoot /var/www/html
    Redirect permanent / https://localhost/

    # HTTPのアクセスログとエラーログ(必要に応じてコメントを外す)
    # ErrorLog ${APACHE_LOG_DIR}/error.log
    # CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

<VirtualHost *:443>
    ServerName localhost
    DocumentRoot /var/www/html
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/localhost+2.pem
    SSLCertificateKeyFile /etc/ssl/private/localhost+2-key.pem

    <Directory /var/www/html>
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
```

この設定は、HTTPからHTTPSへのリダイレクトと、SSL/TLS接続の基本的な設定を提供します。

mkcertとopenssl、Let’s Encryptを使用したSSL設定の比較

mkcertとopenssl、Let’s Encryptを使用したSSL設定の主な違いは、使いやすさと生成される証明書の性質にあります。

mkcertは開発環境に特化しており、簡単な操作で信頼されたSSL証明書を生成できます。一方、opensslはより汎用的で、詳細な設定が可能ですが、使用にはより深い知識が必要です。

開発環境では、mkcertの使用が推奨されます:

  1. セットアップが簡単で、チーム全体で一貫した環境を構築しやすい。
  2. ブラウザ警告がなく、よりスムーズなテストが可能。
  3. 開発者が証明書の詳細な管理に時間を割く必要がない。

一方、以下の場合はopensslの使用が適切です:

  1. 本番環境用の証明書生成。
  2. カスタムな証明書要件がある場合。
  3. 証明書生成プロセスの詳細な制御が必要な場合。

重要なポイントは、開発環境と本番環境で異なるアプローチを取ることが多いということです。開発ではmkcertの簡便性を活かし、本番ではopensslやLet’s Encryptなどを使用して、より厳格なセキュリティを確保することが一般的です。

SSL/TLS証明書ツールの比較 mkcert Let’s Encrypt OpenSSL ・ローカル開発用 ・簡単な操作 ・自動的にCA作成 ・ブラウザ警告なし ・無料の公的証明書 ・自動更新可能 ・Webサーバー必要 ・ドメイン名必須 ・汎用的なツール ・詳細な設定可能 ・自己署名証明書 ・高度な知識必要 開発環境 本番環境 カスタム要件

セキュリティの考慮事項

開発環境でのmkcert使用

利点:

  1. 簡単にローカルでHTTPS環境を構築できる
  2. 開発者の生産性向上
  3. 本番環境に近い条件でのテストが可能

制限:

  1. ローカルマシンでのみ信頼される証明書
  2. 公的に認証された証明書ではない

mkcertはローカル環境に最適化されているため、本番環境特有の問題を見逃す可能性がある

一般的な本番環境要件:

  1. 信頼された認証局(CA)による証明書の使用
  2. 強力な暗号化アルゴリズムの採用
  3. 定期的な証明書の更新
  4. 適切なサーバー設定(TLSバージョン、暗号スイートなど)