のぴぴのメモ

自分用のLinuxとかの技術メモ

BINDのResolverを UserDataとAWS CLIの"ec2 run-instances"で作成する

概要

作成する構成

検証などでVPCの中にDNSゾルバーを個別に立てる場合に、bindのインストールや設定をUserDataに埋め込んでしまうことで、OSへのログインをせずに簡単にbindによるDNSゾルバーを作ってしまう手順です。かつAWS CLIで作業しています。
前後作業がいろりろありますが、手っ取り早く該当部分を見たい方は"(4)DNSゾルバーの作成"を参照ください。
f:id:nopipi:20200623015246p:plain:w400

前提

  • bash環境での作業を前提としています
  • AWS CLI v2の環境で動作確認をしています(AWS CLI v1でも多分OKと思います)

設定手順

(1)準備

(1)-(a)作業環境の準備

AWS CLIで利用するプロファイルなどを設定します。

export PROFILE=default  #利用するプロファイルに変更してください
export AWS_PAGER=""
(1)-(a)作成に必要な情報設定

DNSゾルバーの作成先のVPCやメンテナンス用のSSHの接続情報を指定します。

#作成先VPC情報
VPCID="vpc-xxxxxxxxxxxxxxxxx"
VPC_CIDR="10.1.0.0/16"
DNS_RESOLVER_SUBNET="subnet-xxxxxxxxxxxxxxxxx"

#SSHメンテナンス接続情報
SSH_SRC_CIDR="0.0.0.0/0"   #メンテナンスでのSSHログイン元の CIDRを指定してください。
KEYNAME="CHANGE_KEY_PAIR_NAME"  #環境に合わせてキーペア名を設定してください。

(2)DNSゾルバ用セキュリティーグループの作成

VPC内からのDNSクエリーをセキュリティーグループで許可します。

# DNS用セキュリティーグループ作成
DNS_SG_ID=$(aws --profile ${PROFILE} --output text \
    ec2 create-security-group \
        --group-name DnsSG \
        --description "Allow Dns" \
        --vpc-id ${VPCID}) ;

aws --profile ${PROFILE} \
    ec2 create-tags \
        --resources ${DNS_SG_ID} \
        --tags "Key=Name,Value=DnsSG" ;

# セキュリティーグループにDNSのinboundアクセス許可を追加
aws --profile ${PROFILE} \
    ec2 authorize-security-group-ingress \
        --group-id ${DNS_SG_ID} \
        --protocol tcp \
        --port 53 \
        --cidr ${VPC_CIDR} ;

aws --profile ${PROFILE} \
    ec2 authorize-security-group-ingress \
        --group-id ${DNS_SG_ID} \
        --protocol udp \
        --port 53 \
        --cidr ${VPC_CIDR} ;

#メンテナンス用にSSHのinboundアクセス許可を追加
aws --profile ${PROFILE} \
    ec2 authorize-security-group-ingress \
        --group-id ${DNS_SG_ID} \
        --protocol tcp \
        --port 22 \
        --cidr ${SSH_SRC_CIDR};

(3)Amazon Linux2 AMI ID取得

#最新のAmazon Linux2のAMI IDを取得します。
AL2_AMIID=$(aws --profile ${PROFILE} --output text \
    ec2 describe-images \
        --owners amazon \
        --filters 'Name=name,Values=amzn2-ami-hvm-2.0.????????.?-x86_64-gp2' \
                  'Name=state,Values=available' \
        --query 'reverse(sort_by(Images, &CreationDate))[:1].ImageId' ) ;
echo  "AL2_AMIID = ${AL2_AMIID}"

(4)DNSゾルバーの作成

DNSゾルバー用のEC2インスタンスを作成します。
bindの設定は、EC2インスタンスのUserDataに定義して、起動時にスクリプト実行によりセットアップさせます。BINDのforwarding先のDNSサーバを変更する場合はforwarders { 8.8.8.8; 8.8.4.4; };の部分を修正して下さい。

