Cloudflare + Hashicorp Terraform [ 前編 ]

想定よりも分量が多くなったので、本日分と後日分で前後半で投稿することにしました

## Cloudflareの設定を外部からコントロールしたい
先週のアドベントカレンダーの[記事](https://qiita.com/atsufumi/items/dc171cdd45c18e894c2f)で同僚がCloudflareに対してAPIで接続する記事を投稿していたので、それを受けて外部からCloudflareの環境をコントロールするネタ関連で書いてみたいと思います.

大前提ですが、CloudflareのUIは非常にシンプルで使いやすいものになっています.
一方で昨今のインフラのコンフィグレーション管理にはIAC(Inflastracture As Code)という概念があります.
この点、Cloudflareも例外ではなく対応しており、IACやテキストやコードベースを軸に考えると、既出のAPIでの制御やHashicorp社の「Terraform」などが対応してます.

本記事の情報がCloudflareを「Terraform」を使って運用管理するにはどうするか？を考えるためのファーストステップになれば幸いです.  


### 想定シナリオ
具体的にTerraformを使ってCloudflareに対してどのような運用をおこなうか？ですが、今回は以下のシナリオとします.

- Cloudflareのアカウントの一つ(Free plan)でDNSの運用をしている.
- Full Setupでドメインを持ち込み済みでCloudflareダッシュボード上でDNSのレコードを管理している.
- Terraformを使って新しくDNSレコードを管理するように運用を切り替える.


### 実行環境
本記事のオペレーション再現性をもって実行するためにサクッと環境が用意出来て容易に潰せるものを使おうというコンセプトで今回はAWS上の「Cloud9」を利用します.
Cloud9は標準のAmazon Linuxをベースに利用すると「terraform」の比較的新しいバージョンのものや後述するツールを使うためのgo環境なども最初から用意されています.
なおかつ、それらがブラウザベースで利用できるので、ダッシュボードが優れているCloudflareとの相性も良しということで選定してみました.

## 導入編
### AWS Cloud9
サクッと実行環境を用意します.
名前と説明を入力.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150229/ffaf679e-a45e-aed2-7ecb-6e85a24bce95.png)

`Next step`.

デフォルトのまま特に弄るところはありません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150229/17ff530e-5e5b-a818-935a-dfaaf891a8ab.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150229/c83059cc-73e3-b7eb-dc23-730ecc728feb.png)

`Nextstep`.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150229/a6cd0959-6487-e430-e00b-b34c95067e84.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150229/3696c2a0-c844-a437-e315-9ab97ccb112c.png)

`Create environment`.


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150229/7fe1bdee-66ba-39a1-d495-e8158fe93c08.png)

デプロイメント中(すぐに上がってきます)...


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150229/8978e079-9d2f-0e9d-06fc-f93ff5a504f4.png)

立ち上がりました.


早速、立ち上がった環境のターミナルでコマンドを打ってみます.

> terraform -v
> go version

```
develop:~/environment $ terraform -v
Terraform v1.1.0
on linux_amd64

Your version of Terraform is out of date! The latest version
is 1.1.2. You can update by downloading from https://www.terraform.io/downloads.html
develop:~/environment $ 
develop:~/environment $ go version
go version go1.15.14 linux/amd64
```

TerraformとGoの環境が用意されていることが確認できます.


### Cloudflare Terraform Provider

terraformを実行するための用意をします.
今回の作業はすべての作業を`cloudflare-terraform`というディレクトリを作成し、その配下でおこなうことにします.
後述するツールを利用する上でも`Cloudflare Terraform Provider`が必要となるので、先にセットアップします.


> mkdir cloudflare-terraform
> cd cloudflare-terraform/
> touch provider.tf variable.tf terraform.tfvars

<GAZO>

ファイルへ記述する内容は以下です。

:::note info
今回は手順を簡素化するためクレデンシャル情報をファイルへ記述や環境変数へ投入という手順でやっていますが、実環境でのご利用はご注意ください。
:::

