どんな事でもお気軽にお問い合わせください
0120-803-656
24時間受付いたします

[Terraform]異なるtfstateに記述されているリソースの情報を参照する


インフラエンジニアの寺岡です。

TerraformのHCLを記述する際に便利なものに
terraform_remote_stateというデータソースがあります。
今回はこちらの紹介をしてみようと思います。

■terraform_remote_stateとは

異なるtfstateに記述されているリソースの情報を参照したい。
そんなときに利用すると便利なデータソースです。

そもそもTerraformにはtfstateという
terraform applyでデプロイを実行したときに
作成されたリソース情報が記録されているファイルがあります。

Terraformでインフラを構築する際に
複数の環境(踏み台/本番/開発など)がある場合は
terraform applyが他の環境に影響を及ぼさないように
環境ごとにtfstateを分けるのが鉄則です。

tfstateを分けた場合
踏み台環境で作成したリソースの情報を
本番環境でリソースを作成するときに参照したいということがあります。
その際に便利なのが「terraform_remote_state」です。

■どんなときに使うのか

AWSになりますが以下に1つ例を記載します。

サーバにSSHで接続する際は踏み台サーバを経由する前提とした場合
セキュリティグループとルールをTerraformで作成しようとするとどのようになるでしょうか。
まずは踏み台サーバ用のVPCとセキュリティグループ + ルールを作成すると思います。

bastion.tf

terraform {
  backend "s3" {
    bucket = "terraform-tfstate"
    key    = "terraform-blog/bastion.tfstate"
    region = "ap-northeast-1"
  }
}

resource "aws_vpc" "bastion" {
  cidr_block                     = "10.0.0.0/16"
  enable_dns_hostnames           = true

  tags {
    Name = "vpc-bastion"
  }
}

resource "aws_security_group" "bastion" {
  name        = "bastion-sg"
  description = "for bastion server"
  vpc_id      = "${aws_vpc.bastion.id}"

  tags {
    Name = "bastion-sg"
  }
}

resource "aws_security_group_rule" "prod_sg_rule" {
  security_group_id        = "${aws_security_group.bastion.id}"
  type                     = "ingress"
  from_port                = "22"
  to_port                  = "22"
  protocol                 = "tcp"
  cidr_blocks              = "XXX.XXX.XXX.XXX"
}

backendの設定でtfstateをbastion.tfstateという名前でS3に置いていますが
VPCとセキュリティグループ + 特定IPからの許可ルールを追加しているだけなのでこれは大丈夫です。
では、踏み台から「接続される側」の設定はどのようになるでしょうか。

production.tf

terraform {
  backend "s3" {
    bucket = "terraform-tfstate"
    key    = "terraform-blog/prod.tfstate"
    region = "ap-northeast-1"
  }
}

resource "aws_vpc" "prod" {
  cidr_block                     = "10.0.0.0/16"
  enable_dns_hostnames           = true

  tags {
    Name = "vpc-prod"
  }
}

resource "aws_security_group" "prod" {
  name        = "prod-sg"
  description = "for production server"
  vpc_id      = "${aws_vpc.prod.id}"

  tags {
    Name = "prod-sg"
  }
}

resource "aws_security_group_rule" "prod_sg_rule" {
  security_group_id        = "${aws_security_group.prod.id}"
  type                     = "ingress"
  from_port                = "22"
  to_port                  = "22"
  protocol                 = "tcp"
  source_security_group_id = "${何を指定すれば良い???}"
}

踏み台サーバからのSSH接続を許可したい場合は
踏み台用のセキュリティグループからのアクセスを許可する必要があるので
source_security_group_idで踏み台用のセキュリティグループのIDを指定する必要があります。

ただし、backendの記述で踏み台サーバとtfstateが分かれているので
このままでは、セキュリティグループのIDを参照することができません。

■どのように使うのか

できないことがわかったところで参照できるようにしたいと思います。
まずはbastion.tf側でoutputの設定を追加する必要があります。

bastion.tf

terraform {
  backend "s3" {
    bucket = "terraform-tfstate"
    key    = "terraform-blog/bastion.tfstate"
    region = "ap-northeast-1"
  }
}

resource "aws_vpc" "bastion" {
  cidr_block                     = "10.0.0.0/16"
  enable_dns_hostnames           = true

  tags {
    Name = "vpc-bastion"
  }
}

resource "aws_security_group" "bastion" {
  name        = "bastion-sg"
  description = "for bastion server"
  vpc_id      = "${aws_vpc.bastion.id}"

  tags {
    Name = "bastion-sg"
  }
}

resource "aws_security_group_rule" "prod_sg_rule" {
  security_group_id        = "${aws_security_group.bastion.id}"
  type                     = "ingress"
  from_port                = "22"
  to_port                  = "22"
  protocol                 = "tcp"
  cidr_blocks              = "XXX.XXX.XXX.XXX"
}

## 追加
output "security_group_id" {
  value = "${aws_security_group.bastion.id}"
}

異なるtfstateから値を参照する場合は
参照させたい値を事前にoutputで出力しておく必要があります。
今回は踏み台用セキュリティグループのIDを参照したいので
aws_security_group.bastion.idを出力しておきます。

この状態でproduction.tfからterraform_remote_stateで値を参照できます。

production.tf

terraform {
  backend "s3" {
    bucket = "terraform-tfstate"
    key    = "terraform-blog/prod.tfstate"
    region = "ap-northeast-1"
  }
}

resource "aws_vpc" "prod" {
  cidr_block                     = "10.0.0.0/16"
  enable_dns_hostnames           = true

  tags {
    Name = "vpc-prod"
  }
}

resource "aws_security_group" "prod" {
  name        = "prod-sg"
  description = "for production server"
  vpc_id      = "${aws_vpc.prod.id}"

  tags {
    Name = "prod-sg"
  }
}

resource "aws_security_group_rule" "prod_sg_rule" {
  security_group_id        = "${aws_security_group.prod.id}"
  type                     = "ingress"
  from_port                = "22"
  to_port                  = "22"
  protocol                 = "tcp"
  source_security_group_id = "${data.terraform_remote_state.bastion.security_group_id}"
}

## 追加
data "terraform_remote_state" "bastion" {
  backend = "s3"

  config {
    bucket = "terraform-tfstate"
    key    = "terraform-blog/bastion.tfstate"
    region = "ap-northeast-1"
  }
}

terraform_remote_stateというデータソースを使って
S3に保存している踏み台用のtfstateを読み込みます。
値はoutputで指定した名前で参照できるので
source_security_group_idに指定する値は
data.terraform_remote_state.bastion.security_group_idになります。

■まとめ

terraform_remote_stateは割とよく使うので覚えておいて損はないです。
これでtfstateを分けても問題ないですね!


お問い合わせ 採用情報 エンジニアブログ
ISO27001認証
Contact PageTop
株式会社ビヨンド

© beyond Co., Ltd. All rights reserved.