Terraformで自分のパブリックIPを使う方法

現在自分が使っているパブリックIPをTerraform内で使いたいって時、ありますよね。よくあるのがSSHインバウンドの許可IPとして。Terraformで、使っているIPをサクッと参照し、そのIPを使ってセキュリティグループのルールを作成してみました。
2019.11.20

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

やりたいこと

こんにちは、大阪オフィスのかずえです。今回は今週知ったTerraformのテクニックをご紹介します。

現在自分が使っているパブリックIPをTerraform内で使いたいって時、ありますよね。よくあるのがSSHインバウンドの許可IPとして。コンソールだとこちら、選択肢に「マイIP」が出てきて、それを選択すると現在使っているIPがサクッと入力されますよね。

こんな感じで、Terraformでも使っているIPをサクッと参照できるようにします。そのIPを使ってセキュリティグループのルールを作成します。

とはいえ、現在使っているIP以外をセキュリティグループのルールで使いたい場合もありますよね。より実践的にするためこの点にも対応します。変数値を設定した場合はそのCIDRで、設定しなかった場合は現在使っているIPを/32のCIDRにして参照するようにします。

実装方針

TerraformにはHTTPというProviderがあります。この中のData Sourceにhttpがあります。
Data Sourceとは、Terraformで作成していないリソースのパラメータをTerraform内で参照するための機能です。このhttp Data Sourceは何のリソースを扱うかというと、指定URLへのリクエストのレスポンスです。

世の中には現在使っているパブリックIPを返してくれるwebサービスが多数存在します。それらのサービスにリクエストした結果をTerraform 内で使うことができます。

コード

Provider設定

まずは HTTP providerを利用できるようにします。

provider http {
  version = "~> 1.1"
}

terraform init が必要です。

http Data Source

data http ifconfig {
  url = "https://ifconfig.co/ip"
}
2020/01/24追記:
上記URL「https://ifconfig.co/ip」でエラーになりました。解決法を本エントリ下部に書いておりますのでご確認下さい。

url 引数値で設定するリクエスト先には以下条件があります。

  • 200 OK のステータスコードを返す
  • Content-Typeが text/* もしくは application/json

「AWSなんだったらIP取得に http://checkip.amazonaws.com/ を使えば?」と思われた方もいらっしゃるかもしれません。が、 http://checkip.amazonaws.com/ はContent-Typeがレスポンスヘッダーに含まれていないためエラーになり使えませんでした。。

別途IP指定したい時用の変数

variable allowed-cidr {
  default = null
}

CIDRの決定

上記変数が指定されている場合はそれを、ない場合はhttp Data Sourceで取得した現在使っているパブリックIPを代入します。

locals {
  current-ip = chomp(data.http.ifconfig.body)
  allowed-cidr  = (var.allowed-cidr == null) ? "${local.current-ip}/32" : var.allowed-cidr
}

セキュリティグループで利用

踏み台インスタンスにアタッチするセキュリティグループにSSHインバウンドを許可するルールを付与します。

resource aws_security_group bastion {
  name        = "bastion-sg"
  description = "bastion-sg"
  vpc_id      = aws_vpc.vpc.id
}

resource aws_security_group_rule bastion-ssh-ingress {
  type              = "ingress"
  security_group_id = aws_security_group.bastion.id
  protocol          = "tcp"
  from_port         = 22
  to_port           = 22
  cidr_blocks       = [local.allowed-cidr]
}

※ 余談ですが、egress(アウトバウンド)ルールもちゃんと書きましょうね!

まとめ

http Data Sourceを使って、Terraformで現在自分が使っているパブリックIPを参照する方法をご紹介しました。http Data Source、これ以外にも色々使い道がありそうですね!何かまた思いついたら書いてみたいと思います。

2020/01/24追記: エラーになりました

本機構を入れたコードを terraform apply したところエラーになりました。

Error: HTTP request error. Response code: 403

原因調査したところ、IP取得に使っていたサイト https://ifconfig.co/ip がセキュリティチェック(reCaptcha)を導入したようです… パッとこれの解決方法がわからなかったので、ひとまず同様のサービスを提供している別サイト http://ipv4.icanhazip.com/ に切り替えたところ動作しました。

参考情報