Elastic Cloudの特権アカウント共用から脱却!

Elastic Cloud

はじめに

こんにちは、SRE部 検索基盤SREブロックの花房です。普段は、ZOZOTOWNの検索関連マイクロサービスにおけるQCD改善やインフラ運用を担当しています。

以前まで、検索基盤を支えるチームではElastic Cloudの特権アカウントをメンバーで共用していました。本記事では、2023年4月にリリースされたElastic CloudのRBAC(Role-Based Access Control)機能を活用して、特権アカウントの共用から脱却した取り組みについて紹介します。さらに、既存機能と組み合わせることで実現した、効率的な権限管理についても紹介します。

同様の課題を抱えている読者の方には、下記の部分で参考になれば幸いです。

  • Elastic CloudにおけるSSOの活用
  • Elastic CloudのRBACによる権限管理の実例
  • Elastic Cloudアカウント情報を利用した、ElasticsearchのRole Mappingによる権限管理の実例

目次

背景・課題

Elastic Cloudの利用方法

ZOZOTOWNの検索基盤では、大規模な商品データを扱うためにElastic Cloud上のElasticsearch1を利用しています。Elastic Cloudは、ElasticsearchやKibanaなどのElastic製品をクラウド上で利用できるサービスです。検索基盤を支えるチームは、それぞれ担当業務が異なりますが、全チームがElastic Cloudにアクセスします。以下に業務の例を挙げます。

  • Elasticsearchを利用する検索機能の開発
  • ノード数やマシンスペックの増強
  • アラート発生時の調査

一般的に、クラウドサービスへのアクセスはメンバーそれぞれのアカウントを使用すべきです。さらに、そのアカウントには担当業務にあった権限セット(以降、Roleと表します)を付与します。このように管理することで、情報漏洩などのセキュリティ上のリスクを防ぐことができます。しかし、本記事の取り組みを実施するまで、私たちは特権アカウントを共用してElastic Cloudにログインしていました。その状態を下記の図に示します。

改善前のElastic Cloud権限管理

何故、特権アカウントを共用していたか

Elastic Cloudの利用を開始した当初、登録できるアカウントは1つまでという制限があったため、やむを得ず特権アカウントを共有していました。

特権アカウントを使用すると、Elasticsearchクラスタの管理を担うDeploymentに対して全ての操作が可能です。そのため、特権アカウントの共用は誤操作による重大な事故を引き起こすリスクがありました。例えば、誤って本番環境のクラスタを削除してしまうことが考えられます。

そこで、操作頻度が高くリスクも大きいDeployment管理にはIaC化を施しました。IaC化により、管理画面からDeploymentを変更・削除する機会をなくすことで事故を防いでいました。こちらのIaC化の詳細については、以前の記事を参照ください。

techblog.zozo.com

その後、Elastic Cloudのアップデートにより、Organizationへのアカウント追加が可能になりました。しかし、全てのアカウントに管理者権限が付与されてしまうため、細かい権限管理はできませんでした。以上の理由から特権アカウントの共用が続いていました。

権限管理における課題

これまでに説明した利用方法の問題を整理します。

  • アカウントの共有によるセキュリティ上のリスク
  • 誤操作により重大な事故を引き起こす可能性について、対策を施していたが排除はできていない

上記の問題は、単純にメンバーごとにアカウントを分離すれば解決できそうに思います。しかし、アカウント分離について下記の課題があり、状況は変わりませんでした。

  • チームに合ったRoleを柔軟に設定できない
  • メンバーごとのアカウントを新たに作成する場合、アカウント管理が大きなトイルになる

以降では、上記の問題・課題の解決方法と、改善後の権限管理について説明します。

解決策

Elastic Cloudの権限管理

2023年4月、Elastic CloudのRBAC機能がリリースされました。この機能を利用すると、Organizationへ招待したメンバーに対して細かく権限を設定できます。

私たちは、この機能を利用することで特権アカウントの共用から脱却できました。

Organization RBACの利用

Elastic CloudのRBACでは、用意されたRole(以降、Cloud Role2と表します)をメンバーに付与して権限を管理します。Cloud Roleには下記の5つが存在します。

  • Organization owner
  • Billing admin
  • Admin
  • Editor
  • Viewer

