以前の記事を社内で紹介した際、いろいろと議論が進みまして、非常に面白いツッコミを入れてくださった先輩がいらっしゃいます。
そのツッコミの内容はタイトルの通りなのですが、
「あ、確かにどうなんやろか?Route 53は明確に公式ドキュメントに権威サーバって書いているけど、暗黙的にできるDNSサーバはどうなんやろか?」
と疑問に思いましたので、検証してみました。
長くインフラエンジニアやってる癖に非常にお恥ずかしのですが、DNSの構成にあんまり詳しくないです。
間違えてたらごめんなさい。
検証環境を簡易に作成するために前提としてお伝えすること
AWSもAzureもどちらもEC2、VMを構築した際、暗黙的に内部ネットワーク(AWSだと同一VPC、Azureだと同一仮想ネットワーク、AWSもAzureもどちらもVPC Peering、Vnet Peeringで接続した場合はこの接続されたVPC、仮想ネットワークも含みます)で名前解決可能なFQDNが割り振られます。
検証環境
はい。
当然AWSのEC2もAzureのVMもローカルIPアドレスを持っているので、このローカルIPアドレスと暗黙的に割り振られるFQDNとを管理している権威DNSサーバがどこかにいるはずです。
この暗黙的に割り振られるFQDNと、暗黙的に構築されるDNSサーバで検証を行います。
確認したいこと
この権威サーバが暗黙的に構築されるDNSサーバなのか、はたまた別で権威サーバが構築されているのか?
これを調べます。
環境構築
直前にアップした記事はAWSでSpotインスタンスについての記事ですが、これ実はこの検証環境を作るためのコードなんですよね。
ついでにSpotインスタンスの検証も終わらせました。
なのでTerraformのコードもそのまま同じものを使い回します。
変数設定
# ---------------------------
# Variables - 変数設定
# ---------------------------
# region
# ap-northeast-1 東京リージョン
# ap-south-1 ムンバイリージョン
variable "region" {
default = "ap-south-1"
}
# 環境種別(本番:prd,ステージング:stg,開発:dev)
variable "env_type" {
default = "dev"
}
# システム名
variable "sys_name" {
default = "test_lb_dns"
}
# availability_zone
variable "availability_zone" {
type = object({
a = string
b = string #ムンバイリージョンで利用
c = string
})
default = {
a = "ap-south-1a" # ムンバイ(インド)のアベイラビリティゾーン
b = "ap-south-1b" # ムンバイ(インド)のアベイラビリティゾーン
c = "ap-south-1c" # ムンバイ(インド)のアベイラビリティゾーン
}
}
# ------------------------------
# Web Server と Application Load Balancer用VPC作成
# ------------------------------
# vpc address
variable "vpc_address_pre" {
default = "10.0."
}
variable "vpc_address_suf" {
default = "0.0/23"
}
# private subnet suffix address01
variable "private_address_suf01" {
default = "1.0/26"
}
# private subnet suffix address02
variable "private_address_suf02" {
default = "1.64/26"
}
# private subnet suffix address03
variable "private_address_suf03" {
default = "1.128/26"
}
# public subnet suffix address01
variable "public_address_suf01" {
default = "0.0/24"
}
# EC2のインスタンスタイプ
variable "ec2_instance_type" {
default = "t2.micro"
}
# VPC Endpoint
variable "vpc_endpoints" {
type = list(any)
default = ["ssm", "ssmmessages", "ec2messages"]
}
はい。
どうってことは無いです。
main.tf
# ---------------------------
# main
# ---------------------------
terraform {
required_version = ">= 1.4" # Terraformのバージョンを1.4以上に指定
required_providers {
aws = {
source = "hashicorp/aws"
version = "= 5.22.0" # AWSプロバイダのバージョンを5.22.0に固定
}
}
}
# プロバイダー設定
provider "aws" {
region = var.region
}
これも至ってシンプルですね。
VPC
# ---------------------------
# Web Server用VPC 構築
# ---------------------------
# VPC
resource "aws_vpc" "vpc" {
cidr_block = "${var.vpc_address_pre}${var.vpc_address_suf}"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.env_type}-${var.sys_name}-vpc"
}
}
# ---------------------------
# Subnet 構築
# ---------------------------
resource "aws_subnet" "sn_public_1a" {
vpc_id = aws_vpc.vpc.id
cidr_block = "${var.vpc_address_pre}${var.public_address_suf01}"
availability_zone = var.availability_zone.a
tags = {
Name = "${var.env_type}-${var.sys_name}-sn-public-1a"
}
}
# Internet Gateway
resource "aws_internet_gateway" "igw_vpc" {
vpc_id = aws_vpc.vpc.id
tags = {
Name = "${var.env_type}-${var.sys_name}-igw-vpc"
}
}
# ---------------------------
# Route table 作成
# ---------------------------
resource "aws_route_table" "rt_sn_public" {
vpc_id = aws_vpc.vpc.id
# Default GatewayをInternet Gatewayに向ける
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw_vpc.id
}
tags = {
Name = "${var.env_type}-${var.sys_name}-rt-sn-public"
}
}
# SubnetとRoute tableの関連付け
resource "aws_route_table_association" "associate_rt_sn_public_1a" {
subnet_id = aws_subnet.sn_public_1a.id
route_table_id = aws_route_table.rt_sn_public.id
}
シンプルな構成にしたので本来Public SubnetとPrivate Subnetに分けて管理すべきところをPublic Subnetのみにしました。
security group
# ---------------------------
# Security Group
# ---------------------------
# ---------------------------
# EC2用 Security Group作成
# ---------------------------
#ec2_app01(Front End EC2 1台目用SG)
resource "aws_security_group" "sg_ec2_app01" {
name = "${var.env_type}-${var.sys_name}-sg-ec2-app01"
vpc_id = aws_vpc.vpc.id
tags = {
Name = "${var.env_type}-${var.sys_name}-sg-ec2-app01"
}
# インバウンドルール
# For SSM
ingress {
description = "AllowHttpsInBoundFromVPC(for SSM)"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["${var.vpc_address_pre}${var.vpc_address_suf}"]
}
# アウトバウンドルール
egress {
description = "AllowAnyOutBound"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# クライアント相当Windows Server用SG
resource "aws_security_group" "sg_ec2_client01" {
name = "${var.env_type}-${var.sys_name}-sg-ec2-client01"
vpc_id = aws_vpc.vpc.id
tags = {
Name = "${var.env_type}-${var.sys_name}-sg-ec2-client01"
}
# インバウンドルール
# For EC2-app01 ICMPv4
ingress {
description = "AllowICMPv4InBoundFromEC2(for app01)"
from_port = -1
to_port = -1
protocol = "icmp"
security_groups = [aws_security_group.sg_ec2_app01.id]
}
# For RDPアクセス
ingress {
description = "AllowRdpInBoundFromHome"
from_port = 3389
to_port = 3389
protocol = "tcp"
cidr_blocks = ["123.225.10.132/32"]
}
# アウトバウンドルール
egress {
description = "AllowAnyOutBound"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# ---------------------------
# SSM用 Vpc endpoint Security Group作成
# ---------------------------
resource "aws_security_group" "sg_ssm" {
name = "${var.env_type}-${var.sys_name}-sg-ssm"
vpc_id = aws_vpc.vpc.id
tags = {
Name = "${var.env_type}-${var.sys_name}-sg-ssm"
}
# インバウンドルール
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["${var.vpc_address_pre}${var.vpc_address_suf}"]
}
# アウトバウンドルール
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "sg_ssmmessages" {
name = "${var.env_type}-${var.sys_name}-sg-ssmmessages"
vpc_id = aws_vpc.vpc.id
tags = {
Name = "${var.env_type}-${var.sys_name}-sg-ssmmessages"
}
# インバウンドルール
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["${var.vpc_address_pre}${var.vpc_address_suf}"]
}
# アウトバウンドルール
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "sg_ec2messages" {
name = "${var.env_type}-${var.sys_name}-sg-ec2messages"
vpc_id = aws_vpc.vpc.id
tags = {
Name = "${var.env_type}-${var.sys_name}-sg-ec2messages"
}
# インバウンドルール
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["${var.vpc_address_pre}${var.vpc_address_suf}"]
}
# アウトバウンドルール
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
これもシンプルにしています。
iam
# ---------------------------
# IAM
# ---------------------------
# IAM ROLE 定義
resource "aws_iam_role" "ec2_role" {
name = "${var.env_type}-${var.sys_name}-iam-role"
assume_role_policy = data.aws_iam_policy_document.ec2_assume_role.json
}
# IAMポリシー定義
data "aws_iam_policy_document" "ec2_assume_role" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ec2.amazonaws.com"]
}
}
}
# IAM ROLEのインスタンスプロフィールの作成
resource "aws_iam_instance_profile" "instance_prof" {
name = "${var.env_type}-${var.sys_name}-instance-profile-ssm"
role = aws_iam_role.ec2_role.name
}
# ---------------------------
# FOR SSM
# ---------------------------
# SSM用ポリシーをEC2ロールに設定
resource "aws_iam_role_policy_attachment" "ssm_control" {
role = aws_iam_role.ec2_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}
LinuxのEC2のSSMを使うためのiam設定ですね。
あってもなくてもどっちでも良いかな。
LinuxのEC2に何かあたら困るので、念のため付けました。
結局使わなかったのでなくてもよかったです。
ssmのためのvpc endpoint
# ---------------------------
# VPC Endpoint
# ---------------------------
# SSM用 VPC endpointの作成
resource "aws_vpc_endpoint" "interface" {
for_each = toset(var.vpc_endpoints)
vpc_id = aws_vpc.vpc.id
service_name = "com.amazonaws.${var.region}.${each.value}"
vpc_endpoint_type = "Interface"
subnet_ids = [aws_subnet.sn_public_1a.id]
private_dns_enabled = true
security_group_ids = [aws_security_group.sg_ssm.id]
tags = { "Name" = "${var.env_type}-${var.sys_name}-vpc-endpoint-${each.value}" }
}
はい。
これもSSM結局使わなかったのでなくても大丈夫です。
EC2
# ---------------------------
# EC2作成
# ---------------------------
# Amazon Linux 2023 の最新版AMIを取得
data "aws_ssm_parameter" "al2023-ami-kernel-default-x86_64" {
name = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64"
}
# ---------------------------
# 必要台数のEC2を作成
# ---------------------------
# Front End(Web Server)
# resource "aws_instance" "ec2_app01" {
resource "aws_spot_instance_request" "ec2_app01" { #spot_priceとspot_typeを設定する
spot_price = "0.0047"
spot_type = "one-time"
ami = data.aws_ssm_parameter.al2023-ami-kernel-default-x86_64.value
instance_type = var.ec2_instance_type
availability_zone = var.availability_zone.a
vpc_security_group_ids = [aws_security_group.sg_ec2_app01.id]
subnet_id = aws_subnet.sn_public_1a.id
associate_public_ip_address = "true"
iam_instance_profile = aws_iam_instance_profile.instance_prof.name
root_block_device {
volume_size = 30 # GB
volume_type = "gp3" # 汎用SSD
encrypted = false
tags = {
Snapshot = "false"
}
}
tags = {
Name = "${var.env_type}-${var.sys_name}-ec2-app01"
}
# NAT Gateway構築後にEC2を構築するパラメーター→Route Table設定後に変更、App01はNAT Gateway構築後でもコケないが、App02と03がコケるため構成変更。(EC2構築前にNAT Gatewayが無いとヒアドキュメント内のdnfコマンドでこける)
depends_on = [
aws_route_table_association.associate_rt_sn_public_1a
]
}
# クライアントPC相当のWindows Serverマシンを構築
# ---------------------------
# Windowsマシン用のKey pair作成
# ---------------------------
variable "key_name" {
default = "kp-ec2-01"
}
variable "key_path" {
default = "D:\\OneDrive - sh-style.work\\ドキュメント\\03.技術\\16.GitHub\\AWS\\13.dns_route_server"
}
# 秘密鍵のアルゴリズム設定
resource "tls_private_key" "kp-ec2-01" {
algorithm = "RSA"
rsa_bits = 2048
}
# クライアントPCにKey pair(秘密鍵と公開鍵)を作成
# - Windowsの場合はフォルダを"\\"で区切る(エスケープする必要がある)
# - [terraform apply] 実行後はクライアントPCの公開鍵は自動削除される
locals {
public_key_file = "${var.key_path}\\${var.key_name}.id_rsa.pub"
private_key_file = "${var.key_path}\\${var.key_name}.id_rsa"
}
resource "local_file" "kp_ec2_01_pem" {
filename = "${local.private_key_file}"
content = "${tls_private_key.kp-ec2-01.private_key_pem}"
}
# 上記で作成した公開鍵をAWSのKey pairにインポート
resource "aws_key_pair" "kp_ec2_01" {
key_name = "${var.key_name}"
public_key = "${tls_private_key.kp-ec2-01.public_key_openssh}"
}
# ---------------------------
# クライアント相当のEC2を作成
# ---------------------------
#20240523時点のAMI
#Microsoft Windows Server 2022 Base:ami-0f346136f3b372267
#Microsoft Windows Server 2019 Base:ami-01bd28d73d0053a15
#Microsoft Windows Server 2016 Base:ami-063d3d00f8a97a6d1
#resource "aws_instance" "ec2_client01" {
resource "aws_spot_instance_request" "ec2_client01" { #spot_priceとspot_typeを設定する
spot_price = "0.14"
spot_type = "one-time"
ami = "ami-0f346136f3b372267" #Microsoft Windows Server 2022 Base
instance_type = "m4.large"
availability_zone = var.availability_zone.a
vpc_security_group_ids = [aws_security_group.sg_ec2_client01.id]
subnet_id = aws_subnet.sn_public_1a.id
associate_public_ip_address = "true"
key_name = "${var.key_name}"
iam_instance_profile = aws_iam_instance_profile.instance_prof.name
root_block_device {
volume_size = 100 # GB
volume_type = "gp3" # 汎用SSD
encrypted = false
tags = {
Snapshot = "false"
}
}
tags = {
Name = "${var.env_type}-${var.sys_name}-ec2-client01"
}
}
よく見たらLinux思いっきりヒアドキュメント残ってたんで消しました。
はい。
これで完成です。
同じVPC内、同一サブネット内にLinuxのEC2とWindowsのEC2を構築しました。
Terraform実行結果
まぁ問題起きるわけないですよね。
(最後Windows EC2のグローバルIPアドレスが出力されてませんが、AWSコンソールで確認できるので良いかな・・・)
確認作業
Windows EC2からnslookup -type=ns [Linux EC2の暗黙的に割り振られるFQDN]
を実行してみます。
FQDNは
赤枠内の通りip-10-0-0-13.ap-south-1.compute.internal
です。
実行結果
10.0.0.2
がnslookupを実行した問い合わせ先DNSサーバですね。
1枚目の画像の赤枠内、primary name serverが権威サーバだと思うので、これを2枚目の画像の通り更にnslookupで引っ張てみたところ172.16.0.23
と返ってきました。
結論
AWSで暗黙的に構築されるDNSサーバは権威サーバではない!
ということがわかりました。
調べ方があってるか不安だ・・・
あ、日付が変わってる。
本日はこれまで。