LoginSignup
2
0

More than 1 year has passed since last update.

Terraformで構築したリソースの情報をAWS SAMに引き渡す

Posted at

はじめに

本記事では、Terraformで構築したリソースの情報をAWS SAM テンプレートに引き渡す方法について解説しています。

VPCやサブネット、セキュリティグループなどのネットワーク関連のリソースはTerraformで管理し、Lambda関数はAWS SAMで管理するケースをサンプルコードで説明しています。

本ケースの全体構成

terraform_resource_export.png

本ケースのサンプルコード

ディレクトリ構成

aws-tf-resource-export-sample
├── main.tf
├── provider.tf
├── src
│   └── lambda_function.py
├── template.yaml
└── tf-resource-export.yml

Terraform側のコード

aws_cloudformation_stack を使って、リソースの情報(ここでは、SunbetIdSecurityGroupId)を、CloudFormation のテンプレートのOutputs セクションに組み込んだStackを構築するようにしています。

main.tf
#
# リソースの情報をCloudformationのOutputs機能を使ってエクスポートする
# このStackでTerraformのバックエンド用のリソースを作成する
#
resource "aws_cloudformation_stack" "this" {
  name = "tf-resource-export-sample"

  template_body = templatefile("./tf-resource-export.yml", {

    # tfstateのリソース作成用
    tfstate_backend = {
      s3_bucket_name          = "tf-resource-export-sample"
      dynamodb_for_state_lock = "tf-resource-export-sample"
    },

    # サブネット情報のOutputs用
    network = {
      private_subnet_1a_name = "PrivateSubnet1a"
      private_subnet_1a_id   = module.network.private_subnets[0]
      private_subnet_1c_name = "PrivateSubnet1c"
      private_subnet_1c_id   = module.network.private_subnets[1]
    },

    # セキュリティグループ情報のOutputs用
    security_group = {
      name_for_lambda = "HelloWorldFunctionSG"
      id_for_lambda   = aws_security_group.this.id
    }
  })
}

#
# Terraformで構築するリソース
#
*** 以下、省略 ***

CloudFormation のテンプレート

tf-resource-export.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: "Terraform Resource info Export Template"

Resources:
  TfStateBucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
    Properties:
      BucketName: ${tfstate_backend["s3_bucket_name"]}
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true

  TfStateLockTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: ${tfstate_backend["dynamodb_for_state_lock"]}
      ProvisionedThroughput:
        ReadCapacityUnits: 1
        WriteCapacityUnits: 1
      AttributeDefinitions:
        - AttributeName: "LockID"
          AttributeType: "S"
      KeySchema:
        - AttributeName: "LockID"
          KeyType: "HASH"

#
# Terraform で構築したリソースの情報をこのOutputsセクションに組み込みます。
#
Outputs:
  PrivateSubnet1a:
    Description: "Id for PrivateSubnet 1a"
    Export:
      Name: ${network["private_subnet_1a_name"]}
    Value: ${network["private_subnet_1a_id"]}

  PrivateSubnet1c:
    Description: "Id for PrivateSubnet 1c"
    Export:
      Name: ${network["private_subnet_1c_name"]}
    Value: ${network["private_subnet_1c_id"]}

  HelloWorldFunctionSG:
    Description: "Security Group for HelloWorldFunction"
    Export:
      Name: ${security_group["name_for_lambda"]}
    Value: ${security_group["id_for_lambda"]}

※CloudFormationのテンプレートは、Resources が必須で、Outputs のみを記載することができないため、このサンプルコードでは、Resources にTerraformのtfstateを管理するためのバックエンド用リソースを構築するようにしています。

AWS SAM側のコード

Fn::ImportValue 組み込み関数 を使って、Terraform側で構築したStackのOutputsの値をクロススタック参照するようにAWS SAM Template に組み込みます。

template.yaml
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: "Lambda Function SAM Template"

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: HelloWorldFunction
      Handler: lambda_function.lambda_handler
      Runtime: python3.9
      CodeUri: ./src/
      Timeout: 10
      MemorySize: 128
#
# Fn::ImportValue 組み込み関数で値をインポートします。
#
      VpcConfig:
        SecurityGroupIds:
          - !ImportValue HelloWorldFunctionSG
        SubnetIds:
          - !ImportValue PrivateSubnet1a
          - !ImportValue PrivateSubnet1c
      Policies:
        - AWSLambdaVPCAccessExecutionRole
        - AWSLambdaBasicExecutionRole

Outputs:
  HelloWorldFunction:
    Description: "HelloWorldFunction ARN"
    Value: !GetAtt HelloWorldFunction.Arn

これで、Terraformで構築したリソースの情報をAWS SAMに引き渡すことができるようになります。

本ケースのデプロイ手順

実際に、TerraformAWS SAMを使って、本ケースをデプロイする手順について、記載します。

デプロイ手順確認環境

$ terraform -version
Terraform v1.4.4
on darwin_amd64
+ provider registry.terraform.io/hashicorp/aws v4.62.0

$ sam --version
SAM CLI, version 1.79.0

Terraformの実行

リソースの構築