私たちは、Deployment操作の制限のためにAdminとViewerを使用しています。そのため、今回はその2種類のみ紹介します。その他のCloud Roleの説明は、公式ドキュメントをご確認ください。

Cloud Role 説明
Admin Deploymentの作成や、プロパティ管理、セキュリティ権限の管理が可能
Viewer Deploymentの閲覧が可能

AdminとViewerは、Deployment単位で設定可能です。私たちは、SREチームに全DeploymentのAdmin、バックエンドチームやMLチームには全DeploymentのViewerを設定しています。このように設定している理由は、バックエンドやMLチームの誤操作による事故を防ぐためです。

Deployment管理と同様に、OrganizationのRBACもIaC化したいと考えていました。しかし、Organization機能がTerraformに対応していないため、今回は断念しました。現在は手動で権限を管理していますが、下記の理由から保守は難しくなく問題にはなっていません。

  • 検索基盤を支えるチームは合計20人程度
  • 設定するCloud Roleは、AdminまたはViewerの2種類のみ

SSOによるアカウント管理の省略

RBACのためには、利用メンバーごとにアカウントを分ける必要があります。しかし、新たにElastic Cloudアカウントを作成すると、管理者側と利用者側の両方でアカウント管理がトイルになります。そこで、Elastic CloudへのSSOログインに会社管理のGoogleアカウントを用いるようにしました。

GoogleアカウントでのSSOにより、アカウント管理のトイルを削減できました。招待作業は残りますが、退職時の削除作業やパスワード変更は不要になります。退職時は会社側でGoogleアカウントが削除されるため、自動的にElastic Cloudにもログイン不可になります。また、利用者はElastic Cloud用にアカウントを使い分ける手間がなくなりました。会社管理のGoogleアカウントは、Elastic Cloud以外にも様々なサービスで普段利用しているため、統一することで利便性の向上にも繋がりました。

SSOを利用するために特別なことは必要ありません。通常のアカウントと同様に、Organizationに招待する際、Roleを付与した上でGoogleアカウントのメールアドレスに招待メールを送るだけです。利用者は招待メールからログイン画面に進み、GoogleアカウントでSSOログインするとOrganizationに参加できます。

ここまで説明した改善により、Elastic Cloudへのアクセス方法は下記の図のようになりました。

Organization RBAC利用後のElastic Cloud権限管理

Elastic Cloudアカウントを利用したElasticsearchの権限管理

Elastic Cloudアカウントは、Elasticsearchへのアクセスにも利用可能です。直接アクセスするのではなく、クラスタに紐づくKibanaを通してGUIでアクセスします。Deploymentの管理画面からKibanaにアクセスすると自動的にログインされますが、下記のようなログイン画面が表示されることもあります。その場合は下側の Login in with Elastic Cloud を選択してください。

一方、Elastic CloudとElasticsearchは権限管理の仕組みが分かれているため、Cloud RoleではElasticsearchの権限を定義できません。それらを関連付けるため、Elastic Cloudのアカウント情報を利用した設定がElasticsearchのRole Mappingに標準で追加されました。Role MappingはElasticsearch内のRBACを実現する機能で、以前から存在しました。

その追加された設定では、Elastic Cloudアカウントでのアクセス時、Cloud Roleに対応するElasticsearchのRoleを付与します(以降、Default Mapping3と表します)。この設定のように、Elastic Cloudのアカウント情報はElasticsearchから参照可能になっています。

以下では、Default Mappingと、私たちが追加したSSOアカウントに対するRole Mappingについて説明します。

Cloud Roleに対するRole Mapping

Default Mappingが適用されると、Cloud Roleに対応するElasticsearch側のRole(以降、Stack Roleと表します)が付与されます。

Default Mappingにおいて、Stack Roleとして設定されるものはElaticsearch標準のRoleです。AdminとViewerについて、Cloud RoleとStack Roleのマッピング関係を下記に示します。

Cloud Role Stack Role
Admin superuser
Viewer viewer

