話題の記事

AWSの構成図をChatGPT(GPT-4V)に読み込ませてIaCコードを生成してみた

2023.10.15

こんにちは、つくぼし(tsukuboshi0755)です!

最近ChatGPTがGPT-4Vを発表し、AI業界がさらに盛り上がりを見せてますね。

GPT-4Vを用いる事で、ChatGPTがユーザ側から入力された画像を読み取った上で、応答を返してくれるようになります。

GPT-4V(ision) system card

この機能追加により、なんと以下のようにAWSの構成図を読み取って、IaCコードを生成できる事が話題になっていました。


これを見て私もGPT-4Vを試してみたくなったので、今回はChatGPTを使って、様々なAWSの構成図を入力し、どこまで正確にIaCコードを生成できるか確認してみます!

GPT-4Vを利用する際の注意点

先にGPT-4Vを利用してAWS構成図からIaCコードを生成する場合に関して、注意点を以下の通り明示しておきます。

  • 現状GPT-4Vを利用するには、有料プラン(ChatGPT Plus)の加入が必要になります。

  • 構成図に記載されていないリソースについては、ChatGPTが一部補完してくれる場合もありますが、補完されない場合もあります。構成図上に記載されていないリソースについても確実にIaCコードに含めたい場合、構成図に該当のリソースを追加するか、ユーザ側から該当のリソース情報を追加で補足する必要があります。

  • ChatGPTには文字数(トークン)制限があり、IaCコードの量が膨大な場合、返答の途中でエラーが発生する事があります。その場合、ユーザ側で「コードは3000トークンを超えたら分割し、私が『続き』と入力したら続きの回答を投稿してください」というような文言を追加すると、ChatGPTがいい感じにコードを分割した上で返答してくれます。

  • ChatGPTは現状2022年1月までのデータしかアクセスできません。そのため2022年1月より後のAWSアップデートで追加・変更・削除された設定を反映できない事に注意してください。

  • ChatGPTで生成されるIaCコードは、AWS上で動作保証されているわけではありません。そのためもし生成されたIaCコードを使用したい場合は、事前に想定通り動作するか検証する事を推奨します。

パターン①:Web3層構成図をCloudFormationに変換

まずは構成図をCloudFormationに変換できるか試してみます。

質問内容

以下のようなWeb3層構成図とメッセージをGPT-4に質問した際に、どのようなCloudFormationコードが返ってくるか確認してみます。

  • 構成図

  • メッセージ
この構成図をデプロイするCloudFormationコードを作成してください。ただし、テンプレートは3000トークンを超えたら分割し、私が「続き」と入力したら続きの回答を投稿してください。

GPT-4からの返答

GPT-4からの返答で提供されたコードについて、以下に完全な形で示します。

CloudFormationコード
AWSTemplateFormatVersion: '2010-09-09'
Description: 'AWS VPC with ALB, EC2 and RDS'

