[AWS CDK] grantメソッドでAWS Glueテーブルのパーミッションを付与する

2023.01.24

こんにちは、CX事業本部 IoT事業部の若槻です。

AWS CDKのドキュメントを見ていると、Glue table constructに次のようなメソッドが用意されていました。

Name Description
grant(grantee, actions) Grant the given identity custom permissions.
grantRead(grantee) Grant read permissions to the table and the underlying data stored in S3 to an IAM principal.
grantReadWrite(grantee) Grant read and write permissions to the table and the underlying data stored in S3 to an IAM principal.
grantToUnderlyingResources(grantee, actions) Grant the given identity custom permissions to ALL underlying resources of the table.
grantWrite(grantee) Grant write permissions to the table and the underlying data stored in S3 to an IAM principal.

このgrant**というメソッドを使えば、Glue tableに対するread/writeなどのパーミッション付与を簡潔に行うことができそうです。

試してみた

grantReadを使用して、AWS Step Functions state machineに、Glue TableにAthenaクエリを実行ための権限を付与してみます。

環境作成

一連のリソースの作成はAWS CDKで行います。

CDK App初回作成。

mkdir cdk_sample_app && cd cdk_sample_app
npx cdk init sample-app --language typescript

なお、aws-cdk-libaws_glueは現状L1 Constructまでしか対応していません。なので続けて@aws-cdk/aws-glue-alphaを導入しようとしましたが、Conflictが発生。以前のバージョンではすんなり入ったはずなのに...。

$ npm i @aws-cdk/aws-glue-alpha

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: cdk_sample_app@0.1.0
npm ERR! Found: aws-cdk-lib@2.56.0
npm ERR! node_modules/aws-cdk-lib
npm ERR!   aws-cdk-lib@"2.56.0" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer aws-cdk-lib@"^2.61.1" from @aws-cdk/aws-glue-alpha@2.61.1-alpha.0
npm ERR! node_modules/@aws-cdk/aws-glue-alpha
npm ERR!   @aws-cdk/aws-glue-alpha@"*" from the root project
npm ERR! 
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR! 
npm ERR! See /Users/wakatsuki.ryuta/.npm/eresolve-report.txt for a full report.

バージョンを確認するとなぜかaws-cdk-libaws-cdkが最新版の2.61.1より古いバージョンが入っていたので最新化した上でならすんなり導入できました。

$ npm i aws-cdk-lib@latest aws-cdk@latest

changed 5 packages, and audited 330 packages in 7s

30 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
$ npm i @aws-cdk/aws-glue-alpha@latest

up to date, audited 330 packages in 2s

30 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

Glue tableのパーミッションを付与しない場合

CDKでstate machineを構成する場合は、タスクの実行に必要なパーミッションを自動作成してくれます。これはAthenaクエリ実行タスク(AthenaStartQueryExecution)に関してもそうなのですが、一方でクエリ先のGlue tableの権限までは自動付与してくれません。(ただし後述の通りdefault databaseについては付与されます。)

それを踏まえてまずはGlue tableのパーミッションを付与しない場合を試してみます。次のCDK stackを作成します。

lib/cdk_sample_app-stack.ts

import { Construct } from 'constructs';
import {
  aws_s3,
  aws_athena,
  aws_stepfunctions,
  aws_stepfunctions_tasks,
  RemovalPolicy,
  Stack,
  StackProps,
} from 'aws-cdk-lib';
import * as glue_alpha from '@aws-cdk/aws-glue-alpha';

export class CdkSampleStack extends Stack {
  constructor(scope: Construct, id: string, props: StackProps) {
    super(scope, id, props);

    // データソース格納バケット
    const dataBucket = new aws_s3.Bucket(this, 'dataBucket', {
      bucketName: `data-${this.account}-${this.region}`,
      removalPolicy: RemovalPolicy.DESTROY,
    });

    // Athenaクエリ結果格納バケット
    const athenaQueryResultBucket = new aws_s3.Bucket(
      this,
      'athenaQueryResultBucket',
      {
        bucketName: `athena-query-result-${this.account}-${this.region}`,
        removalPolicy: RemovalPolicy.DESTROY,
      }
    );

    // Glueデータベース
    const glueDataBase = new glue_alpha.Database(this, 'glueDataBase', {
      databaseName: 'glue_data_base',
    });

    // Glueテーブル
    const glueTable = new glue_alpha.Table(this, 'glueTable', {
      tableName: 'glue_table',
      database: glueDataBase,
      bucket: dataBucket,
      s3Prefix: 'data/',
      dataFormat: glue_alpha.DataFormat.JSON,
      columns: [
        {
          name: 'id',
          type: glue_alpha.Schema.STRING,
        },
        {
          name: 'count',
          type: glue_alpha.Schema.INTEGER,
        },
      ],
    });

    // Athenaワークグループ
    const athenaWorkGroup = new aws_athena.CfnWorkGroup(
      this,
      'athenaWorkGroup',
      {
        name: 'athenaWorkGroup',
        workGroupConfiguration: {
          resultConfiguration: {
            outputLocation: `s3://${athenaQueryResultBucket.bucketName}/result-data`,
          },
        },
        recursiveDeleteOption: true,
      }
    );

    // Athenaクエリ実行(同期実行)
    new aws_stepfunctions_tasks.AthenaStartQueryExecution(
      this,
      'startAthenaQueryExecutionTask',
      {
        queryString: `SELECT * FROM ${glueDataBase.databaseName}.${glueTable.tableName}`,
        workGroup: athenaWorkGroup.name,
        integrationPattern: aws_stepfunctions.IntegrationPattern.RUN_JOB,
      }
    );
  }
}