TAGJSON='
[
    {
        "ResourceType": "instance",
        "Tags": [
            {
                "Key": "Name",
                "Value": "Dns"
            }
        ]
    }
]'

USER_DATA='#!/bin/bash -xe
                
yum -y update
yum -y install bind bind-utils
hostnamectl set-hostname dns

LOCAL_IP=$(curl http://169.254.169.254/latest/meta-data/local-ipv4)

cat > /etc/named.conf << EOL
# アクセス制御。trustというグループに属するIPアドレスを定義する。
acl "trust" {
        '"${VPC_CIDR}"';
        127.0.0.1;
};

options {
        # UDP53でDNSクエリを受け付ける自分自身のIPアドレス
        listen-on port 53 {
                127.0.0.1;
                ${LOCAL_IP};
        };
        # IPv6は使わないのでnone
        listen-on-v6 port 53 { none; };
        directory       "/var/named";
        dump-file       "/var/named/data/cache_dump.db";
        statistics-file "/var/named/data/named_stats.txt";
        memstatistics-file "/var/named/data/named_mem_stats.txt";

        # DNSクエリはaclで設定した送信元のみ許可
        allow-query     { trust; };
        allow-query-cache { trust; };

        # 再帰問い合わせもaclで問い合わせした送信元のみ許可
        recursion yes;
        allow-recursion { trust; };

        # DNS問い合わせの転送先
        # Google Public DNSを利用します。
        forwarders { 8.8.8.8; 8.8.4.4; };
        # 問い合わせの転送に失敗した場合は自分自身で名前解決を行う
        # 問い合わせ転送に失敗した際名前解決をあきらめる場合はonlyを設定する
        forward only;

        dnssec-enable yes;
        dnssec-validation yes;

        bindkeys-file "/etc/named.iscdlv.key";

        managed-keys-directory "/var/named/dynamic";

        pid-file "/run/named/named.pid";
        session-keyfile "/run/named/session.key";
};

logging {
        channel default_debug {
                file "data/named.run";
                severity dynamic;
        };
        # DNSクエリログ用の出力設定
        channel query-log {
                # 以下すべてのチャネルで3世代10Mごとにログローテーションを行う
                file "/var/log/named/query.log" versions 3 size 10M;
                severity  info;
                print-category yes;
                print-severity yes;
                print-time yes;
        };
        # ゾーン転送ログ用の出力設定
        channel xfer-log {
                file "/var/log/named/xfer.log" versions 3 size 10M;
                severity  info;
                print-category yes;
                print-severity yes;
                print-time yes;
        };
        # 上記以外の種類のエラーログ用の出力設定
        channel error-log {
                file "/var/log/named/error.log" versions 3 size 10M;
                severity  error;
                print-category yes;
                print-severity yes;
                print-time yes;
        };
 
        # ログ種別ごとの出力先設定指定
        category queries { query-log; };
        category xfer-in { xfer-log; };
        category xfer-out { xfer-log; };
        category default { error-log; };
};

zone "." IN {
        type hint;
        file "named.ca";
};

include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";
EOL

#ログ用フォルダの作成
mkdir /var/log/named
chown -R named:named /var/log/named/

# Bindの起動
systemctl enable named
systemctl start named
'

# DNSサーバの起動
aws --profile ${PROFILE} \
    ec2 run-instances \
        --image-id ${AL2_AMIID} \
        --instance-type t2.micro \
        --key-name ${KEYNAME} \
        --subnet-id ${DNS_RESOLVER_SUBNET} \
        --security-group-ids ${DNS_SG_ID}\
        --associate-public-ip-address \
        --tag-specifications "${TAGJSON}" \
        --user-data "${USER_DATA}" ;

(5)VPC DHCPオプションセットの変更

作成したDNSゾルバーにDNSのクエリーが飛ぶように、新しいDHCPオプションセットを作成しVPCにアタッチします。新しいDHCPオプションでは、下記を設定しています。

  • DNS参照先設定に、作成したDNSゾルバーを指定
  • NTPの同期先にAmazon Time Sync Service(169.254.169.123)を指定
#DNSサーバのローカルIP取得
DnsLocalIP=$(aws --profile ${PROFILE} --output text \
    ec2 describe-instances \
        --filter "Name=tag:Name,Values=Dns" "Name=instance-state-name,Values=running"  \
    --query 'Reservations[].Instances[].PrivateIpAddress' \
)
echo ${DnsLocalIP}

#VPC: DHCPオプションセット作成
DHCPSET_ID=$(aws --profile ${PROFILE} --output text \
    ec2 create-dhcp-options \
        --dhcp-configurations \
            "Key=domain-name,Values=onprem.internal" \
            "Key=domain-name-servers,Values=${DnsLocalIP}" \
            "Key=ntp-servers,Values=169.254.169.123" \
    --query 'DhcpOptions.DhcpOptionsId'; )

#VPC: DHCPオプションセット関連付け
aws --profile ${PROFILE} \
    ec2 associate-dhcp-options \
      --vpc-id ${VPCID} \
      --dhcp-options-id ${DHCPSET_ID} ;

(6)Client作成

(6)-(a)用セキュリティグループ作成
# DNS用セキュリティーグループ作成
CLIENT_SG_ID=$(aws --profile ${PROFILE} --output text \
    ec2 create-security-group \
        --group-name ClientSg \
        --description "Allow ssh" \
        --vpc-id ${VPCID}) ;

aws --profile ${PROFILE} \
    ec2 create-tags \
        --resources ${CLIENT_SG_ID} \
        --tags "Key=Name,Value=ClientSg" ;

#メンテナンス用にSSHのinboundアクセス許可を追加
aws --profile ${PROFILE} \
    ec2 authorize-security-group-ingress \
        --group-id ${CLIENT_SG_ID} \
        --protocol tcp \
        --port 22 \
        --cidr ${SSH_SRC_CIDR};
(6)-(b) Clientインスタンス作成
#クライアントインスタンス作成
TAGJSON='
[
    {
        "ResourceType": "instance",
        "Tags": [
            {
                "Key": "Name",
                "Value": "Client"
            }
        ]
    }
]'

#ユーザデータ設定
USER_DATA='#!/bin/bash -xe
yum -y update
hostnamectl set-hostname client
'

#インスタンス起動
aws --profile ${PROFILE} \
    ec2 run-instances \
        --image-id ${AL2_AMIID} \
        --instance-type t2.micro \
        --key-name ${KEYNAME} \
        --subnet-id ${DNS_RESOLVER_SUBNET} \
        --security-group-ids ${CLIENT_SG_ID}\
        --associate-public-ip-address \
        --tag-specifications "${TAGJSON}" \
        --user-data "${USER_DATA}"; 

(7)動作テスト

(7)-(a) ClientへのSSHログイン
ssh ec2-user@<clientのIP>
(7)-(b) Client確認
#DNS参照先確認
# /etc/resolv.confの設定確認
cat /etc/resolv.conf 
; generated by /usr/sbin/dhclient-script
search onprem.internal
options timeout:2 attempts:5
nameserver 10.1.x.x  <== DNSリゾルバーインスタンスの Private IPが設定されていることを確認

# digによるDNS参照
dig amazon.co.jp

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-9.P2.amzn2.0.3 <<>> amazon.co.jp
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51709
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;amazon.co.jp.			IN	A

;; ANSWER SECTION:  <<==DNS参照の応答が正常にあることを確認
amazon.co.jp.		46	IN	A	52.119.168.48
amazon.co.jp.		46	IN	A	52.119.164.121
amazon.co.jp.		46	IN	A	52.119.161.5

;; Query time: 7 msec
;; SERVER: 10.1.0.14#53(10.1.0.14)   <==DNSリゾルバーインスタンスの Private IPであることを確認
;; WHEN: 月  6月 22 17:33:12 UTC 2020
;; MSG SIZE  rcvd: 89