Synology DS-216J WebStationのベーシック認証を設定した。
確定申告の電子申請で住基カードに搭載した公的個人認証サービスの電子証明書有効期限が2018年内までである事に気がついた。住基カードは、廃止されているので「マイナンバーカード」で対応する必要がある。「マイナンバーカード」を調べていると、「利用者証明用の電子証明書」なる証明書の組込みが出来るようようである。説明によるとログイン認証に使えるようだ(クライアント認証)。
電子証明書にアクセスする「OpenSC JPKIカードドライバ」などが提供されるらしい。「マイナンバーカードでSSH」とか「マイナンバーカードでMacOSにログイン」などの利用確認記事が見つかった。
WebStation(nginx)のベーシック認証に加え、「マイナンバーカード」を利用した「クライアント認証」を加えられるか調べてみた。「nginxでクライアント認証」などの確認記事は、沢山出てくる。
nginxの「Module ngx_http_ssl_module」にssl関連の設定ディレクティブが解説されている。
設定の鍵は、
「ssl client certificate」:
クライアント認証で提示されるユーザの証明書を発行したCAの公開鍵(pem形式)を指定。
ssl trusted certificateとの間に複数のCAがある場合は、指定したファイルにpem形式で複数記載する。
「ssl trusted certificate」:
ssl client certificateで指定したCAのルートCA証明書を指定
「ssl verify client」:
クライアント認証だけの場合は、「on」を指定。
クライアント証明書が提示されない場合にエラーとしないで続行させる「optional」指定を使用する。
「ssl verify depth」:
ssl client certificateとssl trusted certificateのCA数によって指定する。ルートCAまでの数で初期値は「1」。
「ベーシック認証とクライアント認証を両立」させるには、ベーシック認証のON/OFFを変数を利用してクライアント認証時に制御すると良いようだ。
nginxの設定で認証の必要なディレクトリに対して、クライアント認証した結果を「$auth_basic」変数に設定する(クライアント認証した場合は「off」、ベーシック認証させるためには「Restricted」などの文字列)。接続時にクライアントから提示された証明書が有効かどうかは、「埋込変数 $ssl_client_verify」で下記のように判断し設定する。
if ($ssl_client_verify = SUCCESS) { set $auth_basic off; }
if ($ssl_client_verify != SUCCESS) { set $auth_basic Restricted; }
認証の必要なディレクトリの「location」設定などで下記のベーシック認証設定を行う
auth_basic $auth_basic;
「ssl_client_certificate」指定のCAが発行した証明書が接続クライアントから提示されると全て許可になってしまうので、提示された証明書の選別が必要となる。選別は、「埋込変数」から「$ssl_client_s_dn」が得られるので「cn」などから特定のユーザを識別する。「cn」での識別が困難な証明書は、「SubjectAltName」で判断する必要がある。こうなると厄介。「SubjectAltName」は、「$ssl_client_certificate」で「pem」形式で得られる。なのでasn.1からデコードする必要が発生する。有効期限外の証明書は、「$ssl_client_v_remain」が「0」なので判断可能。
「openssl s_client」で接続し、「埋込変数」の内容を確認することとした。
「埋込変数」は、「log_format」と「accesslog」で指定し確認する。
httpセクションでlog_formatを設定
log_format ssl 'ssl($status): $remote_addr - $remote_user [$time_local] '
' $ssl_client_verify($ssl_client_v_remain) "$ssl_client_s_dn / $ssl_client_i_dn" ';
serverセクションでaccess_logを設定
access_log /var/log/nginx/ssl.log ssl;
クライアント認証でSSL接続を確認する方法
「openssl s_client -connect somehost.somedomain:443 -cert client-cert.pem -CApath . -servername somehost.somedomain -quiet」
SSL接続後にページをアクセスする方法
「echo -e "GET / HTTP/1.1¥n¥n" | openssl s_client -connect somehost.somedomain:443 -cert client-cert.pem -CApath . -servername somehost.somedomain -quiet」
ページアクセスでnginxのssl設定が「name virtual」なため「400 Bad Request」となってしまう。openssl の 「-servername」オプションだけでは、対応できない。
http request headerに「HOST:」を加える必要があった。
NameVirtual SSL設定のnginxサーバでクライアント認証アクセス確認方法
「echo -e "GET / HTTP/1.1\nHOST: some host.somedomain\n\n" | openssl s_client -connect somehost.somedomain:443 -cert client-cert.pem -CApath . -servername somehost.somedomain -quiet」
埋込変数の確認結果
(1)クライアント証明書を使わない($ssl_client_verify=NONE)
クライアント証明書が提示されないので、証明書内容を示す「埋込変数」は、全て未設定。
(2)有効な証明書で$ssl_client_certificate指定以外のCA発行した証明書($ssl_client_verify=FAILED)
(3)有効な証明書で$ssl_client_certificate指定のCA発行した証明書($ssl_client_verify=SUCCESS)
(4)有効な証明書で$ssl_client_certificate指定のCA発行した証明書だが有効期限切れ($ssl_client_v_remain=0)のため接続できない($ssl_client_verify=FAILED)
(5)有効な証明書で$ssl_client_certificate指定のCA発行した証明書だが「X509v3 Extended Key Usage」に「TLS Web Client Authentication」が未定義のため接続できない($ssl_client_verify=FAILED)
2018/3/12追記:使用した証明書のKey Usage=(Digital Signature, Key Encipherment) Extended Key Usage=(E-mail Protection)でAppleのiPhone Configuration Utilityが生成するデバイス証明書と同じ定義。ただ、EtendedKeyUsage=emailProtectionが成立するためには、KeyUsage=nonRepudiationが必須のはず。Key Usage=(Digital Signature, Key Encipherment) Extended Key Usageを未定義とすると$ssl_client_verify=SUCCESSとなる事から、ExtendedKeyUsageの未定義による制限なし状態を避けるための設定かもしれない。要調査。
確認結果をもとにnginx「/etc/nginx/sites-enabled/some.conf」のserverセクションにクライアント認証とベーシック認証の併用設定を確定
server {
ssl_client_certificate /usr/local/etc/nginx/conf.d/auth/client-auth-ca-list.pem;
ssl_trusted_certificate /usr/local/etc/nginx/conf.d/auth/client-auth-ca-list.pem;
ssl_verify_client optional;
set $auth_basic Restricted;
if ( $ssl_client_verify ~ FAILED ) { return 403 $ssl_client_s_dn-$ssl_client_i_dn; }
if ( $ssl_client_verify = NONE ) { set $auth_basic Restricted; }
if ( $ssl_client_s_dn ~ " CN=Some USER" ) { set $auth_basic off; }
location /somedirectory {
auth_basic $auth_basic;
auth_basic_user_file /etc/nginx/conf.d/auth/somedirecory;
}
}
「マイナンバーカード」の入手が遅れている。「マイナンバーカード」によるクライアント認証は、入手後にテストする予定。
確定申告の電子申請で住基カードに搭載した公的個人認証サービスの電子証明書有効期限が2018年内までである事に気がついた。住基カードは、廃止されているので「マイナンバーカード」で対応する必要がある。「マイナンバーカード」を調べていると、「利用者証明用の電子証明書」なる証明書の組込みが出来るようようである。説明によるとログイン認証に使えるようだ(クライアント認証)。
電子証明書にアクセスする「OpenSC JPKIカードドライバ」などが提供されるらしい。「マイナンバーカードでSSH」とか「マイナンバーカードでMacOSにログイン」などの利用確認記事が見つかった。
WebStation(nginx)のベーシック認証に加え、「マイナンバーカード」を利用した「クライアント認証」を加えられるか調べてみた。「nginxでクライアント認証」などの確認記事は、沢山出てくる。
nginxの「Module ngx_http_ssl_module」にssl関連の設定ディレクティブが解説されている。
設定の鍵は、
「ssl client certificate」:
クライアント認証で提示されるユーザの証明書を発行したCAの公開鍵(pem形式)を指定。
ssl trusted certificateとの間に複数のCAがある場合は、指定したファイルにpem形式で複数記載する。
「ssl trusted certificate」:
ssl client certificateで指定したCAのルートCA証明書を指定
「ssl verify client」:
クライアント認証だけの場合は、「on」を指定。
クライアント証明書が提示されない場合にエラーとしないで続行させる「optional」指定を使用する。
「ssl verify depth」:
ssl client certificateとssl trusted certificateのCA数によって指定する。ルートCAまでの数で初期値は「1」。
「ベーシック認証とクライアント認証を両立」させるには、ベーシック認証のON/OFFを変数を利用してクライアント認証時に制御すると良いようだ。
nginxの設定で認証の必要なディレクトリに対して、クライアント認証した結果を「$auth_basic」変数に設定する(クライアント認証した場合は「off」、ベーシック認証させるためには「Restricted」などの文字列)。接続時にクライアントから提示された証明書が有効かどうかは、「埋込変数 $ssl_client_verify」で下記のように判断し設定する。
if ($ssl_client_verify = SUCCESS) { set $auth_basic off; }
if ($ssl_client_verify != SUCCESS) { set $auth_basic Restricted; }
認証の必要なディレクトリの「location」設定などで下記のベーシック認証設定を行う
auth_basic $auth_basic;
「ssl_client_certificate」指定のCAが発行した証明書が接続クライアントから提示されると全て許可になってしまうので、提示された証明書の選別が必要となる。選別は、「埋込変数」から「$ssl_client_s_dn」が得られるので「cn」などから特定のユーザを識別する。「cn」での識別が困難な証明書は、「SubjectAltName」で判断する必要がある。こうなると厄介。「SubjectAltName」は、「$ssl_client_certificate」で「pem」形式で得られる。なのでasn.1からデコードする必要が発生する。有効期限外の証明書は、「$ssl_client_v_remain」が「0」なので判断可能。
「openssl s_client」で接続し、「埋込変数」の内容を確認することとした。
「埋込変数」は、「log_format」と「accesslog」で指定し確認する。
httpセクションでlog_formatを設定
log_format ssl 'ssl($status): $remote_addr - $remote_user [$time_local] '
' $ssl_client_verify($ssl_client_v_remain) "$ssl_client_s_dn / $ssl_client_i_dn" ';
serverセクションでaccess_logを設定
access_log /var/log/nginx/ssl.log ssl;
クライアント認証でSSL接続を確認する方法
「openssl s_client -connect somehost.somedomain:443 -cert client-cert.pem -CApath . -servername somehost.somedomain -quiet」
SSL接続後にページをアクセスする方法
「echo -e "GET / HTTP/1.1¥n¥n" | openssl s_client -connect somehost.somedomain:443 -cert client-cert.pem -CApath . -servername somehost.somedomain -quiet」
ページアクセスでnginxのssl設定が「name virtual」なため「400 Bad Request」となってしまう。openssl の 「-servername」オプションだけでは、対応できない。
http request headerに「HOST:」を加える必要があった。
NameVirtual SSL設定のnginxサーバでクライアント認証アクセス確認方法
「echo -e "GET / HTTP/1.1\nHOST: some host.somedomain\n\n" | openssl s_client -connect somehost.somedomain:443 -cert client-cert.pem -CApath . -servername somehost.somedomain -quiet」
埋込変数の確認結果
(1)クライアント証明書を使わない($ssl_client_verify=NONE)
クライアント証明書が提示されないので、証明書内容を示す「埋込変数」は、全て未設定。
(2)有効な証明書で$ssl_client_certificate指定以外のCA発行した証明書($ssl_client_verify=FAILED)
(3)有効な証明書で$ssl_client_certificate指定のCA発行した証明書($ssl_client_verify=SUCCESS)
(4)有効な証明書で$ssl_client_certificate指定のCA発行した証明書だが有効期限切れ($ssl_client_v_remain=0)のため接続できない($ssl_client_verify=FAILED)
(5)有効な証明書で$ssl_client_certificate指定のCA発行した証明書だが「X509v3 Extended Key Usage」に「TLS Web Client Authentication」が未定義のため接続できない($ssl_client_verify=FAILED)
2018/3/12追記:使用した証明書のKey Usage=(Digital Signature, Key Encipherment) Extended Key Usage=(E-mail Protection)でAppleのiPhone Configuration Utilityが生成するデバイス証明書と同じ定義。ただ、EtendedKeyUsage=emailProtectionが成立するためには、KeyUsage=nonRepudiationが必須のはず。Key Usage=(Digital Signature, Key Encipherment) Extended Key Usageを未定義とすると$ssl_client_verify=SUCCESSとなる事から、ExtendedKeyUsageの未定義による制限なし状態を避けるための設定かもしれない。要調査。
確認結果をもとにnginx「/etc/nginx/sites-enabled/some.conf」のserverセクションにクライアント認証とベーシック認証の併用設定を確定
server {
ssl_client_certificate /usr/local/etc/nginx/conf.d/auth/client-auth-ca-list.pem;
ssl_trusted_certificate /usr/local/etc/nginx/conf.d/auth/client-auth-ca-list.pem;
ssl_verify_client optional;
set $auth_basic Restricted;
if ( $ssl_client_verify ~ FAILED ) { return 403 $ssl_client_s_dn-$ssl_client_i_dn; }
if ( $ssl_client_verify = NONE ) { set $auth_basic Restricted; }
if ( $ssl_client_s_dn ~ " CN=Some USER" ) { set $auth_basic off; }
location /somedirectory {
auth_basic $auth_basic;
auth_basic_user_file /etc/nginx/conf.d/auth/somedirecory;
}
}
「マイナンバーカード」の入手が遅れている。「マイナンバーカード」によるクライアント認証は、入手後にテストする予定。