🍣

別VPCのリソースをALBで扱う

2022/02/16に公開

AWS環境の整備を進めていく中で、一時的にALBで別VPCにあるリソースを扱い時があったとする。
そんな時は、どのような対応ができるのか試してみる。

複数VPC環境を構築

まずは、複数VPCにEC2インスタンスを立てる。
片方のVPCにはALBを立てておく。

main.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

# --------------------------------------------------
# VPC alpha
# --------------------------------------------------

module "vpc_alpha" {
  source  = "terraform-aws-modules/vpc/aws"

  name = "my-vpc-alpha"
  cidr = "10.0.0.0/16"

  azs = ["ap-northeast-1a", "ap-northeast-1c"]
  public_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
}

resource "aws_security_group" "alpha" {
  name = "my-sg-alpha"
  vpc_id = module.vpc_alpha.vpc_id
}

resource "aws_security_group_rule" "ingress_alpha" {
  security_group_id = aws_security_group.alpha.id
  type = "ingress"
  description = "Allow from Any HTTP"
  from_port = 80
  to_port = 80
  protocol = "tcp"
  cidr_blocks = ["0.0.0.0/0"]
}

resource "aws_security_group_rule" "egress_alpha" {
  security_group_id = aws_security_group.alpha.id
  type = "egress"
  description = "Allow to Any"
  from_port = 0
  to_port = 0
  protocol = "-1"
  cidr_blocks = ["0.0.0.0/0"]
}

resource "aws_instance" "alpha" {
  ami = "ami-08a8688fb7eacb171"
  instance_type = "t2.micro"
  security_groups = [resource.aws_security_group.alpha.id]
  subnet_id = module.vpc_alpha.public_subnets[0]
  associate_public_ip_address = true
  user_data = join("\n", [
    "#!/bin/bash",
    "sudo yum update -y",
    "sudo amazon-linux-extras install nginx1 -y",
    "sudo systemctl enable nginx",
    "sudo systemctl start nginx",
  ])
  tags = {
    Name = "my-ec2-alpha"
  }
}

# --------------------------------------------------
# VPC beta
# --------------------------------------------------

module "vpc_beta" {
  source  = "terraform-aws-modules/vpc/aws"

  name = "my-vpc-beta"
  cidr = "10.1.0.0/16"

  azs = ["ap-northeast-1a", "ap-northeast-1c"]
  public_subnets = ["10.1.1.0/24", "10.1.2.0/24"]
}

resource "aws_security_group" "beta" {
  name = "my-sg-beta"
  vpc_id = module.vpc_beta.vpc_id
}

resource "aws_security_group_rule" "ingress_beta" {
  security_group_id = aws_security_group.beta.id
  type = "ingress"
  description = "Allow from Any HTTP"
  from_port = 80
  to_port = 80
  protocol = "tcp"
  cidr_blocks = ["0.0.0.0/0"]
}

resource "aws_security_group_rule" "egress_beta" {
  security_group_id = aws_security_group.beta.id
  type = "egress"
  description = "Allow to Any"
  from_port = 0
  to_port = 0
  protocol = "-1"
  cidr_blocks = ["0.0.0.0/0"]
}

resource "aws_instance" "beta" {
  ami = "ami-08a8688fb7eacb171"
  instance_type = "t2.micro"
  security_groups = [resource.aws_security_group.beta.id]
  subnet_id = module.vpc_beta.public_subnets[0]
  associate_public_ip_address = true
  user_data = join("\n", [
    "#!/bin/bash",
    "sudo yum update -y",
    "sudo yum install httpd -y",
    "sudo systemctl enable httpd",
    "sudo systemctl start httpd",
  ])
  tags = {
    Name = "my-ec2-beta"
  }
}

# --------------------------------------------------
# ALB
# --------------------------------------------------

resource "aws_lb" "alpha" {
  name = "my-alb-alpha"
  load_balancer_type = "application"
  security_groups = [resource.aws_security_group.alpha.id]
  subnets = module.vpc_alpha.public_subnets
}

resource "aws_lb_listener" "alpha" {
  load_balancer_arn = aws_lb.alpha.arn
  port = "80"
  protocol = "HTTP"
  default_action {
    type = "fixed-response"
    fixed_response {
      content_type = "text/plain"
      message_body = "503 Service Temporarily Unavailable"
      status_code = "503"
    }
  }
}

resource "aws_lb_target_group" "alpha" {
  name = "my-tg-alpha"
  port = 80
  protocol = "HTTP"
  vpc_id = module.vpc_alpha.vpc_id
}

resource "aws_lb_target_group_attachment" "alpha" {
  target_group_arn = aws_lb_target_group.alpha.arn
  target_id = aws_instance.alpha.id
  port = 80
}

resource "aws_lb_listener_rule" "alpha" {
  listener_arn = aws_lb_listener.alpha.arn
  action {
    type = "forward"
    target_group_arn = aws_lb_target_group.alpha.arn
  }
  condition {
    path_pattern { values = ["/*"] }
  }
}

別VPCのTargetGroupをALBに設定できるか?

できない。
ALBのルールで指定しようと思っても選択できない。

PublicIPでTargetGroupを作成できるか?

できない。
TargetTypeとしてIPを選択し、PublicIPでリソースを指定しようと思っても設定できない。
PrivateIP以外は弾かれてしまう。

別VPCのPrivateIPでTargetGroupを作成できるか?

できる。
TargetTypeとしてIPを選択し、PrivateIPでリソースを指定すると作成できた。

ALBと同じVPCでTargetGroupを作成すれば、ALBのルールに設定することもできた。

ただし、Health statusがUnhealthyになっていて、このままでは使えない。

VPC peeringで繋いでみる

ヘルチェックを通すためには、別VPCのインスタンスに通信できる必要がある。

複数のVPCを繋げる、VPC peeringという機能がある。
その機能を使って、別VPCへと通信できる状態にしてみる。

まずは、Peering connectionを作成する。
作成したあとは、Acceptすることも忘れない。

次に、VPC間で通信するためのRoute tableを設定する。
Targetに作成したPeering connectionと、通信先VPCのIPレンジを指定する。

この状態でALBにアクセスしてみる。
別VPCのインスタンスに設定したApacheの画面が表示された。

ヘルスチェックにはHealth checks failed with these codes: [403]と出ているが、Apacheのテストページが403で返ってくるので良しとする。

CIDRが同じ場合は?

できない。
Peering connectionが作成できない。

当たり前な感じがするが、同じ範囲のIPを使っている場合は、VPCを繋げられない。
この場合は、積んだのかもしれない。

まとめ

別VPCにあるリソースをALBで扱うことができる場合もある、ということがわかった。

ネットワーク設計せずに適当に構築すると、困る場面もあるんだなと思った。
VPCは量産せずに、1環境1VPCにしておくと良いのだろうか。

VPCとか気にせずに構築できるような状態になってくれると嬉しい。

Discussion