AWS IoT TwinMaker によるデジタルツインアプリケーションを AWS CDK で構築する 〜その1 ワークスペース作成編〜

2023.09.24

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

AWS IoT TwinMaker でデジタルツインアプリケーションを構築する際には、下記図のようにいくつかの種類のリソースを組み合わせて作成する必要がありますが、これらの中で最上位のコンテナとなるリソースが下記図の①に該当する ワークスペース (Workspace) です。 What is AWS IoT TwinMaker? - AWS IoT TwinMaker より引用

今回は、AWS IoT TwinMaker によるデジタルツインアプリケーションを AWS CDK で作成する上で、このワークスペース作成する方法と、作成時に遭遇したいくつかのハマりポイントを合わせてご紹介します。

最終的に動作したもの

最終的には以下の CDK コードで、ワークスペースを構築することができました。

lib/cdk-sample-stack.ts

import {
  aws_iam,
  aws_s3,
  aws_iottwinmaker,
  Stack,
  RemovalPolicy,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';

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

    const accounId = this.account;
    const region = this.region;
    const workspaceId = 'CdkDemoWorkspace';

    // ワークスペース用リソース保管バケット
    const workspaceResourceBucket = new aws_s3.Bucket(
      this,
      'WorkspaceResourceBucket',
      {
        removalPolicy: RemovalPolicy.DESTROY,
        autoDeleteObjects: true,
      }
    );

    // IoT TwinMaker ワークスペース実行ロール用プリンシパル
    const principal = new aws_iam.ServicePrincipal(
      'iottwinmaker.amazonaws.com'
    ).withConditions({
      StringEquals: {
        'aws:SourceAccount': accounId,
      },
      StringLike: {
        'aws:SourceArn': `arn:aws:iottwinmaker:${region}:${accounId}:workspace/${workspaceId}`,
      },
    });

    // ワークスペース実行ロール
    const workspaceExecutionRole = new aws_iam.Role(
      this,
      'WorkspaceExecutionRole',
      {
        assumedBy: principal,
        inlinePolicies: {
          readWorkspaceResourceBucket: aws_iam.PolicyDocument.fromJson({
            Version: '2012-10-17',
            Statement: [
              {
                Effect: 'Allow',
                Action: [
                  's3:GetBucket',
                  's3:GetObject',
                  's3:ListBucket',
                  's3:PutObject',
                  's3:ListObjects',
                  's3:ListObjectsV2',
                  's3:GetBucketLocation',
                ],
                Resource: [
                  workspaceResourceBucket.bucketArn,
                  workspaceResourceBucket.arnForObjects('*'),
                ],
              },
              {
                Effect: 'Allow',
                Action: ['s3:DeleteObject'],
                Resource: [
                  workspaceResourceBucket.arnForObjects(
                    `DO_NOT_DELETE_WORKSPACE_${workspaceId}`
                  ),
                ],
              },
            ],
          }),
        },
      }
    );

    // ワークスペース
    new aws_iottwinmaker.CfnWorkspace(this, 'CdkDemoWorkspace', {
      workspaceId,
      s3Location: workspaceResourceBucket.bucketArn,
      role: workspaceExecutionRole.roleArn,
    });
  }
}

  • aws_iottwinmaker で現在利用可能な Construct は L1 のみのため、ワークスペースの作成はCfnWorkspaceを使用します。
    • CfnWorkspaceの必須プロパティは以下の 3 つです。
      • workspaceId
      • s3Location(リソースライブラリとして、シーンで利用する 3D モデルの保管領域)
      • role(ワークスペースが各種 AWS リソースにアクセスする際の実行ロール)
    • その他に設定可能なプロパティは tags および description となります。
    • IAM ロールも明示的に作成する必要があります。
      • 1 つ目の権限がワークスペース作成時に未付与の場合は Could not access S3 with the role provided, verify permissions というエラーとなります。
      • 2 つ目の権限がワークスペース削除時に未付与の場合は Could not assume the role provided, verify permissions というエラーとなります。
  • WorkspaceExecutionRoleのポリシーステートメントは、マネジメントコンソールからワークスペースを作成する際に自動作成される IAM ロールを参考にしています。
    • ワークスペースが他の AWS リソースにアクセスする場合は、そのリソースに対するアクセス権限を付与する必要があります。