Resources:

  # VPC
  VPC:
    Type: 'AWS::EC2::VPC'
    Properties:
      CidrBlock: '10.0.0.0/16'
      EnableDnsSupport: 'true'
      EnableDnsHostnames: 'true'
      Tags:
        - Key: Name
          Value: VPC

  # Internet Gateway
  InternetGateway:
    Type: 'AWS::EC2::InternetGateway'
    Properties:
      Tags:
        - Key: Name
          Value: InternetGateway

  VPCGatewayAttachment:
    Type: 'AWS::EC2::VPCGatewayAttachment'
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

  # Public Subnets
  PublicSubnetA:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      CidrBlock: '10.0.1.0/24'
      MapPublicIpOnLaunch: 'true'
      AvailabilityZone: !Select [ 0, !GetAZs '' ]
      Tags:
        - Key: Name
          Value: PublicSubnetA

  PublicSubnetC:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      CidrBlock: '10.0.3.0/24'
      MapPublicIpOnLaunch: 'true'
      AvailabilityZone: !Select [ 1, !GetAZs '' ]
      Tags:
        - Key: Name
          Value: PublicSubnetC

  # Private Subnets
  PrivateSubnetA1:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      CidrBlock: '10.0.2.0/24'
      AvailabilityZone: !Select [ 0, !GetAZs '' ]
      Tags:
        - Key: Name
          Value: PrivateSubnetA1

  PrivateSubnetC1:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      CidrBlock: '10.0.4.0/24'
      AvailabilityZone: !Select [ 1, !GetAZs '' ]
      Tags:
        - Key: Name
          Value: PrivateSubnetC1

  # Elastic IPs for NAT Gateways
  EIPForNATGatewayA:
    Type: 'AWS::EC2::EIP'

  EIPForNATGatewayC:
    Type: 'AWS::EC2::EIP'

  # NAT Gateways
  NATGatewayA:
    Type: 'AWS::EC2::NatGateway'
    Properties:
      AllocationId: !GetAtt EIPForNATGatewayA.AllocationId
      SubnetId: !Ref PublicSubnetA

  NATGatewayC:
    Type: 'AWS::EC2::NatGateway'
    Properties:
      AllocationId: !GetAtt EIPForNATGatewayC.AllocationId
      SubnetId: !Ref PublicSubnetC

  # ALB Security Group
  ALBSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupDescription: 'ALB security group'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: '80'
          ToPort: '80'
          CidrIp: '0.0.0.0/0'

  # ALB
  ApplicationLoadBalancer:
    Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer'
    Properties:
      Scheme: 'internet-facing'
      Subnets:
        - !Ref PublicSubnetA
        - !Ref PublicSubnetC
      SecurityGroups:
        - !Ref ALBSecurityGroup
      Type: 'application'

  # ALB Listener
  ALBListener:
    Type: 'AWS::ElasticLoadBalancingV2::Listener'
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref ALBTargetGroup
      LoadBalancerArn: !Ref ApplicationLoadBalancer
      Port: 80
      Protocol: HTTP

  # ALB Target Group
  ALBTargetGroup:
    Type: 'AWS::ElasticLoadBalancingV2::TargetGroup'
    Properties:
      VpcId: !Ref VPC
      Port: 80
      Protocol: HTTP
      TargetType: instance

  # EC2 Security Group
  EC2SecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupDescription: 'EC2 security group'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: '80'
          ToPort: '80'
          SourceSecurityGroupId: !Ref ALBSecurityGroup

  # EC2 Instance
  EC2InstanceA:
    Type: 'AWS::EC2::Instance'
    Properties:
      AvailabilityZone: !Select [ 0, !GetAZs '' ]
      InstanceType: t2.micro
      ImageId: 'ami-xxxxxx' # Please replace with a valid AMI ID
      SubnetId: !Ref PrivateSubnetA1
      SecurityGroupIds:
        - !Ref EC2SecurityGroup
      KeyName: YourKeyName # Please replace with your key name

  EC2InstanceC:
    Type: 'AWS::EC2::Instance'
    Properties:
      AvailabilityZone: !Select [ 1, !GetAZs '' ]
      InstanceType: t2.micro
      ImageId: 'ami-xxxxxx' # Please replace with a valid AMI ID
      SubnetId: !Ref PrivateSubnetC1
      SecurityGroupIds:
        - !Ref EC2SecurityGroup
      KeyName: YourKeyName # Please replace with your key name

  # RDS Security Group
  RDSSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      VpcId: !Ref VPC
      GroupDescription: 'RDS security group'
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: '3306'
          ToPort: '3306'
          SourceSecurityGroupId: !Ref EC2SecurityGroup

  # RDS Subnet Group
  RDSSubnetGroup:
    Type: 'AWS::RDS::DBSubnetGroup'
    Properties:
      DBSubnetGroupDescription: 'RDS Subnet Group'
      SubnetIds:
        - !Ref PrivateSubnetA1
        - !Ref PrivateSubnetC1

  # RDS Instance
  RDSInstance:
    Type: 'AWS::RDS::DBInstance'
    Properties:
      AllocatedStorage: '20'
      DBInstanceClass: 'db.t2.micro'
      Engine: 'MySQL'
      MasterUsername: 'admin'
      MasterUserPassword: 'Password123' # Please replace with a secure password
      VPCSecurityGroups:
        - !Ref RDSSecurityGroup
      DBSubnetGroupName: !Ref RDSSubnetGroup
      MultiAZ: 'true'
      EngineVersion: '5.7'
      PubliclyAccessible: 'false'

