🍪

Istio環境下で、cookieデータをもとにアクセス制限を設定する

2022/06/30に公開

はじめに

株式会社イエソドでインフラ管理を担当しています@Omasumasuです。

Istio は Envoy の機能を利用して、アクセス制限をかけることができます。
設定方法については公式ドキュメントに詳しく記載されているので確認してみてください。

Envoy を使用しているということは、Envoy の機能をフル活用してアクセス制限の条件を設定することが可能です。
今回はそれを利用して cookie データをもとにアクセス制限をかける設定を紹介します。
Istio と envoy のバージョンにはズレがあるので誤った設定を避けるためにも、まずは Istio が動作している環境の envoy proxy のバージョンを確認してから envoy のドキュメントを読むようにしましょう。

環境

Istio 1.13.2
envoy 1.21.2-dev

RateLimit.Action.HeaderValueMatch について

RateLimit.Action.HeaderValueMatchとは RateLimitAction のうちの一つであり、これを指定することによって一致する条件を持ったヘッダーがあるかによってアクセス制御を行うことができます。
例として actions に以下のような設定をした場合

header_value_match:
  descriptor_value: "api-path"
  expect_match: true
  headers:
    - name: ":path"
      prefix_match: "/api/"

リクエストのパスの先頭が/api/であるリクエストが来た際に、指定した descriptor_key(デフォルトは header_match)と descriptor_value を Ratelimit service に投げます。
これを利用すれば、cookie の値によってアクセス制御をかけることは可能ですが cookie 内の情報を正規表現一つで表現するのは管理が複雑になり現実的ではありません。

Dynamic Metadata について

Dynamic Metadataは動的なメタデータで、必要な情報を様々な filter においてリクエストやレスポンスに付与することができるものです。
記録されたメタデータはアクセスログに出力することができたり、他の filter によって取り出して利用したりすることも可能です。

Header-To-Metadata Filter について

Header-To-Metadata Filterはヘッダーの値を取り出し、Dynamic Metadata として情報を付与することができる http_filters の一種です。
これを指定することによって cookie が持つ情報を個別に metadata として付与することができます。
以下の例はリクエストに対して、x-user という cookie が存在したら envoy.lb という namespace に user という key で Dynamic Metadata を記録するという filter です。

name: envoy.header_metadata
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.header_to_metadata.v3.Config
request_rules:
  - cookie: x-user
    on_header_present:
      metadata_namespace: envoy.lb
      key: user
      type: STRING
    remove: false

Dynamic metadata が正しく記録されているか確認をしたければIstio のアクセスログフォーマットを修正して出力して確認すると良いです。

RateLimit.Action.MetaData について

RateLimit.Action.MetaDataは RateLimitAction のうちの一つであり、これを指定することによって一致するメタデータを Ratelimit service に指定した key で送ることが可能です。
以下の例は user という Dynamic Metadata を user という descriptor_key で Ratelimit service へデータを転送するためのアクションです。

metadata:
  metadata_key:
    key: cookie
    path:
      - key: user
  descriptor_key: user
  source: "DYNAMIC"

組み合わせてアクセス制限をかける

ここまで紹介したものを組み合わせることによって Cookie にのっている情報を利用してアクセス制限をかけることができます。
以下の例では x-user というユニークなユーザー識別子 cookie を利用して 1 ユーザーあたりごとのアクセス制限を設定します。
まずは、Header-To-Metadata Filter をEnvoyFilterリソースを使って GATEWAY に対して http_filters を追加してあげます。

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: header-to-meta-filter
spec:
  workloadSelector:
    labels:
      istio: ingressgateway
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: GATEWAY
        listener:
          filterChain:
            filter:
              name: "envoy.http_connection_manager"
              subFilter:
                name: "envoy.router"
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.filters.http.header_to_metadata
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.filters.http.header_to_metadata.v3.Config
            request_rules:
              - cookie: x-user
                on_header_present:
                  metadata_namespace: cookie
                  key: user
                  type: STRING
                remove: false

次に RateLimit.Actions をEnvoyFilterリソースを使って VIRTUAL_HOST に対して rate limit action を設定します。

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: filter-ratelimit-svc
spec:
  workloadSelector:
    labels:
      istio: ingressgateway
  configPatches:
    - applyTo: VIRTUAL_HOST
      match:
        context: GATEWAY
        routeConfiguration:
          vhost:
            name: "XXXX"
            route:
              action: ANY
      patch:
        operation: MERGE
        value:
          rate_limits:
            - actions:
                - metadata:
                    metadata_key:
                      key: cookie,
                      path:
                        - key: user
                    descriptor_key: user,
                    source: "DYNAMIC"

これによって cookie 内の x-user の情報が descriptor_key: user として Ratelimit service に送られるようになります。
あとは Ratelimit service の ConfigMap を設定することによってアクセス制限が動作するようになります。

apiVersion: v1
kind: ConfigMap
metadata:
  name: ratelimit-config
  namespace: rate-limit
data:
  config.yaml: |
    domain: ratelimit
    descriptors:
      - key: USERID
        rate_limit:
          unit: minute
          requests_per_unit: 100

この設定によって cookie 内のユーザ識別子データ x-user ごとに 1 分間 100 回までのリクエストしか受け付けないように設定ができます。

おわりに

cookie のデータを利用することでアクセス制限条件に柔軟性を持たせることができます。
今回の例では一つの cookie のみを使用して設定をしていますが、複数の cookie や cookie と別情報を組み合わせてアクセス制限を設定することも可能です。

株式会社イエソドはエンジニアを募集しています

https://herp.careers/v1/yesodco/5yQcbvDulNfy

https://herp.careers/v1/yesodco/9SKtd3pNgxfO

Discussion