つまり、アクセスしたDeploymentについて、AdminのCloud Roleを持っていればStack Roleはsuperuserになります。ViewerのCloud Roleを持っていればStack Roleはviewerになります。

私たちは、バックエンドチームやMLチームにCloud RoleとしてViewerを付与しているため、Stack Roleとしてviewerが付与されます。このviewerでは操作が閲覧のみに制限されるため、そのまま利用するにはElasticsearchに関する権限が足りませんでした。バックエンドチームやMLチームは開発において、Index自体やIndex内のドキュメントを編集する必要があるためです。そこで、オリジナルのRoleを作成して適用することにしました。

先に、オリジナルのRoleをRole Mappingで適用する方法を説明します。その後、オリジナルのRoleについて説明します。

SSOアカウントに対するRole Mappingの追加

Elasticsearchにおいて、Elastic Cloudアカウントを対象としてオリジナルのRoleを付与するには、下記の画面のように設定します。

Kibana画面から確認したCustom Mapping

このUser IDを条件とする方法(以降、Custom Mappingと表します)は、Elasticのサポートの方から教えていただきました。User IDはプロフィール画面やOrganization画面から確認できます。

Custom Mappingの説明のため、上記では画面をお見せしました。実際には、私たちはGUIではなくTerraformで管理しています。Elastic CloudのOrganizationはIaC化できませんでしたが、ElasticsearchのRole MappingはIaC化可能でした。公式のプロバイダーelastic/elasticstackを使用して、下記のように設定できます。

resource "elasticstack_elasticsearch_security_role_mapping" "zozo_default_role_mapping" {
  provider = elasticstack.cuslter_1 # Role Mappingを作成するクラスタを指定
  name     = "dev-zozo-default-role-mapping"
  enabled  = true
  roles = [
    # 付与するRoleを指定
    elasticstack_elasticsearch_security_role.zozo_default_role.name
  ]
  rules = jsonencode({
    # Elastic CloudアカウントのUser IDが一致すればRoleを付与
    any = [for user_id in local.all_ec_user_ids : { field = { username = user_id } }]
  })
}

ここで説明したCustom Mappingの追加により、Elaticsearch内においてもアカウントを増やさず、チームごとの詳細な権限管理を実現しました。

ElasticsearchのオリジナルRole

以下では、Custom Mappingで付与するオリジナルのRoleと、そのIaC化について説明します。

共通のRoleと、チームごとのRoleの作成

オリジナルのRoleの権限設計は下記のように進めました。

  1. 各チームに、環境・Deployment・Indexごとに必要な操作をヒアリング
  2. ヒアリング結果の必要な操作と、Cluster Privileges・Index Privilegesとの照らし合わせ
  3. 運用のしやすさを考慮したRole設計

権限設計の結果、オリジナルのRoleとして下記の2種類を作成しました。実際は本番・ステージング・開発の環境ごとに、さらに分かれています。

  1. 全員が最低限必要となる権限をまとめたRole
  2. チームごとに追加で必要となる権限をまとめたRole

1を作成した理由は、各チームが最低限必要となる権限がまとまっていたため、また、チームごとのRoleを冗長にせず管理しやすくするためです。2を作成した理由は、チームごとに権限が欲しいDeploymentやIndexが異なり、共通のRoleにはまとめられない権限が存在したためです。

TerraformによるIaC化

オリジナルのRoleもIaC化が可能であり、Role Mappingと合わせて下記のように設定しています。Indexに対する権限設定では、dynamic blocksを使用して簡素化しています。

# 共通Role
resource "elasticstack_elasticsearch_security_role" "zozo-default-role" {
  provider = elasticstack.cluster_1
  name     = "dev-zozo-default-role"
  cluster  = local.zozo_default_role_cluster_privileges
  dynamic "indices" {
    for_each = local.zozo_default_role_index_privileges
    content {
      names      = indices.value.names
      privileges = indices.value.privileges
    }
  }
}

