0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

自己証明版ローカルNGINXのEntraID認証

Last updated at Posted at 2025-12-06

自己証明適用手順

Nginxのインストール

sudo apt update
sudo apt install nginx -y
sudo systemctl enable nginx
sudo systemctl start nginx

自己証明書作成

※参考
https://qiita.com/ohakutsu/items/814825a76b5299a96661


$ mkdir -p /etc/nginx/certs

$ openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -aes-256-cbc -out privkey.pem
Enter PEM pass phrase: (パスフレーズを入力)
Verifying - Enter PEM pass phrase: (パスフレーズを再度入力)

$ openssl req -new -key privkey.pem -out csr.pem
-----
Country Name (2 letter code) [AU]:JP <-入力
State or Province Name (full name) [Some-State]:Tokyo <-入力
Locality Name (eg, city) []:Shibuya-ku <-入力
Organization Name (eg, company) [Internet Widgits Pty Ltd]:ohakutsu <-入力
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:localhost:443 <-入力
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

$ openssl x509 -req -in csr.pem -signkey privkey.pem -days 90 -out crt.pem
Enter pass phrase for privkey.pem:
Certificate request self-signature ok
subject=C=JP, ST=Tokyo, L=Shinagawa, O=Sky, CN=myssl.test

$ touch passwd
$ echo 'パスフレーズ' > passwd

$ sudo cp ./crt.pem /etc/nginx/certs/cert.pem
$ sudo cp ./privkey.pem /etc/nginx/certs/key.pem
$ sudo cp ./passwd /etc/nginx/certs/passwd  
$ chmod 600 /etc/nginx/ssl/passwd

※上の設定の場合、Azure上のリダイレクト URIは下記としておく
https://localhost:443/oauth2/callback

Nginxの設定

sudo vi /etc/nginx/sites-available/local
server {
    # SSLポートでリッスン (標準は443)
    listen 443 ssl;
    
    # ドメイン名設定
    server_name localhost;

    # 証明書の設定 (手順1で作ったファイルのパス)
    ssl_certificate     /etc/nginx/certs/cert.pem;
    ssl_certificate_key /etc/nginx/certs/key.pem;
    ssl_password_file   /etc/nginx/certs/passwd;

    location / {
        # バックエンドアプリへの転送
        proxy_pass http://127.0.0.1:8080;

        # --- 重要: Azure AD 認証に必要なヘッダー設定 ---
        
        # クライアントがアクセスしてきたホスト名 (localhost) を維持する
        proxy_set_header Host $host;

        # クライアントの実IPアドレスを転送する
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # プロトコルが HTTPS であることをバックエンドに伝える
        # (これがないと、バックエンドが redirect_uri を http://... で生成してしまい、Azureでエラーになる場合があります)
        proxy_set_header X-Forwarded-Proto https;
    }
}
sudo ln -s /etc/nginx/sites-available/local /etc/nginx/sites-enabled/
sudo systemctl restart nginx

EntraID認証適用

oauth2-proxyのインストールと設定

wget https://github.com/oauth2-proxy/oauth2-proxy/releases/download/v7.10.0/oauth2-proxy-v7.10.0.linux-amd64.tar.gz
tar -xvf oauth2-proxy-v7.10.0.linux-amd64.tar.gz
sudo mv oauth2-proxy-v7.10.0.linux-amd64/oauth2-proxy /usr/local/bin/
sudo rm -rf oauth2-proxy-v7.10.0.linux-amd64 oauth2-proxy-v7.10.0.linux-amd64.tar.gz

Cookie シークレットの生成

python3 -c 'import os; print(os.urandom(16).hex())'

systemd サービスの作成

sudo vi /etc/systemd/system/oauth2-proxy.service
[Unit]
Description=OAuth2 Proxy for Entra ID
After=network.target

[Service]
ExecStart=/usr/local/bin/oauth2-proxy \
  --http-address="0.0.0.0:4180" \
  --upstream="http://localhost:8080" \
  --provider="azure" \
  --client-id="正しく設定" \
  --client-secret="正しく設定" \
  --redirect-url="https://localhost:443/oauth2/callback" \
  --oidc-issuer-url="https://login.microsoftonline.com/正しく設定/v2.0" \
  --cookie-secret="正しく設定" \
  --cookie-domain="localhost:443" \
  --cookie-secure=true \
  --cookie-expire=24h \
  --set-xauthrequest=true \
  --email-domain="*" 
