2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Docker】Nginx + OAuth2-proxyで既存Webサービスに認証を簡単追加

Posted at

image.png

作成日:2025年10月19日(日)

1.はじめに

最近のWebサービスでは、OAuth2.0/OIDC認証による安全なユーザー認証機能を追加するのが一般的になっています。

ただし、OAuth2.0を導入するには、グローバルIPアドレス、DNS設定(*1)、サーバ証明書などが必要で、これらが複雑に絡み合っているため、仕組みを理解するまでに時間がかかり、少しハードルが高く感じられます。

グローバルIPアドレス、ドメイン取得&DNS設定(*1)、サーバ証明書はさすがに設定しておく必要があります。しかし、様々なWebサービスの構造ごとにこれらを設定するのは、Webサーバによって設定方法が異なるため、難しくしている原因の一つです。

そこでこの記事では、NginxとOAuth2-proxyをDockerコンテナで構築するパッケージを作成します。既存のWebサービスをNginxのバックエンドに配置することで、OAuth2.0認証を簡単に実現する方法をまとめます。

(*1):自己サーバ証明書はIPアドレスでも発行できますが、今回はドメイン取得して、サーバ証明書を発行しています。

2.OAuth認証とは

OAuth 2.0は、ユーザーが第三者アプリケーションに対して、パスワードを共有することなく
自分のリソースへのアクセス権を委譲できるオープンな認可プロトコルです。
認証機能が必要な場合は、OAuth 2.0上に構築されたOpenID Connect (OIDC)を使用します。

開発チームと歴史

OAuth 2.0は、OAuth 1.0の後継として2012年10月にRFC 6749として標準化されました。このプロトコルは、Internet Engineering Task Force (IETF)のOAuthワーキンググループによって開発されました。初期の開発には、Google、Microsoft、Facebook、Twitterなどの大手テクノロジー企業のエンジニアが参加し、実際のWebサービスでの使用経験を基に設計されました。OAuth 1.0が2007年に登場した際、Twitter、Google、その他のWeb企業が協力して仕様を策定しましたが、実装の複雑さが課題となっていました。OAuth 2.0はこれらの課題を解決し、よりシンプルで柔軟な実装を可能にすることを目指して開発されました。

現在の人気と普及状況

現在、OAuth 2.0は業界標準の認可プロトコルとして広く採用されています。
OpenID Connect (OIDC)と組み合わせることで、認証と認可の両方をカバーする包括的なソリューションとして実装されています。

Google、Facebook、Microsoft、GitHub、Slack、Spotifyなど、世界中の主要なWebサービスやAPIプロバイダーがOAuth 2.0をサポートしています。特にモバイルアプリケーションやSingle Page Application (SPA)の普及に伴い、OAuth 2.0の重要性はさらに高まっています。また、OpenID Connect (OIDC)という認証レイヤーがOAuth 2.0上に構築され、認証と認可の両方をカバーする包括的なソリューションとして広く使用されています。企業のAPI戦略においても、OAuth 2.0は不可欠な要素となっており、セキュアなサードパーティ統合を実現するための標準的な選択肢となっています。

3.システム構成

以下の構成図では、朱枠部分が既存の非TLSのWebサービス(HTTP)を示しています。今回は、NginxとOAuth2-proxy部分をDocker Composeで導入します。

potofo_oauth2-proxy.png

各コンポーネントの役割

No コンポーネント 役割
1 Webブラウザ TTPS化されたWebシステムにアクセスするためのクライアントブラウザ
2 Nginx Nginxのproxy-pass機能で、非HTTPS(HTTP)のWebアプリをHTTPS化し、Let’s Encryptの証明書更新時のACME Challengeのコールバックの受付、OAuth2-proxyによるOAuth2.0/OIDC認証
3 OAuth2-proxy 認証プロバイダーにOAuth2.0/OIDC認証を転送し、コールバックを受け付ける
4 GCE(Google Compute Engine) Google CloudのIaaS環境でUbunru-24.04のホスティングを実現
5 AWS Route53 hogehoge.netのドメインコントローラ
GCEで確保した静的外部IPのDNS解決を行う
6 Let’s Encrypt hogehoge.netのブラウザ用、サーバ証明書の管理
7 Azure Microsoft Entra ID 外部ドメインのユーザを招待してOAuth2.0/OIDC認証を行う

4.前提条件

全体を説明すると長文になるため、ホスティング、グローバルIP、ドメイン登録、サーバ証明書などは簡単に触れるにとどめ、今回作成したNginxとOAuth2-proxyの構成を中心に説明します。

