はじめに
OAuth2 Proxy を利用してみたいのだが、dockerやらkubernetesやら準備が大変そうだったので、バイナリを利用して動作させてみた。GitHubアカウントとインターネットからアクセスできるLinuxがあれば大丈夫。
作業履歴なので、解説は少なめ。
HTTPなサイトでPHP/Perlを動作させて、OAuth2でGitHub認証したユーザー名を取得して表示させるサンプルを作成する。権限設定とかよりもユーザーの識別って部分をやってるから認可よりも認証っていう意味のほうが強いのかな。
公式ドキュメント
https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/overview
今回はこれの左側の構成になるはず。
で、Auth Provider としては GitHub を利用する。OpenID Provider / Id Provider とか言うらしい。
出典:https://github.com/oauth2-proxy/oauth2-proxy/blob/master/README.md#docs
GitHub側の作業
アプリケーション作成
以下にアクセスしてOAuthアプリケーションを作成する
https://github.com/settings/applications/new
Application name : 適当な名前
Homepage URL : このアプリを適用するURL
Application description : 任意(なくてもいい)
Authorization callback URL : Auth Providerへ認可アクセスしたときのコールバック先
コールバックURLは、アプリと同一サイトの /oauth2/callback を指定するのが基本らしい。
今回は同一サイトで待ち受けているnginxのlocationで /oauth2/ の proxy_pass に ローカルの :4180
を指定している。(上の図の oauth2_proxy の枠の部分)
こんな画面になるので、Generate a new client secretをクリック
ここのClientIDとClientSecretsをメモっておく(Client Secretsは画面を遷移させると見えなくなる)
Webサーバーでの作業
今回はVPSのCentOS7で作業していきます。
LinuxでPHPかPerlの動作するNginxを準備
phpかperlが動作するnginxを準備する。
CentOS7で作る場合の具体的な作業は以下に分離。
ポート開放
認証がないHTTPサイトに対してOAuth2で認証するのでHTTPは閉じて、HTTPSを開けておく。
firewall-cmd --add-service=https --zone=public --permanent
firewall-cmd --remove-service=http --zone=public --permanent
firewall-cmd --reload
サーバー証明書の準備
動作検証のみなので、自己署名証明書でやる。
面倒なのでnginxの設定ディレクトリにSSL関連のディレクトリを作成して、そこに全部いれる。
自己署名なのでどうせ警告がでるが、テストで利用するURLをCNに設定しておく。
mkdir /etc/nginx/ssl
cd /etc/nginx/ssl
CN=webarena01.prosper2.org
openssl req -new -newkey rsa:2048 -sha256 -nodes -outform PEM -keyform PEM -out ${CN}.csr -keyout ${CN}.key -subj "/C=JP/ST=Tokyo/O=${CN}/CN=${CN}"
openssl x509 -req -days 30 -signkey ${CN}.key < ${CN}.csr > ${CN}.crt
NginxのSSL設定
SSLのための設定
cat <<EOF > /etc/nginx/ssl/ssl.conf
ssl_certificate "/etc/nginx/ssl/${CN}.crt";
ssl_certificate_key "/etc/nginx/ssl/${CN}.key";
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
EOF
NginxのOAuth2
nginxの設定は公式ドキュメントをそのまま利用
https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/overview/#configuring-for-use-with-the-nginx-auth_request-directive
cat <<'EOF' > /etc/nginx/conf.d/oauth2-proxy.conf
server {
listen 443 ssl;
#server_name ...;
include ssl/ssl.conf;
location /oauth2/ {
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Auth-Request-Redirect $request_uri;
# or, if you are handling multiple domains:
# proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri;
}
location = /oauth2/auth {
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
# nginx auth_request includes headers but not body
proxy_set_header Content-Length "";
proxy_pass_request_body off;
}
location / {
auth_request /oauth2/auth;
error_page 401 = /oauth2/sign_in;
# pass information via X-User and X-Email headers to backend,
# requires running with --set-xauthrequest flag
auth_request_set $user $upstream_http_x_auth_request_user;
auth_request_set $email $upstream_http_x_auth_request_email;
proxy_set_header X-User $user;
proxy_set_header X-Email $email;
# if you enabled --pass-access-token, this will pass the token to the backend
auth_request_set $token $upstream_http_x_auth_request_access_token;
proxy_set_header X-Access-Token $token;
# if you enabled --cookie-refresh, this is needed for it to work with auth_request
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;
# When using the --set-authorization-header flag, some provider's cookies can exceed the 4kb
# limit and so the OAuth2 Proxy splits these into multiple parts.
# Nginx normally only copies the first `Set-Cookie` header from the auth_request to the response,
# so if your cookies are larger than 4kb, you will need to extract additional cookies manually.
auth_request_set $auth_cookie_name_upstream_1 $upstream_cookie_auth_cookie_name_1;
# Extract the Cookie attributes from the first Set-Cookie header and append them
# to the second part ($upstream_cookie_* variables only contain the raw cookie content)
if ($auth_cookie ~* "(; .*)") {
set $auth_cookie_name_0 $auth_cookie;
set $auth_cookie_name_1 "auth_cookie_name_1=$auth_cookie_name_upstream_1$1";
}
# Send both Set-Cookie headers now if there was a second part
if ($auth_cookie_name_upstream_1) {
add_header Set-Cookie $auth_cookie_name_0;
add_header Set-Cookie $auth_cookie_name_1;
}
proxy_pass http://127.0.0.1/;
# or "root /path/to/site;" or "fastcgi_pass ..." etc
}
}
EOF
で、Nginxを再起動しておく
systemctl restart nginx
OAuth2-Proxyの設定
OAuth2-Proxyのバイナリを準備
公式ドキュメントはこれ
https://oauth2-proxy.github.io/oauth2-proxy/docs/
適当なディレクトリにバイナリをダウンロードしておく
mkdir -p /opt/oidc
cd /opt/oidc
OAUTH2_VERSION=v7.2.0
curl -sSL https://github.com/oauth2-proxy/oauth2-proxy/releases/download/${OAUTH2_VERSION}/oauth2-proxy-${OAUTH2_VERSION}.linux-amd64.tar.gz | tar zx --strip=1
OAuth2-Proxyの設定
OAuth2-proxyを動作させるためのコマンドライン引数、設定ファイルは公式ドキュメントを参照して作成する。
https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/overview
https://github.com/oauth2-proxy/oauth2-proxy/blob/master/contrib/oauth2-proxy.cfg.example
今回は設定ファイルとして oauth2-proxy.cfg
を作成する。
COOKIE_SECRETは公式ドキュメントのPythonをそのまま利用。
client_id / client_secret は GitHubでOAuth2アプリケーションを作成したときに表示されていたもの。
cookie-expire で再認証がかかるまでの時間を設定している。(以下サンプルでは1時間とした)
COOKIE_SECRET=`python -c 'import os,base64; print(base64.urlsafe_b64encode(os.urandom(32)).decode())'`
cat <<EOF > /opt/oidc/oauth2-proxy.cfg
#デフォルトのまま
http_address = "127.0.0.1:4180"
#なくても動作したけどいれておく
redirect_url="https://${HOSTNAME}/oauth2/callback"
upstreams = "http://127.0.0.1/"
#IdPはgithubを使う
provider = "github"
email_domains = "*"
#ユーザーを制限したいときはこれを追加
#github_users = [
# "bashaway"
#]
#HTTP_X_USERのヘッダを利用するのに必要
set_xauthrequest = true
cookie_secret = "$COOKIE_SECRET"
client_id = "fdf334e5b5fdcea8985e"
client_secret = "83bc5f57cb8dc5ee60d8f2676a59519d3fd633b9"
#デフォルトは 168h0m0s らしい
cookie_expire = "1h"
EOF
ここまでで、いったん動作するか確認しておく
# ./oauth2-proxy --config=/opt/oidc/oauth2-proxy.cfg
[2021/11/07 14:12:40] [proxy.go:89] mapping path "/" => upstream "http://127.0.0.1/"
[2021/11/07 14:12:40] [oauthproxy.go:148] OAuthProxy configured for GitHub Client ID: fdf334e5b5fdcea8985e
[2021/11/07 14:12:40] [oauthproxy.go:154] Cookie settings: name:_oauth2_proxy secure(https):true httponly:true expiry:1m0s domains: path:/ samesite: refresh:disabled
設定ファイルに問題があればエラーが表示されプロンプトにもどる。プロンプトに戻らなければ大丈夫。
OAuth2-Proxyのサービス化
バイナリをコマンドラインから動作させるのは面倒なので、サービス化する。そのためのサンプルも公式ドキュメントにあるので、これを参考にする。
https://github.com/oauth2-proxy/oauth2-proxy/blob/master/contrib/oauth2-proxy.service.example
サンプルからの変更点はユーザーとグループを nginx にして ExecStart
のバイナリパスを前述のバイナリをダウンロードしたパスにしたことくらい。
cat <<EOF > /etc/systemd/system/oauth2_proxy.service
# Systemd service file for oauth2-proxy daemon
#
# Date: Feb 9, 2016
# Author: Srdjan Grubor <sgnn7@sgnn7.org>
[Unit]
Description=oauth2-proxy daemon service
After=syslog.target network.target
[Service]
# www-data group and user need to be created before using these lines
User=nginx
Group=nginx
ExecStart=/opt/oidc/oauth2-proxy --config=/opt/oidc/oauth2-proxy.cfg
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=always
[Install]
WantedBy=multi-user.target
EOF
これで、サービス登録とサービス起動する。
systemctl enable oauth2_proxy
systemctl start oauth2_proxy
PHP/Perlスクリプトでユーザー情報を取得する
OAuth2で認証したユーザーの情報を表示するために、Webサーバー上にPHPとPerlスクリプトを配置する。
ヘッダ情報に HTTP_X_USER
にユーザー名が HTTP_X_EMAIL
にメールアドレスが入るので、これを表示させればよい。
PHPスクリプト
PHPは $_SERVER
にいろんな情報が入ってるので、ここから取得する。
cat <<'EOF' > /usr/share/nginx/html/php-oidc-header.php
<?php
print "<html><body>\n";
print "Hello PHP Script!<br>\n";
$user = $_SERVER['HTTP_X_USER'];
$email = $_SERVER['HTTP_X_EMAIL'];
print "USERNAME : $user<br>\n";
print "E-MAIL : $email<br>\n";
print "<hr>\n";
ksort($_SERVER);
foreach($_SERVER as $key => $value){
if ( preg_match( '/^HTTP/', $key ) ) {
print "[\"$key\"] => $_SERVER[$key]<br>\n";
}
}
print "</body></html>\n";
?>
EOF
Perlスクリプト
いまだに %headers = map { $_ => $q->http($_) } $q->http();
の意味がよくわかってない。
cat <<'EOF' > /usr/share/nginx/html/perl-oidc-header.pl
#!/usr/bin/perl
use CGI;
print "Content-type: text/html\n\n";
print "<html><body>\n";
print "Hello Perl Script!<br>\n";
$q = CGI->new;
%headers = map { $_ => $q->http($_) } $q->http();
$user = $headers{'HTTP_X_USER'};
$email = $headers{'HTTP_X_EMAIL'};
print "USERNAME : $user<br>\n";
print "E-MAIL : $email<br>\n";
print "<hr>\n";
foreach( sort keys %headers ) {
print "[\"$_\"] => $headers{$_}<br>\n";
}
print "</body></html>\n";
exit;
EOF
chmod 755 /usr/share/nginx/html/perl-oidc-header.pl
動作確認
配置したスクリプトにアクセスするとOAuth2Proxyの画面が表示されるので、「Sign in with GitHub」をクリック
https://webarena01.prosper2.org/php-oidc-header.php
アプリケーションを認可してよいかの画面が表示されるので、「Authorize XXX」をクリック
作成したページが表示され、ユーザー名とemailが取得できていることが確認できた。
ローカル上で同じページをHTTPとして取得すると、こんな感じ。
ユーザー名ありきで作成すると、HTTPでアクセスされたときに動作しないので、外からはHTTPアクセスはできなくしておくことが必要になる。
# curl http://localhost/php-oidc-header.php
<html><body>
Hello PHP Script!<br>
USERNAME : <br>
E-MAIL : <br>
<hr>
["HTTP_ACCEPT"] => */*<br>
["HTTP_HOST"] => localhost<br>
["HTTP_USER_AGENT"] => curl/7.29.0<br>
</body></html>
そのほか
設定ファイルのデフォルトに助けられてるような気がして、ちゃんと必要な要素が取り込めてるのかよくわからない。redirect_urlとかcookie-secretとかなんだか使えてないような、でも動作してるように見えるし。
むつかしい。。。
GitHubのアプリは削除しているので、このページのURLにアクセスしてもGitHubに転送されて404になる。
出典