[AWS CDK] Amazon QuickSight で Athena の Dataset を作成してみた
こんにちは、CX 事業本部 IoT 事業部の若槻です。
前回のエントリでは Amazon QuickSight のコンソールから Athena の Dataset を作成してみました。(そして数々のエラーに遭遇しとてもハマりました。)
今回は、AWS CDKで QuickSight の Athena の Dataset を作成してみました。また作成するのは前回と同様既存のユーザーがアクセスがアクセス可能な Dataset とします。
やってみた
ざっくりと次のような手順で実装を行いました。
- データソースとなる Resource の CDK Deploy
- データソースとなる Resource のアクセス権限を既存のユーザーに手動設定
- QuickSight の Dataset となる Resource の CDK Deploy
実装
AWS CDK v2(TypeScript)で Stack の記述を作成します。
まずデータソースとなる Glue Table およびデータ格納用 S3 Bucket を作成する Stack です。
import { Construct } from 'constructs'; import { aws_s3, Stack, StackProps, RemovalPolicy } from 'aws-cdk-lib'; import * as glue_alpha from '@aws-cdk/aws-glue-alpha'; export class AwsAppStack extends Stack { public readonly glueDatabase: glue_alpha.Database; public readonly glueTable: glue_alpha.Table; constructor(scope: Construct, id: string, props: StackProps) { super(scope, id, props); // データ格納バケット const dataBucket = new aws_s3.Bucket(this, 'dataBucket', { removalPolicy: RemovalPolicy.DESTROY, }); // Glueデータベース const glueDatabase = new glue_alpha.Database(this, 'glueDatabase', { databaseName: 'glue_database', }); this.glueDatabase = glueDatabase; // 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.FLOAT, }, { name: 'area', type: glue_alpha.Schema.STRING, }, ], }); this.glueTable = glueTable; } }
次に、QuickSight の Datasource および Dataset を作成する Stack です。Dataset の Resource にはpermissions
を設定し、既存のユーザーが Dataset にコンソールからアクセスできるようにしています。
import { Construct } from 'constructs'; import { aws_quicksight, Stack, StackProps } from 'aws-cdk-lib'; import * as glue_alpha from '@aws-cdk/aws-glue-alpha'; interface ProcessStackProps extends StackProps { userName: string; glueDatabase: glue_alpha.Database; glueTable: glue_alpha.Table; } export class ProcessStack extends Stack { constructor(scope: Construct, id: string, props: ProcessStackProps) { super(scope, id, props); // QuickSightデータソース const quickSightAthenaDataSource = new aws_quicksight.CfnDataSource( this, 'quickSightAthenaDataSource', { awsAccountId: this.account, dataSourceId: 'quickSightAthenaDataSource', name: 'quickSightAthenaDataSource', type: 'ATHENA', dataSourceParameters: { athenaParameters: { workGroup: 'primary', }, }, } ); // QuickSightデータセット new aws_quicksight.CfnDataSet(this, 'quickSightAthenaDataSet', { name: 'quickSightAthenaDataSet', awsAccountId: this.account, dataSetId: 'quickSightAthenaDataSet', physicalTableMap: { quickSightAthenaDataSetPhysicalTableMap: { relationalTable: { dataSourceArn: quickSightAthenaDataSource.attrArn, catalog: 'AwsDataCatalog', schema: props.glueDatabase.databaseName, name: props.glueTable.tableName, inputColumns: [ { name: 'id', type: 'STRING', }, { name: 'count', type: 'DECIMAL', }, { name: 'area', type: 'STRING', }, ], }, }, }, logicalTableMap: { quickSightAthenaDataSetPhysicalTableMap: { alias: props.glueTable.tableName, source: { physicalTableId: 'quickSightAthenaDataSetPhysicalTableMap', }, }, }, importMode: 'SPICE', permissions: [ { principal: `arn:aws:quicksight:${this.region}:${this.account}:user/default/${props.userName}`, actions: [ 'quicksight:PassDataSet', 'quicksight:DescribeIngestion', 'quicksight:CreateIngestion', 'quicksight:UpdateDataSet', 'quicksight:DeleteDataSet', 'quicksight:DescribeDataSet', 'quicksight:CancelIngestion', 'quicksight:DescribeDataSetPermissions', 'quicksight:ListIngestions', 'quicksight:UpdateDataSetPermissions', ], }, ], }); } }
App 層ではAwsAppStack
からProcessStack
へ Glue の Resource を渡しています。
#!/usr/bin/env node import 'source-map-support/register'; import * as cdk from 'aws-cdk-lib'; import { ProcessStack } from '../lib/process-stack'; import { AwsAppStack } from '../lib/aws-app-stack'; const app = new cdk.App(); const userName = app.node.tryGetContext('userName'); const awsAppStack = new AwsAppStack(app, 'AwsAppStack', {}); new ProcessStack(app, 'ProcessStack', { userName: userName, glueDatabase: awsAppStack.glueDatabase, glueTable: awsAppStack.glueTable, });
まずデータソース側の Stack を CDK Deploy します。
cdk deploy AwsAppStack
デプロイに成功したら、QuickSight access to AWS servicesを開きます。
[Amazon Athena]が未チェックであればチェックを入れます。
[Amazon Athena permissions]のダイアログが出たら[Skip]をクリックして閉じます。
[Select S3 buckets]をクリック。
先程 CDK Deploy で作成した Bucket にチェックを入れ、[Finish]をクリック。
[Save]をクリックしてアクセス権限の変更を保存します。
ここでManage usersコンソールにて Dataset を利用可能としたい既存のユーザーの Username を確認します。
Context に Username を指定して、QuickSight の Datasource および Dataset を CDK Deploy で作成します。
cdk deploy ProcessStack -c userName=${USER_NAME}
デプロイに成功したら、コンソールのDatasetsを見ると、Dataset が作成されていることが確認できました!
ここでデータソースの Bucket に次の JSON ファイルをアップロードします。
{"id":"u001","count":3,"area":"Shinjuku"} {"id":"u001","count":1,"area":"Akihabara"} {"id":"u002","count":5,"area":"Ikebukuro"} {"id":"u002","count":2,"area":"Akihabara"} {"id":"u003","count":4,"area":"Shinjuku"}
aws s3 cp data1.json s3://${BUCKET_NAME}/data/data1.json
Dataset を開いて Refresh すると、レコードが読み込めています!
おわりに
AWS CDK で QuickSight の Athena の Dataset を作成して、既存のユーザーで使えるようにしてみました。
最初 CDK Stack で Dataset の Permission を設定していなかったため、作成されたはずの Dataset が既存のユーザーでコンソールから見れなくて焦りました。QuickSight ではコンソールにサインインするユーザーに権限を明示的に付与するということを CDK で実装する場合は意識する必要がありました。
以上