背景・目的
前回の記事ではDefinition APIを使ってダッシュボードを作成・更新しました。
本記事では、QuickSight Asset Bundle APIを使ってアセットのエクスポート/インポートを試します。
Asset Bundleは、ダッシュボードとその依存関係(データセット・データソース)をまとめてエクスポートし、別環境にインポートできる機能です。
本記事では以下を試します。
- 既存ダッシュボードをAsset Bundleとしてエクスポート
- エクスポートされたファイルの中身を確認
- CloudFormation形式でもエクスポートして比較
- 別IDでインポートして環境移行を模擬
まとめ
| 項目 | 内容 |
|---|---|
| Asset Bundleとは | アセット(ダッシュボード+依存リソース)の定義をまとめてエクスポート/インポートする機能。実データや認証情報は含まれない |
| エクスポート形式 | QUICKSIGHT_JSON(.qs zip、リソースごとに分割)と CLOUDFORMATION_JSON(1ファイルのCFnテンプレート) |
| include-all-dependencies | 指定したアセットが依存するリソース(データセット・データソース・VPC接続)を自動的に含める |
| PrefixForAllResources | 同一アカウント内で複製する場合、全リソースIDにプレフィックスを付けて新規作成する |
| ダウンロードURL | 署名付きURL(5分有効)。期限切れたらdescribeで再取得可能 |
| Body指定 | fileb:// は使えない。Base64エンコードして渡す |
| 権限 | エクスポート時に --include-permissions を付けないとインポート先で権限なし。別途付与が必要 |
| Definition APIとの違い | Definition APIは「作る・直す」、Asset Bundleは「運ぶ・管理する」 |
概要
Asset Bundleとは
下記を基に整理します。
QuickSightのアセット(ダッシュボード・データセット・データソース等)をまとめてエクスポート/インポートする機能です。
- エクスポートされるのはアセットの定義(設定情報)のみで、実データや認証情報は含まれません
- 用途として下記のようなものが考えられます
- dev環境で作ったダッシュボードをprod環境に持っていく
- アカウント間のアセット移行
- バックアップ
- CloudFormationテンプレートとしてIaC化
Definition APIとAsset Bundleの違い
前回、利用したDefinition APIとの違いを簡単にまとめます。
| Definition API | Asset Bundle | |
|---|---|---|
| やること | ダッシュボード1個の中身を編集 | 複数アセットをまとめて移動 |
| ユースケース | 開発・修正(ビジュアル追加、計算式変更) | デプロイ・移行・管理(dev→prod、バックアップ) |
| 対象 | 単一アセット | 複数アセット+依存関係 |
| 形式 | JSON(直接指定) | .qs zip or CloudFormation |
エクスポートされるファイルの中身
.qsファイル(zip)
├── ダッシュボードの定義
├── データセットの定義(どのテーブルのどの列を使うか)
├── データソースの定義(接続先情報)
├── 権限情報(オプション)
└── タグ情報(オプション)
APIの流れ
エクスポート
StartAssetBundleExportJob(非同期開始)
↓
DescribeAssetBundleExportJob(ポーリング)
↓
成功 → ダウンロードURL取得 → .qs zipダウンロード
インポート
StartAssetBundleImportJob(.qsファイル指定)
↓
DescribeAssetBundleImportJob(ポーリング)
↓
成功 → アセットが作成/更新される
実践
前提
- AWS CLIを使用
- QuickSight Enterprise Editionを利用
- リージョン: ap-northeast-1
- 前回作成したダッシュボード(api-test-dashboard-001)をエクスポート対象とする
シナリオ1: QUICKSIGHT_JSON形式でエクスポート
エクスポート
1. start-asset-bundle-export-job によりエクスポートジョブを開始します
aws quicksight start-asset-bundle-export-job \
--aws-account-id ${AWS_ACCOUNT_ID} \
--asset-bundle-export-job-id export-001 \
--resource-arns '["arn:aws:quicksight:ap-northeast-1:${AWS_ACCOUNT_ID}:dashboard/api-test-dashboard-001"]' \
--include-all-dependencies \
--export-format QUICKSIGHT_JSON \
--region ap-northeast-1
---
json
{
"Status": 202,
"Arn": "arn:aws:quicksight:ap-northeast-1:${AWS_ACCOUNT_ID}:asset-bundle-export-job/export-001",
"AssetBundleExportJobId": "export-001"
}
- asset-bundle-export-job-id: 任意のIDを付けられる
- include-all-dependencies: 指定したアセットが依存するリソースを自動的に一緒にエクスポートするオプション
- データセットやデータソースも含めて抽出します
- export-format:出力の形式
- QUICKSIGHT_JSON:.qs zip(QS独自のJSON)
- CLOUDFORMATION_JSON:CFnテンプレート(JSON)
2. ステータスを確認します。SUCCESSFULになっていました
aws quicksight describe-asset-bundle-export-job \
--aws-account-id ${AWS_ACCOUNT_ID} \
--asset-bundle-export-job-id export-001 \
--region ap-northeast-1
---
{
"Status": 200,
"JobStatus": "SUCCESSFUL",
"DownloadUrl": "https://quicksight-asset-bundle-export-job-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/...",
"AssetBundleExportJobId": "export-001",
"ResourceArns": [
"arn:aws:quicksight:ap-northeast-1:${AWS_ACCOUNT_ID}:dashboard/api-test-dashboard-001"
],
"IncludeAllDependencies": true,
"ExportFormat": "QUICKSIGHT_JSON",
"IncludePermissions": false,
"IncludeTags": false
}
- asset-bundle-export-job-id:要求時に指定したID
- レスポンス
- DownloadUrl:AWS管理しているS3のURLが返される(presigned URL)。有効期限は300秒のようです
- IncludePermissions:false。権限情報無しでエクスポートしています。そのためインポートする場合は別途付与する必要があります
3. ダウンロードURLから .qs ファイルを取得します
curl -o export-001.qs 'https://quicksight-asset-bundle-export-job-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/・・・'
4. ダウンロードできました
ls -la /XXXXX/export-001.qs
-rw-r--r--@ 1 XXXXX XXXXX 2271 Jun 7 21:10 /XXXXXX/export-001.qs
エクスポートされたファイルの中身を確認
1. 展開して確認します
unzip export-001.qs -d export-001-extracted
2. 下記のような構成になっていました
export-001-extracted/
├── dashboard/api-test-dashboard-001.json
├── dataset/monthly-sales-summary.json
├── datasource/redshift-dev.json
└── vpcConnection/qs-redshift-vpc-conn.json
dashboard/api-test-dashboard-001.json
1. ビジュアル・レイアウトの定義が確認できました
{
"resourceType": "dashboard",
"dashboardId": "api-test-dashboard-001",
"name": "API Test Dashboard",
"definition": {
"dataSetIdentifierDeclarations": [
{"identifier": "my_dataset", "dataSetArn": "arn:aws:quicksight:ap-northeast-1:${AWS_ACCOUNT_ID}:dataset/monthly-sales-summary"}
],
"sheets": [{
"sheetId": "sheet-1",
"name": "Sheet 1",
"visuals": [{
"tableVisual": {
"visualId": "table-visual-1",
"title": {"visibility": "VISIBLE", "formatText": {"plainText": "Monthly Sales Summary"}},
"chartConfiguration": {
"fieldWells": {
"tableUnaggregatedFieldWells": {
"values": [
{"fieldId": "sales_month", "column": {"dataSetIdentifier": "my_dataset", "columnName": "sales_month"}},
{"fieldId": "category", "column": {"dataSetIdentifier": "my_dataset", "columnName": "category"}},
{"fieldId": "region", "column": {"dataSetIdentifier": "my_dataset", "columnName": "region"}},
{"fieldId": "quantity", "column": {"dataSetIdentifier": "my_dataset", "columnName": "quantity"}},
{"fieldId": "revenue", "column": {"dataSetIdentifier": "my_dataset", "columnName": "revenue"}}
]
}
}
}
}
}],
"layouts": [{"configuration": {"gridLayout": {"elements": [{"elementId": "table-visual-1", "elementType": "VISUAL", "columnSpan": 36, "rowSpan": 12}]}}}]
}]
},
"validationStrategy": {"mode": "LENIENT"}
}
dataset/monthly-sales-summary.json
1. テーブル・列情報、インポートモードが確認できました
{
"resourceType": "dataset",
"dataSetId": "monthly-sales-summary",
"name": "Monthly Sales Summary",
"physicalTableMap": {
"salesTable": {
"relationalTable": {
"dataSourceArn": "arn:aws:quicksight:ap-northeast-1:${AWS_ACCOUNT_ID}:datasource/redshift-dev",
"schema": "dm",
"name": "monthly_sales_summary",
"inputColumns": [
{"name": "sales_month", "type": "INTEGER"},
{"name": "category", "type": "STRING"},
{"name": "region", "type": "STRING"},
{"name": "quantity", "type": "INTEGER"},
{"name": "revenue", "type": "DECIMAL", "subType": "FIXED"}
]
}
}
},
"importMode": "SPICE"
}
datasource/redshift-dev.json
1. 接続先ホスト・ポート・DB名、認証のSecret ARNが確認できました
{
"resourceType": "datasource",
"dataSourceId": "redshift-dev",
"name": "Redshift Dev",
"type": "REDSHIFT",
"dataSourceParameters": {
"redshiftParameters": {
"host": "${REDSHIFT_ENDPOINT}",
"port": XXXX,
"database": "${REDSHIFT_DB}"
}
},
"vpcConnectionProperties": {
"vpcConnectionArn": "arn:aws:quicksight:ap-northeast-1:${AWS_ACCOUNT_ID}:vpcConnection/qs-redshift-vpc-conn"
},
"credentials": {
"secretArn": "arn:aws:secretsmanager:ap-northeast-1:${AWS_ACCOUNT_ID}:secret:${SECRET_NAME}"
}
}
vpcConnection/qs-redshift-vpc-conn.json
1. サブネット、SG、IAMロールが確認できました
{
"resourceType": "vpcConnection",
"vpcConnectionId": "qs-redshift-vpc-conn",
"name": "QS to Redshift VPC Connection",
"subnetIds": ["subnet-xxx", "subnet-yyy", "subnet-zzz"],
"securityGroupIds": ["sg-xxx"],
"roleArn": "arn:aws:iam::${AWS_ACCOUNT_ID}:role/service-role/aws-quicksight-service-role-v0"
}
シナリオ2: CLOUDFORMATION_JSON形式でエクスポートして比較
エクスポート
- CloudFormation形式でエクスポートします
aws quicksight start-asset-bundle-export-job \
--aws-account-id ${AWS_ACCOUNT_ID} \
--asset-bundle-export-job-id export-cfn-001 \
--resource-arns '["arn:aws:quicksight:ap-northeast-1:${AWS_ACCOUNT_ID}:dashboard/api-test-dashboard-001"]' \
--include-all-dependencies \
--export-format CLOUDFORMATION_JSON \
--region ap-northeast-1
---
{
"Status": 202,
"Arn": "arn:aws:quicksight:ap-northeast-1:${AWS_ACCOUNT_ID}:asset-bundle-export-job/export-cfn-001",
"AssetBundleExportJobId": "export-cfn-001"
}
- export-format:CLOUDFORMATION_JSON。CFnのフォーマットを指定します
2. ステータスを確認します。SUCCESSFUL になりました
aws quicksight describe-asset-bundle-export-job \
--aws-account-id ${AWS_ACCOUNT_ID} \
--asset-bundle-export-job-id export-cfn-001 \
--region ap-northeast-1
---
{
"Status": 200,
"JobStatus": "SUCCESSFUL",
"DownloadUrl": "https://quicksight-asset-bundle-export-job-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/...",
"ExportFormat": "CLOUDFORMATION_JSON"
}
3. ダウンロードします。今回はzipではなく単一のJSONファイル(9,252 bytes)になります
curl -o export-cfn-001.json '<DownloadUrl>'
エクスポートされたファイルの中身を確認
エクスポート結果の確認(CloudFormation形式)
1. QUICKSIGHT_JSON形式とは異なり、1つのCloudFormationテンプレートとして出力されます。
{
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters": {
"qsredshiftvpcconnSecurityGroupId0": {
"Default": "sg-xxx",
"Description": "SecurityGroupId0 for vpcConnection:qs-redshift-vpc-conn",
"Type": "String"
},
"qsredshiftvpcconnSubnetId0": {
"Default": "subnet-xxx",
"Type": "String"
},
"redshiftdevSecretArn": {
"Default": "arn:aws:secretsmanager:ap-northeast-1:${AWS_ACCOUNT_ID}:secret:${SECRET_NAME}",
"Type": "String"
}
},
"Resources": {
"apitestdashboard001": {
"Type": "AWS::QuickSight::Dashboard",
"Properties": {
"AwsAccountId": {"Fn::Sub": "${AWS::AccountId}"},
"DashboardId": "api-test-dashboard-001",
"Name": "API Test Dashboard",
"Definition": {
"DataSetIdentifierDeclarations": [{
"DataSetArn": {"Fn::GetAtt": ["monthlysalessummary", "Arn"]},
"Identifier": "my_dataset"
}],
"Sheets": [{"..."}]
}
}
},
"monthlysalessummary": {
"Type": "AWS::QuickSight::DataSet",
"Properties": {
"AwsAccountId": {"Fn::Sub": "${AWS::AccountId}"},
"DataSetId": "monthly-sales-summary",
"Name": "Monthly Sales Summary",
"ImportMode": "SPICE",
"PhysicalTableMap": {
"salesTable": {
"RelationalTable": {
"DataSourceArn": {"Fn::GetAtt": ["redshiftdev", "Arn"]},
"Schema": "dm",
"Name": "monthly_sales_summary",
"InputColumns": [
{"Name": "sales_month", "Type": "INTEGER"},
{"Name": "category", "Type": "STRING"},
{"Name": "region", "Type": "STRING"},
{"Name": "quantity", "Type": "INTEGER"},
{"Name": "revenue", "Type": "DECIMAL", "SubType": "FIXED"}
]
}
}
}
}
},
"redshiftdev": {
"Type": "AWS::QuickSight::DataSource",
"Properties": {
"AwsAccountId": {"Fn::Sub": "${AWS::AccountId}"},
"DataSourceId": "redshift-dev",
"Name": "Redshift Dev",
"Type": "REDSHIFT",
"DataSourceParameters": {
"RedshiftParameters": {
"Host": "${REDSHIFT_ENDPOINT}",
"Port": XXXX,
"Database": "${REDSHIFT_DB}"
}
},
"Credentials": {
"SecretArn": {"Fn::Sub": "${redshiftdevSecretArn}"}
},
"VpcConnectionProperties": {
"VpcConnectionArn": {"Fn::GetAtt": ["qsredshiftvpcconn", "Arn"]}
}
}
},
"qsredshiftvpcconn": {
"Type": "AWS::QuickSight::VPCConnection",
"Properties": {
"AwsAccountId": {"Fn::Sub": "${AWS::AccountId}"},
"Name": "QS to Redshift VPC Connection",
"VPCConnectionId": "qs-redshift-vpc-conn",
"RoleArn": {"Fn::Sub": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/aws-quicksight-service-role-v0"},
"SecurityGroupIds": [{"Fn::Sub": "${qsredshiftvpcconnSecurityGroupId0}"}],
"SubnetIds": [{"Fn::Sub": "${qsredshiftvpcconnSubnetId0}"}, "..."]
}
}
}
}
形式の比較
シナリオ1と2でエクスポートにより抽出したJSON形式について、比較します
| QUICKSIGHT_JSON | CLOUDFORMATION_JSON | |
|---|---|---|
| ファイル形式 | .qs zip(リソースごとに分割JSON) | 1つのCFnテンプレート(JSON) |
| サイズ | 2,271 bytes | 9,252 bytes |
| リソース参照 | ARN直書き | Fn::GetAtt でリソース間を参照 |
| 環境差分 | インポート時にOverrideParametersで上書き | CFn Parametersで上書き |
| アカウントID | ハードコード | ${AWS::AccountId} で自動解決 |
| デプロイ方法 | start-asset-bundle-import-job | aws cloudformation deploy |
シナリオ3:別IDでインポートして環境移行を模擬
先ほどエクスポートした .qs ファイルを別のダッシュボードIDでインポートしてみます。
インポート
1. Base64エンコードしてBodyに渡してインポートします
BODY_B64=$(base64 -i export-001.qs)
aws quicksight start-asset-bundle-import-job \
--aws-account-id ${AWS_ACCOUNT_ID} \
--asset-bundle-import-job-id import-005 \
--asset-bundle-import-source "{\"Body\":\"$BODY_B64\"}" \
--override-parameters '{"ResourceIdOverrideConfiguration":{"PrefixForAllResources":"copy-"}}' \
--region ap-northeast-1
---
{
"Status": 202,
"AssetBundleImportJobId": "import-005"
}
2. ステータスを確認します。 SUCCESSFUL になりました
aws quicksight describe-asset-bundle-import-job \
--aws-account-id ${AWS_ACCOUNT_ID} \
--asset-bundle-import-job-id import-005 \
--region ap-northeast-1
---
{
"JobStatus": "SUCCESSFUL",
"OverrideParameters": {
"ResourceIdOverrideConfiguration": {
"PrefixForAllResources": "copy-"
}
}
}
3. 権限を付与して確認します。copy-api-test-dashboard-001 として作成されていました
aws quicksight update-dashboard-permissions \
--aws-account-id ${AWS_ACCOUNT_ID} \
--dashboard-id copy-api-test-dashboard-001 \
--grant-permissions '[{
"Principal": "arn:aws:quicksight:ap-northeast-1:${AWS_ACCOUNT_ID}:user/default/${QS_USER_NAME}",
"Actions": ["quicksight:DescribeDashboard","quicksight:QueryDashboard","quicksight:ListDashboardVersions"]
}]' \
--region ap-northeast-1
---
{
"Status": 200,
"DashboardId": "copy-api-test-dashboard-001"
}
4. list-dashboards で確認します。copy-api-test-dashboard-001 が作成されています
aws quicksight list-dashboards \
--aws-account-id ${AWS_ACCOUNT_ID} \
--region ap-northeast-1
---
{
"DashboardSummaryList": [
{
"DashboardId": "api-test-dashboard-001",
"Name": "API Test Dashboard",
"PublishedVersionNumber": 2,
"CreatedTime": "2026-06-07T15:16:22+09:00"
},
{
"DashboardId": "copy-api-test-dashboard-001",
"Name": "API Test Dashboard",
"PublishedVersionNumber": 1,
"CreatedTime": "2026-06-07T22:34:22+09:00"
}
]
}
マネージメントコンソールで確認
1. AWSで確認します
2. ダッシュボードが2つありました。所有者はその他になっています

4. URLを見ると、dashboards/copy-api-test-dashboard-001となっていました
考察
- Asset Bundle APIを使えば、ダッシュボードとその依存リソースをまとめてエクスポート/インポートできることを確認した
- CLOUDFORMATION_JSON形式でエクスポートすると、Fn::GetAtt によるリソース間参照や Parameters による環境差分の外出しが自動生成されるため、手書きなしでIaC化できる
- 同一アカウント内で複製する場合、OverrideParametersの DashboardId ではIDを変更できない。PrefixForAllResources を使う必要がある点はドキュメントから読み取りにくく、ハマりやすい
- インポート後に権限が付与されない問題は、Definition API の create-dashboard と同じ。QS CLIの共通のハマりポイントとして認識しておくべき
- Body パラメータで fileb:// が使えず、Base64エンコードが必要だった
参考
