はじめに
「API Gatewayを分けるべきか(以下API GW)」 という問題について考えてみる。
定義:外部APIと内部API
https://qiita.com/ktdatascience/items/edeb87386e7e3f295698 の記事が非常に参考になったのでこれをベースに考えてみる。
-
内部API(Internal API)
- サービス間通信
- VPC内・組織内ネットワーク
- 比較的信頼できる環境だが、ゼロトラストの考え方で認証は必要
-
外部API(External API)
- クライアント(Web / モバイル / パートナー)向け
- 組織外から不特定多数にアクセスされる
- 厳格なアクセス制御が必要
↓表は参考記事のものをパクり
| 項目 | 内部API | 外部API |
|---|---|---|
| アクセス範囲 | 組織内のみ | 不特定多数 |
| 信頼レベル | 比較的高い | 低い |
| 認証の厳格さ | 中〜高 | 高 |
| レート制限 | 緩やか | 厳格 |
| ドキュメント | 内部向け | 詳細な公開ドキュメント |
| 変更の影響 | 限定的 | 広範囲 |
| バージョニング | 柔軟 | 厳格な管理が必要 |
内部API GWと外部API GWに必要な機能
外部からのアクセスは外部API GWと内部API GW両方を通る前提。内部からのアクセスは内部API GWのみを通る前提。
認証・認可
外部API GW は当然ながら、ゼロトラストの考え方から 内部API GW にも認証は必要。
認可はクライアントが何を許可されるかなので、実行するAPIを制御するには 外部API GW に必要。一方でドメインのロジックやリソースの状態に依存する(=ビジネス要件に引っ張られる)制御は不要。API側でやるべき。
流量制御
流量制御を行う目的。他にもあるかも。
- (D)DoS
- 基本的に外部のケースしか考えられないので 外部API GW
- 不正利用防止
- これも同様に 外部API GW
- クライアント制御
- クライアントによって呼び出し回数に制限をかける。これも 外部API GW
- サービスの過負荷防止(カスケード障害防止)
- これはサービス→サービスを考えると 内部API GW でかける必要がある
WAF
BOT対策とかSQLインジェクション対策とか。外側からの攻撃なので 外部API GW。
リクエスト / レスポンス変換
ヘッダーの付与やフォーマット変換程度なら 外部API GW。内部で呼び出す場合は既存サービスの都合も考えるとクライアント側で調整した方が良い。ドメインのロジックやリソースの状態に依存する(=ビジネス要件に引っ張られる)変換は不要。API側でやるべき。
ログ / 監視
可観測性からどちらも必要だが、 外部API GW はセキュリティの観点。内部API GWは障害・性能の観点。
サーキットブレーカー
カスケード障害のためなので 内部API GW。
リトライ制御
一時障害の制御なので 内部API GW。
タイムアウト制御
スレッド枯渇防止なので 内部API GW。
ロードバランシング
インスタンス分散で 内部API GW。
まとめ
整理するとこうなる。
| 項目 | 内部API GW | 外部API GW |
|---|---|---|
| 認証 | 〇 | 〇 |
| 認可 | - | 〇 |
| 流量制御 | 〇 | 〇 |
| WAF | 〇 | 〇 |
| リクエスト / レスポンス変換 | - | 〇 |
| ログ / 監視 | 〇 | 〇 |
| サーキットブレーカー | 〇 | - |
| リトライ制御 | 〇 | - |
| タイムアウト制御 | 〇 | - |
| ロードバランシング | 〇 | - |
内部API GWと外部API GWを分けるとどうなるか?
本題。内部API GWと外部API GWを分けるべきか?あるいは一緒でもいいんじゃないか問題。
結論、将来的に考えると分ける一択。最初は一緒でも...と思うけど最初に作っちゃうと分離しづらいよね。
内部API GWと外部API GWを分けるメリット。
統合APIの作成
複数の内部APIを組み合わせて一つの外部APIのエンドポイントとして提供することができる。サービス間連携するとかサービス内で色々処理して...と疑似的に同じことはできるが、外部APIとしての事情がサービスへ影響するのは避けたい。外部API GW -> BFF -> 内部API GW -> サービス など、統合APIは呼び出すクライアント側の事情であることは守りたい。提供する側に統合API作るレベルの要件があるというならそれはもう新しい別口のAPIのはず。
統合APIを作る需要がなければこれはメリットにならないが、エンタープライズのAPIはわりとありそう。統合APIを作るメリットはここでは割愛。
信頼境界
外部API GWと内部API GWを分けることで、信頼の境界ができる。逆に考えたとき、API GWが一つだと、そのAPI GWがすべての通信を最大の力で監視する必要がある。APIが増えれば増えるほどそのコストは無視できないものになる。もちろん小規模なAPIではあまりこのメリットはないが、組織横断で進めるAPI施策においては、未来に次々増える内部API GW側がシステム責務に集中することができる。
障害時
単一のAPI GWだとそこが単一障害点となる。分離することで外部API GWが障害の場合に内部処理のみ続行...や内部API GWやサービスが障害の場合にあらかじめ定めておいた別処理へ割り振る...などできる。
負荷分散
単一のAPI GWだと負荷が集中した場合にすべてのクライアントからの処理が遅くなる。分離することで外部からの呼び出しのみ抑えることで内部からの呼び出し、またはすでに内部で行われている処理をスムーズに続行させることができる。
内部API GWと外部API GWを分けるデメリット。
障害点
分離することで 外部API GW -> 内部API GW 間やそれぞれのGWで障害が発生する可能性はあるためどこが原因か気にする箇所が増える。単一のAPI GWだとある意味一か所なのでそこだけ見ればよいが、原因を探すことは困難。
コスト
エンタープライズだとこれは一番大きい気がする。
単一のAPI GWなら運用対象も少ないため、要員やそれにかかる金銭的なコストが少なく済む。
一方で、将来的にAPI GWを増やす場合にかかるコストは外部API GWと内部API GWを分けるよりもかかる。そのあたりはユースケースとその計算次第。
理解までの時間
単一のAPI GWだと
- 構成が直感的
- 学習コスト低い
- デバッグしやすい
=>つまりエンタープライズだと上司や周囲に説明しやすい
分離することで少なくとも今までのような話を説明する必要がある。
内部API GWと外部API GWを分けた上で外部API GWのみ通すパターン
つまりこういう下図のパターンD。
一応パターン分け
| 1 | 2 | 3 |
|---|---|---|
| 内部API GW通る | 外部API通る | パターン |
| A, E | ||
| 〇 | B | |
| 〇 | 〇 | C |
| 〇 | D |
パターンA, E 内部API GWも外部API GWも通らないパターン
API GWを通らないので論外。
パターンB 内部API GWのみ通るパターン
先ほどまでの話の組織内からのパターン。何も問題なし。
パターンC 内部API GWも外部API GWも通るパターン
先ほどまでの話の組織外からのパターン。何も問題なし。
パターンD 外部APIのみ通るパターン
先ほどの表にあった内部API GWの項目を捨てる or 外部API GWへ組み込むことになる。エンタープライズAPIであることを考えると捨てるのはあり得ないと思う。外部API GWに組み込むとどうなるかというのは前述の通り。つまりそこが許容できるなら組み込んでもよいと思う。
| 項目 | 内部API GW | 外部API GW |
|---|---|---|
| 認証 | 〇 | 〇 |
| 認可 | - | 〇 |
| 流量制御 | 〇 | 〇 |
| WAF | 〇 | 〇 |
| リクエスト / レスポンス変換 | - | 〇 |
| ログ / 監視 | 〇 | 〇 |
| サーキットブレーカー | 〇 | - |
| リトライ制御 | 〇 | - |
| タイムアウト制御 | 〇 | - |
| ロードバランシング | 〇 | - |
最後に
今までの経験からの自分の中での整理なので、他の人の考えも知りたい。