AWS CLI で ID CdkDemoWorkspace のワークスペースを取得すると、作成されていることが確認できました。

$ aws iottwinmaker get-workspace --workspace-id CdkDemoWorkspace --region us-east-1
{
    "workspaceId": "CdkDemoWorkspace",
    "arn": "arn:aws:iottwinmaker:us-east-1:XXXXXXXXXXXX:workspace/CdkDemoWorkspace",
    "description": "",
    "s3Location": "arn:aws:s3:::cdksamplestack-workspaceresourcebucketeecc84e2-qgmipjqaxuwi",
    "role": "arn:aws:iam::XXXXXXXXXXXX:role/CdkSampleStack-WorkspaceExecutionRole1C2472E3-1MPWOSXW1BDV5",
    "creationDateTime": 1695557062.46,
    "updateDateTime": 1695557062.46
}

マネジメントコンソールからも作成されていることが確認できました。

またバケットWorkspaceResourceBucketの中を確認すると、コンソールなどから作成する時と同様に、DO_NOT_DELETE_WORKSPACE_<ワークスペース名>という空のファイルが自動で作成されていました。このファイルの用途はドキュメントなどに情報が無いので不明ですが、ワークスペース用のバケットであることを識別するための符号でしょうか。

$ aws s3 ls s3://${workspaceResourceBucket}
2023-09-24 22:39:43          0 DO_NOT_DELETE_WORKSPACE_CdkDemoWorkspace

CfnWorkspaceProps 型定義

参考までに、CfnWorkspaceのプロパティ定義のドキュメントです。

node_modules/aws-cdk-lib/aws-iottwinmaker/lib/iottwinmaker.generated.d.ts

/**
 * Properties for defining a `CfnWorkspace`
 *
 * @struct
 * @stability external
 * @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iottwinmaker-workspace.html
 */
export interface CfnWorkspaceProps {
    /**
     * The description of the workspace.
     *
     * @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iottwinmaker-workspace.html#cfn-iottwinmaker-workspace-description
     */
    readonly description?: string;
    /**
     * The ARN of the execution role associated with the workspace.
     *
     * @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iottwinmaker-workspace.html#cfn-iottwinmaker-workspace-role
     */
    readonly role: string;
    /**
     * The ARN of the S3 bucket where resources associated with the workspace are stored.
     *
     * @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iottwinmaker-workspace.html#cfn-iottwinmaker-workspace-s3location
     */
    readonly s3Location: string;
    /**
     * Metadata that you can use to manage the workspace.
     *
     * @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iottwinmaker-workspace.html#cfn-iottwinmaker-workspace-tags
     */
    readonly tags?: Record<string, string>;
    /**
     * The ID of the workspace.
     *
     * @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iottwinmaker-workspace.html#cfn-iottwinmaker-workspace-workspaceid
     */
    readonly workspaceId: string;
}

試行錯誤

以降は、ワークスペースを CDK で作成する際にハマって試行錯誤したポイントを書き残しておきます。

その1

事象

次の CDK コードでデプロイを行おうとしました。

lib/cdk-sample-stack.ts

