CDKTFでconfig-driven importを試してみる

2023.10.19

CDKTF 0.19でconfig-driven importがサポートされたので、試してみました。

CDKTF 0.19 adds support for config-driven import and refactoring

config-driven importとは

Terraform 1.5で追加された機能です。

従来からTerraformでは、terraform importコマンドで既存リソースをTerraformの構成管理下に置くことができました。

しかし、このコマンドはリソースを1つずつインポートする必要がある・結果をプレビューすることができない等制限もありました。

config-driven importでは、importブロックを利用することで上記の制限をなくし、インポート操作をコードで定義できるようになりました。

import {
  # ID of the cloud resource
  # Check provider documentation for importable resources and format
  id = “i-abcd1234”
 
  # Resource address
  to = aws_instance.example
}

今回のアップデートでCDKTFでもconfig-driven importがサポートされました。

Terraform 1.5 brings config-driven import and checksからコードを引用

Terraform v1.5.0 で追加された import ブロックと check ブロックを試してみた | DevelopersIO

何が嬉しい?

やってみた

アップデートブログと同様にS3バケットをimportしてみます。

前提

  • terraform version : 1.5以上
  • cdktf version: 0.19.0以上
  • 言語はtypescript
  • AWS providerを使用
  • Stateファイルはlocal保存

手動でテスト用のリソースを用意

S3バケットを作成します。

$ BUCKET_NAME="test-cdktf-import-20231018" # 任意の名前に置き換えてください
$ aws s3api create-bucket --bucket $BUCKET_NAME --create-bucket-configuration LocationConstraint=ap-northeast-1

CDKTFのプロジェクトを作成する

検証用にCDKTFのプロジェクトを作成します。

$ mkdir config-driven-import
$ cd config-driven-import
$ npx cdktf init --template="typescript" --providers="aws@~>5.0" --local
Note: By supplying '--local' option you have chosen local storage mode for storing the state of your stack.
This means that your Terraform state file will be stored locally on disk in a file 'terraform.<STACK NAME>.tfstate' in the root of your project.
? Project Name config-driven-import
? Project Description A simple getting started project for cdktf.
? Do you want to start from an existing Terraform project? no
? Do you want to send crash reports to the CDKTF team? Refer to 
https://developer.hashicorp.com/terraform/cdktf/create-and-deploy/configuration-file#enable-crash-reporting-for-the-cli for more information yes

added 2 packages, and audited 57 packages in 784ms

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

found 0 vulnerabilities

added 313 packages, and audited 370 packages in 11s

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

found 0 vulnerabilities
========================================================================================================

  Your CDKTF TypeScript project is ready!

コマンド実行後は以下のディレクトリ構成になります。

$ ls -1
__tests__
cdktf.json
cdktf.out
help
jest.config.js
main.ts
node_modules
package-lock.json
package.json
setup.js
tsconfig.json

手動で作成したS3バケットをCDKTFでimportする

main.tsを以下の用に変更します。

main.ts

import { Construct } from "constructs";
import { App, TerraformStack } from "cdktf";
import { AwsProvider } from "@cdktf/provider-aws/lib/provider";
import { S3Bucket } from "@cdktf/provider-aws/lib/s3-bucket";


class MyStack extends TerraformStack {
  constructor(scope: Construct, id: string) {
    super(scope, id);
    new AwsProvider(this, "AWS", {
      region: "ap-northeast-1",
    });

    // 「test-cdktf-import-20231018」の部分は作成したバケット名に置き換えてください
    new S3Bucket(this, "bucket", {}).importFrom("test-cdktf-import-20231018");
  }
}

const app = new App();
new MyStack(app, "config-driven-import");
app.synth();

AWS認証情報をセットして、diffを確認します。

$ cdktf diff
config-driven-import  Initializing the backend...
config-driven-import  Initializing provider plugins...
                      - Reusing previous version of hashicorp/aws from the dependency lock file
config-driven-import  - Using previously-installed hashicorp/aws v5.21.0

                      Terraform has been successfully initialized!
config-driven-import  
                      You may now begin working with Terraform. Try running "terraform plan" to see
                      any changes that are required for your infrastructure. All Terraform commands
                      should now work.

                      If you ever set or change modules or backend configuration for Terraform,
                      rerun this command to reinitialize your working directory. If you forget, other
                      commands will detect it and remind you to do so if necessary.
config-driven-import  aws_s3_bucket.bucket (bucket): Preparing import... [id=test-cdktf-import-20231018]
config-driven-import  aws_s3_bucket.bucket (bucket): Refreshing state... [id=test-cdktf-import-20231018]
config-driven-import  Terraform will perform the following actions:
config-driven-import    # aws_s3_bucket.bucket (bucket) will be imported
                          resource "aws_s3_bucket" "bucket" {
                              arn                         = "arn:aws:s3:::test-cdktf-import-20231018"
                              bucket                      = "test-cdktf-import-20231018"
                              bucket_domain_name          = "test-cdktf-import-20231018.s3.amazonaws.com"
                              bucket_regional_domain_name = "test-cdktf-import-20231018.s3.ap-northeast-1.amazonaws.com"
                              hosted_zone_id              = "XXXXXXXXXX"
                              id                          = "test-cdktf-import-20231018"
                              object_lock_enabled         = false
                              region                      = "ap-northeast-1"
                              request_payer               = "BucketOwner"
                              tags                        = {}
                              tags_all                    = {}

                              grant {
                                  id          = "XXXXXXXXXX"
                                  permissions = [
                                      "FULL_CONTROL",
                                  ]
                                  type        = "CanonicalUser"
                              }

                              server_side_encryption_configuration {
                                  rule {
                                      bucket_key_enabled = false

                                      apply_server_side_encryption_by_default {
                                          sse_algorithm = "AES256"
                                      }
                                  }
                              }

                              versioning {
                                  enabled    = false
                                  mfa_delete = false
                              }
                          }

                      Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.
                      
                      ─────────────────────────────────────────────────────────────────────────────

                      Saved the plan to: plan

                      To perform exactly these actions, run the following command to apply:
                          terraform apply "plan"

