Envoy を使用して ID Token (OIDC) を検証する

| 6 min read
Author: shigeki-shoji shigeki-shojiの画像

Envoy proxy は API を使って動的に構成すると無停止で設定変更等を行うことができます。このような操作は 通常 Istio や AWS App Mesh のようなコントロールプレーンで行うことになります。

この一連の記事では Envoy proxy 単体の機能を説明するために静的な設定を用いて説明しています。

以前構築した S3 にアクセスする Envoy proxy を拡張して、Amazon Cognito Userpool で認証されたユーザのみがこの静的コンテンツにアクセスできるようにしたいと思います。

図1

Envoy proxy の構成

#

Envoy proxy の定義ファイル (front-envoy.yaml) は次のようになります。

static_resources:
listeners:
- address:
socket_address:
address: 0.0.0.0
port_value: 8080
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: AUTO
stat_prefix: ingress_http
route_config:
name: s3_route
virtual_hosts:
- name: static_web
domains:
- "*"
routes:
- match:
prefix: /
route:
cluster: s3
auto_host_rewrite: true
regex_rewrite:
pattern:
google_re2: {}
regex: '^(.*)\/$'
substitution: '\1/index.html'
http_filters:
- name: envoy.filters.http.jwt_authn
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
providers:
amazoncognito:
issuer: "https://cognito-idp.<REGION>.amazonaws.com/<POOL ID>"
audiences:
- "<CLIENT ID>"
forward_payload_header: jwt-payload
remote_jwks:
http_uri:
uri: "https://cognito-idp.<REGION>.amazonaws.com/<POOL ID>/.well-known/jwks.json"
cluster: jwks
timeout: 5s
cache_duration: 600s
rules:
- match:
prefix: /
requires:
provider_name: amazoncognito
- name: envoy.filters.http.router

clusters:
- name: s3
type: LOGICAL_DNS
dns_lookup_family: V4_ONLY
load_assignment:
cluster_name: s3
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: <BUCKET_NAME>.s3.amazonaws.com
port_value: 443
hostname: <BUCKET_NAME>.s3.amazonaws.com
transport_socket:
name: envoy.transport_sockets.tls
- name: jwks
type: LOGICAL_DNS
dns_lookup_family: V4_ONLY
load_assignment:
cluster_name: jwks
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: cognito-idp.<REGION>.amazonaws.com
port_value: 443
transport_socket:
name: envoy.transport_sockets.tls

admin:
address:
socket_address:
address: 0.0.0.0
port_value: 9901

<> で囲んだプレースホルダーにはそれぞれ利用環境に合わせて設定してください。

OpenID Connect の ID Token を検証するために JWT Authentication フィルターを追加しています。該当部分は次のとおりです。

- name: envoy.filters.http.jwt_authn
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
providers:
amazoncognito:
issuer: "https://cognito-idp.<REGION>.amazonaws.com/<POOL ID>"
audiences:
- "<CLIENT ID>"
forward_payload_header: jwt-payload
remote_jwks:
http_uri:
uri: "https://cognito-idp.<REGION>.amazonaws.com/<POOL ID>/.well-known/jwks.json"
cluster: jwks
timeout: 5s
cache_duration: 600s
rules:
- match:
prefix: /
requires:
provider_name: amazoncognito

Envoy proxy の実装では、OpenID Connect Discovery を経由した JSON Web Key (JWK) の取得はできません。そのため、remote_jwks にキー取得の URI を設定する必要があります。

これに対応して、JSON Web Key を取得するクラスタ設定も必要になります。

- name: jwks
type: LOGICAL_DNS
dns_lookup_family: V4_ONLY
load_assignment:
cluster_name: jwks
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: cognito-idp.<REGION>.amazonaws.com
port_value: 443
transport_socket:
name: envoy.transport_sockets.tls

実行

#

以上の構成を、次のコマンド (nerdctl または docker) で起動することができます。

nerdctl run -it --rm --name envoy -v `pwd`/front-envoy.yaml:/etc/front-envoy.yaml -p 8080:8080 -p 9901:9901 envoyproxy/envoy:v1.21-latest -c /etc/front-envoy.yaml --service-cluster front-proxy

この設定による動作シーケンスの概要は図のようになります。正確に書く場合は、図中の jwks.json の取得は実際には非同期に実行されキャッシュされることに注意してください。

図2

まとめ

#

ここまで説明したとおり、ノーコードで静的コンテンツに対する認証機能の追加ができました。静的コンテンツに限らず、既存の認証機能を持たない API サーバに認証機能を追加する場合も同様の方法で追加することができます。

ここで説明した設定ファイル等は GitHub リポジトリにあります。

参考

#
豆蔵デベロッパーサイト - 先週のアクセスランキング
  1. 自然言語処理初心者が「GPT2-japanese」で遊んでみた (2022-07-08)
  2. Tauri でデスクトップアプリ開発を始める (2022-07-08)
  3. Deno による Slack プラットフォーム(オープンベータ) (2022-09-27)
  4. Jest再入門 - 関数・モジュールモック編 (2022-07-03)
  5. ORマッパーのTypeORMをTypeScriptで使う (2022-07-27)
  6. 第1回 OpenAPI Generator を使ったコード生成 (2022-06-04)
  7. 直感が理性に大反抗!「モンティ・ホール問題」 (2022-07-04)
  8. Rust によるデスクトップアプリケーションフレームワーク Tauri (2022-03-06)
  9. 箱ひげ図で外れ値を確認する (2022-05-18)
  10. Nuxt3入門(第1回) - Nuxtがサポートするレンダリングモードを理解する (2022-09-25)