nginx でホストしたサイトに Cognito で OAuth2 認証をかける


はじめに

Sphinx などで生成したフラットファイルを公開するのに、認証をかけたい場合、Basic認証などもありますが、公開先のユーザーが削除されたりするとパスワード変更や通知の手間が大変なので、OAuth2 認証をかけたい、といった状況があると思います。

そういった場合に、oauth2_proxyと nginx が使えることが、こちらのとても素晴らしいサイトYtaka Kato oauth2_proxy と Auth0 を用いた Nginx のお手軽 OAuth 化に紹介されています。

今回はこちらのサイトに紹介されている内容を、AWS Cognito を使って実施してみました。(Cognito部分以外は前述のページを参照いただいた方が良いかもしれません。。)備忘録としてのメモです。

サイトのSSL化

Cognito で認証をかけるには、コールバックURLが https である必要があります。まず nginx でホストしている、認証をかけたいサイトをSSL化する必要があります。

acme-tinyなどを使って、Let's Encrypt でサーバ証明書を取得し、Virtual Host を SSL化します。

server {
    listen 443 ssl;
    server_name your.domain.name;

    ssl_certificate /path/to/signed.crt;
    ssl_certificate_key /path/to/domain.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA;
    ssl_session_cache shared:SSL:50m;
    ssl_dhparam /path/to/server.dhparam;
    ssl_prefer_server_ciphers on;

    location / {
        index index.html;
        try_files $uri $uri/ =404;
        alias /var/www/somedocument/;
    }

}

oauth2_proxy のインストール

こちら を参考にして、バイナリをダウンロードします。go製なのでセットアップが簡単でいいですね。
今回は nginx と同じマシンにインストールしました。設定は後から行います。

systemdでサービス化するサンプルも、同じプロジェクトの contribで公開されています。

Cognito でユーザープールを作る

Cognito のコンソールにログインします。

「ユーザープールの管理」をクリックします

「ユーザープールの作成」をクリックします

「属性」部分は用途に応じて適当に設定します

「ポリシー」でパスワード強度等を設定します

「MFAそして確認」では多要素認証について設定します

今回はMFAを無効にします。

「アプリクライアント」でアプリケーションを追加します

ここではトークンの有効期限を設定できます。

アプリの統合 / アプリクライアントの設定

「アプリの統合 / アプリクライアントの設定」で、コールバックURL、サインアウトURLを設定します。
* コールバックURLは、oauth2_proxy をホストしているURLを設定します。URLのパスは、/oauth2/callback です。
* コールバックURLは、https である必要があります。
* 「有効なIDプロバイダ」で、「Cognito User Pool」にチェックを入れます

アプリの統合 / ドメイン名

「アプリの統合 / ドメイン名」で、適当な値を設定します。

Oauth2_proxy を Cognito 向けに構成する

こちらのチケットIntegrating oauth2_proxy with AWS Cognitoにサンプルの構成例が出ています。
こちらを参考に、下記のような構成で動作しました。

細かい設定パラメーターについては、OAuth2 Proxy の Configurationページに書かれています。

provider = "oidc"
client_id = "XXXXXXXXXXXXXXXXXXX"
client_secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
oidc-issuer-url = "https://cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_XXXXXXXXX" 
redirect_url = "https://my.oauth2proxy.domain/oauth2/callback"
login-url = "https://tsh-rpa-support-100.auth.ap-northeast-1.amazoncognito.com/oauth2/authorize"
profile-rul =  "https://tsh-rpa-support-100.auth.ap-northeast-1.amazoncognito.com/oauth2/userInfo"
redeem-url = "https://tsh-rpa-support-100.auth.ap-northeast-1.amazoncognito.com/oauth2/token"
scope = "openid"
cookie_secure = false
#upstream = "URL OF THE APP"
email_domains = [
    "*"
]
cookie_secret = "secret"
http_address = "127.0.0.1:4180"
whitelist-domain = "tsh-rpa-support-100.auth.ap-northeast-1.amazoncognito.com"

oidc-issuer-url について

Cognito の Developer Guideに、Issuer (iss)のフォーマットが書かれています。

Issuer (iss)
The iss claim has the following format:
https://cognito-idp.{region}.amazonaws.com/{userPoolId}.
For example, if you created a user pool in the us-east-1 region and its user pool ID is u123456, the ID token issued for users of your user pool have an iss claim value of
https://cognito-idp.us-east-1.amazonaws.com/u123456.

User Pool ID は、ユーザープールの「全般設定」で確認できます。

※ 手元で試した環境では、設定ファイルのoidc-issuer-urlが効かず、起動パラメーターとして指定しました。

/opt/oauth2_proxy/oauth2_proxy -config /etc/oauth2proxy.conf --oidc-issuer-url="https://cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_XXXXXXXXXXX

login-url, profile-rul, redeem-url の URL

このドメインは、「アプリの統合 / ドメイン名」で指定したものを使います。

redirect_url

「アプリの統合 / アプリクライアントの設定」で指定したコールバックURLと同じ物です。
(Oauth2_Proxy をホストしているURLを指定します。URLのパスは、/oauth2/callback です)

サイトに OAuth2 認証を設定する

先ほど SSL化した Virtual Host に対して、OAuth2 認証を設定します。

nginx の auth_request を使うところがポイントのようです。

server {
    listen 443 ssl;
    server_name your.domain.name;

    ssl_certificate /path/to/signed.crt;
    ssl_certificate_key /path/to/domain.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA;
    ssl_session_cache shared:SSL:50m;
    ssl_dhparam /path/to/server.dhparam;
    ssl_prefer_server_ciphers on;

    location / {
        index index.html;
        try_files $uri $uri/ =404;
        alias /var/www/somedocument/;

        auth_request /oauth2/auth;
        error_page 401 = /oauth2/sign_in;
    }


    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;
    }


}

試してみる

認証をかけたサイトを開く

ログインのためのボタンが表示されます。クリックします。

ログイン画面で認証情報を入力する

Cognito のログイン画面が表示されるので、認証情報を入力します。

ログインが成功すると、認証をかけたサイトの内容が表示されます。