コード検証

返答されたCloudFormationコードについて、実際にAWS上でデプロイできるか確認します。

この場合ではGPT-4のコメントでも明示されている通り、ImageIdKeyNameを適切な値に置き換えます。

CloudFormationコード(修正後)
AWSTemplateFormatVersion: '2010-09-09'
Description: 'AWS VPC with ALB, EC2 and RDS'

Resources:

  # VPC
  VPC:
    Type: 'AWS::EC2::VPC'
    Properties:
      CidrBlock: '10.0.0.0/16'
      EnableDnsSupport: 'true'
      EnableDnsHostnames: 'true'
      Tags:
        - Key: Name
          Value: VPC

  # Internet Gateway
  InternetGateway:
    Type: 'AWS::EC2::InternetGateway'
    Properties:
      Tags:
        - Key: Name
          Value: InternetGateway

  VPCGatewayAttachment:
    Type: 'AWS::EC2::VPCGatewayAttachment'
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

  # Public Subnets
  PublicSubnetA:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      CidrBlock: '10.0.1.0/24'
      MapPublicIpOnLaunch: 'true'
      AvailabilityZone: !Select [ 0, !GetAZs '' ]
      Tags:
        - Key: Name
          Value: PublicSubnetA

  PublicSubnetC:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      CidrBlock: '10.0.3.0/24'
      MapPublicIpOnLaunch: 'true'
      AvailabilityZone: !Select [ 1, !GetAZs '' ]
      Tags:
        - Key: Name
          Value: PublicSubnetC

  # Private Subnets
  PrivateSubnetA1:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      CidrBlock: '10.0.2.0/24'
      AvailabilityZone: !Select [ 0, !GetAZs '' ]
      Tags:
        - Key: Name
          Value: PrivateSubnetA1

  PrivateSubnetC1:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      CidrBlock: '10.0.4.0/24'
      AvailabilityZone: !Select [ 1, !GetAZs '' ]
      Tags:
        - Key: Name
          Value: PrivateSubnetC1

  # Elastic IPs for NAT Gateways
  EIPForNATGatewayA:
    Type: 'AWS::EC2::EIP'

  EIPForNATGatewayC:
    Type: 'AWS::EC2::EIP'

  # NAT Gateways
  NATGatewayA:
    Type: 'AWS::EC2::NatGateway'
    Properties:
      AllocationId: !GetAtt EIPForNATGatewayA.AllocationId
      SubnetId: !Ref PublicSubnetA

  NATGatewayC:
    Type: 'AWS::EC2::NatGateway'
    Properties:
      AllocationId: !GetAtt EIPForNATGatewayC.AllocationId
      SubnetId: !Ref PublicSubnetC

  # ALB Security Group
  ALBSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupDescription: 'ALB security group'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: '80'
          ToPort: '80'
          CidrIp: '0.0.0.0/0'

  # ALB
  ApplicationLoadBalancer:
    Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer'
    Properties:
      Scheme: 'internet-facing'
      Subnets:
        - !Ref PublicSubnetA
        - !Ref PublicSubnetC
      SecurityGroups:
        - !Ref ALBSecurityGroup
      Type: 'application'

  # ALB Listener
  ALBListener:
    Type: 'AWS::ElasticLoadBalancingV2::Listener'
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref ALBTargetGroup
      LoadBalancerArn: !Ref ApplicationLoadBalancer
      Port: 80
      Protocol: HTTP

  # ALB Target Group
  ALBTargetGroup:
    Type: 'AWS::ElasticLoadBalancingV2::TargetGroup'
    Properties:
      VpcId: !Ref VPC
      Port: 80
      Protocol: HTTP
      TargetType: instance

  # EC2 Security Group
  EC2SecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupDescription: 'EC2 security group'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: '80'
          ToPort: '80'
          SourceSecurityGroupId: !Ref ALBSecurityGroup

  # EC2 Instance
  EC2InstanceA:
    Type: 'AWS::EC2::Instance'
    Properties:
      AvailabilityZone: !Select [ 0, !GetAZs '' ]
      InstanceType: t2.micro
      ImageId: 'ami-0fd8f5842685ca887' # Amazon Linux 2023のAMI IDを指定
      SubnetId: !Ref PrivateSubnetA1
      SecurityGroupIds:
        - !Ref EC2SecurityGroup
      KeyName: 'tsukuboshi-test-keypair' # 作成済みのキーペアを指定

  EC2InstanceC:
    Type: 'AWS::EC2::Instance'
    Properties:
      AvailabilityZone: !Select [ 1, !GetAZs '' ]
      InstanceType: t2.micro
      ImageId: 'ami-0fd8f5842685ca887' # Amazon Linux 2023のAMI IDを指定
      SubnetId: !Ref PrivateSubnetC1
      SecurityGroupIds:
        - !Ref EC2SecurityGroup
      KeyName: 'tsukuboshi-test-keypair' # 作成済みのキーペアを指定

  # RDS Security Group
  RDSSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      VpcId: !Ref VPC
      GroupDescription: 'RDS security group'
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: '3306'
          ToPort: '3306'
          SourceSecurityGroupId: !Ref EC2SecurityGroup

  # RDS Subnet Group
  RDSSubnetGroup:
    Type: 'AWS::RDS::DBSubnetGroup'
    Properties:
      DBSubnetGroupDescription: 'RDS Subnet Group'
      SubnetIds:
        - !Ref PrivateSubnetA1
        - !Ref PrivateSubnetC1

  # RDS Instance
  RDSInstance:
    Type: 'AWS::RDS::DBInstance'
    Properties:
      AllocatedStorage: '20'
      DBInstanceClass: 'db.t2.micro'
      Engine: 'MySQL'
      MasterUsername: 'admin'
      MasterUserPassword: 'Password123' # Please replace with a secure password
      VPCSecurityGroups:
        - !Ref RDSSecurityGroup
      DBSubnetGroupName: !Ref RDSSubnetGroup
      MultiAZ: 'true'
      EngineVersion: '5.7'
      PubliclyAccessible: 'false'

