既存のAWS環境をTerraform化するときのTips-その1

### 概要
---
既にAWSに作成してしまった環境をTerraform化するときのTipsです。
似たような情報Qiita上にもありますが、Terraformのアップデートが激しいため、現時点(2019.1.17)で自分が作成するにあたりはまった点等々をまとめておきます。


### 作成するファイルについて
---
Terraformで環境を管理するときに必要なファイルは簡単に2種類あります。
* Terraform Configuration File(.tf or .tf.json) - インフラの変数を記述するファイル
* State File(.tfstate) - 現時点の環境の状態を記述するファイル

変更したい部分をConfiguration Fileに記述し実行すると、State Fileとの差分を確認しそれを環境に反映するという構造になっています。

こだわると色々とファイル分割はできますが、ひとまずはこの2種類のファイルを作成するのがゴールとなります。

### 使用するツール
---
現在全リソースを取得するのには2種類の方法があります。

| |説明|Output|メリット|デメリット|
|---|---|---|---|---|
|[Terraform import](https://www.terraform.io/docs/import/index.html)|HashiCorp公式のインポートツール|State Fileのみ| - 公式であるため、サポートされているリソースが多い </br> - 一部出力されない等はなく、出力後の修正が不要　<br> | - 個々のリソースID単位で実行しなければならず、実行数が膨大。</br> - 現時点ではState Fileしか出力できないため、Configuration Fileは別途作成する必要がある <br>||
|[Terraforming](http://terraforming.dtan4.net/)|ユーザによるOSSツール|Configuration File, State File| - Configurationを出力できる唯一のツール| - 完成版ではないため一部出力されない箇所がある|


今はどちらも開発途中・・という状況で、簡単にファイルを作成できる方法がないですね。

Terraform importは今後は公式ツールで簡単に完結できるようになる展望だとは思いますが、今はこの2つを駆使して作成していく方法になります。

ちなみにTerrafromingはもともと日本人の方が作成したようです。世界中でこれだけ使われているものを考えて作った方がいるとは尊敬しますね



### 手順
---
以下の手順で直していきます。
基本Terraformingで作成していき、足りない部分をimportや手作業で修正していくという流れです。

1.Terraformingで必要リソース分のConfiguration Fileを出力する

``` 
$ terraforming s3 > s3.tf
```
* リソースによるディレクトリ階層を切っている場合は適宜出力先を変えてください。

2.Terraformingで必要リソース分のState Fileを出力する

``` 
$ terraforming s3 --tfstate --merge terraform.tfstate
```
* State Fileはデフォルト名称のterraformにしました。適宜変えてください。

3.出力できていないリソースのState情報を特定し、Terraform importの出力結果で書き換える

4.3の出力結果を参照しながら、Configuration Fileを修正する


### 出力できない部分
---
手順3.の出力できていないリソースですが、発見できた限りで羅列していきます。

- Redshiftのパスワード
    - セキュリティ上XXXXという形で出力されているので、外部定義もしくはignoreしておきます。ignoreは以下の定義をresourceに追記すればOKです。
 
    ``` 
    lifecycle {
        ignore_changes = ["master_password"]
    }
    ```
- EC2のDisable Termination
    - オプション定義が記述されてないため、追記が必要
- IAM RoleのDescription
    - 記述されてないため追記
- SecurityGroupのインバウンド・アウトバウンド定義
    - ここが一番時間がかかった気がします。(手順3,4を駆使して作成)
    　TerraformingだとSecurityGroupルールの複雑な記述ができず、以下の通りリソースを分けて記述する必要がありました。

        ```Terraform:Terraforming 
        resource "aws_security_group" "aaa" {
            ....
            ingress {
                from_port       = 80
                to_port         = 80
                protocol        = "tcp"
                security_groups = ["sg-aaa"]
            }
        }
        ```
        
        ```Terraform:修正後 
        resource "aws_security_group" "aaa" {
            ....
        }

        resource "aws_security_group_rule" "aaa" {
            security_group_id = "${aws_security_group.aaa.id}"
            type              = "ingress"
            from_port         = 80
            to_port           = 80
            protocol          = "tcp"
            cidr_blocks       = ["X.X.X.X/X"]
        }
        ```

### サポートされていないサービス
---

AWSのメジャーどころのサービスもTerraformでサポートされていない場合があります。
今回の環境では唯一Sagemakerがサポートされてないので残念ながらCode化できませんでした。

ただIssueは挙がっていてContributerによる開発、HashiCorp社のレビューも進んでいるので早くリリースして欲しいところですね。

https://github.com/terraform-providers/terraform-provider-aws/issues/2493

以下のコンポーネントを定義するような仕組みになりそうです。
 - aws_sagemaker_notebook_instance
 - aws_presigned_notebook_instance_url
 - aws_sagemaker_training_job
 - aws_sagemaker_model
 - aws_sagemaker_endpoint
 - aws_sagemaker_endpoint_configuration



### 次の作業
---
この手順でとりあえずTerraformによるInfraCode化の第一歩が踏めますが、
今のままだと変数参照なし、State Fileが全リソースにつき１つしかない、ディレクトリ階層が洗練されてない・・等の不便があり、ちょっと改善が必要です。

これについては次回の投稿でまとめようと思います。


### まとめ
---
冒頭で書いたとおり、現時点だと完全なツールがなく組み合わせで苦し紛れに作る方法になってしまいました。
投稿日からしばらく経って見ている場合はもっとスマートな方法があるかもしれないです！