AWS-CloudFormation

IaCジェネレーターを用いて手動で作ったリソースをCFnで作り直してみた

はじめに

こんにちは、omkです。
IaCジェネレータで手動構築のAWSリソースをCFnテンプレートに起こせるようになりましたが、そうなればやりたいことは勿論これ、
「手動構築のリソースをCFnで作り直す(さらに別アカウントに持っていく)」です。

同じものが必要になって「あ~最初からCFnで作っておけばよかったぁ~~」となったことありますよね?

IaCジェネレータを用いれば手動で作ったリソースからCFnテンプレートを作成することが出来るのでそれを元に別の環境を作成することが出来ます。
ただし本来は手動で作成したリソースをCFnにインポートすることが目的のサービスだと思うのでこの用途で利用する場合には多少の修正対応が必要となります。
ではどういった修正が必要か、そちらを以下に記載します。

コード管理に切り替えるだけならそのままCFnにインポート出来るのでこちらも合わせて参照ください。
CloudFormation IaCジェネレーターで既存AWSリソースをCFnにインポートしてみた

やってみた

まずはリソースをスキャンして必要なリソースを含めたテンプレートを作成します。
今回の例ではよくあるVPCを例に、VPC、サブネット(パブリック2、プライベート2)、インターネットゲートウェイ、ルートテーブル(パブリックとプライベート)を対象とします。

こんな感じのテンプレートが出力されます。全文を載せると長いので省略しています。

---
Metadata:
  TemplateId: "arn:aws:cloudformation:ap-northeast-1:(AWSアカウントID):generatedTemplate/ac9dd3d4-f68d-466a-9708-1b2647b4f94b"
Resources:
  EC2SubnetRouteTableAssociation00rtbassoc02904f3f534973e6f00Ofr6g:
    UpdateReplacePolicy: "Retain"
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    DeletionPolicy: "Retain"
    Properties:
      RouteTableId:
        Ref: "EC2RouteTable00rtb05ace459107ad42d0003UbVc"
      SubnetId:
        Ref: "EC2Subnet00subnet00edf482151a854be00RDUbQ"
  EC2Subnet00subnet06b596fb98ac98c8900hkCmd:
    UpdateReplacePolicy: "Retain"
    Type: "AWS::EC2::Subnet"
    DeletionPolicy: "Retain"
    Properties:
      VpcId: "vpc-0dbfb733a9c4c444a"
      MapPublicIpOnLaunch: false
      EnableDns64: false
      AvailabilityZoneId: "apne1-az4"
      PrivateDnsNameOptionsOnLaunch:
        EnableResourceNameDnsARecord: false
        HostnameType: "ip-name"
        EnableResourceNameDnsAAAARecord: false
      CidrBlock: "192.168.8.0/24"
      Ipv6Native: false
      Tags:
      - Value: "omukai-vpc-sub-pri1"
        Key: "Name"
  EC2VPC00vpc0dbfb733a9c4c444a00fzZia:
    UpdateReplacePolicy: "Retain"
    Type: "AWS::EC2::VPC"
    DeletionPolicy: "Retain"
    Properties:
      CidrBlock: "192.168.0.0/16"
      EnableDnsSupport: true
      InstanceTenancy: "default"
      EnableDnsHostnames: true
      Tags:
      - Value: "omukai-vpc"
        Key: "Name"

(以下略)

0. そもそも新規リソースの作成に生成されたテンプレートが利用できるか

まずはテンプレートをダウンロードしてそのまま新規スタックの作成時に利用してみます。
「既存リソースと同じアカウントの同じリージョン」「別のアカウント」でそれぞれ実行してみましたが失敗しました。

失敗の原因は同じアカウントパターンでは、サブネットのリソース作成でVPCIDを参照する箇所があり、既存のリソースのIDがベタ書きされていたため、同じCIDRを指定しようとして拒否されていました。
別のアカウントパターンでは同様にサブネットでVPCIDを参照する箇所で既存リソースのIDがベタ書きされていたことで存在しないリソースを参照しようとして失敗していました。

ということでテンプレートのフォーマット自体の改造をしなくても個別のエラーに対応していけば問題なく作り直しが出来そうです。
CFnテンプレートのフォーマットについてはテンプレートの構造分析を参照。

YAMLの場合に先頭についてくるハイフン3つもYAMLのフォーマットなので有って問題ないです。

というわけでテンプレートを直せば作り直しができることが確認できたので具体的な修正対応を考えていきます。

