LoginSignup
10
0

複数のシステムで Amazon Athena を堅牢かつ柔軟に管理する

Last updated at Posted at 2023-12-12

はじめに

  • 複数の AWS アカウントにまたがる複数のシステムが存在する
  • システム間で共通のテーブル構造を Athena で用いたい
  • ただ、お互いのシステムがお互いの管理するデータを参照するリスクは排除したい
  • 今後もシステムが増えていくことが予定されている

このような要件があるシステム群においての秘匿性および柔軟性の高いアーキテクチャを考えてみました。
当記事ではアーキテクチャの留意点やソースコードを踏まえつつまとめます。

前提

複数の AWS アカウントは1つの Organizations に属しているものとします。

サンプルコード

下記リポジトリをご参照ください。以降は当リポジトリのコードに基づいて解説をしていきます。

アーキテクチャ

中央アカウントに Athena で用いるデータバケットを用意します。
各システムアカウントに対しては後述の構成要素のリソースを AWS CloudFormation および AWS CloudFormation StackSets で展開することで AWS アカウント・システムが増える場合のスケーラビリティを確保します。

architecture.png

構成要素

上記のアーキテクチャの構成要素をそれぞれ説明します。

ユニークな要素

当アーキテクチャにおいて1つだけ必要な要素になります。
リポジトリのコードとしては 00-unique.yaml です。

  • Amazon S3 - Bucket
    Athena で利用するデータソース、およびクエリ実行結果ファイルの保管に用います。
    S3 バケットの第一階層はテーブル名(および出力結果フォルダ)、第二階層はシステム名に対応します。

    • バケット構成
      athena-sample-bucket
         ├── table-1/System-1/
         ├── table-1/System-2/
         ├── table-1/System-3/
         ├── table-2/System-1/
         ├── table-2/System-2/
         ├── table-2/System-3/
         ├── output/System-1/
         ├── output/System-2/
         └── output/System-3/
      

アカウント単位の要素

当アーキテクチャにおいて AWS アカウントごとに1つだけ必要な要素になります。
リポジトリのコードとしては 01-account.yaml です。
AWS CloudFormation StackSets で Organizations 内の AWS アカウントに展開されるものとします。
(当記事では StackSets の管理・展開方法については割愛します)

  • AWS Glue - Database
    複数の AWS Glue - Table の管理に用います。

  • AWS Glue - Table
    テーブルの構造、データの参照を管理します。
    テーブルは原則システムごとにパーティション化されます。

  • AWS IAM - Policy
    後述の AWS IAM - Role のアタッチするポリシーとして用います。
    ポリシー記述内で ${aws:PrincipalTag/System} などと記述することで IAM ロールに付与された System タグの値に応じてアクセス制御が可能となります。

    'arn:aws:s3:::${BucketName}/*/${aws:PrincipalTag/System}/*' 
    

システム単位の要素

当アーキテクチャにおいてシステムごとに1つだけ必要な要素になります。
リポジトリのコードとしては 02-system.yaml です。
AWS CloudFormation で展開されるものとします。

  • AWS Glue - Partition
    テーブルのパーティションに用います。
    システムごとの S3 バケットに保管されているデータ参照先を管理します。

  • Amazon Athena - Workgroup
    ワークグループ単位での実行履歴の管理やクエリ実行時の実行結果ファイルの保管に用います。
    システムごとの実行結果ファイルの保管先を管理します。
    s3://${S3Bucket}/output 配下にシステムごとに実行結果が出力されるように設定します。

  • AWS IAM - Role
    Attribute based access control (ABAC) を用いて、IAM ロールのタグに基づいた S3 バケットに対するアクセス制御に用います。
    システムに付与されたタグの値を含む S3 バケットのパスのみアクセス可能な状態を担保します。

このアーキテクチャのねらい