Terraform でネットワーク関連のリソースとその情報をOutputs セクションに組み込んだStackを構築します。

$ export AWS_PROFILE= [ YOUR AWS ACCOUNT PROFILE NAME ]
$ terraform init
Initializing the backend...
Successfully configured the backend "local"! Terraform will automatically

$ terraform plan
Plan: 9 to add, 0 to change, 0 to destroy.

$ terraform apply
Apply complete! Resources: 9 added, 0 changed, 0 destroyed.

tfstateを管理するバックエンドの変更

下記のようにprovider.tf内のtfstateのバックエンド先をLocalからS3に修正します。

provider.tf
  #backend "local" {
  #  path = "terraform.tfstate"
  #}

  backend "s3" {
    bucket         = "tf-resource-export-sample"
    key            = "terraform.tfstate"
    dynamodb_table = "tf-resource-export-sample"
    region         = "ap-northeast-1"
  }

下記コマンドを実行して、tfstateを管理するバックエンドをLocalからS3に変更します。

$ terraform init -migrate-state

Initializing the backend...
Terraform detected that the backend type changed from "local" to "s3".

Do you want to copy existing state to the new backend?
  Pre-existing state was found while migrating the previous "local" backend to the
  newly configured "s3" backend. No existing state was found in the newly
  configured "s3" backend. Do you want to copy this state to the new "s3"
  backend? Enter "yes" to copy and "no" to start with an empty state.

  Enter a value: yes 

下記コマンドを実行して、tfstateが、S3に保存されていることを確認します。

$ aws s3 ls s3://tf-resource-export-sample
9999-99-99 99:99:99      13870 terraform.tfstate

AWS SAMの実行

Lambda関数の構築

下記コマンドを実行して、AWS SAM TemplateでLambda関数をデプロイします。

sam deploy --template-file template.yaml \
           --stack-name tf-resource-import-sample \
           --resolve-s3 \
           --capabilities CAPABILITY_IAM \
           --region ap-northeast-1

CloudFormation stack changeset
---------------------------------------------------------------------------------------------------------------------------------
Operation                        LogicalResourceId                ResourceType                     Replacement                    
---------------------------------------------------------------------------------------------------------------------------------
+ Add                            HelloWorldFunctionRole           AWS::IAM::Role                   N/A                            
+ Add                            HelloWorldFunction               AWS::Lambda::Function            N/A                            
---------------------------------------------------------------------------------------------------------------------------------

デプロイできました。

CloudFormation outputs from deployed stack
---------------------------------------------------------------------------------------------------------------------------------
Outputs                                                                                                                         
---------------------------------------------------------------------------------------------------------------------------------
Key                 HelloWorldFunction                                                                                          
Description         HelloWorldFunction ARN                                                                                      
Value               arn:aws:lambda:ap-northeast-1:999999999999:function:HelloWorldFunction                                      
---------------------------------------------------------------------------------------------------------------------------------

Successfully created/updated stack - tf-resource-import-sample in ap-northeast-1

動作確認

下記コマンドで、デプロイしたLambda関数を実行します。

$ aws lambda invoke --function-name HelloWorldFunction /dev/stdout
{"statusCode": 200, "body": "{\"message\": \"Hello World!\"}"}
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}

クリーンアップ

Lambda関数の削除

下記コマンドで、AWS SAM Template でデプロイしたLambda関数を削除します。

$ sam delete --stack-name tf-resource-import-sample
        Are you sure you want to delete the stack tf-resource-import-sample in the region ap-northeast-1 ? [y/N]: y
        Do you want to delete the template file 71b91735b453182a1c33df8bceda4df3.template in S3? [y/N]: y

Deleted successfully

tfstateを管理するバックエンドの変更

下記のようにprovider.tf内のtfstateのバックエンド先をS3からLocalに修正します。

provider.tf
  backend "local" {
    path = "terraform.tfstate"
  }

  #backend "s3" {
  #  bucket         = "tf-resource-export-sample"
  #  key            = "terraform.tfstate"
  #  dynamodb_table = "tf-resource-export-sample"
  #  region         = "ap-northeast-1"
  #}

下記コマンドを実行して、tfstateを管理するバックエンドをS3からLocalに変更します。

$ terraform init -migrate-state -lock=false

Initializing the backend...
Terraform detected that the backend type changed from "s3" to "local".

Do you want to copy existing state to the new backend?
  Pre-existing state was found while migrating the previous "s3" backend to the
  newly configured "local" backend. No existing state was found in the newly
  configured "local" backend. Do you want to copy this state to the new "local"
  backend? Enter "yes" to copy and "no" to start with an empty state.

  Enter a value: yes

リソースの削除

下記コマンドで、各リソースを削除します。

$ terraform destroy
Destroy complete! Resources: 9 destroyed.

下記コマンドで、tfstate用のS3バケットを削除します。

$ aws s3 rb s3://tf-resource-export-sample --force        
delete: s3://tf-resource-export-sample/terraform.tfstate
remove_bucket: tf-resource-export-sample

以上です。

さいごに

こちらは、あくまで1例になります。参考になれば幸いです。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0