``` provider.tf
terraform {
  required_providers {
    cloudflare = {
      source = "cloudflare/cloudflare"
      version = "~> 3.0"
    }
  }
}
provider "cloudflare" {
  email   = var.cloudflare_email
  api_key = var.cloudflare_api_key
}
```

``` variable.tf
variable "cloudflare_email" {}
variable "cloudflare_api_key" {}
```

``` terraform.tfvars
cloudflare_email = "EMAIL-ADDRESS"
cloudflare_api_key = "CLOUDFLARE-API-KEY"
```

terraform.tfvarsの`EMAIL-ADDRESS`と`CLOUDFLARE-API-KEY`には実際の環境の情報を入力してください.


`terraform init`を実行すると必要な先ほど記述したファイルの情報を基にプロバイダが導入されます.

> terraform init

```
develop:~/environment/cloudflare-terraform $ ls
provider.tf  terraform.tfvars  variable.tf
develop:~/environment/cloudflare-terraform $ terraform init

Initializing the backend...

Initializing provider plugins...
- Finding cloudflare/cloudflare versions matching "~> 3.0"...
- Installing cloudflare/cloudflare v3.5.0...
- Installed cloudflare/cloudflare v3.5.0 (signed by a HashiCorp partner, key ID DE413CEC881C3283)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
develop:~/environment/cloudflare-terraform $ 
```