S3 を1つだけ用意することで、すべてのシステムのデータを1つのバケットに集約します。
S3 を参照するシステムとはクロスアカウントとなるので、明示的なバケットポリシーでの許可が必要となります。

以下の通りのバケットポリシーを S3 バケットに設定することで同じ Organizations に属する AWS アカウントの指定のロールからのアクセスを許可します。

(抜粋)00-unique.yaml
Statement:
  - Action:
      - s3:GetBucketLocation
      - s3:GetObject
      - s3:ListBucket
      - s3:ListBucketMultipartUploads
      - s3:ListMultipartUploadParts
      - s3:AbortMultipartUpload
      - s3:PutObject
    Condition:
      StringEquals:
        aws:PrincipalOrgID:
          - !Ref OrganizationID
      StringLike:
        aws:PrincipalArn:
          - arn:aws:iam::*:role/SystemAccess*
    Effect: Allow
    Principal: '*'
    Resource:
      - !Sub 'arn:aws:s3:::${S3Bucket}'
      - !Sub 'arn:aws:s3:::${S3Bucket}/*'

ただ、このままでは各システムが横断的に S3 のファイルにアクセスできてしまうため、データの秘匿性を確保できません。そこで、下記のコードのようにシステムが利用する IAM ポリシーにて S3 の参照できるパスを制御します。

${aws:PrincipalTag/System} によって IAM ロールに付与される System タグによって、参照できるパスを動的に変えることが可能になります。

(抜粋) 01-account.yaml
Statement:
  - Action:
      - s3:GetBucketLocation
      - s3:GetObject
      - s3:ListBucket
      - s3:ListBucketMultipartUploads
      - s3:ListMultipartUploadParts
      - s3:AbortMultipartUpload
      - s3:PutObject
    Effect: Allow
    Resource:
      - !Sub 'arn:aws:s3:::${BucketName}'
      - !Join
        - ''
        - - 'arn:aws:s3:::'
          - !Ref BucketName
          - '/*/${aws:PrincipalTag/System}/*'

システムが受け持つ IAM ロールに上記のポリシーをアタッチした上で作成し、そのロールに対して System タグを付与します。
これにより例えば、システム1 が利用する IAM ロールの System タグの値が System-1 であれば、s3://${BucketName}/*/System-1/* のみ参照可能な状態を構築することができます。

実際に Athena でクエリを実行する際は system パーティションに具体的な値を指定して実行することで、S3 の適切なロケーションに保管されているデータに対してクエリすることが可能です。

sample-athena-ok.sql
SELECT * FROM sample_table WHERE system = 'System-1';

success-system-1.png

この場合、システム1 においては s3://${BucketName}/*/System-1/* 配下のファイルしか参照をすることができず、システム2 が管理する s3://${BucketName}/*/System-2/* 配下のファイルを参照しようとすると IAM ポリシーにより拒否されます。

sample-athena-ng.sql
SELECT * FROM sample_table WHERE system = 'System-2';

fail-system-2.png

実際にシステム1 の権限を用いて、システム2 が管理するデータに対してクエリを実行すると参照権限が不足しており、クエリ実行結果の確認ができません。

また、パーティション未指定でのクエリに対しても参照権限の不足により失敗してしまいます。

fail-all.png

これらの権限管理により、システム間ではお互いのデータを参照することができず、データの参照リスクを排除することができます。

おわりに

当記事ではシステムごとに制御としていますが、ユーザーごとやアカウントごと、またはリージョンごとといった任意の分け方にも応用できるかと思います。

また、当記事では触れませんでしたが、特定の管理者がシステム横断的にデータを分析するケースがある場合は、横断的に S3 バケットを参照する権限を付与したロールを特定の管理者に付与した上で、パーティションを未指定でクエリを実行することで、全システムのデータを横断的に解析することが可能になります。

success-all.png

Amazon Athena を利用するにあたっての構成に悩んでいる方の参考になれば幸いです。

参考文献

10
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
0