CloudFormationのresource importを試してみた

# はじめに
ソリューションアーキテクトプロフェッショナルの勉強をしていて、CloudFormationのリソースインポートが気になったので、公式を参考に手を動かしてみました。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/resource-import.html

# 概要
- `resource import`は、次の2つができる
    - CloudFormationスタックのリソースとして紐づいていないリソースを、新しいCloudFormationスタックのリソースにできる
    - 既にあるCloudFormationスタックに、どのスタックにも含まれていないリソースを取り込める
        - 同時に既存スタックの変更・削除はできない


# 紐づいていないリソースをスタックにまとめる
以下を参考にしました。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/resource-import-new-stack.html

ここでは、CLIでつくった2つのリソースを、1つのスタックにまとめます。

## 事前準備
以下の2つのIAMユーザを作成します。

```bash
aws iam create-user --user-name Anisphia
aws iam create-user --user-name Euphyllia
```


## 1つのスタックにまとめる
以下のテンプレートを使います。
```yaml:createPair.yaml
AWSTemplateFormatVersion: 2010-09-09

Resources:
  Heroine:
    Type: AWS::IAM::User
    DeletionPolicy: Retain

  Fiancee:
    Type: AWS::IAM::User
    DeletionPolicy: Retain
```

### コンソールから
「既存のリソースを使用（リソースのインポート）)」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/e58832df-7df4-55b9-b844-e6a4a80bf6d0.png)

「リソースを識別」は特に入力がないので遷移し、「テンプレートの指定」では先のファイルを指定します。

「リソースを識別」で、事前準備で作成したリソースの情報を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/9a8ab95e-862d-9c42-856c-6b1a22c9c166.png)

「スタックの詳細を指定」でスタック名を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/b6f4ab61-4f26-13ba-31f7-07642489ad93.png)

「リソースをインポート」で開始します。ステータスは「IMPORT_IN_PROGRESS」でした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/f3084df6-e987-2d08-0ba6-e632608b1958.png)

正常に取り込まれると、「IMPORT_COMPLETE」になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/fd2bc80d-7742-cf61-de3e-c29b94214c7e.png)

CLIから作成したリソースが、スタックのリソースとして取り込まれました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/c09cfcba-e466-7af4-ba94-1ca5c0b2bf56.png)


### CLIから
同様のことをCLIで行います。

#### 設定ファイル作成
最初に、どのインポートリソースに何をあてがうのか、の設定を行います。

以下のコマンドで、テンプレートファイルから、必要な部分を抽出してファイルに書き出します。
```bash
aws cloudformation get-template-summary --template-body file://createPair.yaml --query 'ResourceIdentifierSummaries' > ResourcesToImport.json
```
```json:ResourcesToImport.json
[
    {
        "ResourceType": "AWS::IAM::User",
        "LogicalResourceIds": [
            "Heroine",
            "Fiancee"
        ],
        "ResourceIdentifiers": [
            "UserName"
        ]
    }
]
```
これを、以下のように加工します。配列を辞書型にしたり、複数形のsを消して単数形にしていたり、ちょっとわかりづらい変更点があります。
```json:ResourcesToImport.json
[
    {
        "ResourceType": "AWS::IAM::User",
        "LogicalResourceId": "Heroine",
        "ResourceIdentifier": {
            "UserName":"Anisphia"
        }
    }
    ,
    {
        "ResourceType": "AWS::IAM::User",
        "LogicalResourceId": "Fiancee",
        "ResourceIdentifier": {
            "UserName":"Euphyllia"
        }
    }
]
```

#### 作成
引数に与える文字列を変数に格納します。
```bash
STACKNAME="createPair" && echo $STACKNAME
CHANGESETNAME="changeset-${STACKNAME}" && echo $CHANGESETNAME
```

先ほど作成したファイルを指定して、変更セットを作成します。IAMユーザを作成する例ですので`--capabilities CAPABILITY_NAMED_IAM`があります。
```bash
aws cloudformation create-change-set \
    --stack-name $STACKNAME --change-set-name $CHANGESETNAME \
    --change-set-type IMPORT \
    --resources-to-import file://ResourcesToImport.json \
    --template-body file://createPair.yaml \
    --capabilities CAPABILITY_NAMED_IAM
```

変更セットの詳細は、以下のコマンドで確認できます。
```bash
aws cloudformation describe-change-set \
    --stack-name $STACKNAME --change-set-name $CHANGESETNAME
```
ステータスは以下のようになっていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/f54955bb-e018-e747-c0d7-167fb821f7dd.png)