Environment="GOMAXPROCS=1" # 必要に応じて調整
Restart=always
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=oauth2-proxy

[Install]
WantedBy=multi-user.target

oauth2-proxy サービスの有効化と起動

sudo systemctl daemon-reload
sudo systemctl enable oauth2-proxy
sudo systemctl start oauth2-proxy
sudo systemctl status oauth2-proxy

sudo journalctl -u oauth2-proxy -f 

※修正時
sudo systemctl daemon-reload
sudo systemctl restart oauth2-proxy.service
sudo vi /etc/nginx/sites-available/localhost
server {
    # SSLポートでリッスン (標準は443)
    listen 443 ssl;
    
    # ドメイン名設定
    server_name localhost;

    # 証明書の設定 (手順1で作ったファイルのパス)
    ssl_certificate     /etc/nginx/certs/cert.pem;
    ssl_certificate_key /etc/nginx/certs/key.pem;
    ssl_password_file   /etc/nginx/certs/passwd;

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1h;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE';
    ssl_prefer_server_ciphers on;

    proxy_buffer_size   128k;
    proxy_buffers   4 256k;
    proxy_busy_buffers_size   256k;

    # oauth2-proxy の認証エンドポイント
    location /oauth2 {
        proxy_pass http://localhost:4180; # oauth2-proxy がリッスンしているアドレスとポート
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Scheme $scheme; # oauth2-proxy が HTTPS を認識できるように
        proxy_set_header Cookie $http_cookie; # クッキーを転送
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_buffering off;
    }

    # Web アプリケーションへのリバースプロキシと認証
    location / {
        auth_request /oauth2/auth; # oauth2-proxy に認証を要求
        error_page 401 = /oauth2/start?rd=$request_uri; # 認証失敗時に oauth2-proxy のログインページへリダイレクト

        # oauth2-proxy から受け取ったユーザー情報を Web アプリケーションに転送
        auth_request_set $user $upstream_http_x_auth_request_user;
        auth_request_set $email $upstream_http_x_auth_request_email;
        proxy_set_header X-Auth-Request-User $user;
        proxy_set_header X-Auth-Request-Email $email;

        # Web アプリケーションへのプロキシ設定
        # proxy_pass http://localhost:8080; # Web アプリケーションのポート
        proxy_pass http://127.0.0.1:8080;
        proxy_buffering off;          # 重要:回答のタイピング表示をなめらかにする
        
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # WebSocket対応(将来的な安定性のため)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

}
sudo nginx -t
sudo systemctl restart nginx

※参考
https://qiita.com/tksugar/items/361f77a762e79957bd58

サーバー基本設定 / SSL設定

サーバー全体に関わるリッスンポート、ドメイン、およびSSL/TLSセキュリティに関する設定です。

パラメータ項目 設定値 説明・備考
listen 443 ssl SSLポートでの待ち受けを有効化
server_name localhost サーバーのドメイン名
ssl_certificate /etc/nginx/certs/cert.pem 公開鍵証明書ファイルのパス
ssl_certificate_key /etc/nginx/certs/key.pem 秘密鍵ファイルのパス
ssl_password_file /etc/nginx/certs/passwd 秘密鍵のパスフレーズファイル(暗号化されている場合)
ssl_session_cache shared:SSL:10m SSLセッションキャッシュ(共有メモリ10MB)。
クライアントが同じセッションID(またはセッションチケット)を提示して再接続を試みた際、サーバーは保存されているキャッシュ内のマスターシークレットキーを使用して通信を確立します。これにより、**鍵交換(Key Exchange)や検証(Verification)を含む完全なハンドシェイクプロセス(約2〜3往復)が省略され、**初回接続よりもはるかに高速に通信を開始できます。
ssl_session_timeout 1h SSLセッションのタイムアウト時間
キャッシュの失効: 設定されたタイムアウト時間内にクライアントが再接続した場合、セッション再開が成功し、セッション情報が更新されます(タイムアウト時間がリセットされます)。
再ハンドシェイク: 設定されたタイムアウト時間を経過した後、クライアントがセッションIDを提示して再接続を試みても、キャッシュ内の情報は**無効(失効)**と見なされます。この場合、クライアントとサーバーはセッション再開を諦め、完全なSSL/TLSハンドシェイクを最初からやり直す必要があります。
ssl_protocols TLSv1.2 TLSv1.3 許可するTLSプロトコルのバージョン
ssl_ciphers TLS_AES_256_GCM_SHA384... (※1) 使用する暗号化スイートのリスト(高強度なものを指定)。サーバーはこのリストで定義された暗号スイートのみを、SSL/TLSハンドシェイク時にクライアントに提示します。クライアントから提示された暗号スイートが、このリストに含まれていない場合、サーバーはその暗号スイートを選択肢として考慮しません。
ssl_prefer_server_ciphers on サーバー側の暗号化スイート優先度を優先する。
on:サーバー側が持つ暗号スイートのリスト(ssl_ciphersで定義されたもの)の優先順位に従って、クライアントとサーバーの共通する暗号スイートの中から一つが選択されます。サーバーの優先順位が採用されます。
off:クライアント側が提示した暗号スイートのリストの優先順位に従って、クライアントとサーバーの共通する暗号スイートの中から一つが選択されます。クライアントの優先順位が採用されます。(多くのサーバーでのデフォルト設定)

(※1) 設定値詳細: TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE

oauth2-proxy 構成定義

Unitファイルの起動パラメータに基づく設計値です。

カテゴリ パラメータ引数 設定値 設計内容・役割
基本動作 --http-address 0.0.0.0:4180 リッスンアドレス
全インターフェースのポート4180で待受
--upstream http://localhost:8080 アップストリーム(バックエンド)
※本構成ではNGINXが直接バックエンドへ転送するため、oauth2-proxy側では形式的な設定、あるいは直接アクセス時の転送先となる
--redirect-url https://localhost:443/oauth2/callback コールバックURL
認証完了後にAzure ADから戻ってくる先 (NGINX経由で受ける)
IdP連携 (Azure) --provider azure 認証プロバイダ
Microsoft Entra ID (旧 Azure AD) を使用
--client-id (正しく設定) アプリケーションID
Azure側で発行されたクライアントID
--client-secret (正しく設定) シークレット
Azure側で発行されたクライアントシークレット
--oidc-issuer-url https://login.microsoftonline.com/.../v2.0 OIDC発行者URL
テナントIDを含むOpenID Connectのエンドポイント
セッション管理 --cookie-secret (正しく設定) クッキー暗号化キー
ブラウザに保存するクッキーを暗号化するためのシード
--cookie-domain localhost:443 クッキーの有効ドメイン
ブラウザがクッキーを送信するスコープ
--cookie-secure true Secure属性
HTTPS通信時のみクッキーを送信する(必須設定)
--cookie-expire 24h 有効期限
認証セッションの有効期間を24時間とする
連携制御 --set-xauthrequest true NGINX連携フラグ (重要)
認証成功時、レスポンスヘッダに X-Auth-Request-User/Email を付与してNGINXへ返す設定
--email-domain * 許可メールドメイン
プロバイダ側で認証できればドメインによる制限を行わない
システム環境 GOMAXPROCS 1 CPU使用制限
Go言語ランタイムが使用するCPUコア数を1に制限

2. 通信・稼働フロー設計

ユーザーがブラウザでアクセスした際、NGINXとoauth2-proxyがどのように連携して動作するかを時系列で記述します。

2.1. シーケンス概略

この構成では、NGINXが「関所」となり、oauth2-proxyは「通行手形(クッキー)の確認係」として動作します。

  1. 【未認証時】
    • ユーザー → NGINX (/)
    • NGINX → oauth2-proxy (/oauth2/auth) へ問い合わせ
    • oauth2-proxy → 401 Unauthorized を返却
    • NGINX → ユーザーを https://login.microsoftonline.com/... (Azure AD) へ誘導
  2. 【認証・コールバック】
    • ユーザー → Azure ADでログイン
    • Azure AD → NGINX (/oauth2/callback) へリダイレクト
    • NGINX → oauth2-proxy へ転送
    • oauth2-proxy → トークン検証・Cookie発行 → 元のURLへリダイレクト
  3. 【認証済み(通常利用)】
    • ユーザー → NGINX (/) ※Cookieあり
    • NGINX → oauth2-proxy (/oauth2/auth) へ問い合わせ
    • oauth2-proxy → Cookie検証 → 202 Acceptedユーザー情報ヘッダ を返却
    • NGINX → バックエンドアプリ (localhost:8080) へリクエスト転送

2.2. 詳細動作仕様 (リクエスト単位)

各フェーズにおけるコンポーネント間の具体的なデータの流れです。

フェーズ 通信方向 処理内容詳細
A. 初回アクセス
(Cookieなし)
Client -> NGINX ユーザーが https://localhost/ へアクセス。
NGINX -> oauth2-proxy auth_request /oauth2/auth により、リクエストヘッダのみを oauth2-proxy へ内部送信。
oauth2-proxy -> NGINX Cookieが存在しないため、HTTPステータス 401 を返却。
NGINX -> Client error_page 401 設定に基づき、/oauth2/start 経由で Azure AD ログイン画面へ 302 リダイレクト。
B. 認証プロセス Client <-> Azure AD ユーザーがID/PWを入力し、MFA等を経て認証成功。Azureは /oauth2/callback へリダイレクト指示。
Client -> NGINX https://localhost/oauth2/callback?code=... へアクセス。
NGINX -> oauth2-proxy /oauth2 location設定に基づき、リクエストをそのまま 127.0.0.1:4180 へプロキシ。
oauth2-proxy <-> Azure 受け取った code を使い、Azure ADへアクセストークンを要求・取得・検証。
oauth2-proxy -> NGINX 検証成功。暗号化されたセッションCookie をSet-Cookieヘッダに乗せて、元のURL (/) へのリダイレクトを返却。
NGINX -> Client レスポンスをクライアントへ返す。クライアントはCookieを保存。
C. アプリ利用
(Cookieあり)
Client -> NGINX クッキーを持った状態で https://localhost/ へアクセス。
NGINX -> oauth2-proxy auth_request /oauth2/auth で内部問い合わせ(Cookieも転送)。
oauth2-proxy -> NGINX 【重要】 Cookieを復号し有効性を確認。
OKの場合、ステータス 202 Accepted を返却。
同時にレスポンスヘッダに以下を付与:
X-Auth-Request-User: user@example.com
X-Auth-Request-Email: user@example.com
NGINX -> App (8080) 202を受け取ったNGINXは、上記ヘッダを X-Auth-Request-User 等としてリクエストにコピーし、バックエンドアプリへ送信。
App -> NGINX -> Client アプリケーションが処理を行い、Web画面を表示。

※個人用メモ(Keycloak連携試行)

  • AzureEntraのリダイレクト URI
https://domain.test.001/realms/myrealm/broker/domainazurearias/endpoint
  • Keycloak Version 26.4.7
docker run -d -p 8081:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -e KC_PROXY=edge -e KC_HTTP_ENABLED=true quay.io/keycloak/keycloak:latest start-dev

Frontend URL : https://domain.test.001/
  • Oauth2-Proxy
[Unit]
Description=OAuth2 Proxy for Entra ID
After=network.target

[Service]
ExecStart=/usr/local/bin/oauth2-proxy \
  --http-address="0.0.0.0:4180" \
  --upstream="http://127.0.0.1:8080" \
  --provider="oidc" \
  --client-id="oauth2-proxy" \
  --client-secret="正しく設定" \
  --redirect-url="https://domain.test.001/oauth2/callback" \
  --oidc-issuer-url="https://domain.test.001/realms/myrealm" \
  --cookie-secret="正しく設定" \
  --cookie-domain="domain.test.001" \
  --cookie-secure=true \
  --cookie-samesite=lax \
  --cookie-expire=24h \
  --cookie-refresh=1h \
  --skip-provider-button=true \
  --set-xauthrequest=true \
  --email-domain="*" \
  --insecure-oidc-allow-unverified-email=true \
  --ssl-insecure-skip-verify
Environment="GOMAXPROCS=1" # 必要に応じて調整
Restart=always
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=oauth2-proxy

[Install]
WantedBy=multi-user.target

※v7.2.0 から下記を設定可能
# 例: oauth2-proxy の起動引数に追加
--redeem-url="http://<nginxの内部IPまたはサービス名>/auth/realms/<realm>/protocol/openid-connect/token"
--oidc-jwks-url="http://<nginxの内部IPまたはサービス名>/auth/realms/<realm>/protocol/openid-connect/certs"
--validate-url="http://<nginxの内部IPまたはサービス名>/auth/realms/<realm>/protocol/openid-connect/userinfo"
また、起動オプションに下記を追加
--insecure-oidc-skip-issuer-verification=true
  • Nginx
server {
    listen 80;
    server_name domain.test.001;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name domain.test.001;

    ssl_certificate     /etc/nginx/certs/cert.pem;
    ssl_certificate_key /etc/nginx/certs/key.pem;
    ssl_password_file   /etc/nginx/certs/passwd;

    # 巨大なトークン対策(これは必須)
    proxy_buffer_size   256k;
    proxy_buffers       4 512k;
    proxy_busy_buffers_size   512k;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;

    # 認証除外(OAuth2 Proxy, Keycloak, Dify静的ファイル)
    location /oauth2/ {
        auth_request off;
        proxy_pass http://127.0.0.1:4180;
    }

    location /realms/ {
        auth_request off;
        proxy_pass http://127.0.0.1:8081;
    }

    location /resources/ {
        auth_request off;
        proxy_pass http://127.0.0.1:8081;
    }

    location ~* ^/(favicon\.ico|robots\.txt|static/|assets/|v1/console/api/setup) {
        auth_request off;
        proxy_pass http://127.0.0.1:8080;
    }

    # メインアプリケーション
    location / {
        auth_request /oauth2/auth;
        error_page 401 = /oauth2/start?rd=$request_uri;

        auth_request_set $user $upstream_http_x_auth_request_user;
        auth_request_set $email $upstream_http_x_auth_request_email;
        proxy_set_header X-Auth-Request-User $user;
        proxy_set_header X-Auth-Request-Email $email;

        proxy_pass http://127.0.0.1:8080;
    }
}
  • Nginx(SSLオフロード)
# =========================================================
# 1. 内部アプリケーション役 Nginx (Port 80)
#    - 本番環境のNginxと同じ設定
#    - AGWから受け取ったリクエストをバックエンドへ流す
# =========================================================
server {
    listen 80;
    server_name domain.test.001;

    # -----------------------------------------------------
    # ★重要: 巨大なCookie/トークン対策 (受信側)
    # -----------------------------------------------------
    proxy_buffer_size   256k;
    proxy_buffers       4 512k;
    proxy_busy_buffers_size   512k;

    # -----------------------------------------------------
    # ヘッダー設定
    # -----------------------------------------------------
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
    # ここで強制的に https を指定することで、
    # AGWからの転送漏れがあってもバックエンドはHTTPSとして動作します
    proxy_set_header X-Forwarded-Proto https;

    # -----------------------------------------------------
    # 各種ルーティング
    # -----------------------------------------------------
    
    # 認証除外(OAuth2 Proxy)
    location /oauth2/ {
        auth_request off;
        proxy_pass http://127.0.0.1:4180;
    }

    # 認証除外(Keycloak等のIDP)
    location /realms/ {
        auth_request off;
        proxy_pass http://127.0.0.1:8081;
    }

    location /resources/ {
        auth_request off;
        proxy_pass http://127.0.0.1:8081;
    }

    # 静的ファイル・API除外
    location ~* ^/(favicon\.ico|robots\.txt|static/|assets/|v1/console/api/setup) {
        auth_request off;
        proxy_pass http://127.0.0.1:8080;
    }

    # メインアプリケーション (要認証)
    location / {
        auth_request /oauth2/auth;
        error_page 401 = /oauth2/start?rd=$request_uri;

        # 認証情報の引き渡し
        auth_request_set $user $upstream_http_x_auth_request_user;
        auth_request_set $email $upstream_http_x_auth_request_email;
        proxy_set_header X-Auth-Request-User $user;
        proxy_set_header X-Auth-Request-Email $email;

        proxy_pass http://127.0.0.1:8080;
    }
}

# =========================================================
# 2. AGW (SSLオフロード) 模倣用 Nginx (Port 443)
#    - クライアントとはHTTPSで通信
#    - 裏側のNginx(Port 80)へはHTTPで転送
# =========================================================
server {
    listen 443 ssl;
    server_name domain.test.001;

    ssl_certificate     /etc/nginx/certs/cert.pem;
    ssl_certificate_key /etc/nginx/certs/key.pem;
    ssl_password_file   /etc/nginx/certs/passwd;

    # -----------------------------------------------------
    # ★修正ポイント: 巨大なCookie/トークン対策 (中継側)
    # これがないと、80番から返ってきた巨大ヘッダーを受け取れずエラーになります
    # -----------------------------------------------------
    proxy_buffer_size   256k;
    proxy_buffers       4 512k;
    proxy_busy_buffers_size   512k;

    location / {
        # 自分自身の80番ポート(本番Nginx役)へ転送
        proxy_pass http://127.0.0.1:80;

        # -------------------------------------------------
        # AGWの挙動を模倣するためのヘッダー付与
        # -------------------------------------------------
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # ★最重要: 「元はHTTPS・ポート443でした」と伝える
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-Port 443;

        # -------------------------------------------------
        # WebSocket対応 (Dify等のAIアプリで推奨)
        # -------------------------------------------------
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        
        # タイムアウト設定(生成待ちなどの長時間接続用)
        proxy_read_timeout 300s;
    }
}

情報連携用設定

[Unit]
Description=OAuth2 Proxy for Entra ID
After=network.target

[Service]
ExecStart=/usr/local/bin/oauth2-proxy \
  --http-address="0.0.0.0:4180" \
  --upstream="http://127.0.0.1:8080" \
  --provider="oidc" \
  --client-id="oauth2-proxy" \
  --client-secret="A9ouGj26faCMjQxz5I7euMLpRltxNrNW" \
  --redirect-url="https://domain.test.001/oauth2/callback" \
  --oidc-issuer-url="https://domain.test.001/realms/myrealm" \
  --cookie-secret="dfd5b7eefe822e3caf0bad6133e2349e" \
  --cookie-domain="domain.test.001" \
  --cookie-secure=true \
  --cookie-samesite=lax \
  --cookie-expire=24h \
  --cookie-refresh=1h \
  --skip-provider-button=true \
  --set-xauthrequest=true \
  --email-domain="*" \
  --insecure-oidc-allow-unverified-email=true \
  --ssl-insecure-skip-verify=true \
  --pass-authorization-header=true \
  --set-xauthrequest=true \
  --pass-user-headers=true \
  --user-id-claim="email" \
  --pass-access-token=true
Environment="GOMAXPROCS=1" # 必要に応じて調整
Restart=always
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=oauth2-proxy

[Install]
WantedBy=multi-user.target

nginx.conf
      # ---------------------------------------------------------
      map $host $token { default ""; }
      map $host $user  { default ""; }
      map $host $email { default ""; }

      # ---------------------------------------------------------
      # ログフォーマット定義 (既存の記述)
      # ---------------------------------------------------------
      log_format oidc_debug '$remote_addr - [$time_local] "$request" '
                            'Status:$status '
                            'User:"$user" '
                            'Email:"$email" '
                            'Token:"$token"';
                            
# =========================================================
# 1. 内部アプリケーション役 Nginx (Port 80)
#    - 本番環境のNginxと同じ設定
#    - AGWから受け取ったリクエストをバックエンドへ流す
# =========================================================
server {
    listen 80;
    server_name domain.test.001;

    # 定義したフォーマット "oidc_debug" を適用
    #access_log /var/log/nginx/access_oidc_debug.log oidc_debug;

    # -----------------------------------------------------
    # ★重要: 巨大なCookie/トークン対策 (受信側)
    # -----------------------------------------------------
    proxy_buffer_size   256k;
    proxy_buffers       4 512k;
    proxy_busy_buffers_size   512k;

    # -----------------------------------------------------
    # ヘッダー設定
    # -----------------------------------------------------
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
    # ここで強制的に https を指定することで、
    # AGWからの転送漏れがあってもバックエンドはHTTPSとして動作します
    proxy_set_header X-Forwarded-Proto https;

    # -----------------------------------------------------
    # 各種ルーティング
    # -----------------------------------------------------
    
    # 認証除外(OAuth2 Proxy)
    location /oauth2/ {
        auth_request off;
        proxy_pass http://127.0.0.1:4180;
    }

    # 認証除外(Keycloak等のIDP)
    location /realms/ {
        auth_request off;
        proxy_pass http://127.0.0.1:8081;
    }

    location /resources/ {
        auth_request off;
        proxy_pass http://127.0.0.1:8081;
    }

    # 静的ファイル・API除外
    location ~* ^/(favicon\.ico|robots\.txt|static/|assets/|v1/console/api/setup) {
        auth_request off;
        proxy_pass http://127.0.0.1:8080;
    }


    # メインアプリケーション (要認証)
    location / {
        auth_request /oauth2/auth;
        error_page 401 = /oauth2/start?rd=$request_uri;

        # -----------------------------------------------------
        # 認証情報の引き渡し
        # -----------------------------------------------------
        auth_request_set $user   $upstream_http_x_auth_request_user;
        auth_request_set $email  $upstream_http_x_auth_request_email;
        
        auth_request_set $token  $upstream_http_x_auth_request_access_token;

        proxy_set_header X-Auth-Request-User  $user;
        proxy_set_header X-Auth-Request-Email $email;
        
        proxy_set_header X-Access-Token $token;
        
        proxy_pass http://127.0.0.1:8080;
    }

}

# =========================================================
# 2. AGW (SSLオフロード) 模倣用 Nginx (Port 443)
#    - クライアントとはHTTPSで通信
#    - 裏側のNginx(Port 80)へはHTTPで転送
# =========================================================
server {
    listen 443 ssl;
    server_name domain.test.001;

    ssl_certificate     /etc/nginx/certs/cert.pem;
    ssl_certificate_key /etc/nginx/certs/key.pem;
    ssl_password_file   /etc/nginx/certs/passwd;

    # -----------------------------------------------------
    # ★修正ポイント: 巨大なCookie/トークン対策 (中継側)
    # これがないと、80番から返ってきた巨大ヘッダーを受け取れずエラーになります
    # -----------------------------------------------------
    proxy_buffer_size   256k;
    proxy_buffers       4 512k;
    proxy_busy_buffers_size   512k;

    location / {
        # 自分自身の80番ポート(本番Nginx役)へ転送
        proxy_pass http://127.0.0.1:80;

        # -------------------------------------------------
        # AGWの挙動を模倣するためのヘッダー付与
        # -------------------------------------------------
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # ★最重要: 「元はHTTPS・ポート443でした」と伝える
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-Port 443;

        # -------------------------------------------------
        # WebSocket対応 (Dify等のAIアプリで推奨)
        # -------------------------------------------------
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        
        # タイムアウト設定(生成待ちなどの長時間接続用)
        proxy_read_timeout 300s;
    }
}

Keycloak マッパーの再確認
Azure の設定が終わったら、Keycloak のマッパーがそれを受け取れるようになっているか確認します。

Keycloak 管理画面 > Identity Providers > Azure Entra ID > Mappers。

Email 用のマッパー:
Name: email-map
Mapper Type: Attribute Importer
Claim: email
User Attribute Name: email

Username 用のマッパー:
Name: username-map
Mapper Type: Username Template Importer
Template: ${CLAIM.email}
Target: LOCAL

パラメータ消失対策

server {
    listen 80;
    server_name domain.test.001;

    # ログ設定(必要に応じてコメントアウトを解除)
    # access_log /var/log/nginx/access_oidc_debug.log oidc_debug;

    # -----------------------------------------------------
    # バッファ設定
    # -----------------------------------------------------
    proxy_buffer_size   256k;
    proxy_buffers       4 512k;
    proxy_busy_buffers_size   512k;

    # -----------------------------------------------------
    # ヘッダー設定 (全体共通)
    # -----------------------------------------------------
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;

    # -----------------------------------------------------
    # 除外ルーティング
    # -----------------------------------------------------
    
    # 認証除外(OAuth2 Proxy)
    location /oauth2/ {
        auth_request off;
        proxy_pass http://127.0.0.1:4180;
    }

    # 認証除外(Keycloak等のIDP)
    location /realms/ {
        auth_request off;
        proxy_pass http://127.0.0.1:8081;
    }

    location /resources/ {
        auth_request off;
        proxy_pass http://127.0.0.1:8081;
    }

    # 静的ファイル・API除外
    location ~* ^/(favicon\.ico|robots\.txt|static/|assets/|v1/console/api/setup) {
        auth_request off;
        proxy_pass http://127.0.0.1:8080;
    }

    # -----------------------------------------------------
    # メインアプリケーション (要認証)
    # -----------------------------------------------------
    location / {
        auth_request /oauth2/auth;

        # 【変更点】401エラー時はJSリダイレクト用のロケーションへ飛ばす
        error_page 401 = @oauth2_start;

        # -----------------------------------------------------
        # 認証情報の引き渡し
        # -----------------------------------------------------
        auth_request_set $user   $upstream_http_x_auth_request_user;
        auth_request_set $email  $upstream_http_x_auth_request_email;
        auth_request_set $token  $upstream_http_x_auth_request_access_token;

        proxy_set_header X-Auth-Request-User  $user;
        proxy_set_header X-Auth-Request-Email $email;
        proxy_set_header X-Access-Token $token;
        
        proxy_pass http://127.0.0.1:8080;
    }

    # -----------------------------------------------------
    # 【追加・重要】JSリダイレクト処理
    # -----------------------------------------------------
    location @oauth2_start {
        # ブラウザにHTMLを返し、JSでURLエンコードさせてからOAuth2 Proxyへ遷移させます。
        # これにより "&" がURLの区切りとして誤認識されるのを防ぎます。
        
        default_type text/html;
        
        # リダイレクト用HTMLがキャッシュされないように設定
        add_header Cache-Control "no-cache, no-store, must-revalidate";
        add_header Pragma "no-cache";
        add_header Expires "0";

        # JavaScriptを含むHTMLを返却
        return 200 '<html>
<head><title>Redirecting...</title></head>
<body>
<script>
    // 現在のパスとクエリパラメータ(?email=...&token=...)を取得
    var currentPath = window.location.pathname + window.location.search;
    
    // URLエンコードを行って rd パラメータに設定
    // encodeURIComponentを使うことで & は %26 に変換され、安全に渡されます
    var targetUrl = "/oauth2/start?rd=" + encodeURIComponent(currentPath);
    
    // リダイレクト実行
    window.location.href = targetUrl;
</script>
</body>
</html>';
    }
}

/usr/share/nginx/html/redirect_oauth2.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Redirecting to Authentication...</title>
</head>
<body>
    <script>
        /**
         * 現在のパスとクエリパラメータを取得し、URLエンコードを行う。
         * これにより "&" や "=" が区切り文字として誤認識されるのを防ぎ、
         * OAuth2 Proxy へパラメータを完全に渡すことができる。
         */
        var currentPath = window.location.pathname + window.location.search;
        var targetUrl = "/oauth2/start?rd=" + encodeURIComponent(currentPath);
        
        window.location.href = targetUrl;
    </script>
    <noscript>
        <p>JavaScript is required to proceed to authentication.</p>
    </noscript>
</body>
</html>
server {
    listen 80;
    server_name domain.test.001;

    # ログ設定(必要に応じてコメントアウトを解除)
    # access_log /var/log/nginx/access_oidc_debug.log oidc_debug;

    # -----------------------------------------------------
    # バッファ設定
    # -----------------------------------------------------
    proxy_buffer_size   256k;
    proxy_buffers       4 512k;
    proxy_busy_buffers_size   512k;

    # -----------------------------------------------------
    # ヘッダー設定 (全体共通)
    # -----------------------------------------------------
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;

    # -----------------------------------------------------
    # 除外ルーティング
    # -----------------------------------------------------
    
    # 認証除外(OAuth2 Proxy)
    location /oauth2/ {
        auth_request off;
        proxy_pass http://127.0.0.1:4180;
    }

    # 認証除外(Keycloak等のIDP)
    location /realms/ {
        auth_request off;
        proxy_pass http://127.0.0.1:8081;
    }

    location /resources/ {
        auth_request off;
        proxy_pass http://127.0.0.1:8081;
    }

    # 静的ファイル・API除外
    location ~* ^/(favicon\.ico|robots\.txt|static/|assets/|v1/console/api/setup) {
        auth_request off;
        proxy_pass http://127.0.0.1:8080;
    }

    # -----------------------------------------------------
    # メインアプリケーション (要認証)
    # -----------------------------------------------------
    location / {
        auth_request /oauth2/auth;

        # 【変更点】
        # 401エラー時は、サーバー内部で作成した外部HTMLファイルを表示します。
        # "=200" を指定することで、ブラウザに正常なページとしてHTMLを処理させます。
        error_page 401 =200 /redirect_oauth2.html;

        # -----------------------------------------------------
        # 認証情報の引き渡し
        # -----------------------------------------------------
        auth_request_set $user   $upstream_http_x_auth_request_user;
        auth_request_set $email  $upstream_http_x_auth_request_email;
        auth_request_set $token  $upstream_http_x_auth_request_access_token;

        proxy_set_header X-Auth-Request-User  $user;
        proxy_set_header X-Auth-Request-Email $email;
        proxy_set_header X-Access-Token $token;
        
        proxy_pass http://127.0.0.1:8080;
    }

    # -----------------------------------------------------
    # 【追加】リダイレクト用HTMLファイルの配信設定
    # -----------------------------------------------------
    location = /redirect_oauth2.html {
        # 作成したHTMLファイルがあるディレクトリを指定
        # (ステップ1で作成した場所に合わせてください)
        root /usr/share/nginx/html;
        
        # 内部リダイレクト専用にする(直接URLを叩かせないセキュリティ対策)
        internal;
        
        # HTML自体がキャッシュされないようにヘッダーを付与
        add_header Cache-Control "no-cache, no-store, must-revalidate";
        add_header Pragma "no-cache";
        add_header Expires "0";
    }
}
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?