- 記事一覧 >
- ブログ記事
oauth2-proxyで既存アプリにAzure AD OpenID Connect認証機能を追加
はじめに
oauth2-proxy で既存アプリに Azure AD(Microsoft Entra ID) OpenID Connect 認証機能を追加しました。
過去記事で、SimpleSAMLphp, go-oidc と同じようなことをやってきましたが、今回の構成は、プロキシ型の認証になります。
プロキシ型の特徴として、既存の Web アプリケーションの実装を変更しないまま認証機能を実現できるということがあります。
プロキシ型の認証は、アプリケーションに認証ロジックを組み込むことが困難な場合や、認証機能を分離したい場合に有用です。
構成は、公式サイト(https://oauth2-proxy.github.io/oauth2-proxy/
)Architecture の図の左側です。
今回、簡単なアプリケーション実装(PHP で phpinfo()
を実行するだけ。) ~
Azure AD(Microsoft Entra ID)設定 ~
oauth2-proxy 設定 ~
OpenID Connect 認証を通過したらアプリにアクセス
まで全手順を紹介していきます。
なお、oauth2-proxy は、VSCode で F5 で起動してデバッグできるようにします。
Azure AD(Azure Active Directory)は、Microsoft Entra ID に名称が変わりましたが、この記事では、Azure AD 表記のままでいきます。
手順は、OS(Ubuntu22) インストール & SSH 接続成功直後からスタートとします。
今回の手順では、Nginx & oauth2-proxy と Nginx & Web アプリケーション(PHP) は同一サーバーに同居します。
【検証環境】
Ubuntu 22.04.3 LTS
Nginx 1.18.0
PHP 8.3.1
oauth2-proxy V7.5.1
Web アプリケーション環境構築
今回、Web アプリケーションサーバーの URI は、
http://webapps-php.example.com/info.php
とします。
root で作業するため、sudo は省略しています。
# apt update
# add-apt-repository ppa:ondrej/php -y
# apt update
# apt -y install php8.3 php8.3-gd php8.3-mbstring php8.3-common php8.3-curl
# php -v
PHP 8.3.1 (cli) (built: Dec 21 2023 20:12:13) (NTS)
# apt -y remove apache2-*
# apt install php-fpm -y
# apt install nginx -y
# nginx -v
nginx version: nginx/1.18.0 (Ubuntu)
# vi /etc/nginx/fastcgi_params
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
↓
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
# mkdir -p /opt/webapps/php
# chown -R www-data: /opt/webapps
# mkdir -p /var/log/webapps/php
# vi /opt/webapps/php/info.php
<?php
phpinfo();
# vi /etc/nginx/conf.d/webapps-info.conf
server # サーバーブロックの開始
{
listen 80; # サーバーが待ち受けるポート番号(HTTPのデフォルトポートは80)
server_name webapps-php.example.com; # サーバーの名前(ドメイン名)
access_log /var/log/webapps/php/access.log; # アクセスログの出力先
error_log /var/log/webapps/php/error.log; # エラーログの出力先
proxy_buffer_size 8k; # プロキシバッファのサイズ(8キロバイト)
root /opt/webapps/php; # サーバーのルートディレクトリ
location / # ルートディレクトリに対する設定
{
index index.html index.htm index.php; # デフォルトで使用するインデックスファイル
}
location ~ [^/]\.php(/|$) # .phpで終わるリクエストに対する設定
{
fastcgi_split_path_info ^(.+?\.php)(/.*)$; # パス情報を分割する正規表現
if (!-f $document_root$fastcgi_script_name) # ファイルが存在しない場合
{
return 404; # 404エラーを返す
}
client_max_body_size 100m; # クライアントからの最大ボディサイズ(100メガバイト)
fastcgi_param HTTP_PROXY ""; # HTTP_PROXYパラメータを空に設定(セキュリティ対策)
fastcgi_pass unix:/run/php/php8.3-fpm.sock; # FastCGIサーバーへのパス
fastcgi_index index.php; # FastCGIサーバーのインデックスファイル
include fastcgi_params; # FastCGIパラメータのインクルード
}
}
# vi /etc/php/8.3/fpm/php.ini
date.timezone = Asia/Tokyo
# vi /etc/hosts
192.168.11.9 webapps-php.example.com
今回、Web アプリケーションサーバーの IP アドレスは、192.168.11.9 とします。
# systemctl restart nginx
# systemctl restart php8.3-fpm
ひとまず、http://webapps-php.example.com/info.php
にアクセスして、単体で動作しているか確認します。
本来であれば、直接アクセス不可の場所に構築されているはずですが、ここでは簡略化のため、このまま進めます。(この記事の最後まで実施しても :80 直接アクセスの場合、認証無しになります。)
golang-go インストール
Go 言語をインストールします。
# apt update -y
# apt install golang-go -y
# go version
go version go1.18.1 linux/amd64
oauth2-proxy 設置
/opt/oauth2-proxy
を配置します。
# apt install git -y
# cd /opt
# git clone https://github.com/oauth2-proxy/oauth2-proxy.git
Azure AD - アプリの登録
OP(Azure AD)側の設定を行います。
Azure ポータルから、Microsoft Entra ID に移動して、アプリの登録 をクリックします。
+新規作成 をクリックします。
アプリ情報を入力し、登録 をクリックします。
名前: oauth2-proxy
(任意です。)
サポートされているアカウントの種類:この組織ディレクトリのみに含まれるアカウント (<テナント名> のみ - シングル テナント)
リダイレクト URI (省略可能):Web
https://webapps-php.example.com/oauth2/callback
概要 をクリックして、
アプリケーション (クライアント) ID から client_id(後で行う oauth2-proxy 設定項目)を確認しておきます。
証明書とシークレット をクリックし、+新しいクライアント シークレット をクリックします。
説明、有効期限 を任意の値に設定し、追加 をクリックします。
ここで出てくる 値 の文字列が client_secret(後で行う oauth2-proxy 設定項目)の文字列になります。(シークレット ID の方ではありません。)
二度と表示されないため、ここで、メモっておきます。
グループ読み取りアクセス許可を追加します。
公式ドキュメント(
https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/oauth_provider/#azure-auth-provider
)に指示がある手順です。必須ではないかもしれません。今回の手順では、これを省略しても動作しました。
API アクセス許可 をクリックし、Microsoft Graph をクリックします。
Group.Read.All にチェックを入れて、アクセス許可の更新 をクリックします。
***に管理者の同意を与えます をクリックして、はい をクリックします。
公式ドキュメント(
https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/oauth_provider/#azure-auth-provider
)に指示がある手順です。これを行わないと以下のエラーになります。
管理者の承認が必要
には、組織内のリソースへのアクセス許可が必要です。このアクセス許可を付与できるのは管理者のみです。アプリケーションを使用するには、まず管理者に依頼してこのアプリにアクセス許可を付与してください。
v2.0 Azure Auth エンドポイントを使用する予定がある場合は、マニフェスト をクリックして、マニフェストページに移動し、"accessTokenAcceptedVersion": 2
をアプリ登録マニフェストファイルに設定し、保存 をクリックします。
公式ドキュメント(
https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/oauth_provider/#azure-auth-provider
)に指示がある手順です。今回の手順では、必須ではありません。
VSCode 拡張機能 Go インストール
SSH Remote 機能により、oauth2-proxy の Ubuntu に接続し、/opt/oauth2-proxy を開きます。
SSH Remote 機能の手順に関しては、別記事「Alpine Linux をインストールして VS Code Remote SSH してみた」を参考にしてください。
拡張機能 Go をインストールします。
拡張機能 Go が必要とする gopls をインストールします。
# go install -v golang.org/x/tools/gopls@latest
gopls(Go Please/ゴプルス)は、Go 言語が公式にサポートしている Language Server です。これは、エディタや統合開発環境(IDE)がソースコードを解析し、コード補完やシンボルのリネームなどの機能を提供するためのツールです。
インストールが必要とメッセージが表示される場合、Install をクリックしても同じことです。
Nginx oauth2-proxy 用設定追加
Nginx から oauth2-proxy へ通信が行われるように設定します。
# mkdir -p /var/log/webapps/oauth2-proxy
自己署名証明書と秘密鍵を作成し、配置します。
# openssl genrsa -out ca.key 2048
# openssl req -new -key ca.key -out ca.csr
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Aichi
Locality Name (eg, city) []:Toyota
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:webapps-php.example.com
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
# echo "subjectAltName=DNS:*.example.com,IP:192.168.11.9" > san.txt
# openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt -extfile san.txt
Signature ok
subject=C = JP, ST = Aichi, L = Toyota, O = Default Company Ltd, CN = webapp.example.com
Getting Private key
# mkdir -p /etc/pki/tls/certs
# mkdir /etc/pki/tls/private
# mv ca.crt /etc/pki/tls/certs/oauth2-proxy.crt
# mv ca.key /etc/pki/tls/private/oauth2-proxy.key
# mv ca.csr /etc/pki/tls/private/oauth2-proxy.csr
Nginx の設定を追加します。
# vi /etc/nginx/conf.d/oauth2-proxy.conf
server # サーバーブロックの開始。このブロック内の設定は、特定のサーバーまたは仮想ホストに適用されます。
{
listen 443 ssl; # サーバーが443ポートでSSL接続をリッスンするように指示します。
ssl_certificate /etc/pki/tls/certs/oauth2-proxy.crt; # SSL証明書のパスを指定します。
ssl_certificate_key /etc/pki/tls/private/oauth2-proxy.key; # SSL証明書の秘密鍵のパスを指定します。
server_name _; # サーバー名を指定します。ここではワイルドカード(_)が使用されています。
access_log /var/log/webapps/oauth2-proxy/access.log; # アクセスログの出力先を指定します。
error_log /var/log/webapps/oauth2-proxy/error.log; # エラーログの出力先を指定します。
proxy_buffer_size 8k; # プロキシバッファのサイズを8KBに設定します。
resolver 127.0.0.53 ipv6=off; # DNSリゾルバとして127.0.0.53を使用し、IPv6を無効にします。
location / # ロケーションブロックの開始。このブロック内の設定は、特定のURLパターンに適用されます。
{
auth_request /oauth2/auth; # 認証リクエストを指定したURLに送信します。
error_page 401 = /oauth2/sign_in?rd=$request_uri; # 401エラー(未認証)が発生した場合のリダイレクト先を指定します。
index index.html index.htm index.php; # ディレクトリインデックスとして使用するファイルを指定します。
proxy_pass http://$host; # リクエストを指定したプロキシサーバーに転送します。
#proxy_ssl_verify off; # プロキシサーバーのSSL証明書の検証を無効にします(コメントアウトされています)。
}
location /oauth2/ { # /oauth2/ ロケーションブロックの開始。
proxy_pass http://127.0.0.1:4180; # リクエストを指定したoauth2-proxyサーバーに転送します。
proxy_set_header Host $host; # プロキシリクエストのHostヘッダーを設定します。
proxy_set_header X-Real-IP $remote_addr; # プロキシリクエストのX-Real-IPヘッダーを設定します。
proxy_set_header X-Scheme $scheme; # プロキシリクエストのX-Schemeヘッダーを設定します。
}
location /oauth2/auth { # /oauth2/auth ロケーションブロックの開始。
proxy_pass http://127.0.0.1:4180; # リクエストを指定したoauth2-proxyサーバーに転送します。
proxy_set_header Host $host; # プロキシリクエストのHostヘッダーを設定します。
proxy_set_header X-Real-IP $remote_addr; # プロキシリクエストのX-Real-IPヘッダーを設定します。
proxy_set_header X-Scheme $scheme; # プロキシリクエストのX-Schemeヘッダーを設定します。
proxy_set_header Content-Length ""; # プロキシリクエストのContent-Lengthヘッダーを空に設定します。
proxy_pass_request_body off; # プロキシリクエストのボディの転送を無効にします。
}
}
resolver 127.0.0.53 ipv6=off;
の部分は、/etc/hosts を読み取る設定です。今回の場合、
webapps-php.example.com
の名前解決のために必要です。
error_page 401 = /oauth2/sign_in?rd=$request_uri;
の
?rb=
の部分は、認証通過後、元々アクセスしに来た URI に戻るために必要です。これが無いと、以下の例のように / に戻ります。
例:
https://webapps-php.example.com/info.php
↓
認証通過
↓
https://webapps-php.example.com
Nginx の設定を反映します。
# systemctl restart nginx
VSCode でデバッグ起動環境作成
今回、oauth2-proxy (の main.go)を F5(デバッグモード) で起動します。 起動するための準備になります。
main.go を開いて、 実行とデバッグ → launch.json ファイルを作成します をクリックします。
Go: Launch Package をクリックします。
launch.json が作成されたら準備完了です。
とりあえず、main.go に戻って、F5 キーを押して起動します。The "dlv" command is not available. Run "go install -v github.com/go-delve/delve/cmd/dlv@latest" to install.
と表示されるため、
Install をクリックします。
ここでインストールされる dlv(delve) は、Go 言語のデバッガです。単体でも機能しますが、VSCode と連携して VSCode で Go 言語のデバッグが可能になります。
go install -v github.com/go-delve/delve/cmd/dlv@latest
でインストールしても構いません。
インストールし終えたら、F5 で起動!
といきたいところですが、今回の環境の場合、以下のエラーになり、起動できません。
Build Error: go build -o /opt/oauth2-proxy/__debug_bin2712808634 -gcflags all=-N -l .
# google.golang.org/grpc
/root/go/pkg/mod/google.golang.org/grpc@v1.58.3/server.go:2096:14: undefined: atomic.Int64
note: module requires Go 1.19 (exit status 2)
Go のバージョンが低すぎるため、ビルドエラーです。
Go 更新
Go を最新版に更新します。
# add-apt-repository ppa:longsleep/golang-backports -y
# apt update
# apt install golang-go -y
# go version
go version go1.21.4 linux/amd64
VSCode でTools (gopls, dlv) need recompiling to work with go version go1.21.4 linux/amd64
と表示されるため、
Update tools をクリックします。
再び、F5 で main.go を起動します。
ビルドエラーは解消して、起動しようとするところまで進みますが、設定を全く指定していないため、以下のエラーになります。
[2024/01/04 21:07:24] [main.go:54] invalid configuration:
missing setting: cookie-secret
provider missing setting: client-id
missing setting: client-secret or client-secret-file
missing setting for email validation: email-domain or authenticated-emails-file required.
use email-domain=* to authorize all email addresses
Process 12927 has exited with status 1
Detaching
oauth2-proxy 設定
oauth2-proxy の設定を行います。
起動オプションで設定もできますが、今回は、設定ファイルで設定します。
そのためには、まず、--config=/opt/oauth2-proxy/oauth2-proxy.cfg
オプションありで oauth-proxy を起動して、設定ファイル /opt/oauth2-proxy/oauth2-proxy.cfg を読み込むようにします。
オプションを付けてデバッグ起動したいので、launch.json に"args": ["--config=/opt/oauth2-proxy/oauth2-proxy.cfg"],
を追加して、以下のようにします。
{
// IntelliSense を使用して利用可能な属性を学べます。
// 既存の属性の説明をホバーして表示します。
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${fileDirname}",
"args": ["--config=/opt/oauth2-proxy/oauth2-proxy.cfg"],
}
]
}
oauth2-proxy.cfg を編集します。
# head -c 24 /dev/urandom | base64
6s1wlAH00x80vPOftMiBwCzcEeyr23y4
# vi /opt/oauth2-proxy/oauth2-proxy.cfg
# Azure ADを使用して認証を行います。
provider = "azure"
# OAuth2 ProxyがHTTP/HTTPSクライアントを待ち受けるアドレスとポートを指定します。
http_address = "127.0.0.1:4180"
# 許可されるEメールのドメインを指定します。ここではワイルドカードが使われており、どのドメインのEメールアドレスも許可されます。
email_domains = ["*"]
# OAuth2 プロバイダに要求するスコープを指定します。"openid" は OpenID Connect フローを使用することを意味します。
scope = "openid"
# OAuth2プロキシが発行するCookieのシードに使われる値を指定します。
cookie_secret = "6s1wlAH00x80vPOftMiBwCzcEeyr23y4"
# この行はコメントアウトされていますが、もし有効化された場合、CookieがHTTPS接続でのみ送信されることを指定します。
#cookie_secure = false
# この行もコメントアウトされていますが、もし有効化された場合、セッションCookieが最小限の情報のみを含むようになります。
#session_cookie_minimal = true
# OpenID ConnectプロバイダのURLを指定します。
oidc_issuer_url = "https://login.microsoftonline.com/<Azure AD ディレクトリ (テナント) ID>/v2.0"
# OAuth2プロバイダに登録したクライアントのIDを指定します。
client_id = "<Azure AD アプリケーション (クライアント) ID>"
# OAuth2プロバイダに登録したクライアントシークレットを指定します。
client_secret = "<Azure AD 証明書とシークレットの「値」>"
# OAuth2プロバイダからの認証応答を受け取るためのリダイレクトURLを指定します。
redirect_url = "https://webapps-php.example.com/oauth2/callback"
# Azure AD のテナントIDを指定します。
azure_tenant = "<Azure AD ディレクトリ (テナント) ID>"
# プロバイダの選択ボタンをスキップするかどうかを指定します。true が指定されている場合、ユーザーは直接プロバイダのログインページにリダイレクトされます。
skip_provider_button = true
cookie_secret は、OAuth2 Proxy が発行する Cookie のシード(初期値)として使われます。
24 バイトのランダムなバイト列を base64 エンコードしたものを設定しています。
長すぎると、以下のエラーになります。
[2023/12/12 20:17:11] [main.go:54] invalid configuration:
cookie_secret must be 16, 24, or 32 bytes to create an AES cipher, but is 44 bytes
Process 11727 has exited with status 1
Detaching
起動時引数でも、同様の設定ができますが、設定項目の名称と異なるため、注意が必要です。
例:
設定の場合:email_domains
引数の場合:email-domain
動作確認
F5 で起動します。
起動しました!
https://webapps-php.example.com/info.php
にアクセスします。
成功!ヨシっ!
その他、宣伝、誹謗中傷等、当方が不適切と判断した書き込みは、理由の如何を問わず、投稿者に断りなく削除します。
書き込み内容について、一切の責任を負いません。
このコメント機能は、予告無く廃止する可能性があります。ご了承ください。
コメントの削除をご依頼の場合はTwitterのDM等でご連絡ください。