自宅の Kubernetes 上のサービスに Google OAuth認証をつける方法

サーバー
スポンサーリンク

自宅の Kubernetes 上で動かしているサービスをインターネットに公開し,そこに Google OAuth 認証を付ける方法を紹介します.

スポンサーリンク

前提とする環境

次の環境を前提とします.

  • PPPoE だけでなく,IPv6 IPoE でもインターネットに接続している.
  • 固定 IP はもっていない.
  • インターネットには YAMAHA RTX830 で接続し,内部ネットワークはその下流の Ubiquiti Dream Machine Pro 以下に配置.
  • 独自ドメインを Google Domains で取得済.
  • Kubernetes クラスタには MetalLB を配置し,サービスは type: LoadBalancer で運用.

該当しない場合,関連した設定は省略できます.

設定

設定は,下記の3ステップで行っていきます.

  1. INGRESS によるサービスの公開
  2. Let’s Encrypt による TLS 対応
  3. Google OAuth 認証の設定

順番に説明していきます.

INGRESS によるサービスの公開

この設定を行うことで,Kubernetes 上のサービスにインターネットからアクセスできるようになります.

設定が必要になるのは,下図の①~⑤の5項目になります.

①~③によってインターネットから自宅サーバの内のリバースプロキシにアクセスできるようにします.④ によって自宅サーバの IP アドレスをドメイン名で指定できるようにします.⑤ はリバースプロキシの設定です.

前提として,RTX830 には下記のような設定があり,pp 1 で PPPoE 接続,tunnele 2 で IPoE 接続がされているものとします.また,pp 1 にはディスクリプタ番号 1000 の NAT が設定されているものとします.

内部ルータの RTX830 側のプライベートアドレスは 192.168.4.2,INGRESS のプライベートアドレスは 192.168.4.250 とします.INGRESS のアドレスの設定方法は以降で説明します.

① 宛先が Port 80, 443 のパケットを内部ルータに中継

RTX830 に対して下記の設定を行います.

これにより,PPPoE から入ってきた,Port 80, 443 宛のパケットは 192.168.8.2 に転送されるようになります.

IPv6 IPoE については,外部からアクセスされる際に使えるポートに制約があるので,類似の設定は行いません(行う意味がありません).

② 送信元が Port 80, 443 のパケットは PPPoE で応答

RTX830 に対して下記の設定を行います.

これによって,インターネットから Port 80, 443 にアクセスした際の応答を正常に受け取れるようになります.

PPPoE と IPoE を併用している場合,基本的には IPoE を優先していると思います.そのため,何も設定を行わないとインターネットから Port 80, 443 へアクセスした際の応答も IPoE から返されてしまうことになり,発信元はパケットを破棄してしまいます.

③ 宛先がPort 80, 443 のパケットを INGRESS に中継

Ubiquiti を使っている場合,Network の Setting – Firewall & Security から行います.

具体的にはPort Forwarding に対して以下のような設定を追加します.

設定値はこんな感じ.

④ ダイナミック DNS の更新

大きく次の3点を行います.

  • ダイナミック DNS 対象ホスト名の指定
  • PPPoE 側の IP アドレスの取得方法準備
  • ダイナミック DNS クライアントの設定
ダイナミック DNS 対象ホスト名の指定

Goole Domains の設定画面の DNS の設定の一番下にある「詳細設定を表示」をクリックすると「ダイナミック DNS の管理」の項目が出てくるので,そこから設定を行います.

まず,「xxxx.kubernetes.ドメイン名」(xxxx は任意)でアクセスできるようにしたいので,ホスト名として「*.kubernetes」を指定します.

ホスト名の設定が終わると,そのホスト名の IP アドレスを設定する際に必要になる認証情報が取得できるのでメモしておきます.

PPPoE 側の IP アドレスの取得方法準備

ダイナミック DNS で設定する IP アドレスの取得方法を準備します.RTX830 の場合,下記のようにして SNMP を有効化しておけば,

