検証に使うための内部ネットワーク(自己署名証明書Webサーバー+内部DNS)をCloudFormationでテンプレート化してみた
いわさです。
オンプレミス側のプライベートネットワーク環境とAWSを接続して検証などを行いたい場合がよくあります。
VPNやDirectConnectの環境を用意するのはちょっと大変ですが、VPCでプライベートネットワーク環境を用意してVPCピアリングさせる程度であれば簡単に用意出来ますし、割と近い環境が再現出来るかなと思ってよく使っています。
ただし、毎度Webサーバーだったり、DNSサーバーだったりを構築するのは面倒です。
そこで今回はミドルウェアの設定部分も含めてテンプレート化しておきました。
そして、これだけの小さな構築にも関わらずまぁまぁ詰まったので公開しておきたいと思います。
テンプレート
テンプレートはこちらになります。
プライベートサブネットにWebサーバーとDNSサーバーを構築します。
Webサーバーは自己署名証明書を設定済みのPHPアプリケーションをデプロイし、内部DNSはDHCPオプションでVPCに関連付けしています。
内部DNSサーバーのフォワーダーにはAmazonProvidedDNSを指定し、通信はNATゲートウェイでアウトバウンドさせているので初期セットアップが失敗しないようにされています。
テンプレートで構築される構成は以下のようなシングルAZのシンプルなものです。
パラメータで各CIDRやWebアプリケーションのホストゾーンなどを設定する形になっています。
今回見送りましたが、そのうちアップデートしてNATゲートウェイではなくてプロキシサーバーを通すようにするつもりです。
少し抜粋すると、今回はほとんどユーザーデータで設定しています。
Webサーバー
こちらはWebサーバーです。
PHPをセットアップし、自己署名証明書を設定しています。
UserData: Fn::Base64: !Sub - | #cloud-config repo_update: true repo_upgrade: all packages: - httpd - mod_ssl - openssl - php runcmd: - openssl genrsa -out ca.key 2048 - openssl req -new -key ca.key -out ca.csr -subj "${sslsubject}" - openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt - cp -p ca.crt /etc/pki/tls/certs/ - cp -p ca.key /etc/pki/tls/private/ - cp -p ca.csr /etc/pki/tls/private/ - sed -i 's/localhost/ca/g' /etc/httpd/conf.d/ssl.conf - service httpd start - chkconfig httpd on write_files: - path: /var/www/html/index.php permissions: 0644 owner: root content: | <?php echo "<pre>"; var_dump($_SERVER); echo "</pre>"; ?> - { sslsubject: !Ref SslSubject }
証明書周りなどこちらの記事を参考にさせて頂きました。
DNSサーバー
こちらはDNSサーバーです。
BINDを使っています。
設定ファイルとゾーンファイルをそのまま作成しているだけですね。
一部動的パラメータを埋め込んでいます。
UserData: Fn::Base64: !Sub - | #cloud-config repo_update: true repo_upgrade: all packages: - bind runcmd: - service named start - chkconfig named on write_files: - path: /etc/named.conf permissions: 0644 owner: root content: | options { listen-on-v6 port 53 { ::1; }; 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"; recursing-file "/var/named/data/named.recursing"; secroots-file "/var/named/data/named.secroots"; allow-query { any; }; recursion no; dnssec-enable yes; dnssec-validation yes; bindkeys-file "/etc/named.root.key"; managed-keys-directory "/var/named/dynamic"; pid-file "/run/named/named.pid"; session-keyfile "/run/named/session.key"; forwarders { ${providedDns}; }; }; logging { channel default_debug { file "data/named.run"; severity dynamic; }; }; zone "." IN { type hint; file "named.ca"; }; zone "${zonename}" IN { type master; file "${zonename}"; }; include "/etc/named.rfc1912.zones"; include "/etc/named.root.key"; - path: /var/named/${zonename} permissions: 0644 owner: root content: | $TTL 86400 @ IN SOA dns.${zonename}. root.${zonename}. ( 2021111401 3600 3600 604800 86400 ) IN NS ns.${zonename}. IN A ${webServerIp} ns.${zonename}. IN A 127.0.0.1 - { zonename: !Ref HosteZone, webServerIp: !GetAtt WebServer.PrivateIp, providedDns: !Ref AmazonProvidedDns }
確認
念の為確認もしておきます。
テンプレート実行直後は上記のようになり、以下のような形でこのプライベートネットワーク内に任意のHTTPクライアントをEC2で新規作成してアクセスしてみます。
[ec2-user@ip-10-103-0-216 ~]$ curl --insecure https://iwasa20211114.com/ <pre>array(61) { ["UNIQUE_ID"]=> string(27) "YZDAWDfT4GNpMkXp9JwyPwAAAAQ" ["HTTPS"]=> string(2) "on" ["SSL_TLS_SNI"]=> string(17) "iwasa20211114.com"
問題なく名前解決出来ていますね。
さいごに
テンプレート作成を通して、OpenSSLやBINDなどAWSレイヤーより少し上の部分や、DHCPオプションなど普段触らない部分を結構トライ&エラー出来たのでおもしろかったです。
テンプレートのユーザーデータを見ていただくことわかるのですが、まとめてごちゃごちゃとやっております。
ユーザーデータで無理やりやりすぎたか...と少し思っているのでこうやったらもっと簡単に出来るよなどフィードバック頂けると幸いです。
Webアプリケーション部分は、PHPのサーバー変数をダンプ出力しているだけの状態です。
ゾーンファイルについては各パラメータ適当な感じでなので、こちらは構築時に適宜パラメータ調整すると良いと思います。
この環境を使って、VPC PeeringやPrivate Linkなどを使って別のネットワークやパブリックAWSサービスと通信検証する際などに使うことを想定しています。