ForgeVision Engineer Blog

フォージビジョン エンジニア ブログ

CloudFormationの機能をおさらいしよう!~スタックへの既存リソースのインポート編~

初めまして。伊藤です。
フォージビジョンに入社して初めてのブログ執筆となります。よろしくお願いいたします。

本記事では、CloudFormationのインポート機能について紹介いたします。
手動で作成したIAMロールをインポートすることで検証作業を行います。

前提

CloudFormationのインポート機能はリソースによってサポートされていない場合があります。
今回の例で言えば、IAMロールはインポート可能ですが、IAMポリシーはインポートすることができません。

サポートされているリソースは一覧としてリストアップされているため、作業前に必ず確認してください。

docs.aws.amazon.com

手順

CloudFormationスタックが無い場合と有る場合とで内容が若干異なりますが、 大まかな手順は以下のようになっています。

  1. AWSコンソールで取り込み対象リソースの内容を確認する
  2. インポート用テンプレートを作成する
  3. インポート用コマンドを用意する
  4. コマンドを実行しAWSコンソールでスタックの状態を確認する

CloudFormationの操作はAWS CLIを想定して記載していきます。

CloudFormationスタックが無い場合

AWSコンソールで取り込み対象リソースの内容を確認する

対象のリソースがどのような設定で作成されているのかを確認します。
同様の設定内容でテンプレートファイルを作成する必要があるためです。

対象リソースの確認01

対象リソースの確認02

インポート用テンプレートを作成する

対象リソースと同様の設定内容で定義するだけでなく、「DeletionPolicy: Retain」が付与されている必要があります。
また、同一テンプレート内ではリソースの新規作成や設定変更を行わず、インポート処理のみを行うように記述しましょう。

---
AWSTemplateFormatVersion: 2010-09-09
Description: IAM Tempalate for Import Feasibility

Resources:
  TestRole:
    Type: AWS::IAM::Role
    DeletionPolicy: Retain
    Properties:
      RoleName: fv_ito_test_role
      Path: /
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: s3.amazonaws.com
            Action: "sts:AssumeRole"

インポート用コマンドを用意する

スタックが無い場合でもcreate-change-setを使用します。

aws cloudformation create-change-set \
    --stack-name test-ito-cfn-stack-import \
    --change-set-name test-ito-cfn-change-set-import \
    --change-set-type IMPORT \
    --resources-to-import "[{\"ResourceType\":\"AWS::IAM::Role\",\"LogicalResourceId\":\"TestRole\",\"ResourceIdentifier\":{\"RoleName\":\"fv_ito_test_role\"}}]" \
    --template-body file://IAM/template_import.yaml \
    --capabilities CAPABILITY_NAMED_IAM


aws cloudformation execute-change-set \
    --stack-name test-ito-cfn-stack-import \
    --change-set-name test-ito-cfn-change-set-import

コマンドを実行しAWSコンソールでスタックの状態を確認する

スタックが無い状態でcreate-change-setを実行すると以下のようになります。

スタックの確認01

変更セットの確認01

スタックのイベントが「REVIEW_IN_PROGRESS」となっています。
このイベントは変更セットを実行するまで進みません。

変更セットではアクションの内容が「Import」になっていることがわかります。

execute-change-setを実行するとスタックのイベントが進み、インポートが完了します。
リソースタブにて取り込み対象のリソースが表示されていることを確認します。

スタックの確認02

スタックの確認03

CloudFormationスタックが有る場合

AWSコンソールで取り込み対象リソースの内容を確認する

対象リソースがどのような設定で作成されているのかを確認します。
ここでは先ほど取り込んだものと別のIAMロールを対象として進めていきます。

対象リソースの確認03

対象リソースの確認04

インポート用テンプレートを作成する

先ほどと同様にインポート処理のみを行うよう記述しますが、
CloudFormation上で更新のない記述であればテンプレート内に存在していても問題ありません。

---
AWSTemplateFormatVersion: 2010-09-09
Description: IAM Tempalate for Import Feasibility

Resources:
  TestRole:
    Type: AWS::IAM::Role
    DeletionPolicy: Retain
    Properties:
      RoleName: fv_ito_test_role
      Path: /
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: s3.amazonaws.com
            Action: "sts:AssumeRole"

  Test2Role:
    Type: AWS::IAM::Role
    DeletionPolicy: Retain
    Properties:
      RoleName: fv_ito_test2_role
      Path: /
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: "sts:AssumeRole"
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess

インポート用コマンドを用意する

既存スタックを指定する形でcreate-change-setを使用します。
--resources-to-import」で指定するリソース情報はコマンドラインでも問題ありませんが、
リソース数が多い場合を想定するとファイルとして渡す方が簡潔になります。

aws cloudformation create-change-set \
    --stack-name test-ito-cfn-stack-import \
    --change-set-name test-ito-cfn-change-set-import \
    --change-set-type IMPORT \
    --resources-to-import file://IAM/import_target.txt \
    --template-body file://IAM/template_import.yaml \
    --capabilities CAPABILITY_NAMED_IAM


