- 公開日
- 最終更新日
【Terraform】VPCエンドポイント(インターフェース型)構築&SSMセッションマネージャーでEC2接続
この記事を共有する

目次
はじめに
皆さんこんにちは!パーソル&サーバーワークスの榎本です。
以前のブログではプライベートサブネットにEC2を構築、パブリックサブネットにNATゲートウェイを構築してEC2がNATゲートウェイ経由でインターネット接続できる環境をTerraformで構築しました。
今回はNATゲートウェイ経由ではなく、VPCエンドポイント(インターフェース型)経由でSystems Manager(以下、SSM)セッションマネージャーを使ってEC2に接続するためのコードや手順を整理しました。
本ハンズオンの目的
プライベートサブネットにあるEC2に対して、VPCエンドポイント(インターフェース型)経由でSSMセッションマネージャーを使用して接続できる構成をTerraformで構築できるようになること
前提
- 構築用のEC2にTerraformインストール済み
- 構築対象のEC2はWebサーバーを想定して作成し、構築時にApacheをインストールする
- AmazonSSMManagedInstanceCoreポリシーが許可されているIAMロール(本ハンズオンではterraform-handson-iamroleという名前)を事前作成
本ハンズオン概要
- Terraformのコードを記載し、以下構成図のようにSSMセッションマネージャーからVPCエンドポイント経由でEC2に接続できる構成をTerraformで構築する
構成図
構築環境
- AWS
- 東京リージョン(ap-northeast-1)
- AvailabilityZone(ap-northeast-1a、ap-northeast-1c)
構築対象
- VPC ×1
- EC2 ×2(プライベートサブネットの各AZに1つずつ)
- EC2用セキュリティグループ ×1
- VPCエンドポイント ×2
- IAMインスタンスプロファイル ×1
ハンズオン手順
1. 構築用のEC2にログインし、以下コマンドで作業用ディレクトリに移動する
# terraform-handson/vpceディレクトリ作成
mkdir -p terraform-handson/vpce
# terraform-handson/vpceディレクトリに移動
cd terraform-handson/vpce
2. 移動したディレクトリ配下に、構築に必要なファイルを作成する
# provider.tfファイルを新規作成
touch provider.tf
# vpc.tfファイルを新規作成
touch vpc.tf
# ec2.tfファイルを新規作成
touch ec2.tf
3. 作成したprovider.tfファイル内に以下記載して保存する
# プロバイダー指定 AWSの東京リージョンを使用することを定義
provider "aws" {
region = "ap-northeast-1"
}
4. 作成したvpc.tfファイルに以下記載して保存する
# VPC作成
resource "aws_vpc" "main_vpc" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "terraform-handson-vpc"
}
}
# インターネットゲートウェイ作成
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main_vpc.id
tags = {
Name = "terraform-handson-igw"
}
}
# パブリックサブネットa作成
resource "aws_subnet" "public_subnet_a" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.0.0/24"
availability_zone = "ap-northeast-1a"
tags = {
Name = "terraform-handson-public-subnet-a"
}
}
# パブリックサブネットc作成
resource "aws_subnet" "public_subnet_c" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-northeast-1c"
tags = {
Name = "terraform-handson-public-subnet-c"
}
}
# プライベートサブネットa作成
resource "aws_subnet" "private_subnet_a" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.10.0/24"
availability_zone = "ap-northeast-1a"
tags = {
Name = "terraform-handson-private-subnet-a"
}
}
# プライベートサブネットc作成
resource "aws_subnet" "private_subnet_c" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.11.0/24"
availability_zone = "ap-northeast-1c"
tags = {
Name = "terraform-handson-private-subnet-c"
}
}
# パブリックルートテーブル作成
resource "aws_route_table" "route_table_public" {
vpc_id = aws_vpc.main_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
tags = {
Name = "terraform-handson-public-rt"
}
}
# プライベートルートテーブル作成
resource "aws_route_table" "route_table_private" {
vpc_id = aws_vpc.main_vpc.id
tags = {
Name = "terraform-handson-private-rt"
}
}
# パブリックルートテーブルa関連付け
resource "aws_route_table_association" "route_table_association_public_a" {
route_table_id = aws_route_table.route_table_public.id
subnet_id = aws_subnet.public_subnet_a.id
}
# パブリックルートテーブルc関連付け
resource "aws_route_table_association" "route_table_association_public_c" {
route_table_id = aws_route_table.route_table_public.id
subnet_id = aws_subnet.public_subnet_c.id
}
# プライベートルートテーブルa関連付け
resource "aws_route_table_association" "route_table_association_private_a" {
route_table_id = aws_route_table.route_table_private.id
subnet_id = aws_subnet.private_subnet_a.id
}
# プライベートルートテーブルc関連付け
resource "aws_route_table_association" "route_table_association_private_c" {
route_table_id = aws_route_table.route_table_private.id
subnet_id = aws_subnet.private_subnet_c.id
}
# VPCエンドポイント用セキュリティグループ
resource "aws_security_group" "vpc_endpoint_sg" {
name_prefix = "terraform-handson-ap1-vpce-sg"
vpc_id = aws_vpc.main_vpc.id
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = [
"10.0.10.0/24",
"10.0.11.0/24"
]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "terraform-handson-ap1-vpce-sg"
}
}
# SSM用VPCエンドポイント(インターフェース型)
resource "aws_vpc_endpoint" "ssm_endpoint" {
vpc_id = aws_vpc.main_vpc.id
service_name = "com.amazonaws.ap-northeast-1.ssm"
vpc_endpoint_type = "Interface"
subnet_ids = [aws_subnet.private_subnet_a.id, aws_subnet.private_subnet_c.id]
security_group_ids = [aws_security_group.vpc_endpoint_sg.id]
private_dns_enabled = true
tags = {
Name = "terraform-handson-ap1-ssm-endpoint"
}
}
# SSM Messages用VPCエンドポイント(インターフェース型)
resource "aws_vpc_endpoint" "ssmmessages_endpoint" {
vpc_id = aws_vpc.main_vpc.id
service_name = "com.amazonaws.ap-northeast-1.ssmmessages"
vpc_endpoint_type = "Interface"
subnet_ids = [aws_subnet.private_subnet_a.id, aws_subnet.private_subnet_c.id]
security_group_ids = [aws_security_group.vpc_endpoint_sg.id]
private_dns_enabled = true
tags = {
Name = "terraform-handson-ap1-ssmmessages-endpoint"
}
}
5. 作成したec2.tfファイル内に以下記載して保存する
# EC2作成(Webサーバー1)
resource "aws_instance" "web1" {
ami = "ami-023ff3d4ab11b2525"
instance_type = "t3.micro"
subnet_id = aws_subnet.private_subnet_a.id
security_groups = [aws_security_group.web_sg.id]
iam_instance_profile = aws_iam_instance_profile.instance_profile.name
# ユーザーデータを指定
user_data = <<-EOT
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Welcome to my website!</h1>" > /var/www/html/index.html
EOT
tags = {
Name = "terraform-handson-ec2-web1"
}
}
# EC2作成(Webサーバー2)
resource "aws_instance" "web2" {
ami = "ami-023ff3d4ab11b2525"
instance_type = "t3.micro"
subnet_id = aws_subnet.private_subnet_c.id
security_groups = [aws_security_group.web_sg.id]
iam_instance_profile = aws_iam_instance_profile.instance_profile.name
# ユーザーデータを指定
user_data = <<-EOT
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Welcome to my website!</h1>" > /var/www/html/index.html
EOT
tags = {
Name = "terraform-handson-ec2-web2"
}
}
# EC2用セキュリティグループ作成
resource "aws_security_group" "web_sg" {
vpc_id = aws_vpc.main_vpc.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "terraform-handson-web-sg"
}
}
# web1にElasticIP付与
resource "aws_eip" "web1_eip" {
domain = "vpc"
instance = aws_instance.web1.id
}
# web2にElasticIP付与
resource "aws_eip" "web2_eip" {
domain = "vpc"
instance = aws_instance.web2.id
}
# IAMインスタンスプロファイル作成(SSMセッションマネージャ接続のために必要)
resource "aws_iam_instance_profile" "instance_profile" {
name = "terraform-handson-instance-profile"
role = "terraform-handson-iamrole"
}
6. 以下コマンドを順番に実行する
# 必要なモジュールをインストール
terraform init
# 実行内容を事前確認
terraform plan
# 構築実行
terraform apply
7. マネジメントコンソールを開き、VPCエンドポイント(インターフェース型)が新規作成されていることを確認する
8. SSMセッションマネージャーを開き、EC2に接続できることを確認する
※作成してから接続できるようになるまで2分ほど時間がかかる可能性がありますので、
初めて開いた時に接続できなくても少し時間を空けて再度ご確認ください。
9. 作成されていることを確認できたら、以下コマンドを実行して作成した環境を削除する
#環境を削除
terraform destroy
まとめ
NATゲートウェイは常時置いておく必要があり、コストが高くなる傾向にあります。
インターネット接続要件が無い場合や、コストを抑えたい場合などはVPCエンドポイント(インターフェース型)を使用することも選択肢となります。
ただVPCエンドポイント(インターフェース型)も場合によってはNATゲートウェイよりもコストが高くなりますので、ご注意ください。
この記事は私が書きました
榎本 将希
記事一覧2024 Japan AWS All Certifications Engineers サッカー観戦とサウナが好きです! 機械学習を勉強中です!
