新しいことにはウェルカム

技術 | 電子工作 | ガジェット | ゲーム のメモ書き

Webサーバの設定だけでBasic認証の代わりにGoogle認証を使う方法

サイトに手軽にアクセス制限をかける方法としてBasic認証を使うことがあります。

Basic認証は便利なのですが、ブラウザがID・パスワードを覚えてくれなくて毎回入力する必要があったり、ID・パスワードを知っていれば誰でもアクセスできてしまうのが問題だったりします。

もう少しちゃんとした認証を入れたいのですが、認証システムを作るまではやりたくなく…

そこで、Webサーバーの設定だけで、Basic認証の代わりにGoogle認証を使って、指定したGmailアカウントしかアクセスできないようにしてみました。

概要

WebサーバーにはNginxを使い、oauth2_proxyという認証周りの処理をやってくれるリバースプロキシを使用します。

Nginxにアクセスがあると、Nginxはoauth2_proxyに有効なユーザーかを問い合わせ、有効であれば次の処理、つまりサイト表示を行います。ユーザーが無効であれば、oauth2_proxyがエラーページを表示します。

また、ユーザーがログインしていない状態ならば、oauth2_proxyが、ログイン画面の表示からログイン完了まで、ログイン関連の面倒な作業を行ってくれます。

インストール

  1. oauth2_proxyはバイナリで配布されているので、https://github.com/bitly/oauth2_proxy/releasesからoauth2_proxyのファイルをダウンロードします。
  2. Nginxのサーバーの「/usr/sbin」に「oauth2_proxy」を置いてパスを通します。

Google認証クライアント登録

oauth2_proxyは、Google APIを使ってログインしているユーザーのメールアドレスを取得し、そのアドレスが指定したユーザーかをチェックします。

Google APIを使うには、Google APIを使うサイトをクライアントとして、Googleに登録しておく必要があります。

  1. https://console.developers.google.com/projectでプロジェクトを作成
  2. [ナビゲーションメニュー]-[APIとサービス]-[認証情報]
  3. [OAuth同意画面]タブで「アプリケーション名」を設定して保存
  4. [認証情報]タブで[認証情報を作成]-[OAuthクライアントID]
  5. [OAuthクライアントIDの作成]画面で下記に設定して作成
    • 「アプリケーションの種類」を「ウェブアプリケーション」
    • 「承認済みのJavaScript生成元」を「https://<サイトドメイン名>」
    • 「承認済みのリダイレクトURI」を「https://<サイトドメイン名>/oauth2/callback」
  6. 「クライアントID」と「クライアントシークレット」が発行されるのでメモしておく

oauth2_proxyの設定

oauth2_proxyの設定はコマンドライン引数による方法と、設定ファイルによる方法があるのですが、今回は設定ファイル「oauth2_proxy.cfg」を用意しました。

  • アクセス許可するメールアドレス一覧を記載したファイル「authenticated_emails_file」を用意しておきます。
  • メールアドレスは、ファイルを用いた個別指定だけでなく、「email_domains」設定で、ドメインによる一括指定も可能です。
  • 他のサーバーへの転送(upstream)を行わない場合でも、「upstreams」に何らかの登録がないとエラーになるので、適当な値を登録しておきます。

oauth2_proxy.cfg

## <addr>:<port> to listen on for HTTP/HTTPS clients
http_address = "127.0.0.1:4180"

## the OAuth Redirect URL.
redirect_url = "https://<サイトドメイン>/oauth2/callback"

## the http url(s) of the upstream endpoint. If multiple, routing is based on path
upstreams = [
    "http://127.0.0.1:8080/"
]

## The OAuth Client ID, Secret
client_id = "<クライアントID>"
client_secret = "<クライアントシークレット>"

## Email Domains to allow authentication for (this authorizes any email on this domain)
## for more granular authorization use `authenticated_emails_file`
## To authorize any email addresses use "*"
#email_domains = [
#    "<許可アドレスドメイン>"
#]

## Authenticated Email Addresses File (one email per line)
authenticated_emails_file = "/etc/nginx/authenticated_emails_file"

## Cookie Settings
## Name     - the cookie name
## Secret   - the seed string for secure cookies; should be 16, 24, or 32 bytes
##            for use with an AES cipher when cookie_refresh or pass_access_token
##            is set
## Domain   - (optional) cookie domain to force cookies to (ie: .yourcompany.com)
## Expire   - (duration) expire timeframe for cookie
## Refresh  - (duration) refresh the cookie when duration has elapsed after cookie was initially set.
##            Should be less than cookie_expire; set to 0 to disable.
##            On refresh, OAuth token is re-validated.
##            (ie: 1h means tokens are refreshed on request 1hr+ after it was set)
## Secure   - secure cookies are only sent by the browser of a HTTPS connection (recommended)
## HttpOnly - httponly cookies are not readable by javascript (recommended)
cookie_name = "_oauth2_proxy"
cookie_secret = "0123456789abcdef"

Nginxの設定

お馴染み

f:id:kwbtblog:20181219022450p:plain

を表示する「default.conf」は下記のようになります。

  • 表示処理の一番始めに「auth_request /oauth2/auth」を入れて、表示する前に「oauth2_proxy」に許可されたユーザーか問い合わせています。
  • 問い合わせ結果がNGだった場合、エラーページ・ログインページを表示します。
  • 問い合わせ結果がOKだった場合、引き続き次の処理、つまり表示処理を行います。

default.conf

server {
    listen 443 default ssl;
    ssl_certificate /etc/nginx/server.crt;
    ssl_certificate_key /etc/nginx/server.key;

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

    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;

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

        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}

上記は静的ページなので特に何もしていませんが、他のサーバーへの転送(upstream)や動的なページの場合は、コメントアウトしている「auth_request_set」等の、設定が必要になってくる場合がありますので、詳細設定はoauth2_proxyのサイトを参照してください。

起動

Dockerを使って構成・起動を行いました。

oauth2_proxyバイナリを実行すると永続するので、シェルスクリプトで[Nginx]→[oauth2_proxy]の順に実行しています。

Dockerfileとシェルスクリプトは下記のような感じになります。

Dockerfile

FROM nginx:alpine

RUN apk update
RUN apk add bash
RUN apk add ca-certificates
RUN rm -rf /var/cache/apk/*

COPY default.conf /etc/nginx/conf.d/
COPY server.crt /etc/nginx/
COPY server.key /etc/nginx/

COPY oauth2_proxy /usr/sbin/
COPY oauth2_proxy.cfg /etc/nginx/
COPY authenticated_emails_file /etc/nginx/

COPY start.sh /root/
CMD ["/root/start.sh"]

start.sh

#!/bin/bash

nginx
oauth2_proxy -config=/etc/nginx/oauth2_proxy.cfg

後はDockerでNginxを立ち上げれば、Google認証によるアクセス制限されたサイトの完成です。

初めてアクセスすると下記のようなログインページが表示されます。

f:id:kwbtblog:20181219025321p:plain

ボタンを押すとGoogleのログイン画面に転送され、ログイン後に「Welcome to nginx!」が表示されるようになります。

その他

oaut2_proxyのデフォルト認証はGoogleですが、他にもOffice365(Azure)・Facebook・GitHub等にも対応しています。