概要
やりたいこと
過去に OWASP Juice shop を EC2 で作成した。これを HTTPS 化し、 Terraform で管理したい。
以下のような通信の流れになる。
- ブラウザ -> https(443) -> AlB -> http(80) -> EC2 -> port_forwading(3000) -> owasp-shop
Route53
ドメインの管理を行うサービス。
今回は HTTPS でアクセスしたいため、ドメインの取得を行った。
ACM
SSL 証明書の管理を行うサービス。
ALB
HTTPS の終端。EC2 は今回2つ作成し、バランシングする。
実践
準備
過去の記事を参照。
作業ディレクトリを作成し、プロバイダーと tfstate ファイルを S3 バケットに保存する設定をする。
mkdir alb-ec2 cd alb-ec2 vi main.tf
provider "aws" {
profile = "terraform"
region = "ap-northeast-1"
}
terraform {
required_version = ">= 0.12.0"
backend "s3" {
profile = "terraform"
region = "ap-northeast-1"
bucket = "terraform-tfstate-runble1"
key = "alb-ec2/terraform.tfstate"
encrypt = true
}
}
初期化し、ワークスペース名をつける。
terraform init terraform workspace new alb-ec2-acm
Route53
AWSコンソールより、適当なドメインを登録する。
VPC + ルーティング + セキュリティグループ
最初に、土台となるネットワークを作る。
# ====================
#
# VPC
#
# ====================
resource "aws_vpc" "example" {
cidr_block = "10.0.0.0/16"
instance_tenancy = "default"
enable_dns_hostnames = true
enable_dns_support = true
}
# ====================
#
# Subnet
#
# ====================
resource "aws_subnet" "public_a" {
vpc_id = aws_vpc.example.id
cidr_block = "10.0.1.0/24"
map_public_ip_on_launch = true
availability_zone = "ap-northeast-1a"
}
resource "aws_subnet" "public_c" {
vpc_id = aws_vpc.example.id
cidr_block = "10.0.2.0/24"
map_public_ip_on_launch = true
availability_zone = "ap-northeast-1c"
}
resource "aws_subnet" "public_a_web" {
vpc_id = aws_vpc.example.id
cidr_block = "10.0.3.0/24"
map_public_ip_on_launch = true
availability_zone = "ap-northeast-1a"
}
resource "aws_subnet" "public_c_web" {
vpc_id = aws_vpc.example.id
cidr_block = "10.0.4.0/24"
map_public_ip_on_launch = true
availability_zone = "ap-northeast-1c"
}
resource "aws_subnet" "private_a" {
vpc_id = aws_vpc.example.id
cidr_block = "10.0.5.0/24"
map_public_ip_on_launch = false
availability_zone = "ap-northeast-1a"
}
resource "aws_subnet" "private_c" {
vpc_id = aws_vpc.example.id
cidr_block = "10.0.6.0/24"
map_public_ip_on_launch = false
availability_zone = "ap-northeast-1c"
}
# ====================
#
# Internet Gateway
#
# ====================
resource "aws_internet_gateway" "example" {
vpc_id = aws_vpc.example.id
}
# ====================
#
# Route Table
#
# ====================
resource "aws_route_table" "public" {
vpc_id = aws_vpc.example.id
}
resource "aws_route" "public" {
route_table_id = aws_route_table.public.id
gateway_id = aws_internet_gateway.example.id
destination_cidr_block = "0.0.0.0/0"
}
resource "aws_route_table_association" "public_a" {
subnet_id = aws_subnet.public_a.id
route_table_id = aws_route_table.public.id
}
resource "aws_route_table_association" "public_c" {
subnet_id = aws_subnet.public_c.id
route_table_id = aws_route_table.public.id
}
デプロイする。
terraform apply
ALB
# ====================
#
# ALB
#
# ====================
resource "aws_lb" "for_webserver" {
name = "webserver-alb"
internal = false
load_balancer_type = "application"
security_groups = [
aws_security_group.alb.id
]
subnets = [
aws_subnet.public_a.id,
aws_subnet.public_c.id,
]
}
# ====================
#
# Security Group
#
# ====================
resource "aws_security_group" "alb" {
name = "alb"
vpc_id = aws_vpc.example.id
ingress {
from_port = 443
to_port = 443
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"]
}
}
# ====================
#
# Listner
#
# ====================
resource "aws_lb_listener" "for_webserver" {
load_balancer_arn = aws_lb.for_webserver.arn
port = "443"
protocol = "HTTPS"
certificate_arn = aws_acm_certificate.example.arn #証明書
ssl_policy = "ELBSecurityPolicy-2016-08"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.for_webserver.arn
}
}
resource "aws_lb_listener_rule" "forward" {
listener_arn = aws_lb_listener.for_webserver.arn
priority = 99
action {
type = "forward"
target_group_arn = aws_lb_target_group.for_webserver.arn
}
condition {
path_pattern {
values = ["/*"]
}
}
}
# ====================
#
# Target Group
#
# ====================
resource "aws_lb_target_group" "for_webserver" {
name = "for-webserver-lb-tg"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.example.id
health_check {
path = "/index.html"
}
}
resource "aws_lb_target_group_attachment" "for_webserver_a" {
target_group_arn = aws_lb_target_group.for_webserver.arn
target_id = aws_instance.a.id
port = 80
}
resource "aws_lb_target_group_attachment" "for_webserver_c" {
target_group_arn = aws_lb_target_group.for_webserver.arn
target_id = aws_instance.c.id
port = 80
}
Route53 + ACM
# ====================
#
# Route53
#
# ====================
data "aws_route53_zone" "example" {
name = "登録したドメイン"
}
resource "aws_route53_record" "example" {
zone_id = data.aws_route53_zone.example.zone_id
name = data.aws_route53_zone.example.name
type = "A"
alias {
name = aws_lb.for_webserver.dns_name
zone_id = aws_lb.for_webserver.zone_id
evaluate_target_health = true
}
}
# ====================
#
# ACM
#
# ====================
resource "aws_acm_certificate" "example" {
domain_name = aws_route53_record.example.name
subject_alternative_names = []
validation_method = "DNS"
lifecycle {
create_before_destroy = true
}
}
# 検証用DNSレコード
resource "aws_route53_record" "example_certificate" {
name = aws_acm_certificate.example.domain_validation_options[0].resource_record_name
type = aws_acm_certificate.example.domain_validation_options[0].resource_record_type
records = [aws_acm_certificate.example.domain_validation_options[0].resource_record_value]
zone_id = data.aws_route53_zone.example.id
ttl = 60
}
# SSL証明書の検証
resource "aws_acm_certificate_validation" "example" {
certificate_arn = aws_acm_certificate.example.arn
validation_record_fqdns = [aws_route53_record.example_certificate.fqdn]
}
# ====================
#
# Output
#
# ====================
output "domain_name" {
value = aws_route53_record.example.name
}
EC2
owasp-juice-shop というやられアプリを建てる。
# ====================
#
# EC2
#
# ====================
resource "aws_instance" "a" {
ami = "ami-0c3fd0f5d33134a76"
vpc_security_group_ids = [aws_security_group.for_webserver_ec2.id]
instance_type = "t2.micro"
subnet_id = aws_subnet.public_a.id
user_data = <<EOF
#!/bin/bash
yum update -y
yum install -y docker
service docker start
docker pull bkimminich/juice-shop
docker run -d -p 80:3000 bkimminich/juice-shop
EOF
}
resource "aws_instance" "c" {
ami = "ami-0c3fd0f5d33134a76"
vpc_security_group_ids = [aws_security_group.for_webserver_ec2.id]
instance_type = "t2.micro"
subnet_id = aws_subnet.public_c.id
user_data = <<EOF
#!/bin/bash
yum update -y
yum install -y docker
service docker start
docker pull bkimminich/juice-shop
docker run -d -p 80:3000 bkimminich/juice-shop
EOF
}
# ====================
#
# Security Group
#
# ====================
resource "aws_security_group" "for_webserver_ec2" {
name = "for-ec2"
vpc_id = aws_vpc.example.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
security_groups = [aws_security_group.alb.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
登録したドメインに HTTPS でアクセスし閲覧できればOK。
コードは github に。
コメント