はじめに
このようなシチュエーションはあまりないような気がしますが、実際これを設定する必要があり、暫く試行錯誤してしまったのでまとめておきます。
- Apache+SSLで、ユーザー毎のクライアント証明書による認証を有効化
- 当該サーバー上の特定のパスだけは、認証を外して誰でもアクセスできるようにする
前提
Apacheでは、このような設定をしているものとします。典型的な設定先は /etc/httpd/conf.d/ssl.conf
あるいは /etc/apache2/sites-available/default-ssl.conf
となるでしょう。
<VirtualHost _default_:443>
# サーバー証明書の設定
SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
# クライアント認証局(自己署名)の設定
SSLCACertificateFile /etc/pki/local/ca/cert.pem
SSLVerifyClient require
SSLVerifyDepth 10
SSLCARevocationCheck leaf
SSLCARevocationFile /etc/pki/local/ca/crl.pem
</VirtualHost>
この設定によって、/etc/pki/local/ca/cert.pem
で署名したクライアント証明書をインストールしていない端末からはアクセスできなくなります。1
やりたいこと
新しくアクセスを許可するユーザーのために作った証明書をダウンロードしてもらうパスを同じサーバー上に用意するようなシチュエーション、を考えます。
https://example.com/client_certs/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
のような長いURLでアクセスさせる感じです。
失敗例
LocationなりDirectoryなりのディレクティブで制御すればいいのよね、ということで、安易に
<Location />
SSLVerifyClient require
</Location>
<Location /client_certs/>
SSLVerifyClient none
</Location>
としてみましたが、ダメでした。
他に、
<If "%{REQUEST_URI} !~ m!^/client_certs/!">
SSLVerifyClient require
</If>
も試してみました。これもダメ。
落ち着いて考えればわかるのですが、証明書の検証とクライアント認証は、SSLハンドシェーク時に行うので、ハンドシェーク後のHTTP GET等のコマンドを与えた後に分岐するような設定は効果がないのです。
クライアントIPアドレスのような、ハンドシェーク時にわかる値であれば、後者のやり方で制御できます。
考察
結局のところ、証明書なしで接続を許すリソースが存在する以上、ハンドシェーク時には証明書があってもなくても繋がる状態にする必要があります。
SSLVerifyClient optional
で、証明書が必要なリソースについては、別の手段でアクセス制御をかけることになります。
今回はSSLRequire
が使えそうです。クライアント証明書のDNのベース部分(例えばC/ST/O)を固定にして、ユーザー毎にその下(CN等)を変えるような運用を想定すると、SSL_CLIENT_S_DN_O
を条件にすれば、「クライアント認証を必須とするパス」を定義可能となるはずです。2
成功例
これでうまくいきました。ついでにいうと、証明書なしでアクセスした際に、SSLエラーでなくForbiddenが出るようになったので、これはこれでわかりやすい気がします。34
SSLVerifyClient optional
<If "%{REQUEST_URI} !~ m!^/client_certs/!">
SSLRequire %{SSL_CLIENT_S_DN_O} eq "Your Company"
</If>
おわりに
本件、ちょっと必要にかられてこういうのを作っていて、はて、と止まってしまったやつです。せっかくなので切り出して記事化してみました。
もし興味あればどうぞ。特に、なんとなく勢いでI18nなyml書いちゃったのだけど、多分ものすごく不自然な翻訳になってるだろうから(特に中台韓独5)、このへんフィードバックいただける奇特な方がおられましたら嬉しいです。もちろん翻訳の追加も大歓迎。需要あるかはわかりませんが…