HTTPSについて¶
HTTPSは「有効」か「無効」かのどちらかだと安易に考えてしまいがちです。
しかし、実際はそれよりもはるかに複雑です。
ヒント
急いでいる場合や気にしない場合は、さまざまな手法で全てをセットアップするためのステップバイステップの手順について次のセクションに進んでください。
HTTPSの基本を消費者視点から学ぶには、https://howhttps.works/を参照してください。
さて、開発者の視点から、HTTPSについて考える際に留意すべき点がいくつかあります。
- HTTPSの場合、サーバーはサードパーティによって生成された「証明書」を持つ必要があります。
- これらの証明書は実際にはサードパーティから取得されるもので、「生成」されるものではありません。
- 証明書には有効期限があります。
- 証明書は期限切れになります。
- そして、それらを更新し、サードパーティから再度取得する必要があります。
- 接続の暗号化はTCPレベルで行われます。
- それはHTTPより1つ下のレイヤーです。
- したがって、証明書と暗号化の処理はHTTPの前に行われます。
- TCPは「ドメイン」について知りません。IPアドレスについてのみです。
- 要求された特定のドメインに関する情報は、HTTPデータに入ります。
- HTTPS証明書は特定のドメインを「証明」しますが、プロトコルと暗号化はTCPレベルで、どのドメインが扱われているかを知る前に行われます。
- デフォルトでは、これはIPアドレスごとに1つのHTTPS証明書しか持つことができないことを意味します。
- サーバーがどれだけ大きくても、そこにある各アプリケーションがどれだけ小さくてもです。
- ただし、これには解決策があります。
- TLSプロトコル(HTTPの前、TCPレベルで暗号化を処理するプロトコル)には、SNIと呼ばれる拡張機能があります。
- このSNI拡張機能を使用すると、1つのサーバー(単一のIPアドレスを持つ)が複数のHTTPS証明書を持ち、複数のHTTPSドメイン/アプリケーションを提供できます。
- これが機能するためには、サーバー上の単一のコンポーネント(プログラム)がパブリックIPアドレスをリッスンし、サーバー内のすべてのHTTPS証明書を持っている必要があります。
- 安全な接続を取得した後、通信プロトコルは引き続きHTTPです。
- 内容は暗号化されていますが、HTTPプロトコルで送信されています。
サーバー(マシン、ホストなど)で実行されている1つのプログラム/HTTPサーバーを持ち、すべてのHTTPS部分を管理するのが一般的な方法です。具体的には、暗号化されたHTTPSリクエストを受信し、同じサーバーで実行されている実際のHTTPアプリケーション(この場合はFastAPIアプリケーション)に復号化されたHTTPリクエストを送信し、アプリケーションからのHTTPレスポンスを取得し、適切なHTTPS証明書を使用して暗号化し、HTTPSを使用してクライアントに送り返します。このサーバーはしばしばTLS終端プロキシと呼ばれます。
TLS終端プロキシとして使用できるオプションのいくつかを以下に示します。
- Traefik (証明書の更新も処理できます)
- Caddy (証明書の更新も処理できます)
- Nginx
- HAProxy
Let's Encrypt¶
Let's Encrypt以前は、これらのHTTPS証明書は信頼できるサードパーティによって販売されていました。
これらの証明書の1つを取得するプロセスは煩雑で、かなりの事務手続きが必要で、証明書は非常に高価でした。
しかし、その後、Let's Encryptが作成されました。
これはLinux Foundationのプロジェクトです。HTTPS証明書を無料で、自動化された方法で提供します。これらの証明書は、すべての標準的な暗号化セキュリティを使用しており、有効期間が短い(約3か月)ため、有効期間が短縮されているため、セキュリティが実際には向上しています。
ドメインは安全に検証され、証明書は自動的に生成されます。これにより、これらの証明書の更新も自動化できます。
このアイデアは、これらの証明書の取得と更新を自動化することで、安全なHTTPSを無料で永久に利用できるようにすることです。
開発者向けのHTTPS¶
ここでは、開発者にとって重要なアイデアに焦点を当てて、HTTPS APIがどのように見えるかをステップごとに説明します。
ドメイン名¶
おそらく、最初にドメイン名を取得することから始まるでしょう。次に、DNSサーバー(おそらく同じクラウドプロバイダー)で設定します。
おそらく、クラウドサーバー(仮想マシン)またはそれに類するものを用意し、それには固定のパブリックIPアドレスが割り当てられるでしょう。
DNSサーバーで、ドメインをサーバーのパブリックIPアドレスに向けるレコード(「Aレコード
」)を設定します。
おそらく、これは最初の設定時に一度だけ行うでしょう。
ヒント
このドメイン名の部分はHTTPSよりもずっと前の段階ですが、すべてがドメインとIPアドレスに依存するため、ここで言及する価値があります。
DNS¶
それでは、実際のHTTPSの部分に焦点を当てましょう。
まず、ブラウザはDNSサーバーに、このドメイン、つまりsomeapp.example.com
のIPアドレスを問い合わせます。
DNSサーバーは、ブラウザに特定のIPアドレスを使用するように指示します。それは、DNSサーバーで設定したサーバーのパブリックIPアドレスです。
TLSハンドシェイク開始¶
次に、ブラウザはポート443(HTTPSポート)でそのIPアドレスと通信します。
通信の最初の部分は、クライアントとサーバー間の接続を確立し、使用する暗号鍵などを決定することです。
TLS接続を確立するためのクライアントとサーバー間のこのやり取りは、TLSハンドシェイクと呼ばれます。
SNI拡張を使用したTLS¶
サーバーでは、特定のIPアドレスの特定のポートでリッスンできるのは1つのプロセスだけです。同じIPアドレスの他のポートでリッスンしている他のプロセスが存在する可能性がありますが、IPアドレスとポートの組み合わせごとに1つだけです。
TLS (HTTPS) はデフォルトで特定のポート443
を使用します。したがって、それが私たちが必要とするポートになります。
このポートでリッスンできるのは1つのプロセスだけなので、それを行うプロセスはTLS終端プロキシになります。
TLS終端プロキシは、1つ以上のTLS証明書(HTTPS証明書)にアクセスできます。
上記で説明したSNI拡張を使用して、TLS終端プロキシは、クライアントが期待するドメインに一致するものを利用して、この接続に使用するTLS(HTTPS)証明書をチェックします。
この場合、someapp.example.com
の証明書を使用します。
クライアントは、そのTLS証明書を生成したエンティティ(この場合はLet's Encryptですが、後で説明します)をすでに信頼しているため、証明書が有効であることを検証できます。
次に、証明書を使用して、クライアントとTLS終端プロキシは、残りのTCP通信を暗号化する方法を決定します。これでTLSハンドシェイクの部分が完了します。
この後、クライアントとサーバーは暗号化されたTCP接続を持ちます。これがTLSが提供するものです。そして、その接続を使用して、実際のHTTP通信を開始できます。
そして、それがHTTPSです。それは、純粋な(暗号化されていない)TCP接続の代わりに、安全なTLS接続内でのただのHTTPです。
ヒント
通信の暗号化はHTTPレベルではなく、TCPレベルで行われることに注意してください。
HTTPSリクエスト¶
クライアントとサーバー(具体的にはブラウザとTLS終端プロキシ)が暗号化されたTCP接続を持つようになったので、HTTP通信を開始できます。
したがって、クライアントはHTTPSリクエストを送信します。これは、暗号化されたTLS接続を介したHTTPリクエストにすぎません。
リクエストの復号化¶
TLS終端プロキシは、合意された暗号化を使用してリクエストを復号化し、アプリケーションを実行するプロセス(たとえば、FastAPIアプリケーションを実行しているUvicornを使用しているプロセス)にプレーン(復号化された)HTTPリクエストを送信します。
HTTPレスポンス¶
アプリケーションはリクエストを処理し、TLS終端プロキシにプレーン(暗号化されていない)HTTPレスポンスを送信します。
HTTPSレスポンス¶
次に、TLS終端プロキシは、以前に合意した暗号化(someapp.example.com
の証明書で開始された)を使用してレスポンスを暗号化し、ブラウザに送り返します。
次に、ブラウザはレスポンスが有効であり、正しい暗号鍵で暗号化されていることなどを検証します。次に、レスポンスを復号化して処理します。
クライアント(ブラウザ)は、以前にHTTPS証明書を使用して合意した暗号化を使用しているため、レスポンスが正しいサーバーから来ていることを認識します。
複数のアプリケーション¶
同じサーバー(または複数のサーバー)に、他のAPIプログラムやデータベースなど、複数のアプリケーションが存在する可能性があります。
特定のIPとポートを処理できるプロセスは1つだけ(私たちの例ではTLS終端プロキシ)ですが、他のアプリケーション/プロセスは、同じパブリックIPとポートの組み合わせを使用しようとしない限り、サーバー上でも実行できます。
そうすることで、TLS終端プロキシは、複数のドメイン、複数のアプリケーションのHTTPSと証明書を処理し、それぞれの場合に適切なアプリケーションにリクエストを送信できます。
証明書の更新¶
将来のある時点で、各証明書は(取得後約3か月で)有効期限切れになります。
その後、別のプログラム(場合によっては別のプログラム、場合によっては同じTLS終端プロキシである可能性もあります)がLet's Encryptと通信し、証明書を更新します。
TLS証明書は、IPアドレスではなく、ドメイン名に関連付けられています。
したがって、証明書を更新するには、更新プログラムが、自分が実際にそのドメインを「所有」および制御していることを機関(Let's Encrypt)に証明する必要があります。
それを行うため、およびさまざまなアプリケーションのニーズに対応するために、いくつかの方法があります。一般的な方法をいくつかご紹介します。
- DNSレコードを変更する.
- このためには、更新プログラムがDNSプロバイダーのAPIをサポートする必要があります。したがって、使用しているDNSプロバイダーによっては、これがオプションではない場合があります。
- ドメインに関連付けられたパブリックIPアドレスで、(少なくとも証明書の取得プロセス中は)サーバーとして実行します。
- 上で述べたように、特定のIPとポートでリッスンできるプロセスは1つだけです。
- これは、同じTLS終端プロキシが証明書更新プロセスも処理する場合に非常に役立つ理由の1つです。
- そうでない場合は、TLS終端プロキシを一時的に停止し、更新プログラムを開始して証明書を取得し、TLS終端プロキシで構成してから、TLS終端プロキシを再起動する必要がある場合があります。TLS終端プロキシがオフになっている間はアプリケーションが利用できなくなるため、これは理想的ではありません。
アプリケーションを提供しながらのこの更新プロセス全体は、アプリケーションサーバー(例:Uvicorn)でTLS証明書を直接使用するのではなく、TLS終端プロキシを使用してHTTPSを処理するための別のシステムが必要になる主な理由の1つです。
まとめ¶
HTTPSを持つことは非常に重要であり、ほとんどの場合、非常に重要です。開発者としてHTTPSに関して費やす必要のある労力のほとんどは、単にこれらの概念とそれらがどのように機能するかを理解することです。
しかし、開発者向けのHTTPSの基本情報を知っていれば、さまざまなツールを組み合わせて構成し、すべてを簡単な方法で管理するのに役立ちます。
次のいくつかの章では、FastAPIアプリケーションのHTTPSを設定する具体的な例をいくつか紹介します。🔒