TerraformでAWS S3バケットを操作

# 概要
[Teraform](http://terraform.io/) は、インフラのコード化(Infrastructure as code)を実現すべく、インフラの構築・変更・バージョン管理を、安全かつ効率的に行うためのツール。Vagrant、Serf、Consul 等を提供する [HashiCorp](http://www.hashicorp.com/) がオープンソースで提供している。

本稿は、Teraform がサポートしている事業者(provider)の１つである Amazon Web Services (AWS)のうち、Simple Storage Service (S3) のバケット追加・削除を行うためのチュートリアルである。

本チュートリアルを通し、Terraform を使ったインフラのコード化に対する理解を深める事を目的とする。

* 参考：Terraform入門 日本語訳 - Qiita
 * http://qiita.com/zembutsu/items/84f5478701c5391df537

Terraform を使うにあたり、既存のインフラ環境に対して何ら設定を加える必要は無い。Terraform は、既存の設定を読み込むものではなく、あくまで現状に対する変更しか管理しない。

なお、S3 を扱うのは、Terraform の挙動を理解・確認するにあたり、AWS の中では S3 がシンプルで分かりやすいと考えたため。

追記：セキュリティグループ編を作成した。

 * TerraformでAWS(EC2)のセキュリティグループを管理 - Qiita
  * http://qiita.com/zembutsu/items/5de875ed99ac8a56a998



## 作業の流れ

* Terraform で、S3 のリソースファイル作成
* S3 バケットの作成
* AWS マネジメント・コンソールで確認
* S3 バケットの削除
* コンソールで確認

## 事前準備

* AWS のアカウント
* Terraform の実行環境

Terraform の導入がまだの場合、以下のチュートリアルを参照のこと。

* Terraform簡易チュートリアル on AWS - Qiita
 * http://qiita.com/zembutsu/items/93e546df765f8b2c4f32

## Terraform の設定ファイルを作成

### AWS とリージョンの指定

Terraform の実行時、カレントディレクトリにある拡張子 `*.tf` のファイルを読み込む。AWS に接続するにあたり、まずアクセスキーと、シークレットキーを記述したファイルを用意する。エディタ等で `vi aws_region.tf` ファイル（例）を作成する。

```file:aws_region.tf
provider "aws" {
    access_key = "自分のアクセスキー"
    secret_key = "自分のシークレットキー"
    region = "us-east-1"
}
```

`provider` は Teraform が取り扱うことのできるサービス提供者（事業者）＝プロバイダの指定である。`provider "aws"` とは、事業者としての AWS を使う事を明示している。`version 0.1.0 で提供されているのは、AWS、CloudFlare、Consul、DigialOcean、DNSimple、Heroku である。これらはプラグイン形式で拡張可能であり、IRC や issue では、OpenStack や VMware 対応が議論されている 。

なお、ここでは S3 を利用するため、リージョンは `us-east-1` を明示する必要がある。EC2 などで、東京リージョンを使いたい場合は `ap-northeast-1` を指定する事は可能。

### S3 用の定義ファイル作成

次に `s3.tf` など、拡張子が `.tf` で s3 を識別できるファイルを作成する。

```file:s3.tf
resource "aws_s3_bucket" "bucket1" {
    bucket = "任意名称_tf_bucket"
    acl = "private"
}
```
これは、`resource`リソースとして、`aws_s3_bucket`(S3上のバケット)を指定し、リソース名称が `bucket1`である事を示す。そして内容は以下の通りである。

 * `bucket` = AWS 上の実際のバケット名称
 * `acl` = S3 上の [ACL 指定](http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html) ※現バージョンでは private しか指定できない

上記のように、Terraform を実行するのに必要なのは、`provider` (プロバイダ) と `resoruce` (リソース)の指定である。ここでは、AWS というプロバイダと、S3 バケットのリソースを指定した。

## Terraform の build でバケット作成

### plan (計画)

次に、実際にバケットを作成する。Terraform では、実行（インフラに対する適用 `apply` ) の前に、計画 `plan` を行い、変更内容を確認する事ができる（`plan` を行わず `apply` をすることも可能だが、作業前の確認という意味では、 `plan` を実行すべきだろう）。

先の `aws_region_tokyo.tf` と `s3.tf` が展開されているディレクトリで、`terraform plan`を実行する。

```
$ ./terraform plan
Refreshing Terraform state prior to plan...


The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

+ aws_s3_bucket.bucket1
    bucket: "" => "任意名称_tf_bucket"
```

実行すると `+` (リソースの追加) として、`aws_s3_backet` リソースの、リソース名称 `bucket1`を指定している事が分かる。この段階では `plan` なので、変更の計画を意味している。`bucket:` の行は作業内容であり、`""` (空白のバケット) => `任意名称_tf_bucket` という名称のバケット名に変更、つまり作成しようとしている事を意味している。

### apply (適用)

変更内容が想定通りであれば、`terraform apply` を実行して設定を適用する。なお、コマンドを入力した瞬間、即座に処理が進行する。以下は `zem_bucket1` というバケットを作成している例である。

```
$ ./terraform apply
aws_s3_bucket.bucket1: Creating...
  bucket: "" => "zem_bucket1"
aws_s3_bucket.bucket1: Creation complete

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: terraform.tfstate
```

注目すべきは `Apply complete!` (適用完了)と、`1 added` と表示されている点である。ここでは１つのバケットを展開することができた。

この時点で、ブラウザから AWS マネジメントコンソールにアクセスすると、指定したバケットが作成されている事が確認できる。

また、ブラウザにアクセスしなくても、どのような処理が進行したかは `show` コマンドを使って確認できる。

```
$ ./terraform show ./terraform.tfstate
aws_s3_bucket.bucket1:
  id = zem_bucket1
```

### リソースの変更・削除

リソースを削除するには２つの方法がある。`s3.tf` のファイルを消すか、`s3.tf` の内容を更新することである。

※ただし、更新を指定しても、実際に行うのはリソースの削除と新規追加である。Terraform は、あくまで既存の作業手順（ワークフロー）を自動処理してくれるのにすぎないので、あるリソースの名称変更という、AWS の S3 が提供していない機能を実現することはできない。

では、`s3.tf` を `s3.tf.bak` と名称変更してみよう。terraform が認識できるのは、`aws_region.tf` のみとなり、S3 のリソース情報は（設定ファイル上）存在しなくなる。

この状態を確認するためには、`terraform plan` を実行する。

```
$ ./terraform plan
Refreshing Terraform state prior to plan...

aws_s3_bucket.bucket1: Refreshing state... (ID: zem_bucket1)

The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

- aws_s3_bucket.bucket1

```

これは、現在の AWS 上のリソースと、手元の terraform が処理した内容を比較して、リソース差分として `aws_s3_backet.bucket1` というリソースを `-` (削除) する事を意味している（実際には、複数のリソースの追加・削除を同時に行う事ができる。また処理の優先付けを行う事も可能。詳しくはドキュメント参照）。

リソース削除を適用するには `terraform apply` を実行する。ただし、事前にバケットの中にファイルが一切ない事が条件である。ファイルがあると削除することはできないので注意する。

```
$ ./terraform apply
aws_s3_bucket.bucket1: Refreshing state... (ID: zem_bucket1)
aws_s3_bucket.bucket1: Destroying...
aws_s3_bucket.bucket1: Destruction complete

Apply complete! Resources: 0 added, 0 changed, 1 destroyed.
```

このように `1 destroyed` と表示され、対象リソースが破棄されたことが分かる。

ここで再びマネジメント・コンソールを確認すると、対象バケットが削除されている事がわかる。

あるいは、`show` コマンドを使っても、同様にリソースが存在していない事が確認出来る。

```
$ ./terraform show ./terraform.tfstate
The state file is empty. No resources are represented.
```

あとは、任意のバケット名の作成してみたり、ファイルがバケットに存在していれば削除出来ない事を確認すること。


### 補足

Teffarom が行うのは、あくまでインフラに関する定義と処理であり、バケットの中の高度な操作を行う事ができない。そのような処理を行いたい場合は、CLI を使った操作を推奨する。

参考：
 * [JAWS-UG CLI] S3:#1 ハイレベルS3コマンドを使ってみる (バケットの作成から静的Webホスティング、削除まで) - Qiita
 http://qiita.com/tcsh/items/edd5d65f1bc2f8d1819a



## 参考

* Provider: AWS - Terraform
 * http://www.terraform.io/docs/providers/aws/index.html

* AWS: aws_s3_bucket - Terraform
 * http://www.terraform.io/docs/providers/aws/r/s3_bucket.html