・import_target.txt

[
    {
        "ResourceType": "AWS::IAM::Role",
        "LogicalResourceId": "Test2Role",
        "ResourceIdentifier":
            {
                "RoleName": "fv_ito_test2_role"
            }
    }
]


aws cloudformation execute-change-set \
    --stack-name test-ito-cfn-stack-import \
    --change-set-name test-ito-cfn-change-set-import

コマンドを実行しAWSコンソールでスタックの状態を確認する

変更セットの作成と実行を行います。
リソースタブに対象リソースが含まれていることを確認します。

変更セットの確認02

スタックの確認04

スタックの確認05

インポート作業で気になったこと

IAMポリシーのアタッチについて

冒頭にて、CloudFormationのインポート機能ではIAMポリシーがサポートされていないと書きましたが、
IAMポリシーがアタッチされたままIAMロールをインポートすることは可能です。

ただし、IAMロールはCloudFormationの管理下にあるものの、アタッチされているIAMポリシーは管理下にない、
という状態になってしまいますので、インポート後に何らかの対応をすべきかと思います。

例)IAMポリシーを手動削除後、CloudFormationで新規作成

ResourceIdentifierとは?

--resources-to-import」にてリソース情報を指定する際、ResourceIdentifierという値が必要になります。

リソースタイプごとに特定の値が定義されているのですが、どこかにリストアップされている訳でもないため、
最初はどんな値を設定すればよいか判断できない場合があるかもしれません。

私も当初は「リソースが特定できればいいだろう」くらいの認識だったため、
以下のような値で実行しようとしたことがありました。

[
    {
        "ResourceType": "AWS::IAM::Role",
        "LogicalResourceId": "Test2Role",
        "ResourceIdentifier":
            {
                "Arn": "arn:aws:iam::{AWS::AccountId}:role/fv_ito_test2_role"
            }
    }
]


その結果、(当然ですが)エラーが返ってきました。

An error occurred (ValidationError) when calling the CreateChangeSet operation: Invalid resource identifier for resource type AWS::IAM::Role. Expected [RoleName]

ありがたいことに、
AWS::IAM::Roleのresource identifierは[RoleName]かも!
といったメッセージが含まれていたため、修正して作業を進めることができました。

とはいえ毎回エラーメッセージに教えてもらうのも大変です。
ResourceIdentifierの確認についてはCloudFormationのドキュメントに記載があります。

オプションで GetTemplateSummary を実行して、テンプレート内の各リソースタイプを識別するプロパティを確認できます。 たとえば、AWS::DynamoDB::Table リソースは TableName プロパティを使用して識別できます。

> aws cloudformation get-template-summary 
    --template-url https://DOC-EXAMPLE-BUCKET.s3.us-west-2.amazonaws.com/TemplateToImport.json

docs.aws.amazon.com

get-template-summaryを実行すると、指定したテンプレートに関する情報を取得することができます。

awscli.amazonaws.com

試しに検証で使用したテンプレートに対して実行してみましょう。

$ aws cloudformation get-template-summary \
>     --template-body file://IAM/template_import.yaml
{
    "CapabilitiesReason": "The following resource(s) require capabilities: [AWS::IAM::Role]", 
    "Description": "IAM Tempalate for Import Feasibility", 
    "Parameters": [], 
    "Capabilities": [
        "CAPABILITY_NAMED_IAM"
    ], 
    "ResourceTypes": [
        "AWS::IAM::Role"
    ], 
    "Version": "2010-09-09", 
    "ResourceIdentifierSummaries": [
        {
            "ResourceType": "AWS::IAM::Role", 
            "LogicalResourceIds": [
                "TestRole"
            ], 
            "ResourceIdentifiers": [
                "RoleName"
            ]
        }
    ]
}


このコマンド結果から、
リソースタイプがAWS::IAM::Roleの時、ResourceIdentifierはRoleNameであることがわかります。

初めてインポートするリソースタイプの場合は、このコマンドからResourceIdentifierを確認しておくとスムーズに進められるかと思います。

まとめ

上記の手順によってリソースのインポートを行うことができました。
インポート後は通常通りCloudFormationを介して更新することができます。

ただし、インポート直後のテンプレートには「DeletionPolicy: Retain」が付与されたままですので、
運用フローを考慮して不要な場合は削除しておきましょう。

2023/11/21 追記

コメントをいただきましたので補足として追記いたします。

前提としてインポート機能によってサポートされているリソースを確認しましょう、というお話をしました。
そこで「IAMポリシーはインポートすることができない」と記載いたしましたが、
英語ドキュメントではサポート一覧に含まれておりました。

docs.aws.amazon.com

英語ドキュメントと日本語ドキュメントではアップデートにラグが発生することがあります。
時間が経てば日本語ドキュメントにも反映されるはずですが、
それまでは英語ドキュメントを参照していただければと思います。