プライベートネットワークでLet's Encryptを使用する際の誤った方法
Go言語で書かれた小さなアプリを開発しているのですが、Go言語を組み込んだウェブサーバーへのローカルエリアネットワーク接続をhttps経由で行いたいと思っています。クライアントのほとんどは、複数のサーバーで実行されるスクリプトになる予定です。
残念ながら、これはプライベートIPアドレス範囲であるため、証明書の検証が必要になります。この問題を解決するにはいくつかの方法があります。
- 証明書をチェックしないが、それは最適ではないようだ
- 独自のプライベートCAを作成し、すべてのクライアントに信頼してもらい、証明書を発行する
おそらく、#2 がこれを行う正しい方法です。
でも、ふと気づいたんです。https が実際にやっているのは、「はい、その証明書を使用している somehost.com はその証明書の秘密鍵を所有しています」と言っているだけです。拡張検証などもあるようですが、実際にはそれだけです。ただし、クライアントと CA が somehost.com の所在地で合意していることが前提です。もし合意していなかったらどうなるのでしょうか…
試してみることにしました。クラウド上のdnsg1.lowend.partyというサーバーにアクセスし、server2.lowend.partyにそのサーバーを指すAレコードを作成しました(server1は別のチュートリアルで既に使用されています)。
次に、dnsg1 に certbot をインストールしました。
apt-get で certbot をインストール
そして、certbot を使用して、Let's Encrypt 証明書を取得します。
dnsg1:~ # certbot certonly --standalone -d server2.lowend.party デバッグログを /var/log/letsencrypt/letsencrypt.log に保存しています 選択されたプラグイン: Authenticator スタンドアロン、インストーラー なし server2.lowend.party の証明書を要求しています 次の課題を実行します。 server2.lowend.party の http-01 チャレンジ 検証を待っています... 課題の解決 重要な注意事項: - おめでとうございます!証明書とチェーンは次の場所に保存されました: /etc/letsencrypt/live/server2.lowend.party/fullchain.pem キーファイルは次の場所に保存されています: /etc/letsencrypt/live/server2.lowend.party/privkey.pem 証明書の有効期限は2022年7月3日です。新規または…を取得するには (何とか)
これで、「server2.lowend.party」用のLet's Encrypt署名付き証明書ができました。プライベートネットワークでも使えるでしょうか? 念のため、「続きを読む」をクリックして確認してもらいます。ちなみに、この投稿のために作った1990年代の映画のミームもプレゼントするので、別に悪くないと思っています。

レザボア・ドッグス、1992年
実際の server2.lowend.party で、いくつかの基本的な golang コードをコンパイルしました。
パッケージメイン
輸入(
「ネット/http」
「fmt」
"ログ"
)
関数main() {
http.HandleFunc( "/", func( res http.ResponseWriter, req *http.Request ) {
fmt.Fprint( res, "うまくいきました!\n" )
} )
log.Fatal( http.ListenAndServeTLS( ":9000", "fullchain.pem", "privkey.pem", nil ) )
}
このコードが行うことは、ポート 9000 で https サーバーを起動し、/ へのリクエストに「It works\n」で応答することだけです。
では、実際に動作するか確認してみましょう。別のサーバー(crash)で、/etc/hostsを編集してserver2.lowend.partyをローカルIPに設定しました。これで、crashがserver2.lowend.partyのアドレスを検索する際に、/etc/hostsのエントリがDNSを上書きするようになります。
正確に言うと、/etc/nsswitch.conf が参照され、次のような行が見つかります (少なくとも標準の Debian 11 では)。
ホスト: ファイルDNSこれは、まず「ファイル」(/etc/hosts)を参照し、次にdnsを参照することを意味します。リストにはldapなど、他のものが含まれている可能性があります。ファイル内のコメントには「 GNU Name Service Switch」という記述がありますが、このファイルはSunOS 4.x、おそらくそれ以前のバージョンにも存在していました。もしかしたら、本来はGNU/SunOSという名前だったのかもしれません。
さて、テストに戻りましょう。wget を使ってみましょう。
root@crash:~# wget https://server2.lowend.party:9000 --2022-04-04 17:43:25-- https://server2.lowend.party:9000/ server2.lowend.party (server2.lowend.party) を解決しています... 192.168.1.10 server2.lowend.party (server2.lowend.party)|192.168.1.10|:9000 に接続しています...接続されました。 HTTP リクエストが送信され、応答を待っています... 200 OK 長さ: 10 [テキスト/プレーン] 保存先: 'index.html' index.html 100%[========================================================================>] 10 --.-KB/秒(0 秒単位) 2022-04-04 17:43:25 (20.3 MB/秒) - 'index.html' を保存しました [10/10] root@crash:~# cat index.html うまくいきました! ルート@クラッシュ:~#
もちろん、いずれ期限が切れますが、更新スクリプトを書いてserver2にrsyncするのは簡単です。ちょっと安っぽいですが、ちゃんと動きますよ!