次のコマンドで IP アドレスを取得できるようになります.(192.168.8.1 は,LAN1 側の RTX830 のアドレス)

ダイナミック DNS クライアントの設定

クライアントソフトとしては,比較的新しそうな inadyn (In-a-Dyn) を使うことにします.

設定ファイルとして次の内容のファイル inadyn.conf を用意します.

続いて次の内容の Dockerfile を準備します.inadyn には公式の Docker イメージもありますが,checkip-command として snmpget を使いたいので,コンテナを作ることにします.

次のように実行してエラーが出なければ OK です.

上手くいっていると次のように出力されて,ホスト名に対応する IP アドレスが設定されます.

dig で名前引きできるようになっているはずです.

⑤ リバースプロキシの設定

リバースプロキシとしては,Ingress NGINX Controller を使うことにします.

Ingress NGINX Controller の IP アドレスを「192.168.4.250」に固定するため,IP アドレスが1つだけの Pool を設定し,Ingress NGINX Controller にはそのプールから IP アドレスを取得するようにします.

具体的な設定としては次の2つを行います.

  • MetalLB に専用のプールを準備
  • Ingress NGINX Controllerの配置
MetalLB に専用のプールを準備

name: ingress-pool な IPAddressPool を定義して,L2Advertisement の ipAddressPools に追加します.

具体的には,次のような YAML を用意して apply します.(一番目の name: ingress-pool な IPAddressPool は既存の pool です)

Ingress NGINX Controllerの配置

まず,下記の Quick Start にある YAML をダウンロードします.

Installation Guide - Ingress-Nginx Controller

ingress-nginx-controller の Service に annotation を追加して,先ほど準備した ingress-pool からアドレスを取得するようにして apply します.

動作確認

ここまできたら,ブラウザで「http://x.kubernetes.green-rabbit.net/」にアクセスしています.今回は NGINX までアクセスできるかの確認が目的なので,「x」部分は何でもOKです.

以下の用に表示されれば,ひとまず OK です.NGINX の設定を何も行っていないので,NGINX が「404 Not Found」と出力するのが期待値です.

Let’s Encrypt による TLS 対応

続いて,NGINX を実際にリバースプロキシ機能させた上で,TLS 対応を行います.

  • cert-manager のインストール
  • Let’s Encrypt を使う ClusterIssuer の設定
  • Ingress の設定

cert-manager のインストール

公式ページに従って,cert-manager.yaml を apply すれば OK.

Installation
Learn about the various ways you can install cert-manager and how to choose between them

Let’s Encrypt を使う ClusterIssuer の設定

次のような YAML を用意して apply します.name: letsencrypt-production で指定した「letsencrypt-production」は ingress の設定の際に使います.

Ingress の設定

例として,次の設定を行うことにします.

  • ネームスペース「ingress-nginx」に Ingress を配置
  • ホスト名は,「grafana.kubernetes.green-rabbit.net」
  • バックエンドは,ネームスペース「server」の grafana サービス

次のような YAML を用意して apply すれば OK.

cert-manager.io/cluster-issuer: letsencrypt-production の「letsencrypt-production」は先ほど ClusterIssuer の設定で使った名前です.

2番目の項目は,ネームスペース跨ぎのために必要な設定です.Ingress と Service は同一ネームスペースにある必要がありるのですが,今回使いたいバックエンドは異なるネームスペースにあります.そこで,Ingress と同じネームスペースに Service を定義して,その中の ExternalName で別のネームスペースのサービスを参照しています.

別のネームスペースの内容は「サービス名.ネームスペース名.svc.cluster.local」で参照できます.

動作確認

設定してからしばらくしてから,「https://grafana.kubernetes.green-rabbit.net」にアクセスします.上手くいっていれば,証明書の警告無くアクセスできるようになっていると思います.

上手くいっていない場合,次のコマンドで cert-manager のログを確認するとヒントを得られると思います.

Google OAuth 認証の設定