該当のS3バケットをimportしようとしていることがわかります。

importを実行します。

$ cdktf deploy
# 省略
Apply complete! Resources: 1 imported, 0 added, 0 changed, 0 destroyed.

No outputs found.

Terraformのimportブロックと同様に、cdktf deploy(apply)後はimportFromの記述は削除して問題ありません。

main.tf

import { Construct } from "constructs";
import { App, TerraformStack } from "cdktf";
import { AwsProvider } from "@cdktf/provider-aws/lib/provider";
import { S3Bucket } from "@cdktf/provider-aws/lib/s3-bucket";
import { S3BucketVersioningA } from "@cdktf/provider-aws/lib/s3-bucket-versioning";


class MyStack extends TerraformStack {
  constructor(scope: Construct, id: string) {
    super(scope, id);
    new AwsProvider(this, "AWS", {
      region: "ap-northeast-1",
    });

    new S3Bucket(this, "bucket", { });
  }
}

const app = new App();
new MyStack(app, "config-driven-import");
app.synth();

importFrom削除後も、差分が出ないことが確認できます。

$ cdktf diff
# 省略
No changes. Your infrastructure matches the configuration.

importFromは残しておいても動作に問題はありませんが、importFromの返り値がvoidのため、「S3バケット クラスを変数に入れて他の部分で使う」といったことができません。 (「動作確認: importしたリソースをcdktf経由で変更してみる」のconst bucket = new S3Bucket(...のようなことができない)

そのため、import後はimportFromを削除するようにしましょう。

動作確認: importしたリソースをcdktf経由で変更してみる

cdktf経由でリソースを変更してみましょう。

S3バケットのバージョニングをcdktf経由で有効化してみます。

import時点では、バケットのバージョニングが無効です。

コード上でバケットのバージョニングを有効化します。

main.tf

import { Construct } from "constructs";
import { App, TerraformStack } from "cdktf";
import { AwsProvider } from "@cdktf/provider-aws/lib/provider";
import { S3Bucket } from "@cdktf/provider-aws/lib/s3-bucket";
import { S3BucketVersioningA } from "@cdktf/provider-aws/lib/s3-bucket-versioning";


class MyStack extends TerraformStack {
  constructor(scope: Construct, id: string) {
    super(scope, id);
    new AwsProvider(this, "AWS", {
      region: "ap-northeast-1",
    });

    const bucket = new S3Bucket(this, "bucket", { });
    
    new S3BucketVersioningA(this, "versioning", {
      bucket: bucket.id,
      versioningConfiguration: {
        status: "Enabled",
      }
    })
  }
}

const app = new App();
new MyStack(app, "config-driven-import");
app.synth();

diffで変更内容を確認します。

$ cdktf diff                                                         
config-driven-import  Initializing the backend...
config-driven-import  Initializing provider plugins...
                      - Reusing previous version of hashicorp/aws from the dependency lock file
config-driven-import  - Using previously-installed hashicorp/aws v5.21.0

                      Terraform has been successfully initialized!
config-driven-import  
                      You may now begin working with Terraform. Try running "terraform plan" to see
                      any changes that are required for your infrastructure. All Terraform commands
                      should now work.

                      If you ever set or change modules or backend configuration for Terraform,
                      rerun this command to reinitialize your working directory. If you forget, other
                      commands will detect it and remind you to do so if necessary.
config-driven-import  aws_s3_bucket.bucket (bucket): Refreshing state... [id=test-cdktf-import-20231018]
config-driven-import  Terraform used the selected providers to generate the following execution
                      plan. Resource actions are indicated with the following symbols:
                        + create

                      Terraform will perform the following actions:
config-driven-import    # aws_s3_bucket_versioning.versioning (versioning) will be created
                        + resource "aws_s3_bucket_versioning" "versioning" {
                            + bucket = "test-cdktf-import-20231018"
                            + id     = (known after apply)

                            + versioning_configuration {
                                + mfa_delete = (known after apply)
                                + status     = "Enabled"
                              }
                          }

                      Plan: 1 to add, 0 to change, 0 to destroy.
                      
                      ─────────────────────────────────────────────────────────────────────────────

                      Saved the plan to: plan

                      To perform exactly these actions, run the following command to apply:
                          terraform apply "plan"

バージョニングがEnabledになることがわかります。変更を適用します。

$ cdktf deploy
# 省略
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

コンソール上からも有効化できていることを確認できました。

おわりに

CDKTFを使って、既存リソースをimportしてCDKTF経由で変更を試してみました。

config-driven importのサポートでCDKTFはますます便利になりました。

バックエンドがterraformなだけあり、快適にimportできます。

以上、AWS事業本部の佐藤(@chari7311)でした。