LayerX エンジニアブログ

LayerX の エンジニアブログです。

マイクロサービス環境における Amazon OpenSearch Serverless のポリシー設計 #LayerXテックアドカレ

バクラク事業部 Platform Engineering 部の uehara です。

この記事は LayerX テックアドカレ (概念) の45日目で、昨日は y_matsuwitter の「LayerXののびしろ、2023年を振り返る」でした。

今回は、バクラクで導入した Amazon OpenSearch Serverless の設計について紹介します。

バクラクでは全文検索エンジンとして OpenSearch を利用しており、2023年に Serverless が正式リリースされたことを受け、今後は Serverless を積極的に活用する方針となりました。

Amazon OpenSearch Serverless とは

その名の通り OpenSearch のサーバレス版で、スケールイン・スケールアウトが自動で行われるためインスタンスタイプやディスクのキャパシティ管理が不要となるサービスです。

従来の OpenSearch ではドメインという単位でリソースを管理していましたが、Serverless ではコレクションと呼ばれる単位で管理します。
データは全て暗号化される仕様で、コレクション作成時に指定した暗号化キーが使用されます。

リソースは OCU (OpenSearch Capacity Unit) 単位でスケールし、コレクションには最低 4 OCU (インデックス作成用 x 2, 検索用 x 2) が必要です。東京リージョンの OCU 単価は $0.334 / hour のため、最低でも月額 975 ドルが掛かる計算となります。

OCU はリージョンおよび暗号化キーが同一であれば複数のコレクションで共有されます。
暗号化キーが異なる場合は共有されないため、新たに 4 OCU が必要です。

バクラクにおける OpenSearch Serverless の利用方針

バクラクでは OpenSearch を利用するサービスが複数存在することを考慮し、2つの案を検討しました。

  • (A) サービスごとにコレクションと暗号化キーを分離する
    • KMS レベルでデータを完全に分離できる
    • OCU の総数が増えるため毎月のコストが増大する
  • (B) サービスごとにコレクションを分離し暗号化キーは共有する
    • OCU の利用効率が高まりコストメリットが大きい
    • 他サービスのデータへアクセスさせないための適切な制御が必要

今後もサービスが増えていくことを考慮すると、A 案ではコスト面が大きな懸念でした。B 案と比べると数倍以上のコストを要する試算です。

公式ドキュメントを中心に調査した結果、OpenSearch Serverless のデータアクセスポリシーで十分なアクセス制御を行えると判断し、今回は B 案を採用しました。

これらの検討結果や背景は ADR (Architecture Decision Record) として社内ドキュメントに残してあります。

データアクセスポリシーの設計

上記の方針を踏まえて、データアクセスポリシーは以下の設計としました。

  • サービス (Principal) ごとに専用のアクセスポリシーを作成
  • 命名規則としてコレクション名にはサービス名を用いる
  • 自サービスのコレクションおよび配下のインデックスのみアクセスを許可

アクセスポリシー例

[
  {
    "Principal": [
      "<ecs-task-role-arn>"
    ],
    "Rules": [
      {
        "Permission": [
          "aoss:DescribeCollectionItems",
          "aoss:CreateCollectionItems",
          "aoss:UpdateCollectionItems"
        ],
        "Resource": [
          "collection/<service-id>"
        ],
        "ResourceType": "collection"
      },
      {
        "Permission": [
          "aoss:DescribeIndex",
          "aoss:ReadDocument",
          "aoss:CreateIndex",
          "aoss:UpdateIndex",
          "aoss:WriteDocument",
          "aoss:DeleteIndex"
        ],
        "Resource": [
          "index/<service-id>/*"
        ],
        "ResourceType": "index"
      }
    ]
  }
]

命名規則によりサービスを識別し、マッチするリソースのみ操作を許可することで、他サービスへのデータアクセスを防ぎます。

データアクセスポリシーはコレクションと紐づかない独立したリソースで複数作成できるため、サービス (Principal) ごとに専用ポリシーを作成しています。

ポリシー生成の効率化

データアクセスポリシーが今後も増えていくことを見据えて、Terraform module を用意することでポリシー生成を効率化しています。

必要なパラメータを渡すことでポリシー JSON を生成できるほか、ADR で定めた「他サービスのデータへのアクセスを防ぐ」するバリデーションも実装しました。今後は semgrep のルールとしても追加予定です。

resource "aws_opensearchserverless_access_policy" "xxxx" {
  name   = var.service_id
  type   = "data"
  policy = module.aoss_data_access_policy_document.json
}
module "aoss_data_access_policy_document" {
  source          = "../../modules/aoss-data-access-policy-document"
  collection_name = var.service_id
  index_name      = "*"
  role            = "writer"
  principals      = ["arn:aws:iam::123456789012:role/zzzz"]
}

この module を用いることで、前述のようなポリシー JSON を容易に生成できます。

余談ですが、データアクセスポリシーのポリシー名は32文字までしか指定できないため注意が必要です。AWS さんぜひ緩和をお願いします!

まとめ

マイクロサービス環境における Amazon OpenSearch Serverless の設計例について紹介しました。

暗号化キーを共通化することで OCU の利用効率を高めてコストを抑えられますが、アクセス制御を適切に行うためのポリシー設計も重要となってきます。

LayerX のアドカレはまだまだ続きます。 明日は noritama さんの記事です。お楽しみに!