やることは次の2つです.

  • クライアントID、クライアントシークレットの取得
  • OAuth2 Proxy の設定
  • Ingress の設定

クライアントID、クライアントシークレットの取得

ざっと流れだけ説明します.

  1. 次の URL にアクセスします.
    Google Cloud Platform
    Google Cloud Platform lets you build, deploy, and scale applications, websites, and services on the same infrastructure ...
  2. 上の方にある,丸が三角形に配置された部分をクリックします.
    ※ 右上に「有効化」と書かれたボタンが現れますが,これは有効化する必要ありません.
  3. 右上にある「新しいプロジェクト」をクリックして,プロジェクトを適当に定義します.
  4. 「OAuth 同意画面」の設定を行います.Google Workspace を使っている場合は「User Type」を「内部」に,そうでない場合は「外部」を選択したうえで「公開ステータス」を「テスト」にして,アクセスできるユーザを限定すると良いです.
  5. 「認証情報」-「認証情報を作成」をクリックして,「OAuth 2.0 クライアント ID」の作成を行います.アプリケーションの種類は「ウェブアプリケーション」にして下記のように設定します.
  6. 作成した OAuth 2.0 クライアント ID の右端にある矢印アイコンをクリックすると,「クライアント ID」と「クライアント シークレット」が表示されますので,コピーします.

OAuth2 Proxy の設定

次のような YAML を用意します.

環境に合わせて,次の箇所は書き換えてください.

  • 名前やラベルの接尾辞.今回 Grafana 用なので「-grafana」を付与しています.
  • --client-id--client-secret の指定は,先ほど入手した「クライアント ID」と「クライアント シークレット」に置き換えます.
  • --cookie-domain--email-domain--whitelist-domain は,お使いのドメインに変更します.
  • --cookie-name は,複数のサイトに個別に認証をつける場合,ユニークになる名前をセットしておくとよいと思います.
  • --cookie-secret は,任意のランダム文字列.文字数の規定がありますので,16文字で指定すると良いと思います.

Ingress の設定

前のステップで設定した Ingress 設定の annotations に「ginx.ingress.kubernetes.io/auth-signin」と「nginx.ingress.kubernetes.io/auth-url」の指定を追加します.これにより,最初にアクセスしたブラウザは,「https://grafana.kubernetes.green-rabbit.net/oauth2/auth」に飛ばされるようになります.

続いて,「https://grafana.kubernetes.green-rabbit.net/oauth2/auth」用の Ingress を設定します.

これにより,先ほど定義した OAuth2 Proxy が使われるようになります.

動作確認

「https://grafana.kubernetes.green-rabbit.net/」にアクセスすると,良く見慣れた Google のログイン画面が表示されると思います.無事にログインできると,本来表示したかったサービスが表示されるはずです.

お疲れさまでした.

参考文献

自宅Kubernetesクラスタはじめました
Ingress と cert-manager の設定を参考にしました.特に MetalLB で専用プールを用意して IP を固定する部分は丸パクリです.
Kubernetes環境における証明書管理の自動化
Ingress と cert-manager の設定が詳しめに解説されています.現時点で情報の鮮度も良さそうです.
Google-OAuth2 With Kubernetes Nginx Controller
Google の OAuth2 との連携させる方法はここをベースにしています.ただ,少し情報古いかも.
External OAUTH Authentication
Ingress-Nginx Controller 公式の,外部 OAuth 認証の解説ページです.
単なる OAuth 2.0 を認証に使うと、車が通れるほどのどでかいセキュリティー・ホールができる
OAuth 2.0 のフローと技術的な弱点が分かりやすく解説されています.
OAuth 2.0 + OpenID Connect のフルスクラッチ実装者が知見を語る
OAuth 2.0 と OpenID Connect の関係がなんとなく見えてきます.この記事ではでてきてないですが,Google の OpenID Connect に準拠した OAuth 2.0 を使うと,Google 基準のバリバリのリスクベース認証の恩恵に預かれるというメリットがでかいと個人的には思います.

コメント