このCloudFormationコードをデプロイした結果をコンソールで確認すると、想定通りのリソースが作成されている事が分かります。

この場合はかなり想定通りにIaCコードを生成してくれたように感じました!

パターン②:静的Webサイトホスティング構成図をTerraformに変換

次に構成図をTerraformに変換できるか試してみます。

質問内容

以下のような静的Webサイトホスティング構成図とメッセージをGPT-4に流した際に、どのようなTerraformコードが返ってくるか確認してみます。

  • 構成図

  • メッセージ
この構成図をデプロイするTerraformコードを作成してください。ただし、テンプレートは3000トークンを超えたら分割し、私が「続き」と入力したら続きの回答を投稿してください。

GPT-4からの返答

GPT-4からの返答で提供されたコードについて、以下に完全な形で示します。

Terraformコード
provider "aws" {
  region = "ap-northeast-1"
}

resource "aws_s3_bucket" "my_bucket" {
  bucket = "my-s3-bucket-name"
  acl    = "private"
}

resource "aws_cloudfront_origin_access_identity" "example" {
  comment = "example"
}

resource "aws_cloudfront_distribution" "s3_distribution" {
  origin {
    domain_name = aws_s3_bucket.my_bucket.bucket_regional_domain_name
    origin_id   = "myS3Origin"

    s3_origin_config {
      origin_access_identity = aws_cloudfront_origin_access_identity.example.cloudfront_access_identity_path
    }
  }

  enabled             = true
  is_ipv6_enabled     = true
  comment             = "S3 bucket distribution"
  default_root_object = "index.html"

  default_cache_behavior {
    allowed_methods  = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = "myS3Origin"

    forwarded_values {
      query_string = false

      cookies {
        forward = "none"
      }
    }

    viewer_protocol_policy = "allow-all"
    min_ttl                = 0
    default_ttl            = 3600
    max_ttl                = 86400
  }

  price_class = "PriceClass_100"
  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }
}

