プライベートネットワークでLet's Encryptを使用する際の誤った方法

プライベートネットワークでLet's Encryptを使用する際の誤った方法

httpsプライベート Go言語で書かれた小さなアプリを開発しているのですが、Go言語を組み込んだウェブサーバーへのローカルエリアネットワーク接続をhttps経由で行いたいと思っています。クライアントのほとんどは、複数のサーバーで実行されるスクリプトになる予定です。

残念ながら、これはプライベートIPアドレス範囲であるため、証明書の検証が必要になります。この問題を解決するにはいくつかの方法があります。

  1. 証明書をチェックしないが、それは最適ではないようだ
  2. 独自のプライベート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するのは簡単です。ちょっと安っぽいですが、ちゃんと動きますよ!

おすすめの記事