初めに
以前👇の記事で、Terraformの環境を整備しました。
今回の記事ではこの環境を使って検証用のLinuxサーバを構築するテンプレートを作ってみようと思います。
目次
- 基本設定
- VPC、サブネットの作成
- IAMロールの作成
- VPCエンドポイントの作成
- EC2の作成
- 構築
リソース構築
基本設定
tfファイルはモジュールごとに分割して管理する方法もありますが、今回は大した量のコードではないので1つのtfファイルに全記述をします。
それでは早速リソースを記述する前の基本設定を書いていきます。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
required_version = ">= 1.13.0"
}
provider "aws" {
region = "ap-northeast-1"
default_tags {
tags = {
terraform = "true"
}
}
}
terraform セクション
-
required_providersでは利用するプロバイダーの設定を記載します。
今回はAWSのみなので、awsセクションのみの記載で、source = "hashicorp/aws"でTerraform公式のAWSプロバイダを利用するようにし、version = "~> 6.0"の記載でバージョンを6.XX系に固定します。
provider "aws" セクション
- 上記で設定した、プロバイダーに関する設定を記載します。今回は
region = "ap-northeast-1"と記載し作成するリソースを東京リージョンと明示的に指定します。 - Terraformで管理するリソースすべてにタグを付与したいので、
default_tagsセクションでリソースに付与するタグを設定します。
VPC、サブネットの作成
続いてはVPCとサブネットを記載します。
# --------------------------
# VPC & Private Subnet
# --------------------------
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = { Name = "miyazaki-ssm-vpc" }
}
resource "aws_subnet" "private" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
map_public_ip_on_launch = false
availability_zone = "ap-northeast-1a"
tags = { Name = "miyazaki-private-subnet" }
}
resource "aws_security_group" "ec2_sg" {
name = "ssm-ec2-sg"
description = "Allow SSM communication"
vpc_id = aws_vpc.main.id
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = { Name = "miyazaki-ssm-ec2-sg" }
}
resource "aws_security_group" "vpcep_sg" {
name = "miyazaki-ssm-vpcep-sg"
description = "Allow SSM communication"
vpc_id = aws_vpc.main.id
ingress {
from_port = 443
to_port = 443
protocol = "TCP"
cidr_blocks = ["0.0.0.0/0"]
}
tags = { Name = "miyazaki-ssm-vpcep-sg" }
}
resource "aws_vpc" "main" セクション
-
aws_vpcという機能を使ってVPCを作成します。作成するリソースにはローカルで使えるmainという名前を与えます。 ※以降もresourceの文法は同じになるので説明は省略します。 -
cidr_block = "10.0.0.0/16"名前の通りCIDR範囲を指定します。 -
enable_dns_support = trueVPC内のDNS解決を有効にします。 -
enable_dns_hostnames = trueVPC内のDNSホスト名を有効にします。 -
tags付与したいタグを記載します。 ※以降はtagsの説明は省略します。
resource "aws_subnet" "private" セクション
-
vpc_id = aws_vpc.main.idどのVPCにサブネットを作成するか指定します。aws_vpc.main.idで👆で作成したVPCのVPCIDを指定します。 -
map_public_ip_on_launch = falseパブリックIPv4の自動割り当ての設定です。EC2へはSSMで接続するので、今回はfalseを指定します。 -
availability_zone = "ap-northeast-1a"サブネットを"ap-northeast-1a"に作成する記載です。
resource "aws_security_group" セクション
- EC2用にアウトバウンドのみ許可したSCG、VPCエンドポイント用の443のインバウンドを許可したルールを持つSCGを作ります。
-
egressでアウトバウンドルール、ingressでインバウンドルールを設定します。
IAMロールの作成
続いてはEC2にアタッチするIAMロールを作成していきます。
# --------------------------
# IAM Role for EC2 SSM
# --------------------------
resource "aws_iam_role" "ec2_ssm_role" {
name = "miyazaki-ec2-ssm-role"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [{
Effect = "Allow",
Principal = { Service = "ec2.amazonaws.com" },
Action = "sts:AssumeRole"
}]
})
}
resource "aws_iam_role_policy_attachment" "ssm_core" {
role = aws_iam_role.ec2_ssm_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}
resource "aws_iam_instance_profile" "ec2_ssm_profile" {
name = "miyazaki-ec2-ssm-profile"
role = aws_iam_role.ec2_ssm_role.name
}
resource "aws_iam_role" "ec2_ssm_role" セクション
- EC2に付与する用のIAMロールを作成します。
-
assume_role_policy = jsonencodeで信頼されたエンティティを指定しています。今回はEC2がこのロールを引き受けられるように設定しています。
resource "aws_iam_role_policy_attachment" "ssm_core" セクション
- ロールにポリシーをアタッチする記載です。
-
role = aws_iam_role.ec2_ssm_role.nameで対象のロールを指定しています。 -
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"でアタッチするポリシーを指定しています。今回はAmazonSSMManagedInstanceCoreを付与しています。
resource "aws_iam_instance_profile" "ec2_ssm_profile" セクション
- インスタンスプロファイルを作成する記載です。
-
name = "miyazaki-ec2-ssm-profile"で作成するインスタンスプロファイル名を、role = aws_iam_role.ec2_ssm_role.nameでプロファイルに紐づけるIAMロールを指定しています。
VPCエンドポイントの作成
# --------------------------
# VPC Endpoints for SSM
# --------------------------
resource "aws_vpc_endpoint" "ssm" {
vpc_id = aws_vpc.main.id
service_name = "com.amazonaws.ap-northeast-1.ssm"
vpc_endpoint_type = "Interface"
subnet_ids = [aws_subnet.private.id]
security_group_ids = [aws_security_group.vpcep_sg.id]
private_dns_enabled = true
tags = { Name = "miyazaki-ssm-endpoint" }
}
resource "aws_vpc_endpoint" "ec2messages" {
vpc_id = aws_vpc.main.id
service_name = "com.amazonaws.ap-northeast-1.ec2messages"
vpc_endpoint_type = "Interface"
subnet_ids = [aws_subnet.private.id]
security_group_ids = [aws_security_group.vpcep_sg.id]
private_dns_enabled = true
tags = { Name = "miyazaki-ec2messages-endpoint" }
}
resource "aws_vpc_endpoint" "ssmmessages" {
vpc_id = aws_vpc.main.id
service_name = "com.amazonaws.ap-northeast-1.ssmmessages"
vpc_endpoint_type = "Interface"
subnet_ids = [aws_subnet.private.id]
security_group_ids = [aws_security_group.vpcep_sg.id]
private_dns_enabled = true
tags = { Name = "miyazaki-ssmmessages-endpoint" }
}
resource "aws_vpc_endpoint" "ssm" セクション
-
service_name = "com.amazonaws.ap-northeast-1.ssm"で作成するVPCエンドポイントのサービス名を指定します。 -
vpc_endpoint_type = "Interface"は作成するエンドポイントのタイプを指定します。今回はすべて"Interface"型で作成します。 -
security_group_ids = [aws_security_group.vpcep_sg.id]エンドポイントに付与するセキュリティグループを指定します。付与するものはVPC作成の際に合わせて作成した、エンドポイント用のセキュリティグループです。 -
private_dns_enabled = trueVPC内でDNSをこのエンドポイントで解決させる必要があるのですべてtrueで作成します。
※※※他2つのリソースもサービス名が異なるだけなので説明は割愛します。
EC2の作成
# --------------------------
# EC2 Instance
# --------------------------
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-gp2"]
}
}
resource "aws_instance" "ssm_ec2" {
ami = data.aws_ami.amazon_linux.id
instance_type = "t3.micro"
subnet_id = aws_subnet.private.id
vpc_security_group_ids = [aws_security_group.ec2_sg.id]
iam_instance_profile = aws_iam_instance_profile.ec2_ssm_profile.name
associate_public_ip_address = false
tags = {
Name = "miyazaki-ssm-private-ec2"
}
}
data "aws_ami" "amazon_linux" セクション
-
dateではリソースの構築に用いる情報を定義します。 - 今回は起動するEC2のAMIを常に最新のものを使いたかったの
dateセクションを用意しています。 -
most_recent = trueの記述で、常に最新のバージョンのAMIを取得するようにします。 -
owners = ["amazon"]で対象をAWS公式のAMIを対象にします。 - 今回はSSMエージェントがあらかじめインストールされているものを使いたいため、
filterでAmazonLinuxに絞ります。
resource "aws_instance" "ssm_ec2" セクション
-
ami = data.aws_ami.amazon_linux.idで👆で取得したAMIを指定します。 -
instance_type = "t3.micro"インスタンスタイプは無料利用枠のものを指定します。 -
vpc_security_group_ids = [aws_security_group.ec2_sg.id]はVPCの作成時に作ったEC2用のセキュリティグループを指定します。 -
iam_instance_profile = aws_iam_instance_profile.ec2_ssm_profile.nameこちらもEC2用に作成したIAMロールを指定します。 -
associate_public_ip_address = falseSSM接続をするのにパブリックIPは必要ないので、falseをしてします。
構築
コードがそろったので、あとは実行するだけです。
terraform ini #初期化
terraform plan #構築リソースの確認
terraform apply #リソースの構築
applyが完了すれば、コンソールからSSM接続ができるようになっているはずです。
エラーが出た際や、コードの値を変えたい場合はteraformの公式ドキュメントを参照してみてください。