resource "aws_s3_bucket_policy" "bucket_policy" {
  bucket = aws_s3_bucket.my_bucket.id

  policy = jsonencode({
    Version   = "2012-10-17",
    Statement = [
      {
        Effect    = "Allow",
        Principal = {
          AWS = "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${aws_cloudfront_origin_access_identity.example.id}"
        },
        Action   = "s3:GetObject",
        Resource = "arn:aws:s3:::${aws_s3_bucket.my_bucket.bucket}/*",
      }
    ]
  })
}

コード検証

返答されたTerraformコードについて、実際にAWS上でデプロイできるか確認します。

この場合では、GPT-4では明示されていませんが、S3バケットの名前が一意になるように変更します。

Terraformコード(修正後)
provider "aws" {
  region = "ap-northeast-1"
}

resource "aws_s3_bucket" "my_bucket" {
  bucket = "chatgpt-static-website-hosting-bucket-<AWS ID>"
  acl    = "private"
}

resource "aws_cloudfront_origin_access_identity" "example" {
  comment = "example"
}

resource "aws_cloudfront_distribution" "s3_distribution" {
  origin {
    domain_name = aws_s3_bucket.my_bucket.bucket_regional_domain_name
    origin_id   = "myS3Origin"

    s3_origin_config {
      origin_access_identity = aws_cloudfront_origin_access_identity.example.cloudfront_access_identity_path
    }
  }

  enabled             = true
  is_ipv6_enabled     = true
  comment             = "S3 bucket distribution"
  default_root_object = "index.html"

  default_cache_behavior {
    allowed_methods  = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = "myS3Origin"

    forwarded_values {
      query_string = false

      cookies {
        forward = "none"
      }
    }

    viewer_protocol_policy = "allow-all"
    min_ttl                = 0
    default_ttl            = 3600
    max_ttl                = 86400
  }

  price_class = "PriceClass_100"
  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }
}

resource "aws_s3_bucket_policy" "bucket_policy" {
  bucket = aws_s3_bucket.my_bucket.id

  policy = jsonencode({
    Version   = "2012-10-17",
    Statement = [
      {
        Effect    = "Allow",
        Principal = {
          AWS = "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${aws_cloudfront_origin_access_identity.example.id}"
        },
        Action   = "s3:GetObject",
        Resource = "arn:aws:s3:::${aws_s3_bucket.my_bucket.bucket}/*",
      }
    ]
  })
}

このTerraformコードをデプロイした結果をターミナルで確認すると、想定通りのリソースが作成されている事が分かります。

$ terraform state list
aws_cloudfront_distribution.s3_distribution
aws_cloudfront_origin_access_identity.example
aws_s3_bucket.my_bucket
aws_s3_bucket_policy.bucket_policy

この場合も想定通りにIaCコードを生成してくれた一方で、2022年1月までの情報しか持っていないGPT-4はCloudFrontのOrigin Access Controlの設定に対応できない等の点もあり、あと一歩というような感じですかね。

パターン③:サーバレス構成図をCDKv2(TypeScript)に変換

最後に構成図をCDKに変換できるか試してみます。

質問内容

以下のようなHTTPAPIを用いたサーバレスCRUD構成図とメッセージをGPT-4に流した際に、どのようなCDKコードが返ってくるか確認してみます。

  • 構成図

  • メッセージ
この構成図をデプロイするCDKv2(TypeScript)コードを作成してください。ただし、テンプレートは3000トークンを超えたら分割し、私が「続き」と入力したら続きの回答を投稿してください。

GPT-4からの返答

GPT-4からの返答で提供されたコードについて、以下に完全な形で示します。

