CloudFormationを使用してアカウント間でのリソース移行をしてみた
こんにちは、中根です。
コンソール画面から手動で構築したリソースを、複製したり別アカウントへ移行したいということもあるかと思います。
その際に、同じ設定のリソースを手動で構築するのは手間がかかりますし、ミスにも繋がります。
そこで今回は、CloudFormationというサービスを使用して、リソースをテンプレートとして管理し、別アカウントに移行するという方法を紹介します!
CloudFormationとは
CloudFormationは、JSONまたはYAML形式のテキストファイルを使用して、AWSリソースを自動構築するサービスです。
AWSリソースの設定をテンプレート化できるため、同じ環境を何度でも自動で構築することが可能となります。
CloudFormation自体は無料で使用できますが、CloudFormationで構築された各リソースは通常通り課金の対象となります。
今回の目標
今回は、CloudFront・S3・API Gateway・Lambdaを使用したサービスを別アカウントに複製していきます。
以下が移行するサービスの画面となります。

「Lambda実行」のボタンを押すと、Lambdaが「Hello World!」を返すものとなっています。
Lambdaのソースコードは以下のようなシンプルなものです。
exports.handler = async (event) => {
console.log('Lambda Start');
const response = {
statusCode: 200,
body: 'Hello World!',
};
return response;
};
構成図
別アカウントに移行するサービスの構成図は以下のようになっています。

S3+CloudFrontのテンプレート作成
はじめにS3とCloudFrontの部分のテンプレートをYAML形式で作成しました。
テンプレートは以下のような設定で作成しています。
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Globals:
Api:
OpenApiVersion: 3.0.2
Resources:
#S3バケット
S3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: S3BucketName
PublicAccessBlockConfiguration: #パブリックアクセスブロックを有効化
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
#バケットポリシー
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref S3Bucket
PolicyDocument:
Id: MyPolicy
Version: 2012-10-17
Statement: #OAIからのみのアクセスに制限
- Sid: '1'
Effect: Allow
Action: s3:GetObject
Resource: arn:aws:s3:::S3BucketName/*
Principal:
OriginAccessIdentity: !Sub 'origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}'
#CloudFront
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- Id: S3Origin
DomainName: !GetAtt S3Bucket.DomainName
S3OriginConfig:
OriginAccessIdentity: !Sub 'origin-access-identity/cloudfront/{CloudFrontOriginAccessIdentity}' #OAIを紐づけ
Enabled: true #ディストリビューションを有効化
DefaultRootObject: index.html
DefaultCacheBehavior:
AllowedMethods: #許可された HTTP メソッド
- GET
- HEAD
TargetOriginId: S3Origin
ForwardedValues:
QueryString: false
ViewerProtocolPolicy: https-only #ビューワープロトコルポリシー
CloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig: #OAIを作成
Comment: !Ref AWS::StackName
API Gateway+Lambdaのテンプレート作成
先ほどのテンプレートの続きに、API GatewayとLambdaの設定を記述していきます。
#API Gateway
APIGateway: #論理ID
Type: AWS::Serverless::Api
Properties:
StageName: dev #ステージ名
Name: api-blog-test
DefinitionBody: #解説①
Fn::Transform:
Name: AWS::Include
Parameters:
#API構成ファイルのパス
Location: s3://×××××/××××××××-swagger-apigateway.yaml
#Lambda
LambdaFunction: #論理ID
Type: 'AWS::Serverless::Function'
Properties:
Handler: index.handler
Runtime: nodejs16.x
#解説②
CodeUri: s3://×××××/××××××××××.zip
Description: ''
MemorySize: 128
Timeout: 3
Role: 'arn:aws:iam::××××:role/lambdaRole' #実行ロール(IAMロールが無い場合は事前に作成する必要がある)
Events: #API Gatewayを紐づけ
Api:
Type: Api
Properties:
Path: /
Method: GET
RestApiId: !Ref APIGateway
解説① DefinitionBody
DefinitionBodyには、API Gatewayの定義ファイルを設定します。
定義ファイルはコンソール画面からエクスポートすることができます。

エクスポートした定義ファイルを開き、紐づけるLambdaを指定している「uri」の部分を、複製するLambda用に書き換えます。

続いて、定義ファイルを配置するためのS3バケットを作成します。
作成したS3バケットに、編集した定義ファイルをアップロードして、S3 URIを控えます。

控えておいたS3 URIをDefinitionBodyのLocationにセットすることで、API Gatewayの設定を複製することができます。
開発② CodeUri
CodeUriには、Lambda関数のソースコードをzip化したものを配置したフォルダパスを指定します。
zip化したソースコードはLambdaのコンソール画面からエクスポートすることができます。
Lambda関数の画面から、「アクション」⇒「関数のエクスポート」をクリックすると、以下のようなエクスポート画面が表示されます。
zipファイルをエクスポートするには、「デプロイパッケージのダウンロード」をクリックします。

エクスポートしたzipファイルを、先ほどのAPI Gatewayの定義ファイルをアップロードしたS3バケットにアップロードします。

S3 URIをテンプレートのCodeUriにセットすることで、Lambda関数のソースコードを複製することができます。
テンプレートの読込
テンプレートの作成が完了したら、複製したいアカウントのCloudFormationの画面からテンプレートを読み込んで、リソースを作成します。
CloudFormationの画面から、「スタックの作成」⇒「新しいリソースを使用(標準)」をクリックして、スタックを作成する画面へ遷移します。
ちなみにスタックとは、テンプレートによって作成されたリソースの集まりのことを表します。

スタックの作成画面で、ローカルにあるテンプレートファイルをアップロードします。

スタックの詳細を指定する画面では、スタックの名前を設定します。

次のスタックオプションの設定画面では、何も変更せずに進みます。
最後のレビュー画面で、以下のような確認項目が表示された場合は、すべてチェック入れてスタックの作成を行います。

スタックの作成を開始すると、各リソースの作成状況が表示されます。
スタックのステータスが「UPDATE_COMPLATE」と表示されたら、作成が成功しているということになります。

動作確認
Lambdaが作成され、API Gatewayと紐づいていることが確認できます。

CloudFrontとS3も作成されているかと思いますが、S3はバケットとバケットポリシーを作成しただけなので、HTMLファイルなどは再度アップロードする必要があります。
CloudFrontのディストリビューションドメイン名にアクセスすると、S3にアップロードした画面が表示され、ボタンクリックでLambdaが実行できるようになっています。

さいごに
今回は、CloudFormationを使用してコンソール画面から手動で作成したリソースを、別アカウントに移行する方法を紹介しました。
今回の構成のテンプレートは90行ほどのボリュームとなりましたが、一度作成しておけば何度でも複製できたり、部分的に編集して使いまわすことも可能です!
作成したスタックを更新することも可能なので、今後試してみたいと思います。