### cf-terratorming
既存のコンフィグレーションも含めterraformの運用を始めるということは、既存のコンフィグをterraform管理下に入れる必要があります.
一からコンフィグレーションを作ってもよいのですが、[cf-terraforming](https://github.com/cloudflare/cf-terraforming)というツールが用意されていますので、今回はこちらも使えるようにしていきます.

Goの環境変数を設定します.（環境に応じて読み替えてください）

> vi ~/.bash_profile

``` ~/.bash_profile
# 末尾に追記
export GOPATH=$HOME/go
export PATH=$PATH:$HOME/go/bin:$GOPATH/bin
```

> source ~/.bash_profile
> echo $GOPATH

```
develop:~/environment/cloudflare-terraform $ vi ~/.bash_profile
develop:~/environment/cloudflare-terraform $ source ~/.bash_profile
develop:~/environment/cloudflare-terraform $ echo $GOPATH
/home/ec2-user/go
develop:~/environment/cloudflare-terraform $ 
```

> GO111MODULE=on go get -u github.com/cloudflare/cf-terraforming/...

```
develop:~/environment/cloudflare-terraform $ GO111MODULE=on go get -u github.com/cloudflare/cf-terraforming/...
：略：
go: downloading github.com/cncf/xds/go v0.0.0-20211216145620-d92e9ce0af51
develop:~/environment/cloudflare-terraform $ 
```

cf-terraformingが実行できることを確認.

```
develop:~/environment/cloudflare-terraform $ cf-terraforming -help
cf-terraforming is an application that allows Cloudflare users
to be able to adopt Terraform by giving them a feasible way to get
all of their existing Cloudflare configuration into Terraform.

Usage:
  cf-terraforming [command]

Available Commands:
  completion  Generate the autocompletion script for the specified shell
  generate    Fetch resources from the Cloudflare API and generate the respective Terraform stanzas
  help        Help about any command
  import      Output `terraform import` compatible commands in order to import resources into state
  version     Print the version number of cf-terraforming

Flags:
  -a, --account string                  Use specific account ID for commands
  -c, --config string                   Path to config file (default "/home/ec2-user/.cf-terraforming.yaml")
  -e, --email string                    API Email address associated with your account
  -h, --help                            help for cf-terraforming
  -k, --key string                      API Key generated on the 'My Profile' page. See: https://dash.cloudflare.com/profile
      --resource-type string            Which resource you wish to generate
      --terraform-install-path string   Path to the Terraform installation (default ".")
  -t, --token string                    API Token
  -v, --verbose                         Specify verbose output (same as setting log level to debug)
  -z, --zone string                     Limit the export to a single zone ID

Use "cf-terraforming [command] --help" for more information about a command.
```

パスも通って無事実行(ヘルプを表示)できました.
次にGithubのサンプルに沿って簡単な参照をしてみようと思います.

```
$ cf-terraforming generate \
  --account $CLOUDFLARE_ACCOUNT_ID \
  --resource-type "cloudflare_record"
```

terraformの時と同様、cf-terraformingにも環境にアクセスするための認証情報は必要で、
[Github](https://github.com/cloudflare/cf-terraforming#authentication)でも書かれている通り

- API Tokenベースの認証(CLOUDFLARE_API_TOKEN)
- API Key ベースの認証(CLOUDFLARE_EMAIL, CLOUDFLARE_API_KEY)

のどちらかが必要になります.
ファイルへの記述`~/.cf-terraforming.yaml`が使えるということなので、今回試してみました.

ファイルにはEmailとAPIキーの情報のみを記載してみます

> $ touch .cf-terraforming.yaml

```
email: "EMAIL-ADDRESS"
key: "CLOUDFLARE-API-KEY"
```
アカウントIDは環境変数で指定します.

> export CLOUDFLARE_ACCOUNT_ID='CLOUDFLARE-ACCOUNT-ID'

ここまでを一通り渡してみて実行してみると、、

```
develop:~/environment/cloudflare-terraform $ cf-terraforming generate \
> --account $CLOUDFLARE_ACCOUNT_ID \
> --resource-type "cloudflare_record" \
> --config ./.cf-terraforming.yaml
FATA[0002] HTTP status 400: Could not route to /zones/dns_records, perhaps your object identifier is invalid? (7003), No route for that URI (7000) 
```

となり、Zoneの指定が必要となっていますので、

環境変数でZONE-IDも指定します.
> export ZONE_ID='ZONE-ID'

`CLOUDFLARE-ACCOUNT-ID` と`ZONE-ID`はご利用の環境に応じたものに置き換えてえ実行してください.

```
develop:~/environment/cloudflare-terraform $ cf-terraforming generate \
> --account $CLOUDFLARE_ACCOUNT_ID \
> --zone $ZONE_ID \
> --resource-type "cloudflare_record" \
> --config ./.cf-terraforming.yaml
resource "cloudflare_record" "terraform_managed_resource_65b157b60750cdf47f36a4e275a83764" {
  name    = "www1"
  proxied = true
  ttl     = 1
  type    = "A"
  value   = "176.32.67.255"
  zone_id = "e877843d3b162b87089f8c956134fc1c"
}
```

ということで無事に既存のレコードの情報が引っ張ってこれました.

ちなみに、、上記では一部コンフィグファイルへの記述、一部を環境変数としてしまったのですが全てをファイルに記述することも可能です.
また、`--config`でコンフィグファイルを指定しない場合には`~/.cf-terraforming.yaml`が参照されるので、

> touch ~/.cf-terraforming.yaml

とし、

``` ~/.cf-terraforming.yaml
email: "EMAIL-ADDRESS"
key: "CLOUDFLARE-API-KEY"
account: "CLOUDFLARE_ACCOUNT_ID"
zone: "ZONE-ID"
```
のように記述することで、

```
develop:~/environment/cloudflare-terraform $ cf-terraforming generate --resource-type "cloudflare_record" 
resource "cloudflare_record" "terraform_managed_resource_65b157b60750cdf47f36a4e275a83764" {
  name    = "www1"
  proxied = true
  ttl     = 1
  type    = "A"
  value   = "176.32.67.255"
  zone_id = "e877843d3b162b87089f8c956134fc1c"
}
```
シンプルにコマンドが実行できます.

返ってきた内容や、実際の運用を加味した話はまた次回(12/25公開)に持ち越します.