変更セットを実行するため、以下のコマンドを流します。
```bash
aws cloudformation execute-change-set \
    --stack-name $STACKNAME --change-set-name $CHANGESETNAME
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/7281dc3a-781c-ac14-d935-bc34e0a78bb8.png)

成功するとスタックに組み込まれました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/7f197fce-32d1-7812-bd45-cd5f0f141461.png)


# 既にあるスタックに組み込む
以下を参考にします。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/resource-import-existing-stack.html

ここでは作成済みのCloudFormationスタックに、CLIで作成したリソースを取り込みます。

## 事前準備
作成済みのスタックを用意するため、以下のスタックを作成します。
```yaml:createHeroine.yaml
AWSTemplateFormatVersion: 2010-09-09

Resources:
  Heroine:
    Type: AWS::IAM::User
    Properties:
      UserName: 'Anisphia'
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/e71f503f-d3d8-e100-f37c-60158b53ec87.png)

以下のコマンドでリソースを作ります。これを先のスタックに取り込みます。
```bash
aws iam create-user --user-name Euphyllia
```

## 取り込む
以下のテンプレートを使います。
```yaml:addFiancee.yaml
AWSTemplateFormatVersion: 2010-09-09

Resources:
  Heroine:
    Type: AWS::IAM::User
    Properties:
      UserName: 'Anisphia'

  Fiancee:
    Type: AWS::IAM::User
    DeletionPolicy: Retain
```

### コンソールから
対象のスタックを選択して、「スタックへのリソースのインポート」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/f68504e0-4059-f8c8-fe1d-eed1ef60fce4.png)

「リソースを識別」は特に入力がないので遷移し、「テンプレートの指定」では先のファイルを指定します。

「リソースを識別」では、追加分のリソースについて指定できますので、CLIから作成したリソースを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/7eaa1bda-8343-313d-2d73-c4fb2506322e.png)

あとは「リソースをインポート」で実行されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/75e11cf0-5879-3301-cbc7-e66e4840f97d.png)

完了すると、取り込まれました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/c5c7d6d1-0473-6be0-0d5a-7ec46167d367.png)

### CLIから
#### 設定ファイル作成
取り込むリソースに何をあてがうのか、の設定用ファイルを作成します。

先と同様、テンプレートファイルから、必要な部分を抽出してファイルに書き出します。
```bash
aws cloudformation get-template-summary --template-body file://addFiancee.yaml --query 'ResourceIdentifierSummaries' > ResourcesToImport.json
```
```json:ResourcesToImport.json
[
    {
        "ResourceType": "AWS::IAM::User",
        "LogicalResourceIds": [
            "Heroine",
            "Fiancee"
        ],
        "ResourceIdentifiers": [
            "UserName"
        ]
    }
]
```
今回はリソースを1つ追加するので、定義は1つになります。
```json:ResourcesToImport.json
[
    {
        "ResourceType": "AWS::IAM::User",
        "LogicalResourceId": "Fiancee",
        "ResourceIdentifier": {
            "UserName":"Euphyllia"
        }
    }
]
```

#### 作成
使う文字列を変数に格納します。
```bash
STACKNAME="createHeroine" && echo $STACKNAME
CHANGESETNAME="changeset-${STACKNAME}" && echo $CHANGESETNAME
```
変更セットを作成します。
```bash
aws cloudformation create-change-set \
    --stack-name $STACKNAME --change-set-name $CHANGESETNAME \
    --change-set-type IMPORT \
    --resources-to-import file://ResourcesToImport.json \
    --template-body file://addFiancee.yaml  \
    --capabilities CAPABILITY_NAMED_IAM
```
中身を確認します。
```bash
aws cloudformation describe-change-set \
    --stack-name $STACKNAME --change-set-name $CHANGESETNAME
```
問題なければ、実行します。
```bash
aws cloudformation execute-change-set \
    --stack-name $STACKNAME --change-set-name $CHANGESETNAME
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/d72f9fec-a607-e848-f328-1d8cb017a39a.png)


正常に組み込まれました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/2dc6b332-83a2-9bbc-5231-fd723d075b9e.png)

# おわりに
今回はCloudFormationのresource importを実際に使ってみました。

運用中に、CloudFormation外で作成したリソースを、既存のスタックとまとめたいということはあるかと思いますので、そういう際に使っていこうと思います。