# 共通RoleのRole Mapping
resource "elasticstack_elasticsearch_security_role_mapping" "zozo_default_role_mapping" {
  provider = elasticstack.cluster_1
  name     = "dev-zozo-default-role-mapping"
  enabled  = true
  roles = [
    elasticstack_elasticsearch_security_role.zozo_default_role.name
  ]
  rules = jsonencode({
    # 全員のElastic CloudアカウントUser IDを条件に指定
    any = [for user_id in local.all_ec_user_ids : { field = { username = user_id } }]
  })
}

# バックエンドチーム用Role
resource "elasticstack_elasticsearch_security_role" "backend_team_role" {
  provider = elasticstack.cluster_1
  name     = "dev-backend-team-role"
  cluster  = local.backend_team_role_cluster_privileges
  dynamic "indices" {
    for_each = local.backend_team_role_index_privileges
    content {
      names      = indices.value.names
      privileges = indices.value.privileges
    }
  }
}

# バックエンドチーム用RoleのRole Mapping
resource "elasticstack_elasticsearch_security_role_mapping" "backend_team_role_mapping" {
  provider = elasticstack.cluster_1
  name     = "dev-backend-team-role-mapping"
  enabled  = true
  roles = [
    elasticstack_elasticsearch_security_role.backend_team_role.name
  ]
  rules = jsonencode({
    # XチームメンバーのElastic CloudアカウントUser IDを条件に指定
    any = [for user_id in local.backend_team_ec_user_ids : { field = { username = user_id } }]
  })
}

local.tfは下記サンプルのように設定しています。

# zozo_default_roleに関する部分のみ抜粋

locals {
  all_ec_user_ids = [
    "1234567890",
    "1234567891",
    "1234567892"
  ]

  zozo_default_role_cluster_privileges = [
    "monitor",
    "monitor_snapshot",
    "manage_index_templates",
    "manage_ilm",
    "manage_slm"
  ]

  zozo_default_role_index_privileges = [
    {
      names      = ["sample-1-*"]
      privileges = ["all"]
    },
    {
      names      = ["sample-2-*"]
      privileges = ["create_snapshot"]
    },
    {
      names      = ["sample-3-*"]
      privileges = [
        "monitor",
        "read",
        "view_index_metadata"
      ]
    }
  ]
}

結果

Elastic Cloudの権限管理は、最終的に下記の図のようになりました。SREチームは、Default MappingによりElasticsearch内でsuperuserが付与されるため、チーム用Roleの設定はありません。

最終的な、改善後のElastic Cloud権限管理

今回の取組みにより、特権アカウント共用による下記の問題が解消されました。

  • アカウントの共有によるセキュリティ上のリスク
  • 誤操作により重大な事故を引き起こす可能性

さらに、SSO対応・Role管理・IaC化を進めたことで下記の効果も得られました。

  • アカウント運用管理により発生するトイルの削減
  • Googleアカウントを用いたSSOログインによる利便性向上
  • RBAC利用による柔軟かつ統一された権限管理の実現
  • IaC化による権限管理の保守性の向上とヒューマンエラーの防止

おわりに

本記事では、Elastic CloudのRBAC機能を活用した、安全・効率的・柔軟な権限管理を紹介しました。

今回の取組みにより、特権アカウントの共用から脱却できました。しかし、下記のようにIaC化出来ていない箇所やリスクを排除できていない課題は残っているため、引き続き改善を進めていきます。

  • Elastic CloudのOrganization機能はTerraform未対応のためIaC化できていないこと
  • マイクロサービスからElasticsearchへはsuperuserでアクセスしており、意図しない動作により関係のないIndexなどを削除してしまう可能性があること

ZOZOでは、一緒にサービスを作り上げてくれる方を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください。

hrmos.co


  1. Elasticsearchはバージョン8.2.3以降を利用しています。
  2. Cloud Roleは正式名称ではありません。公式ドキュメントでは、Elastic Cloud roleと表現されています。本記事では、似た名称であるElastic Stack roleが登場するため、読みやすさを考慮してそれぞれCloud RoleStack Roleと表現しています。
  3. Default Mappingは正式名称ではありません。公式ドキュメントでは、説明の後、the default mappingと表現されています。本記事では、独自に作成したRole Mappingと区別して読みやすくするため、それぞれDefault MappingCustom Mappingと表現しています。
カテゴリー