1. 論理IDの変更

割り当てられたランダムな文字でのテンプレートの修正は対象リソースが見えづらくしんどいので論理IDを変更します。
プロパティから頑張って対象リソースを特定して変更していきます。
論理IDの置き換えはテキストエディタなどで置換も可能ですがIaCジェネレータ側でも可能です。

命名はともかく先程よりはすっきり見やすくなりました。

---
Metadata:
  TemplateId: "arn:aws:cloudformation:ap-northeast-1:(AWSアカウントID):generatedTemplate/ac9dd3d4-f68d-466a-9708-1b2647b4f94b"
Resources:
  PublicRouteTable:
    UpdateReplacePolicy: "Retain"
    Type: "AWS::EC2::RouteTable"
    DeletionPolicy: "Retain"
    Properties:
      VpcId:
        Ref: "VPC"
      Tags:
      - Value: "omukai-vpc-pub-route"
        Key: "Name"
  VPC:
    UpdateReplacePolicy: "Retain"
    Type: "AWS::EC2::VPC"
    DeletionPolicy: "Retain"
    Properties:
      CidrBlock: "192.168.0.0/16"
      EnableDnsSupport: true
      InstanceTenancy: "default"
      EnableDnsHostnames: true
      Tags:
      - Value: "omukai-vpc"
        Key: "Name"
(以下略)

2. 参照リソースの変更・リソース名の変更・リージョンIDやアカウントIDの変更

多くの場合、テンプレートをそのまま利用できない原因はここにあると思います。
先ほどそのまま流してみてエラーになった原因も参照先リソースがリソースIDでベタ書きされていたためでした。

参照の記述は組み込み関数を利用して論理IDで表現するのが良いでしょう。

また、同一アカウント内や同一リージョン内、もしくはグローバルで一意の名前を指定しなければならないリソースがある場合も注意が必要です(S3バケットなど)。
インポートする場合には新たに名前を考慮する必要はありませんが新規リソースの作成に利用する場合は別です。
別名を設定するかパラメータで都度入力できるようにします。

参照先のリソース指定がARNを要求するプロパティもあります。
別のリージョンや別のアカウントで利用する際にはこの点も修正が必要です。
同じテンプレート内にリソースが存在してGetAtt関数でARNが取得できる場合はそれに置き換え、できない場合は「AWS::Region」や「AWS::AccountId」の疑似パラメータを利用してSub関数で置き換えるのが良いと思います。

ではではテンプレートを修正していきます。
変更前はサブネットのVPCIDがベタ書きでした。

      VpcId: "vpc-0dbfb733a9c4c444a"

RefでVPCIDを参照するようにしました。

      VpcId: !Ref "VPC"

3. 個別のエラーに対応

CFnのリファレンスを見ながらエラー対応をしていきます。

今回だとインターネットゲートウェイへのルートで「GatewayId」でRefでVPCIDを参照しているのとは別に「VpcEndpointId」にVPCIDがベタ書きされていてエラーになりました。この場合「VpcEndpointId」は指定しなくていいので消すという対応をしました。
また、ルートテーブルのローカル向きのルートもIaCジェネレーターでは生成されますが、新規リソースの作成においてはルートテーブルの作成時に勝手にルートも作成されるので消しました。

こんな感じでリソース特有のエラーが出ることもあると思います。
その他にもリソースの依存関係を明示する必要がある場合にDependsOn属性を追加したりと普通の新規リソース作成時に躓くポイントを潰していきます。

4. 標準化対応

必要であればリソース名や設定値をパラメータやマッピングに含めて可変にしたり他のテンプレートで参照するような属性をアウトプットするようにしたりの対応を実施します。
今回の例ではVPCのCIDRがベタ書きになっているのでパラメータで指定するなどです。その場合はサブネットのCIDRも合わせて変更されるようにCidr関数を利用するよう修正するというように別のリソースが受ける影響も考慮します。

5 完成

実行してリソースが作成されることを確認します。
元のリソースが存在したAWSアカウントとは別のアカウントにデプロイしてみました。

問題なくリソースが作成されました。

おわりに

IaCジェネレータで既存リソースをスキャンして作成したテンプレートでリソースの引っ越しが出来るかを検証してみました。
全部が全部これで対応できるわけではないと思いますが一部だけでも持っていけると少しは楽になると思います。

以上、最後までお付き合いありがとうございました。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA