401は誰か分からないという意味で、403は分かっているが駄目だという意味だ
一言でいうと
認証の問題を絞り込む最も安価な道具は、ステータスコード2つで、証明書の問題を絞り込む最も安価な道具は、サーバーが実際に送っている証明書の枚数です。
なぜ必要なのか
FDEは、他人の家の鍵を扱う人です。そして、認証の問題は、障害報告の中で、再現が最も厄介な部類に入ります。トークンごと、ユーザーごと、時間帯ごとに、違う形で失敗するからです。
ところが、この複雑さを半分に減らす区別が1つあります。
401は認証(authentication)の失敗です。「あなたが誰なのか確認できない」。トークンがない、形式が間違っている、期限が切れている、署名が合わない、といった場合です。
403は認可(authorization)の失敗です。「あなたが誰なのかはわかったが、これはできないことになっている」。身元確認は通過し、権限が足りないのです。
この2つを区別すると、調査の方向が正反対に分かれます。401なら、認証情報そのものを見ます。トークンが正しく渡されているか、期限が切れていないか。403なら、認証情報には手を付ける必要がなく、権限の設定とスコープを見ます。この区別なしに「権限エラー」とひとまとめにすると、見当違いの方向を何時間も掘ることになります。
もう1つ。401が返されたのに、応答に再認証の経路が案内されていないと、クライアントが無限リトライに陥ります。トークンを更新する方法を知らないまま、ずっと同じトークンを送り続けるからです。
そして、401の中でも理由が分かれます。トークンなし、不明なトークン、期限切れのトークンは、すべて401ですが、対応が違います。そのため、応答本文の理由の文字列も一緒に見る必要があります。ステータスコードだけを見て判断すると、「トークンを新しく発行してください」と答えるべき状況で、「設定を確認してみてください」と答えてしまいます。
どう動くのか
証明書の問題は、失敗モードがいくつかに決まっていて、それぞれ証拠が違います。
期限切れは、notAfterが過ぎています。ところが、ここで必ず一緒に確認すべきことがあります。クライアントの時計です。時計のない組み込み機器、長く停止してから起動したVM、ホストとずれたコンテナで、「証明書が期限切れだ」というエラーが出る場合が、かなり多く、そのとき、サーバーの証明書は問題ありません。有効期限と現在時刻を一緒に表示してみる習慣が必要です。
名前の不一致は、接続した名前が証明書にありません。ここでよく間違えるのが、CNを見ることです。現代のクライアントはCNをまったく見ず、subjectAltNameだけを検査します。CNにドメインを入れたから大丈夫だという判断は、2017年以降、間違いです。
中間証明書の欠落は、FDEが最もよく出会うタイプで、症状が特徴的です。ブラウザーでは鍵マークが正常なのに、サーバー対サーバーの呼び出しだけが失敗します。原因はクライアントではなく、サーバーです。サーバーが中間証明書を一緒に送っていなくて、ブラウザーは、証明書の中のリンクをたどって、欠落した中間証明書を自分でダウンロードし、サーバーのミスを代わりに補っているだけです。curlや、ほとんどの言語ランタイムは、そのリンクをたどりません。
そのため、判定方法は単純です。サーバーが送る証明書が何枚かを数えればよいのです。リーフ証明書1枚だけが来たなら、その瞬間に原因が確定で、直す場所はクライアントではなくサーバーです。
現場での姿
ここで、FDEがよく誘惑される近道が1つあります。検証をオフにすることです。
症状はすぐに消えます。そして、その状態で本番にデプロイされると、中間者攻撃にそのままさらされます。さらに悪いのは、検証をオフにしたまま開発すると、本番に存在しない環境で作業することになり、ほかの問題まで一緒に隠されるという点です。隠された問題は、あとでまとめて噴き出します。
検証のオフは、原因を確定させたあとに、「いまこの問題のせいで合っている」ことを確認する用途にだけ使い、その確認の直後に元に戻します。
他人の認証情報を扱うルール
FDEが他人の家の鍵を扱うという言葉には、技術以上の重みがあります。顧客企業のトークンと証明書を受け取って使っている間に、守るべきことがいくつかあり、これを破ると、診断がどれだけうまくても、そのプロジェクトは終わりです。
必要な最小限の権限だけを受け取ります。調べようとしているのが照会APIの1つなら、読み取りトークンで足ります。「楽だから管理者トークンをください」は、こちらから先に言ってはいけない文で、顧客が先に渡してきたとしても、なぜそこまで必要なのかを説明できないなら、返すほうがよいです。事故が起きたときに、そのトークンで何ができたかが、そのまま調査の範囲になります。
有効期間を決めて、終わったら返します。調査が終わったら、失効を依頼し、その事実を記録として残します。プロジェクトが終わってから半年後にも、生きているトークンがノートPCに残っていることが、最もよくある事故の経路です。
置き場所を決めておきます。前のコースで見たとおり、環境変数は、同じホストの別のプロセスが読めて、シェルの履歴やコマンドライン引数にも残ります。一時的に使うとしても、ファイルに置いて権限を絞るほうがよいです。そして、画面共有中は、そのファイルを開きません。
ログとレポートから取り除きます。診断の過程を貼り付けるときに、認証ヘッダーが一緒についていくことがよくあります。貼り付ける前に、一度ざっと見る習慣が必要で、チームに共有するスクリプトなら、最初から値を出力しないように作っておくほうが確実です。
そして、検証をオフにしたことは、記録に残します。前に、原因の確定用にだけ使うようにと言いましたが、そこに1つ加えます。オフにしたなら、なぜオフにして、いつ元に戻したかを、報告に1行書きます。書いておけば、そのコードがミスで残ることが減り、何より、顧客があとでその痕跡を見つけたときに、説明できることがあります。
次のラボですること
トークン4種類をそれぞれ入れて、401と403を手で作ってみて、期限切れの理由の文字列を取得し、期限切れの証明書と、名前が異なる証明書から、それぞれ必要な値を取り出して、診断レポートを作ります。