CDKデプロイしてリソースを作成します。

npx cdk deploy "*" --require-approval never

作成されたIAM policyのステートメントは次のようになりました。

stateMachineRoleDefaultPolicy9579E9AD

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "athena:getDataCatalog",
                "athena:getQueryExecution",
                "athena:startQueryExecution"
            ],
            "Resource": [
                "arn:aws:athena:ap-northeast-1:XXXXXXXXXXXX:datacatalog/AwsDataCatalog",
                "arn:aws:athena:ap-northeast-1:XXXXXXXXXXXX:workgroup/athenaWorkGroup"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "lakeformation:GetDataAccess",
                "s3:AbortMultipartUpload",
                "s3:CreateBucket",
                "s3:GetBucketLocation",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:ListBucketMultipartUploads",
                "s3:ListMultipartUploadParts",
                "s3:PutObject"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "glue:BatchCreatePartition",
                "glue:BatchDeletePartition",
                "glue:BatchDeleteTable",
                "glue:BatchGetPartition",
                "glue:CreateDatabase",
                "glue:CreatePartition",
                "glue:CreateTable",
                "glue:DeleteDatabase",
                "glue:DeletePartition",
                "glue:DeleteTable",
                "glue:GetDatabase",
                "glue:GetDatabases",
                "glue:GetPartition",
                "glue:GetPartitions",
                "glue:GetTable",
                "glue:GetTables",
                "glue:UpdateDatabase",
                "glue:UpdatePartition",
                "glue:UpdateTable"
            ],
            "Resource": [
                "arn:aws:glue:ap-northeast-1:XXXXXXXXXXXX:catalog",
                "arn:aws:glue:ap-northeast-1:XXXXXXXXXXXX:database/default",
                "arn:aws:glue:ap-northeast-1:XXXXXXXXXXXX:table/default/*",
                "arn:aws:glue:ap-northeast-1:XXXXXXXXXXXX:userDefinedFunction/default/*"
            ],
            "Effect": "Allow"
        }
    ]
}

最初の2つはAthena workgroupの利用に必要なパーミッションです。3つ目はデフォルトのGlue databaseおよびその中に作成されたtableに対するパーミッションです。今回はGlue databaseおよびtableをCDKで独自に作成しているためこの記述では権限が不足してしまいそうです。

作成されたstate mmachineを実行すると、Glue tabelへのパーミッション不足によりAthena queryがエラーとなりました。想定通りの動作です。

Glue tableのパーミッションを付与した場合

Stack定義を次のように修正します。grantReadメソッドでGlue tableへの読み取りパーミッションをstate machineに付与しています。

    // State Machine
    const stateMachine = new aws_stepfunctions.StateMachine(
      this,
      'stateMachine',
      {
        stateMachineName: 'stateMachine',
        definition: startAthenaQueryExecutionTask,
      }
    );

    // Glue tableの権限付与
    glueTable.grantRead(stateMachine);

CDKデプロイすると、IAM policyのステートメントに次の記述が追加されました。独自に作成したGlue tableに対する権限が付与されていますね。

stateMachineRoleDefaultPolicy9579E9AD

        {
            "Action": [
                "glue:BatchGetPartition",
                "glue:GetPartition",
                "glue:GetPartitions",
                "glue:GetTable",
                "glue:GetTableVersion",
                "glue:GetTableVersions",
                "glue:GetTables"
            ],
            "Resource": "arn:aws:glue:ap-northeast-1:XXXXXXXXXXXX:table/glue_data_base/glue_table",
            "Effect": "Allow"
        },
        {
            "Action": [
                "s3:GetBucket*",
                "s3:GetObject*",
                "s3:List*"
            ],
            "Resource": [
                "arn:aws:s3:::data-XXXXXXXXXXXX-ap-northeast-1",
                "arn:aws:s3:::data-XXXXXXXXXXXX-ap-northeast-1/data/*"
            ],
            "Effect": "Allow"
        }

これで十分な権限を付与できてかと思いましたが、Glue databaseに対する権限が不足していました。

Glue databaseに関しても独自に作成している場合は権限の付与が必要なるようです。tableに対するgrantだけではよろしくやってくれないのですね。

仕方がないのでGlue databaseのみ明示的に権限を付与します。

    // Glue databaseの権限付与
    stateMachine.role.addToPrincipalPolicy(
      new aws_iam.PolicyStatement({
        actions: ['glue:Get*'],
        effect: aws_iam.Effect.ALLOW,
        resources: [glueDataBase.databaseArn],
      })
    );

今度こそstate machineの実行を成功させられました。

まとめ

  • Athena workgroupの権限はstate machineリソースの作成時に暗黙的に付与される
  • Glue tableの権限はgrantReadで簡潔に付与できる
  • Glue databaseの権限はaddToPrincipalPolicyなどで明示的に付与が必要

grantメソッドは万能ではなく必要に応じて個別の権限付与は必要でしたが、便利なことには変わりないので有効活用して行きたいです。

参考

以上