【AWS】暗黙的に構築されるDNSサーバは権威サーバなのか？

[以前の記事](https://qiita.com/hidekko/items/19871f8fd14304c13e84)を社内で紹介した際、いろいろと議論が進みまして、非常に面白いツッコミを入れてくださった先輩がいらっしゃいます。
そのツッコミの内容はタイトルの通りなのですが、
**「あ、確かにどうなんやろか？Route 53は明確に公式ドキュメントに権威サーバって書いているけど、暗黙的にできるDNSサーバはどうなんやろか？」**
と疑問に思いましたので、検証してみました。

:::note info
長くインフラエンジニアやってる癖に非常にお恥ずかしのですが、DNSの構成にあんまり詳しくないです。
間違えてたらごめんなさい。
:::

# 検証環境を簡易に作成するために前提としてお伝えすること
AWSもAzureもどちらもEC2、VMを構築した際、暗黙的に内部ネットワーク(AWSだと同一VPC、Azureだと同一仮想ネットワーク、AWSもAzureもどちらもVPC Peering、Vnet Peeringで接続した場合はこの接続されたVPC、仮想ネットワークも含みます)で名前解決可能なFQDNが割り振られます。

# 検証環境
はい。
当然AWSのEC2もAzureのVMもローカルIPアドレスを持っているので、この**ローカルIPアドレスと暗黙的に割り振られるFQDNとを管理している<font color="Red">権威DNSサーバがどこかにいるはず</font>です。**
この暗黙的に割り振られるFQDNと、暗黙的に構築されるDNSサーバで検証を行います。

# 確認したいこと
この権威サーバが暗黙的に構築されるDNSサーバなのか、はたまた別で権威サーバが構築されているのか？
これを調べます。

# 環境構築
[直前にアップした記事](https://qiita.com/hidekko/items/9dc664114e5bd9dfa3b8)はAWSでSpotインスタンスについての記事ですが、これ実はこの検証環境を作るためのコードなんですよね。
ついでにSpotインスタンスの検証も終わらせました。
なのでTerraformのコードもそのまま同じものを使い回します。

## 変数設定
```varriable.tf
# ---------------------------
# 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.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
```vpc.tf
# ---------------------------
# 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.tf
# ---------------------------
# 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.tf
# ---------------------------
# 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.tf
# ---------------------------
# 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.tf
# ---------------------------
# 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実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/b9f3c6a4-ef6d-796b-be57-5a878de52a84.png)
まぁ問題起きるわけないですよね。
(最後Windows EC2のグローバルIPアドレスが出力されてませんが、AWSコンソールで確認できるので良いかな・・・)

# 確認作業
Windows EC2から```nslookup -type=ns [Linux EC2の暗黙的に割り振られるFQDN]```を実行してみます。
FQDNは
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/d02be78f-27fb-01ec-60fa-2b46c81704fc.png)
<font color="Red">赤枠内</font>の通り```ip-10-0-0-13.ap-south-1.compute.internal```です。

## 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/d8d7d1db-abb2-bda9-a80a-d6de9c4e761f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643392/2664d147-a231-843f-1635-f8b7677a669c.png)

```10.0.0.2```がnslookupを実行した問い合わせ先DNSサーバですね。
1枚目の画像の<font color="Red">赤枠内</font>、primary name serverが権威サーバだと思うので、これを2枚目の画像の通り更にnslookupで引っ張てみたところ```172.16.0.23```と返ってきました。

# 結論
**AWSで暗黙的に構築されるDNSサーバは<font color="Red">権威サーバではない！</font>**
ということがわかりました。

調べ方があってるか不安だ・・・

あ、日付が変わってる。

本日はこれまで。