Terraform で CloudFlare の IP を取得して GCP のファイアウォールに設定する

# Terraform で CloudFlare の IP を取得して GCP のファイアウォールに設定する

今日も若干手抜き気味ですが、Terraform の機能を使っていきたいと思います。

## 前提条件

- CloudFlare のアカウントがあること。
- GCP のサービスアカウントを作成しておき（権限はファイアウォール関連がついてれば OK です）、キーJSONを「account.json」で保存しておきます。

## なんで CloudFlare の IP を取得するの？

CloudFlare をフロントにして、GCP のサーバをバックエンドにする場合、ファイアウォールで制限してやらないと、CloudFlare 以外からのアクセスが直接サーバの方にきてしまいます。それを避けるためには、IP でフィルタリングしてやる方法が１つあります。そのためまず、CloudFlare の使用している IP 一覧を取得していきます。

下記に行くと、IP の一覧があります。

[IP Ranges](https://www.cloudflare.com/ips/)

Terraform で取得する場合は、API を使用して行います。

## CloudFlare の API Key を取得する

CloudFlare にログインした後に、右上のアカウントアイコンから「My Profile」クリックし、スクロールして「API Keys」にある「Global API Key」の「View」をクリックします。パスワードを入れていくと、「API Key」が表示されるのでコピーしておきます。

![cloudflare_001.png](https://qiita-image-store.s3.amazonaws.com/0/318450/c4f3e281-8865-d09d-2b3f-ada6ce51e13e.png)

## まず、定義ファイル作成

```gcp.tf
provider "google" {
  credentials = "${file("account.json")}"
  project     = "<project id>"
  region      = "asia-northeast1"
}

resource "google_compute_firewall" "allow_cloudflare_ingress" {
  name    = "from-cloudflare"
  network = "default"

  source_ranges = ["${data.cloudflare_ip_ranges.cloudflare.ipv4_cidr_blocks}"]

  allow {
    ports    = ["443"]
    protocol = "tcp"
  }
}
```
gcp の provider を入れてやらないと動かないので、入れておきます。
Terraform のドキュメントと違って、`ports` には　`[]` をつけてやらないとエラーになります。
ipv4 しか書かれていませんが、`source_ranges` が ipv4 にしか対応していないのでそうなっています。

```cloudflare.tf
data "cloudflare_ip_ranges" "cloudflare" {}
```

```account.json
取得した JSON をコピペ
```

## 実行していきましょう

```
> ./terraform plan
provider.cloudflare.email
  A registered Cloudflare email address.

  Enter a value: <CloudFlare のログインメール>

provider.cloudflare.token
  The token key for API operations.

  Enter a value: <CloudFlare の API Key>

Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

data.cloudflare_ip_ranges.cloudflare: Refreshing state...

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  + google_compute_firewall.allow_cloudflare_ingress
      id:                       <computed>
      allow.#:                  "1"
      allow.680193008.ports.#:  "1"
      allow.680193008.ports.0:  "443"
      allow.680193008.protocol: "tcp"
      creation_timestamp:       <computed>
      destination_ranges.#:     <computed>
      direction:                <computed>
      name:                     "from-cloudflare"
      network:                  "default"
      priority:                 "1000"
      project:                  <computed>
      self_link:                <computed>
      source_ranges.#:          "14"
      source_ranges.1522842365: "104.16.0.0/12"
      source_ranges.1672285077: "103.21.244.0/22"
      source_ranges.1752645322: "141.101.64.0/18"
      source_ranges.1868834826: "162.158.0.0/15"
      source_ranges.1888211271: "131.0.72.0/22"
      source_ranges.2080650126: "173.245.48.0/20"
      source_ranges.2544550675: "172.64.0.0/13"
      source_ranges.2846298560: "108.162.192.0/18"
      source_ranges.3880048275: "103.22.200.0/22"
      source_ranges.3882917684: "103.31.4.0/22"
      source_ranges.3959341401: "197.234.240.0/22"
      source_ranges.4264853869: "188.114.96.0/20"
      source_ranges.56480987:   "198.41.128.0/17"
      source_ranges.578481240:  "190.93.240.0/20"


Plan: 1 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.
```

では、apply していきましょう。

```
> ./terraform apply
provider.cloudflare.email
  A registered Cloudflare email address.

  Enter a value: <CloudFlare のログインメール>

provider.cloudflare.token
  The token key for API operations.

  Enter a value: <CloudFlare の API Key>

data.cloudflare_ip_ranges.cloudflare: Refreshing state...

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  + google_compute_firewall.allow_cloudflare_ingress
      id:                       <computed>
      allow.#:                  "1"
      allow.680193008.ports.#:  "1"
      allow.680193008.ports.0:  "443"
      allow.680193008.protocol: "tcp"
      creation_timestamp:       <computed>
      destination_ranges.#:     <computed>
      direction:                <computed>
      name:                     "from-cloudflare"
      network:                  "default"
      priority:                 "1000"
      project:                  <computed>
      self_link:                <computed>
      source_ranges.#:          "14"
      source_ranges.1522842365: "104.16.0.0/12"
      source_ranges.1672285077: "103.21.244.0/22"
      source_ranges.1752645322: "141.101.64.0/18"
      source_ranges.1868834826: "162.158.0.0/15"
      source_ranges.1888211271: "131.0.72.0/22"
      source_ranges.2080650126: "173.245.48.0/20"
      source_ranges.2544550675: "172.64.0.0/13"
      source_ranges.2846298560: "108.162.192.0/18"
      source_ranges.3880048275: "103.22.200.0/22"
      source_ranges.3882917684: "103.31.4.0/22"
      source_ranges.3959341401: "197.234.240.0/22"
      source_ranges.4264853869: "188.114.96.0/20"
      source_ranges.56480987:   "198.41.128.0/17"
      source_ranges.578481240:  "190.93.240.0/20"


Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value:
```

`yes` 入れていきましょう。

```
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

google_compute_firewall.allow_cloudflare_ingress: Creating...
  allow.#:                  "" => "1"
  allow.680193008.ports.#:  "" => "1"
  allow.680193008.ports.0:  "" => "443"
  allow.680193008.protocol: "" => "tcp"
  creation_timestamp:       "" => "<computed>"
  destination_ranges.#:     "" => "<computed>"
  direction:                "" => "<computed>"
  name:                     "" => "from-cloudflare"
  network:                  "" => "default"
  priority:                 "" => "1000"
  project:                  "" => "<computed>"
  self_link:                "" => "<computed>"
  source_ranges.#:          "" => "14"
  source_ranges.1522842365: "" => "104.16.0.0/12"
  source_ranges.1672285077: "" => "103.21.244.0/22"
  source_ranges.1752645322: "" => "141.101.64.0/18"
  source_ranges.1868834826: "" => "162.158.0.0/15"
  source_ranges.1888211271: "" => "131.0.72.0/22"
  source_ranges.2080650126: "" => "173.245.48.0/20"
  source_ranges.2544550675: "" => "172.64.0.0/13"
  source_ranges.2846298560: "" => "108.162.192.0/18"
  source_ranges.3880048275: "" => "103.22.200.0/22"
  source_ranges.3882917684: "" => "103.31.4.0/22"
  source_ranges.3959341401: "" => "197.234.240.0/22"
  source_ranges.4264853869: "" => "188.114.96.0/20"
  source_ranges.56480987:   "" => "198.41.128.0/17"
  source_ranges.578481240:  "" => "190.93.240.0/20"
google_compute_firewall.allow_cloudflare_ingress: Still creating... (10s elapsed)
google_compute_firewall.allow_cloudflare_ingress: Creation complete after 12s (ID: from-cloudflare)

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

お、できたようですね。
GCP 側でも確認してみます。

![cloudflare_002.png](https://qiita-image-store.s3.amazonaws.com/0/318450/80927278-d390-54c7-d1be-653e3f0391d7.png)

こちらでもちゃんとできてますね。

## まとめ

IP は変わることがあるので、定期的に取得して設定するという場合には便利かもしれないですね。
ipv6 はそのうち対応するんでしょうかね・・・

## 参照

https://www.terraform.io/docs/providers/cloudflare/d/ip_ranges.html
https://www.terraform.io/docs/providers/google/index.html