CDKコード
import { Stack, StackProps, Construct } from 'aws-cdk-lib';
import { aws_lambda as lambda, aws_lambda_nodejs as nodejs } from 'aws-cdk-lib';
import { aws_apigatewayv2 as apigateway } from 'aws-cdk-lib';
import { aws_dynamodb as dynamodb } from 'aws-cdk-lib';

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

    // DynamoDBテーブルの作成
    const table = new dynamodb.Table(this, 'Table', {
      partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
      removalPolicy: cdk.RemovalPolicy.DESTROY // 本番環境ではこの行は削除してください
    });

    // Lambda関数の作成
    const lambdaFunction = new nodejs.NodejsFunction(this, 'LambdaFunction', {
      runtime: lambda.Runtime.NODEJS_14_X,
      handler: 'handler',
      entry: 'path_to_your_lambda_file/index.ts', // Lambda関数のファイルパスを指定
      environment: {
        TABLE_NAME: table.tableName
      },
    });

    // Lambda関数へのDynamoDBテーブルのアクセス権を付与
    table.grantReadWriteData(lambdaFunction);

    // API Gatewayの作成
    const api = new apigateway.HttpApi(this, 'API');
    api.addRoutes({
      path: '/',
      methods: [ apigateway.HttpMethod.GET, apigateway.HttpMethod.POST ],
      integration: new apigateway.LambdaProxyIntegration({
        handler: lambdaFunction,
      }),
    });
  }
}

コード検証

返答されたCDKコードについて、実際にAWS上でデプロイできるか確認します。

この場合、aws-cdk-lib.aws_apigatewayv2をコードそのままで使用しようとするとエラーが起きるため、該当箇所を@aws-cdk/aws-apigatewayv2-alpha及び@aws-cdk/aws-apigatewayv2-integrations-alphaに置き換えます。

またNode.jsのバージョンについても、NODEJS_14_Xは近々非推奨化されるため、NODEJS_18_Xに変更します。

CDKコード(修正後)
import { Stack, StackProps, RemovalPolicy } from 'aws-cdk-lib';
import { aws_lambda as lambda, aws_lambda_nodejs as nodejs } from 'aws-cdk-lib';
import { HttpApi, HttpMethod } from '@aws-cdk/aws-apigatewayv2-alpha';
import { HttpLambdaIntegration }  from '@aws-cdk/aws-apigatewayv2-integrations-alpha';
import { aws_dynamodb as dynamodb } from 'aws-cdk-lib';
import { Construct } from 'constructs';

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

    // DynamoDBテーブルの作成
    const table = new dynamodb.Table(this, 'Table', {
      partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
      removalPolicy: RemovalPolicy.DESTROY // 本番環境ではこの行は削除してください
    });

    // Lambda関数の作成
    const lambdaFunction = new nodejs.NodejsFunction(this, 'LambdaFunction', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'handler',
      entry: 'lib/index.ts', // Lambda関数のファイルパスを指定
      environment: {
        TABLE_NAME: table.tableName
      },
    });

    // Lambda関数へのDynamoDBテーブルのアクセス権を付与
    table.grantReadWriteData(lambdaFunction);

    // API Gatewayの作成
    const api = new HttpApi(this, 'API');
    api.addRoutes({
      path: '/',
      methods: [ HttpMethod.GET, HttpMethod.POST ],
      integration: new HttpLambdaIntegration('LambdaIntegration',  lambdaFunction),
    });
  }
}

このCDKコードをデプロイした結果を(CloudFormation)コンソールで確認すると、想定通りのリソースが作成されている事が分かります。

残念ながら提供されたCDKコードについてはそのまま使えなかったため、いくつかエラーを調査し修正を入れた上でデプロイする事が可能になりました。

最後に

今回はChatGPTの新機能であるGPT-4Vを使って、様々なAWSの構成図を入力し、どこまで正確にIaCコードが生成できるか確認してみました。

きちんと情報が盛り込まれている構成図を入力した場合、体感8-9割方は正確にIaCコードを生成してくれるように感じました。

しかし残りの1-2割程度は、必要な情報が不足していたり、誤っている情報が含まれてしまうため、適宜ユーザ側で補足・修正する必要がありそうです。

さすがに提供されたIaCコードに手を加える事なく利用するのは難しいと感じましたが、それでも構成図だけでIaCコードを推測し生成してくれるのはかなり便利だと思いました。

普段IaCツールを使用してAWSリソースをデプロイしている方は、ぜひ一度GPT-4Vを触ってみてはいかがでしょうか。

以上、つくぼし(tsukuboshi0755)でした!