No 項目 内容 説明
1 利用するコンテナ nginx:latest TLS終端、リバースプロキシを行います
2 quay.io/oauth2-proxy/oauth2-proxy:v7.2.1 認証プロバイダ認証仲介、セッション管理を行います
※今回はMicrosoft Azure Entra IDですが、OAuth2.0/OIDCをサポートしていればなんでも良いと思います。
3 redis:7-alpine 分散セッションストレージ、セッションを管理します。
4 certbot/certbot:latest Let’s Encryptのサーバ証明書の自動取得・更新を行います。
5 ホスティング Ubuntu-24.04をGCE(Google Compute Engine)にインストール GCEの無料枠(オレゴンリージョンのe2.micro)を使用しました
5 グローバルIP Google CloudのGCEに静的外部IPの設定 GCEの無料枠のグローバルIPはインスタンスの再起動で変動するためにDNS登録用の静的外部IPを取得しました。(4.00USD)
※今回の構成でこれが一番高いかも
6 独自ドメイン登録 AWS Route53 今回は比較的安価な.netドメインをRoute53で取得しました。(年間17.00USD)
7 HTTPS グローバルIPとサーバ証明書が必須 Microsoft EntraID エンタープライズアプリケーションではコールバックアドレスにHTTPSのFQDNアドレスと実験用のhttp://localhostしか設定できません。HTTPS化が必須となります。
8 サーバ証明書 Let’s Encryptで3ヵ月間無料のサーバ証明書を発行 Let’s Encryptはサーバの証明書を3ヵ月毎に更新すれば無料で利用し続けられます。
9 Cookie ブラウザのサイトに対するCookie設定 OAuth2.0/OIDC認証ではクライアントのCookieを利用するためCookie設定が必須

5.費用概算

今回は最低限の運用のため、コストを抑えた構成で作成しました。
無料のホスティングを利用しても、グローバルIPやドメイン維持費は必要です。以下が費用の試算となります。

No 項目 説明 費用(月額)
1 ホスティング GCEの永久無料枠(E2-Micro)を使用。CPUパワーとメモリ不足のため正直お勧めできませんが、NginxとOAuth2-proxy + 軽量なWebサーバ程度ならかろうじて動作します。
固定グローバルIPの維持に4.00USD(月額600円)が必要です。
600円
(4.00USD/月)
2 DNSサービス Route 53(.netドメイン) 212.5円
(17.00USD/年間)
3 サーバ証明書 Let's Encryptの無料サーバ証明書
※3ヵ月ごとに更新が必要
0円
4 IDプロバイダー Microsoft Entra ID 無料プラン
※セキュリティグループで認可リストを管理する場合はMicrosoft Entra ID P2プランが必要
0円
合計 812.5円/月

6.前提条件のメモ

