Dig into the Heroku AppLink (not a deep dive) - サービスメッシュについて

Heroku AppLinkを導入するにあたり、heroku-applink-service-mesh をビルドパックとして追加するようドキュメントに明記されている。
https://devcenter.heroku.com/articles/getting-started-heroku-applink-agentforce#install-the-heroku-applink-buildpack
このサービスメッシュの役割について少し触れてみよう。

サービスメッシュは、Heroku RouterとHerokuアプリケーション(自前で作るアプリケーション)の間に入って、HerokuアプリケーションのAPIを守る役割を持っている。

大まかに言えば以下のような流れとなる。

  1. 外部からのリクエストが、Heroku Routerにやってくる
  2. Heroku Routerがweb dynoに向かってリクエストを転送する
  3. web dynoに組み込まれたサービスメッシュが、リクエスト内容をチェックする
  4. リクエスト内容がokであれば、Herokuアプリケーションにリクエストを転送する
  5. リクエスト内容がngであれば、Heroku Routerに401エラーを返して、Herokuアプリケーションには転送しない

サービスメッシュがリクエスト内容をチェックすることでHerokuアプリケーションのAPIをセキュアにするという仕組みである。

※さらに、リクエスト内容がokの場合、リクエストヘッダに値をセットしてくれるので、Herokuアプリケーション側でsdkを使うと、リクエストヘッダ内の値からアクセストークンが取得できるようになる。結果として、HerokuアプリケーションからもSalesforceへのクエリやデータ操作が可能となる。

Heroku AppLinkの世界では、「外部からのリクエスト」とはSalesforceからのリクエストを想定している。したがって、Salesforceからのリクエストであれば、サービスメッシュ内のプログラムがokと判定(サービスメッシュ内でどのように判定しているのか...その詳細な実装については不明)して、Herokuアプリケーション側の処理が実行される。

こうすることで、Herokuアプリケーション側ではリクエストに対するチェック機構を自前で用意することなく、APIの実装に注力することができる。

これまで、Salesforceの機能拡張としてHerokuアプリケーションを活用しようにも、Herokuアプリケーション側には認証機構が必要だった。
しかし、Heroku AppLinkの世界では、HerokuアプリケーションのAPIへのセキュリティはSalesforceとHerokuが担保してくれるので、自前で認証機構を用意する必要がなくなる、という大きなメリットがある。

Heroku AppLinkを導入すると、Heroku Routerからやってくるリクエストを全てサービスメッシュが一旦受け取って、認証チェックを行う。

構築しているHerokuアプリケーションが、Salesforceからのリクエストのみを受け付けるもの、という前提があるならそれで問題ない。

しかし、特定のAPIは別のWebサービスからのリクエストを処理したい...という場合には非常に困るのである。

例えば、一般公開しているECサイトの商品データを返すAPIと、Salesforceからしか受け付けないAPIを、1つのアプリケーションに同居させたい場合がこれにあたる。
一般公開しているECサイトは、当然ながらSalesforceの認証情報なんぞ持っていない。したがって、そんなサイトからのリクエストはサービスメッシュが拒否してしまい、サイトに商品データを表示することができなくなる。

こんな場合、Herokuアプリケーション側で特定のURLパターンではサービスメッシュをバイパスするよう設定することができる(ようになった)。

1. バイパス用の設定ファイルを設置する

Herokuアプリケーションのrootディレクトリに、heroku-applink-service-mesh.yaml というファイル名で、以下のようなyamlファイルを用意する。
※ファイル名が違うと設定が読み込まれない
バイパスしたいURLパターンや、URLを列挙しておく。

mesh:
  authentication:
    bypassRoutes:
      - "/app/**"
      - "/admin/**"
      - "/auth/**"
      - "/box/**"
      - "/salesforce/**"
      - "/store/**"
      - "/custom/**"
      - "/hooks/**"
      - "/favicon.ico"
      - "/robots.txt"

2. 環境変数を定義する

HEROKU_APPLINK_SERVICE_MESH_ACKNOWLEDGE_RISK_BYPASS という名前の環境変数を用意して、 true をセットする。
バイパスするリスクは認識していることを明示する...という具合だ。

上記の設定が完了してHerokuアプリケーションを起動すると、以下のようなログが出力される。

xxx xx 00:00:00 (heroku app name) app/web.1 level=WARN msg="Authentication bypass routes: /app/**, /admin/**, /auth/**, /box/**, /salesforce/**, /store/**, /custom/**, /hooks/**, /favicon.ico, /robots.txt" app=(heroku app name) source=heroku-applink-service-mesh

そして、バイパスに設定したAPIへのリクエストがあると、以下のようなログが出力され、確かにサービスメッシュの処理がスキップされる。

xxx 00 00:00:00 (heroku app name) app/web.1 level=INFO msg="Processing request to /store/product-categories..." app=(heroku app name) source=heroku-applink-service-mesh request-id=d85d442d-4216-1b1d-9916-312219e76156
xxx 00 00:00:00 (heroku app name) app/web.1 level=WARN msg="Bypassing validation and authentication for route /store/product-categories" app=(heroku app name) source=heroku-applink-service-mesh request-id=d85d442d-4216-1b1d-9916-312219e76156
xxx 00 00:00:00 (heroku app name) app/web.1 level=INFO msg="Forwarding request..." app=(heroku app name) source=heroku-applink-service-mesh request-id=d85d442d-4216-1b1d-9916-312219e76156

もちろん、1つのHerokuアプリケーションに同居させなければ、バイパス設定は不要になるが、もし!どうしても!同居させたい場合にはこういう裏技的な設定が必要になる。

ご利用は計画的に。