import {
  aws_iam,
  aws_s3,
  aws_iottwinmaker,
  Stack,
  RemovalPolicy,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';

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

    // ワークスペース用リソース保管バケット
    const workspaceResourceBucket = new aws_s3.Bucket(
      this,
      'WorkspaceResourceBucket',
      {
        removalPolicy: RemovalPolicy.DESTROY,
        autoDeleteObjects: true,
      }
    );

    // ワークスペース実行ロール
    const workspaceExecutionRole = new aws_iam.Role(
      this,
      'WorkspaceExecutionRole',
      {
        assumedBy: new aws_iam.ServicePrincipal('iottwinmaker.amazonaws.com'),
      }
    );

    // ワークスペース
    new aws_iottwinmaker.CfnWorkspace(this, 'CdkDemoWorkspace', {
      workspaceId: 'CdkDemoWorkspace',
      s3Location: workspaceResourceBucket.bucketArn,
      role: workspaceExecutionRole.roleArn,
    });
  }
}

CDK デプロイすると次のようなエラーが発生しました。

$ cdk deploy

(中略)

CdkSampleStack: deploying... [1/1]
CdkSampleStack: creating CloudFormation changeset...

 ❌  CdkSampleStack failed: Error [ValidationError]: Template format error: Unrecognized resource types: [AWS::IoTTwinMaker::Workspace]
    at Request.extractError (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:46430)
    at Request.callListeners (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:90083)
    at Request.emit (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:89531)
    at Request.emit (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:196289)
    at Request.transition (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:189841)
    at AcceptorStateMachine.runTo (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:154713)
    at /Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:155043
    at Request.<anonymous> (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:190133)
    at Request.<anonymous> (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:196364)
    at Request.callListeners (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:90251) {
  code: 'ValidationError',
  time: 2023-09-24T08:49:43.465Z,
  requestId: '79a1b11d-4dd8-4adf-ae08-2459dee00763',
  statusCode: 400,
  retryable: false,
  retryDelay: 128.52823210877085
}

 ❌ Deployment failed: Error [ValidationError]: Template format error: Unrecognized resource types: [AWS::IoTTwinMaker::Workspace]
    at Request.extractError (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:46430)
    at Request.callListeners (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:90083)
    at Request.emit (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:89531)
    at Request.emit (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:196289)
    at Request.transition (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:189841)
    at AcceptorStateMachine.runTo (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:154713)
    at /Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:155043
    at Request.<anonymous> (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:190133)
    at Request.<anonymous> (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:196364)
    at Request.callListeners (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:349:90251) {
  code: 'ValidationError',
  time: 2023-09-24T08:49:43.465Z,
  requestId: '79a1b11d-4dd8-4adf-ae08-2459dee00763',
  statusCode: 400,
  retryable: false,
  retryDelay: 128.52823210877085
}

Template format error: Unrecognized resource types: [AWS::IoTTwinMaker::Workspace]

解決

AWS IoT TwinMaker は現在、以下のリージョンで利用可能です。

  • us-east-1
  • us-west-2
  • ap-southeast-1
  • ap-southeast-2
  • eu-central-1
  • eu-west-1

私の CDK 環境では東京リージョン(ap-northeast-1)をデフォルトで使用する設定となっていたため、今回のエラーが発生していました。よって、次のように StackProps の env.region で対応するリージョンを指定する必要がありました。

$ git diff bin/cdk_sample_app.ts
diff --git a/bin/cdk_sample_app.ts b/bin/cdk_sample_app.ts
index e0fb935..708882e 100644
--- a/bin/cdk_sample_app.ts
+++ b/bin/cdk_sample_app.ts
@@ -3,4 +3,6 @@ import { CdkSampleStack } from '../lib/cdk-sample-stack';
 
 const app = new App();
 
-new CdkSampleStack(app, 'CdkSampleStack');
+new CdkSampleStack(app, 'CdkSampleStack', {
+  env: { region: 'us-east-1' },
+});