No 項目 メモ 備考
1 ホスティング Google Cloudの永久無料枠
リージョン:us-west1(オレゴン)、ゾーン:us-west1-a、マシンタイプ:e-micro(2vCPU、1GBメモリ、ストレージ:30GB、ファイアウォール:443許可
VPCからIPアドレスを辿り外部IPアドレスで静的外部IPアドレスを割り当て固定する
2 DNS AWSのRoute53
hogehoge.netドメインを登録し、ホストゾーンのAレコードにホスティングで割り当てた外部IPアドレスを設定する
3 サーバ証明書 certbot/certbotコンテナでLet's EncryptでDNS名でサーバ証明書を発行する

7.potofo/oauth2-proxyとは

potofo/oauth2-proxyは、既存のWebサービスにOAuth2.0/OIDC認証を追加するパッケージです。既存のWebサーバの設定を一切変更せず、NginxでOAuth2-proxyのリバースプロキシを構成することで、既存のWebサービスと簡単に連携できます。

リポジトリのクローン

git clone https://github.com/potofo/oauth2-proxy.git

フォルダ構成
potofo/oauth2-proxyをローカルにクローンすると以下のようなフォルダ構成となります。

📁oauth2-proxy
 ┗📁images
 ┗📁nginx
 ┗📁spec
 ┗📁web
 ┗.env.example
 ┗.gitignore
 ┗LICENSE.txt
 ┗README.ja-JP.md
 ┗README.md
 ┗docker-compose.yaml

potofo/oauth2-proxyの詳細はREADME.ja-JP.mdをご覧ください

8.設定

8.1. Microsoft Entra IDエンタープライズアプリケーションの作成

Microsoft Entra IDエンタープライズアプリケーションとは、Entra IDでOAuth/OIDC認証を
行うためのアプリケーション登録のことです。ここでOAuth2.0のクライアントIDやシークレット、
リダイレクトURIなどを設定します。

作成の仕方はLibreChatの「OpenID with Azure Entra」というページが分かり易いです。
以下に簡単に記載します。

①Azureポータルにサインイン
 https://portal.azure.com/

②アプリの登録を開く
 [Microsoft Entra ID]⇒[アプリの登録]を開く
③アプリケーションの登録
 アプリケーションを新規作成する
 名前:oauth2-proxy
 アクセス:この組織ディレクトリのみに含まれるアカウント
 リダイレクトURI:Web https://hogehoge.net/oauth2/callback
 ※リダイレクトURIはEntra IDエンタープライズアプリケーションがユーザの認証・認可を行ったあとに、OAuth2.0のトークンを引きついて戻る戻り先のURIのoauth2-proxyのコールバックアドレスを記載します。oauth2-proxy/nginx/templates/default.conf.templateのserverディレクティブで/oauth2のロケーションを定義しています。
④アクセストークンとIDトークンを有効にする
 [Microsoft Entra ID]⇒[アプリの登録]⇒⇒[認証]で「アクセストークン」と「IDトークン」を有効にする
⑤トークン構成でemail、prefered_usernameを追加する
 [Microsoft Entra ID]⇒[アプリの登録]⇒⇒[トークン構成]で「オプションの要求の追加」からIDでemail、prefered_usernameを追加する(恐らくemailだけあればよい)
⑥シークレットの発行

 [Microsoft Entra ID]⇒[アプリの登録]⇒⇒[証明書とシークレット]から「新しいクライアントシークレット」を追加し、「値」をOAUTH2_PROXY_CLIENT_SECRETとして控える
⑦クライアントIDとテナントIDを控える
 [Microsoft Entra ID]⇒[アプリの登録]⇒⇒[概要]から以下を控える
 「アプリケーション (クライアント) ID…」をOAUTH2_PROXY_CLIENT_IDとして控える
 「ディレクトリ (テナント) ID」をOAUTH2_PROXY_AZURE_TENANTとして控える

※外部ユーザー(ゲストユーザー)として登録した場合、メールアドレスは以下のような
形式に変換されます

 元のメールアドレス: potofo@hogehoge.com
 Entra ID上の表記: potofo_hogehoge.com#EXT#@potofohogehoge.onmicrosoft.com

 OAuth2認証時は元のメールアドレス(potofo@hogehoge.com)を使用し、
 Microsoft Authenticatorアプリで2FA認証を行います。

8.2. .envファイルの作成

 .env.exampleを.envにコピーして環境変数を環境に合わせて編集します。

cp .env.example .env
# Oauth2 Proxy Configuration
OAUTH2_PROXY_CLIENT_ID=your_client_id
OAUTH2_PROXY_AZURE_TENANT=your_azure_tenant_id
OAUTH2_PROXY_CLIENT_SECRET=your_client_secret
OAUTH2_PROXY_REDIRECT_URL=https://your-domain.com/oauth2/callback
OAUTH2_PROXY_COOKIE_SECRET=your_cookie_secret

# Nginx Configuration
NGINX_SERVER_NAME=your-domain.com
NGINX_SERVER_NAME_WWW=www.your-domain.com
NGINX_PROXY_PASS=http://host.docker.internal:8080
No 環境変数 説明
1 OAUTH2_PROXY_CLIENT_ID Microsoft Entra IDエンタープライズアプリケーションの作成で控えたOAUTH2_PROXY_CLIENT_ID
2 OAUTH2_PROXY_AZURE_TENANT Microsoft Entra IDエンタープライズアプリケーションの作成で控えたOAUTH2_PROXY_AZURE_TENANT
3 OAUTH2_PROXY_CLIENT_SECRET Microsoft Entra IDエンタープライズアプリケーションの作成で控えたOAUTH2_PROXY_CLIENT_SECRET
4 OAUTH2_PROXY_REDIRECT_URL AWSのRoute53のホストゾーンのAレコードに登録したホストのFQDNをURLにしたもの
例:hogehoge.netならば以下の通り
https://hogehoge.net/oauth2/callback
5 OAUTH2_PROXY_COOKIE_SECRET OAuth2-Proxyが利用するクッキーのパスフレーズ
32文字の値
「`openssl rand -base64 32
6 NGINX_SERVER_NAME Nginxのサーバ名
例:hogehoge.net
7 NGINX_SERVER_NAME_WWW www付きのNginxのサーバ名
例:www.hogehoge.net
※www.hogehoge.netでもアクセスを受け付けるように
8 NGINX_PROXY_PASS 既存のWWWサーバのURL
同一ホストの8080ポートで動いている場合Dockerのhost-gatewayのアドレスのhost.docker-internalを指定します。
http://host.docker.internal:8080
勿論ネットワーク的に接続されていればVPC内の別ホストでも大丈夫です。
私はSoftEtherVPN(Azure)を使って自宅のLinuxを接続しています。

8.3. 同一ホストでPlantuml Serverをポート8080で動かすcomposeファイル

/docker/plantuml/docker-compose.yml

version: '3.7'

services:
  plantuml-server:
    image: plantuml/plantuml-server
    ports:
      - 8080:8080

PlantUML Serverの起動
docker-compose.yamlと同じフォルダでdocker compose up -dコマンドを実行すれば動作します。

docker compose up -d

9.起動

potofo/oauth2-proxyの展開フォルダのdocker-compose.yamlと同じフォルダでdocker compose up -dコマンドを実行すれば動作します。

docker compose up -d

10.Google Compute Engineの無料枠

正直1GBのメモリではまともに動かせるものが少ないため、私は30GBのストレージのうち4GBをUbuntu-24.04のスワップにしています。

こうすればかろうじてn8nやPlantUMLサーバが動かせます。

但しそれでもかなりのモッサリ感があったので、現在はGCEはOAuth2.0認証とNginxのフロントエンド動作に専念させ、バックエンドのWebサーバはSoftEther VPN(Azure)で接続した自宅Linuxマシンで動かしているLibreChatと接続しています。

SoftEtherをAzure VPNモードにすることで、自宅側はグローバルIPを割り当てずにサーバ公開ができます。

LibreChat_screen.png

vpn_home_vpnという仮想NiCでGoogle Cloudから自宅LinuxにVPN接続しています。

root@instance-20250922-213313:/docker/plantuml-server# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute
       valid_lft forever preferred_lft forever
2: ens4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1460 qdisc mq state UP group default qlen 1000
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet xxx.xxx.xxx.xxx/32 brd xxx.xxx.xxx.xxx scope global dynamic ens4
       valid_lft 3478sec preferred_lft 3028sec
    inet6 xxxx::xxxx:xxx:xxxx:4/64 scope link
       valid_lft forever preferred_lft forever
3: vpn_home_vpn: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 1000
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet xxx.xxx.xxx.xxx/24 scope global vpn_home_vpn
       valid_lft forever preferred_lft forever
    inet6 xxxx::xxxx:xxxx:xxxx:xxxx/64 scope link
       valid_lft forever preferred_lft forever

11.運用

11.1. Let’s EncryptのSSL証明書の取得

# 一時的なWebサーバーでHTTP-01チャレンジ
docker run --rm -d \
  --name nginx-temp \
  -p 80:80 \
  -v $(pwd)/certbot-www:/var/www/certbot \
  nginx:latest

# 証明書取得
docker run --rm \
  -v $(pwd)/letsencrypt:/etc/letsencrypt \
  -v $(pwd)/certbot-www:/var/www/certbot \
  certbot/certbot:latest \
  certonly --webroot --webroot-path=/var/www/certbot \
  --email your-email@example.com \
  --agree-tos --no-eff-email \
  -d your-domain.com -d www.your-domain.com

# 一時的なWebサーバーを停止
docker stop nginx-temp

11.2. システムの起動

# サービス起動
docker compose up -d

# 起動状況確認
docker compose ps

# ログの確認
docker compose logs -f

11.3. 基本的な利用の流れ

  1. ブラウザで https://your-domain.com にアクセス
  2. 未認証の場合、Microsoft Entra IDのログイン画面にリダイレクト
  3. 組織アカウントでログイン
  4. 認証成功後、バックエンドサービスへアクセス可能

11.4. バックエンドサービスの変更

.envファイルのNGINX_PROXY_PASSを変更してサービスを再起動

# .envファイルを編集(例:ポート変更)
sed -i 's|http://host.docker.internal:8080|http://host.docker.internal:3000|g' .env

# nginx サービスのみ再起動
docker compose restart nginx

11.5. Nginx設定のカスタマイズ

nginx/templates/default.conf.templateを編集してカスタマイズ可能

  • カスタムヘッダーの追加
  • レート制限の設定
  • 追加のプロキシ設定
  • カスタムエラーページ

11.6. ログ管理

# 全サービスのログ
docker compose logs -f

# 特定サービスのログ
docker compose logs -f oauth2-proxy
docker compose logs -f nginx
docker compose logs -f redis

# エラーログのみ表示
docker compose logs --since=1h | grep -i error

11.7. Let’s EncryptのSSL証明書の更新

# 証明書更新コマンド(3ヶ月に1回cron実行推奨)
docker compose run --rm certbot renew --webroot -w /var/www/certbot && docker compose exec nginx nginx -s reload

# 証明書の有効期限確認
openssl x509 -in letsencrypt/live/your-domain.com/cert.pem -text -noout | grep "Not After"

# cron設定例(毎月1日の午前2時に実行、期限が近い場合のみ更新)
# crontab -e で以下を追加:
# 0 2 1 */3 * cd /path/to/oauth2-proxy && docker compose run --rm certbot renew --webroot -w /var/www/certbot && docker compose exec nginx nginx -s reload

※certbot renewコマンドは証明書の有効期限が30日未満の場合のみ更新を実行するため、
 毎月実行しても問題ありません。むしろ更新忘れを防ぐため、毎月実行を推奨します。

11.8. ヘルスチェック

# サービス状態確認
docker compose ps

# oauth2-proxy ヘルスチェック
curl -I http://localhost:4180/ping

# nginx ヘルスチェック
curl -I https://your-domain.com/oauth2/ping

11.9. バックアップ

# 設定ファイルのバックアップ
tar -czf oauth2-proxy-config-$(date +%Y%m%d).tar.gz \
  .env docker-compose.yaml nginx/ letsencrypt/

# Redis セッションデータのバックアップ(任意)
docker compose exec redis redis-cli --rdb /data/dump.rdb

12.トラブルシュート

12.1. ユーザ情報の確認

認証済みユーザの情報を確認

# ブラウザで以下にアクセス
https://your-domain.com/oauth2/userinfo

12.2. セッション管理

# セッション情報の確認(Redis)
docker compose exec redis redis-cli keys "*"

# 特定ユーザーのセッション削除
docker compose exec redis redis-cli del "session:xxxxxxxxx"

12.3. 認証後にリダイレクトループが発生

原因:リダイレクトURLが誤っている

# .envファイルのリダイレクトURLを確認
grep OAUTH2_PROXY_REDIRECT_URL .env

# Azure ADの設定と一致することを確認

12.4. SSL証明書エラー

# 証明書の状態確認
docker compose logs certbot

# 手動で証明書を再取得
docker compose run --rm certbot certonly --webroot \
  --webroot-path=/var/www/certbot \
  --email your-email@example.com \
  --agree-tos -d your-domain.com

12.5. バックエンドサービスに接続できない

原因:ネットワーク通信 or プロキシ設定の問題

# バックエンドサービスの疎通確認
curl -I http://host.docker.internal:8080

# nginxの設定確認
docker compose exec nginx nginx -t

12.6. セッションがほじされない

原因:セッション管理しているRedis DBとの接続の問題

# Redis接続確認
docker exec oauth2-proxy-redis-1 redis-cli -h oauth2-proxy-redis-1 ping

# Redis のログ確認
docker logs oauth2-proxy-redis-1

12.7. デバッグ用エンドポイント

エンドポイント 用途
/oauth2/userinfo 認証済みユーザー情報表示
/oauth2/ping oauth2-proxy ヘルスチェック
/oauth2/sign_out 手動ログアウト

13.まとめ

本記事では、OAuth2.0/OIDC認証をDockerで簡単に導入する方法について解説しました。従来、OAuth2.0の実装にはグローバルIPアドレス、DNS設定、サーバ証明書など多くの要素が必要で、各Webサービスごとに異なる設定方法に対応する必要がありました。

しかし、NginxとOAuth2-proxyをDockerコンテナとして利用することで、これらの複雑な設定を大幅に簡素化できます。本記事で紹介した構成では、既存のWebサービスの前段にNginxリバースプロキシとOAuth2-proxyを配置し、Microsoft Entra IDを認証プロバイダとして活用することで、既存システムに手を加えることなくOAuth2.0認証を追加できます。

具体的には、以下の手順で実装が可能です:

  • 前提条件の準備(グローバルIPアドレス、ドメイン、DNS設定、サーバ証明書)
  • Microsoft Entra IDでのエンタープライズアプリケーション登録
  • 環境変数ファイル(.env)の設定
  • Docker Composeによる起動

この方法により、PlantUML Serverのような既存のWebサービスに対して、最小限の設定でセキュアな認証機能を追加できます。

Microsoft Entra IDの2要素認証機能と組み合わせることで、Microsoft Authenticatorアプリを
使ったセキュアな認証も実現できます。

Docker化されているため、環境の再現性が高く、他のプロジェクトへの展開も容易です。OAuth2.0/OIDC認証の導入を検討されている方は、ぜひこの方法を試してみてください。

14.関連リンク

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?