Nginx + OAuth2 Proxy で静的 Web サイトに認証機能を追加してみる
TL;DR
- OAuth2 Proxy を使って Docusaurus で作成したドキュメントサイトに認証機能をつける
- OAuth2 Proxy は、認証と認可を外部の認証基盤に委譲するためのリバースプロキシサーバ
- 外部の認証基盤には、Amazon Cognito(認証・認可およびユーザ管理機能を提供する AWS のマネージドサービス)を利用
はじめに
前回の記事では、ドキュサウルスはコンテナ時代を航海するために、Docker の背中に乗り込みました。
とはいえ、いきなりインターネットに飛び出すのも気が引けますよね。
そこで、今回は信頼できるお友達とだけドキュサウルスに会えるようにしてあげましょう。
イメージとしては👇のような構成になります。
ローカル環境で認証機能の確認をする
OAuth2 Proxy って?
認証と認可を外部の認証基盤に委譲するためのリバースプロキシサーバです。
MIT License の OSS なので誰でも自由に使えます。
Google や GitHub などの OIDC プロバイダーを利用して認証を提供し、アカウントを検証することができます。
詳細が知りたい方は、👇のドキュメントをご覧ください。
あれ?、気づいちゃいましたか?
実は OAuth2 Proxy のドキュメントサイトは Docusaurus で作成されているんです🦖
認証するのは誰?
今回は、Amazon Cognito(ユーザープール)を外部の認証基盤として使ってみます。
Cognito は、認証・認可およびユーザ管理機能を提供する AWS のマネージドサービスです。
認証機能を追加してみよう
では、認証基盤の準備ができたので、各種設定ファイルを見ていきましょう。
Nginx の設定ファイルを編集
次のように、OAuth2 Proxy 用のパス設定を追加しています。
events {
multi_accept on;
}
http {
sendfile on;
tcp_nopush on;
server_tokens off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80;
server_name localhost;
location / {
+ auth_request /oauth2/auth;
+ error_page 401 = /oauth2/sign_in;
root /usr/share/nginx/html;
index index.html index.htm;
}
+ 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;
+ }
+ 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;
+ proxy_set_header Content-Length "";
+ proxy_pass_request_body off;
+ }
+ }
}
OAuth2 Proxy の設定ファイルを作成
次に、server-config
配下に OAuth2 Proxy の設定ファイルのテンプレート(oauth2proxy.conf.template
)を新規に作成します。
中身は次のようにします。(おそらく最小構成だと思います🙏)
provider = "oidc"
http_address = "127.0.0.1:4180"
email_domains = ["*"]
scope = "openid"
cookie_secret = "${COOKIE_SECRET}"
cookie_secure = false
session_cookie_minimal = true
oidc_issuer_url = "https://cognito-idp.ap-northeast-1.amazonaws.com/${USER_POOL_ID}"
client_id = "${APPLICATION_CLIENT_ID}"
client_secret = "${APPLICATION_CLIENT_SECRET}"
redirect_url = "${REDIRECT_URL}"
ファイル内には、次の環境変数を埋め込んでいます。
環境変数 | 設定値 |
---|---|
COOKIE_SECRET | Cookie のシード文字列(後ほど、Python で生成します) |
USER_POOL_ID | Cognito のユーザープール ID |
APPLICATION_CLIENT_ID | Cognito のアプリケーションクライアント ID |
APPLICATION_CLIENT_SECRET | Cognito のアプリケーションクライアントのシークレット |
REDIRECT_URL | Cognito のアプリケーションクライアントのコールバック URL |
詳細な設定項目は次を参照してください。
Supervisor の設定ファイルを作成
Supervisor は複数のプロセスを制御してくれるツールです。
今回は、コンテナ起動時に Nginx と OAuth2 Proxy の二つのプロセスを立ち上げますので、これらのプロセスをデーモン化する用途で使用します。
server-config
配下に Supervisor の設定ファイル(supervisord.conf
)を新規に作成します。
中身は次のようにします。
[supervisord]
nodaemon=true
[program:nginx]
command=nginx -g "daemon off;"
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
startretries=10
autorestart=true
[program:oauth2_proxy]
command=/usr/local/bin/oauth2-proxy --config /etc/oauth2proxy.conf
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
startretries=10
autorestart=true
コンテナ起動時のスタートアップスクリプトを作成
コンテナ起動時に実行するスタートアップスクリプト(startup.sh
)を新規に作成します。
中身は次のようにします。
#!/bin/bash
envsubst < /etc/oauth2proxy.conf.template > /etc/oauth2proxy.conf
/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
Dockerfile を編集
Dockerfile を次のように編集します。
FROM node:lts-alpine3.16 AS build
COPY ./my-website ./
RUN npm install
RUN npm run build
FROM nginx:1.23.2
+ ARG CPU_ARCH=amd64
+ ARG OAUTH2_PROXY_VERSION=7.4.0
+ RUN set -x && \
+ apt update && \
+ apt install --no-install-recommends --no-install-suggests -y \
+ supervisor wget gettext-base
+ RUN wget https://github.com/oauth2-proxy/oauth2-proxy/releases/download/v${OAUTH2_PROXY_VERSION}/oauth2-proxy-v${OAUTH2_PROXY_VERSION}.linux-${CPU_ARCH}.tar.gz && \
+ tar xf oauth2-proxy-v${OAUTH2_PROXY_VERSION}.linux-${CPU_ARCH}.tar.gz -C /usr/local/bin/ --strip-components 1 && \
+ rm oauth2-proxy-v${OAUTH2_PROXY_VERSION}.linux-${CPU_ARCH}.tar.gz
COPY ./server-config/nginx.conf /etc/nginx/nginx.conf
+ COPY ./server-config/oauth2proxy.conf.template /etc/oauth2proxy.conf.template
+ COPY ./server-config/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
+ COPY ./startup.sh /startup.sh
COPY --from=build /build /usr/share/nginx/html
- CMD [ "nginx", "-g", "daemon off;" ]
+ CMD [ "sh", "startup.sh" ]
アーキテクチャやバージョンを指定して OAuth2 Proxy をインストールしています。
ARG CPU_ARCH=amd64
ARG OAUTH2_PROXY_VERSION=7.4.0
・・・
RUN wget https://github.com/oauth2-proxy/oauth2-proxy/releases/download/v${OAUTH2_PROXY_VERSION}/oauth2-proxy-v${OAUTH2_PROXY_VERSION}.linux-${CPU_ARCH}.tar.gz && \
tar xf oauth2-proxy-v${OAUTH2_PROXY_VERSION}.linux-${CPU_ARCH}.tar.gz -C /usr/local/bin/ --strip-components 1 && \
rm oauth2-proxy-v${OAUTH2_PROXY_VERSION}.linux-${CPU_ARCH}.tar.gz
apt のインストールを高速化するようなオマジナイなんかがついていますが、必要なツールをインストールしているだけです。
-
supervisor
は、Nginx および OAuth2 Proxy をデーモン化するため -
wget
は、OAuth2 Proxy のダウンロードで使用するため -
gettext-base
は、テンプレートファイルの環境変数を展開するenvsubst
を使えるようにするため
RUN set -x && \
apt update && \
apt install --no-install-recommends --no-install-suggests -y \
supervisor wget gettext-base
追加した設定ファイルおよびコンテナ起動時に実行するスタートアップスクリプトの COPY を追加しています。
COPY ./server-config/oauth2proxy.conf.template /etc/oauth2proxy.conf.template
COPY ./server-config/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY ./startup.sh /startup.sh
コンテナ起動時にスタートアップスクリプトを実行するようにします。
CMD [ "sh", "startup.sh" ]
認証機能の確認をしてみよう!
長かったですが、いよいよ認証機能の確認をしてみます。
Docker ビルドして、コンテナを起動してみましょう!
Docker ビルド
それでは、Docker ビルドをしてみましょう。
DOCKER_BUILDKIT=1 docker build --progress=plain --no-cache -t my-website:1.0.0 .
コンテナの起動
コンテナを起動してみます。
コンテナ起動時に Cognito のクレデンシャル情報等の環境変数の値を渡すため、--env
オプションを指定します。
docker run --rm -p 80:80 \
--env COOKIE_SECRET=`python3 -c 'import os,base64; print(base64.urlsafe_b64encode(os.urandom(32)).decode())'` \
--env USER_POOL_ID=xxxxxxxxxxxxxx_xxxxxxxxx \
--env APPLICATION_CLIENT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxx \
--env APPLICATION_CLIENT_SECRET=*************************************************** \
--env REDIRECT_URL=http://localhost/oauth2/callback \
my-website:1.0.0
http://localhost
にアクセスして、認証画面が表示されれば成功です!
作成したユーザで早速ログインしてみましょう✨
ログインしている様子
最後に
いかがだったでしょうか?
これで信頼できるお友達だけをドキュサウルスに会わせることができました。
一安心ですね😌
えっ?ローカル環境だから、同一ネットワーク内の人じゃないとドキュサウルスに会えないじゃないかって?
ですよね、それでは次回は認証付きのドキュメントサイトをインターネットに公開してみましょう!
そうすればドキュサウルスも一躍有名になれますね😎✨
ちなみに、今回は静的 Web サイトに認証機能をつけただけなのであまり面白味はないかもしれませんが、コンテナ化しているので当然 K8s 上で動く場合であっても OAuth2 Proxy が使えて、手軽に認証機能を組み込むことができます。
やっぱりコンテナは素晴らしいですね。
それではまた次回のアドベントカレンダー(勝手にシリーズ化)でお会いしましょう😉
Discussion