$ git diff lib/cdk-sample-stack.ts
diff --git a/lib/cdk-sample-stack.ts b/lib/cdk-sample-stack.ts
index cbee49f..a7f72fb 100644
--- a/lib/cdk-sample-stack.ts
+++ b/lib/cdk-sample-stack.ts
@@ -3,13 +3,14 @@ import {
   aws_s3,
   aws_iottwinmaker,
   Stack,
+  StackProps,
   RemovalPolicy,
 } from 'aws-cdk-lib';
 import { Construct } from 'constructs';
 
 export class CdkSampleStack extends Stack {
-  constructor(scope: Construct, id: string) {
-    super(scope, id);
+  constructor(scope: Construct, id: string, props: StackProps) {
+    super(scope, id, props);
 
     // ワークスペース用リソース保管バケット
     const workspaceExecutionRole = new aws_iam.Role(

参考

その2

事象

その 1 の修正を施した次の CDK コードでデプロイを行おうとしました。

bin/cdk_sample_app.ts

import {
  aws_iam,
  aws_s3,
  aws_iottwinmaker,
  Stack,
  StackProps,
  RemovalPolicy,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';

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

    // ワークスペース用リソース保管バケット
    const workspaceResourceBucket = new aws_s3.Bucket(
      this,
      'WorkspaceResourceBucket',
      {
        removalPolicy: RemovalPolicy.DESTROY,
        autoDeleteObjects: true,
      }
    );

    // ワークスペース実行ロール
    const workspaceExecutionRole = new aws_iam.Role(
      this,
      'WorkspaceExecutionRole',
      {
        assumedBy: new aws_iam.ServicePrincipal('iottwinmaker.amazonaws.com'),
      }
    );

    // ワークスペース
    new aws_iottwinmaker.CfnWorkspace(this, 'CdkDemoWorkspace', {
      workspaceId: 'CdkDemoWorkspace',
      s3Location: workspaceResourceBucket.bucketArn,
      role: workspaceExecutionRole.roleArn,
    });
  }
}

CDK デプロイすると次のようなエラーが発生しました。

$ cdk deploy

✨  Synthesis time: 3.11s

CdkSampleStack:  start: Building 21f85708daa63a0f16cfcdae79d9f49a016831248c0dfe5f402f6fae11ddc7f7:current_account-us-east-1
CdkSampleStack:  success: Built 21f85708daa63a0f16cfcdae79d9f49a016831248c0dfe5f402f6fae11ddc7f7:current_account-us-east-1
CdkSampleStack:  start: Publishing 21f85708daa63a0f16cfcdae79d9f49a016831248c0dfe5f402f6fae11ddc7f7:current_account-us-east-1
CdkSampleStack:  success: Published 21f85708daa63a0f16cfcdae79d9f49a016831248c0dfe5f402f6fae11ddc7f7:current_account-us-east-1
CdkSampleStack: deploying... [1/1]
CdkSampleStack: creating CloudFormation changeset...
6:31:27 PM | CREATE_FAILED        | AWS::IoTTwinMaker::Workspace | CdkDemoWorkspace
Resource handler returned message: "Could not access S3 with the role provided, verify permissions (Service: IoTTwinMaker, Status Code: 400, Request ID: fd17142a-7504-434c-9209-6fab0df1a9df)" (RequestToken: 7491e545-bbfd-e57a-126b-c7c13e1f5d09, HandlerErrorCode: InvalidRequest)


 ❌  CdkSampleStack failed: Error: The stack named CdkSampleStack failed creation, it may need to be manually deleted from the AWS console: ROLLBACK_COMPLETE: Resource handler returned message: "Could not access S3 with the role provided, verify permissions (Service: IoTTwinMaker, Status Code: 400, Request ID: fd17142a-7504-434c-9209-6fab0df1a9df)" (RequestToken: 7491e545-bbfd-e57a-126b-c7c13e1f5d09, HandlerErrorCode: InvalidRequest)
    at FullCloudFormationDeployment.monitorDeployment (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:454:10232)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Object.deployStack2 [as deployStack] (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:457:179910)
    at async /Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:457:163158

 ❌ Deployment failed: Error: The stack named CdkSampleStack failed creation, it may need to be manually deleted from the AWS console: ROLLBACK_COMPLETE: Resource handler returned message: "Could not access S3 with the role provided, verify permissions (Service: IoTTwinMaker, Status Code: 400, Request ID: fd17142a-7504-434c-9209-6fab0df1a9df)" (RequestToken: 7491e545-bbfd-e57a-126b-c7c13e1f5d09, HandlerErrorCode: InvalidRequest)
    at FullCloudFormationDeployment.monitorDeployment (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:454:10232)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Object.deployStack2 [as deployStack] (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:457:179910)
    at async /Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:457:163158

The stack named CdkSampleStack failed creation, it may need to be manually deleted from the AWS console: ROLLBACK_COMPLETE: Resource handler returned message: "Could not access S3 with the role provided, verify permissions (Service: IoTTwinMaker, Status Code: 400, Request ID: fd17142a-7504-434c-9209-6fab0df1a9df)" (RequestToken: 7491e545-bbfd-e57a-126b-c7c13e1f5d09, HandlerErrorCode: InvalidRequest)

解決

ワークスペースに設定する実行ロールに、S3 バケットへのアクセス権を付与しておく必要がありました。

$ git diff
diff --git a/lib/cdk-sample-stack.ts b/lib/cdk-sample-stack.ts
index d35f128..bc5371c 100644
--- a/lib/cdk-sample-stack.ts
+++ b/lib/cdk-sample-stack.ts
@@ -28,6 +28,36 @@ export class CdkSampleStack extends Stack {
       'WorkspaceExecutionRole',
       {
         assumedBy: new aws_iam.ServicePrincipal('iottwinmaker.amazonaws.com'),
+        inlinePolicies: {
+          readWorkspaceResourceBucket: aws_iam.PolicyDocument.fromJson({
+            Version: '2012-10-17',
+            Statement: [
+              {
+                Effect: 'Allow',
+                Action: [
+                  's3:GetBucket',
+                  's3:GetObject',
+                  's3:ListBucket',
+                  's3:PutObject',
+                  's3:ListObjects',
+                  's3:ListObjectsV2',
+                  's3:GetBucketLocation',
+                ],
+                Resource: [
+                  `${workspaceResourceBucket.bucketArn}/*`,
+                  workspaceResourceBucket.bucketArn,
+                ],
+              },
+              {
+                Effect: 'Allow',
+                Action: ['s3:DeleteObject'],
+                Resource: [
+                  `${workspaceResourceBucket.bucketArn}/DO_NOT_DELETE_WORKSPACE_CdkDemoWorkspace`,
+                ],
+              },
+            ],
+          }),
+        },
       }
     );

これにより冒頭の最終的に動作したものと同じ CDK コードとなりました。

その3

事象

CDK デプロイ時に次の S3 Bucket: arn:aws:s3:::<bucket name>is used by workspaceId: cdkDemo. Use another S3 bucket というエラーが発生しました。

$ cdk deploy

✨  Synthesis time: 2.73s

CdkSampleStack:  start: Building 11d40e081cc93440682e7dbd4b8178f0c6ff6d8a62dacbd832067fbc409b9dbc:current_account-us-east-1
CdkSampleStack:  success: Built 11d40e081cc93440682e7dbd4b8178f0c6ff6d8a62dacbd832067fbc409b9dbc:current_account-us-east-1
CdkSampleStack:  start: Publishing 11d40e081cc93440682e7dbd4b8178f0c6ff6d8a62dacbd832067fbc409b9dbc:current_account-us-east-1
CdkSampleStack:  success: Published 11d40e081cc93440682e7dbd4b8178f0c6ff6d8a62dacbd832067fbc409b9dbc:current_account-us-east-1
CdkSampleStack: deploying... [1/1]
CdkSampleStack: creating CloudFormation changeset...
8:58:23 PM | UPDATE_FAILED        | AWS::IoTTwinMaker::Workspace | CdkDemoWorkspace
Resource handler returned message: "S3 Bucket: arn:aws:s3:::cdksamplestack-workspaceresourcebucketeecc84e2-qgmipjqaxuwi is used by workspaceId: cdkDemo. Use another S3 bucket (Service: IoTTwinMaker, Status Code: 400, Request ID: 22cfd1b3-fa
0b-4cb8-82bb-6df0338eb8ae)" (RequestToken: 408fc0d5-d01e-ed66-ceec-db0ec1fb15a7, HandlerErrorCode: InvalidRequest)


 ❌  CdkSampleStack failed: Error: The stack named CdkSampleStack failed to deploy: UPDATE_ROLLBACK_COMPLETE: Resource handler returned message: "S3 Bucket: arn:aws:s3:::cdksamplestack-workspaceresourcebucketeecc84e2-qgmipjqaxuwi is used by workspaceId: cdkDemo. Use another S3 bucket (Service: IoTTwinMaker, Status Code: 400, Request ID: 22cfd1b3-fa0b-4cb8-82bb-6df0338eb8ae)" (RequestToken: 408fc0d5-d01e-ed66-ceec-db0ec1fb15a7, HandlerErrorCode: InvalidRequest)
    at FullCloudFormationDeployment.monitorDeployment (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:454:10232)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Object.deployStack2 [as deployStack] (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:457:179910)
    at async /Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:457:163158

 ❌ Deployment failed: Error: The stack named CdkSampleStack failed to deploy: UPDATE_ROLLBACK_COMPLETE: Resource handler returned message: "S3 Bucket: arn:aws:s3:::cdksamplestack-workspaceresourcebucketeecc84e2-qgmipjqaxuwi is used by workspaceId: cdkDemo. Use another S3 bucket (Service: IoTTwinMaker, Status Code: 400, Request ID: 22cfd1b3-fa0b-4cb8-82bb-6df0338eb8ae)" (RequestToken: 408fc0d5-d01e-ed66-ceec-db0ec1fb15a7, HandlerErrorCode: InvalidRequest)
    at FullCloudFormationDeployment.monitorDeployment (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:454:10232)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Object.deployStack2 [as deployStack] (/Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:457:179910)
    at async /Users/wakatsuki.ryuta/.nvm/versions/node/v18.17.0/lib/node_modules/aws-cdk/lib/index.js:457:163158

The stack named CdkSampleStack failed to deploy: UPDATE_ROLLBACK_COMPLETE: Resource handler returned message: "S3 Bucket: arn:aws:s3:::cdksamplestack-workspaceresourcebucketeecc84e2-qgmipjqaxuwi is used by workspaceId: cdkDemo. Use another S3 bucket (Service: IoTTwinMaker, Status Code: 400, Request ID: 22cfd1b3-fa0b-4cb8-82bb-6df0338eb8ae)" (RequestToken: 408fc0d5-d01e-ed66-ceec-db0ec1fb15a7, HandlerErrorCode: InvalidRequest)

これは、CDK デプロイによるワークスペース作成を試行錯誤する際に、途中でワークスペースの ID を変更したため、変更前の ID のワークスペースが残ってしまったが、複数のワークスペース間で同じ S3 バケットを共有できないことによるエラーのようです。

解決

変更前の ID のワークスペースを削除すると、CDK デプロイが成功するようになりました。

aws iottwinmaker delete-workspace --workspace-id cdkDemo --region us-east-1

おわりに

AWS IoT TwinMaker によるデジタルツインアプリケーションを AWS CDK で作成する上で、ワークスペース作成する方法と、作成時に遭遇したいくつかのハマりポイントを合わせてご紹介しました。

今までは IoT TwinMaker の作成や更新を行う際には、サンプルスクリプトがある場合を除き、マネジメントコンソールを利用することがほとんどだったのですが、やはり CDK による IaC を実現したいと常々感じていました。今回は手始めにワークスペースのみでしたが、続けて他のリソースの作成も追って行ってみたいと思います。

参考

以上