OAuth2-Proxy と Traefik でプロキシ型の認証

OAuth2 の認証を実装するときに、認証ロジックをアプリケーション自体に組み込んでしまうケースと、プロキシで認証してしまうケースがあります。私はこれまで組み込み型での実装を中心としていたのですが、認証機能を分離してしまいたいと考えた為、今回プロキシ型の認証へ取り組んでみました。

## 前提

* oidc
* docker-compose
* nginx
* oauth2-proxy

## 結果だけ欲しい方へ

以下ソースコードをクローン頂ければ

https://github.com/ymuichiro/oauth2-proxy/

## コード

traefik config
```traefik.yml
entryPoints:
  web:
    address: ":80"
api:
  insecure: true
  dashboard: true
providers:
  file:
    filename: /etc/traefik/traefik-rule.yml
log:
  level: INFO
```

```traefik-ruke.yml
http:
  routers:
    express1:
      rule: "Host(`localhost`)"
      service: node
      middlewares:
        - oauth-auth
        - autodetect
    oauth:
      rule: "Host(`localhost`) && PathPrefix(`/oauth2/`)"
      middlewares:
        - auth-headers
      service: auth
  services:
    node:
      loadBalancer:
        passHostHeader: true
        servers:
          - url: "http://server:3001"
    auth:
      loadBalancer:
        servers:
          - url: http://auth:4180
  middlewares:
    autodetect:
      contentType:
        autoDetect: true
    auth-headers:
      headers:
        stsSeconds: 315360000
        browserXssFilter: true
        contentTypeNosniff: true
        forceSTSHeader: true
        stsIncludeSubdomains: true
        stsPreload: true
        frameDeny: true
    oauth-auth:
      forwardAuth:
        address: http://auth:4180/
        trustForwardHeader: true
        authResponseHeaders:
          - X-Auth-Request-Access-Token
          - Authorization
```

docker compose
```docker-compose.yml
version: "3"
services:
  proxy:
    image: traefik
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - ./configs:/etc/traefik:ro
  server:
    build:
      context: ./node
      dockerfile: ./Dockerfile
  auth:
    image: quay.io/oauth2-proxy/oauth2-proxy:v7.5.0
    env_file:
      - .env.local
    ports:
      - "4180:4180"
    environment:
      OAUTH2_PROXY_PROVIDER: oidc
      OAUTH2_PROXY_REDIRECT_URL: http://localhost/oauth2/callback
      OAUTH2_PROXY_COOKIE_SECURE: "false"
      OAUTH2_PROXY_COOKIE_NAME: "auth"
      OAUTH2_PROXY_EMAIL_DOMAINS: "*"
      OAUTH2_PROXY_HTTP_ADDRESS: 0.0.0.0:4180
      OAUTH2_PROXY_UPSTREAMS: static://202
      OAUTH2_PROXY_REVERSE_PROXY: true
      OAUTH2_PROXY_SCOPE: email profile openid
      OAUTH2_PROXY_SKIP_PROVIDER_BUTTON: true
      OAUTH2_PROXY_SET_AUTHORIZATION_HEADER: true
      OAUTH2_PROXY_SET_XAUTHREQUEST: true
      OAUTH2_PROXY_PASS_ACCESS_TOKEN: true
```

::: note
ドキュメントを参照しながらより詳しい説明が必要な場合は、以下を参照して下さい。
[OAuth2-Proxy Overview](https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/overview/#forwardauth-with-static-upstreams-configuration)
:::

## 解説

ポイント
* JWT を Authorization から取得し、ユーザー情報を利用します
* oauth2-proxy は OP とのやりとりを担当し、認証済みの場合は nginx に202 を返却します
* nginx は oauth2-proxy と upstream 先のアプリケーション の間に入り、リクエストのヘッダーを書き換えて JWT を渡します
* upstream 先のアプリケーションは JWT を検証し、ユーザー情報を取り出してアプリケーションのロジックに利用します

## まとめ

このような実装方法でプロキシ型の認証を実装することが出来ました。勿論、アプリケーションに認証ロジックを組み込んでしまうことは悪いことではありません。寧ろ、クイックにシンプルなインフラ構成でアプリケーションを構築する必要があるのなら、このようなプロキシ型の構成は逆効果でもあると思います。あくまでも一例としてプロキシ型認証が必要になった時に、参考になれば幸いです（後、コードのご指摘歓迎）。

当方ブロックチェーン関連も活動しているので、もし何か実装してみたいと思っている方がいましたら、是非プロフィールから過去記事も是非閲覧下さい。