2026/07/08(水)nginxにクライアント証明書認証の設定をした

管理領域など、自分以外などにアクセスを許可したくない場所にパスフレーズ付きクライアント証明書で制限を掛け、自分以外アクセスできないようにしたので、そのログ。

確認環境

サーバーと証明書作成環境

Env Ver
OS Ubuntu 24.04.4 LTS
nginx 1.24.0
OpenSSL 3.0.13 30

クライアント証明書を設定してアクセスした環境1

Env Ver
OS Windows 11 Pro 25H2 (OSビルド 26200.8783)
クライアント Microsoft Edge バージョン 150.0.4078.48

クライアント証明書を設定してアクセスした環境2

Env Ver
OS Android 16
クライアント Microsoft Edge バージョン 149.0.4022.105

手順

CAやクライアント証明書の作成

ここから行うコマンドはその全てでパスワード入力プロンプトが出るため、個別に流す必要がある。

  1. 判別しやすくするためにファイル名の頭に付与する接頭辞を決める
    file_prefix=lyco_
    
  2. CA(認証局)を作成する

    1. CAの秘密鍵の作成
      # -pass=pass:<PASSWORD>でもパスワードを掛けられるが平文になるらしいので-aes-128-cbcでパスワードを掛ける
      openssl genpkey \
        -algorithm EC \
        -pkeyopt ec_paramgen_curve:P-256 \
        -out ${file_prefix}ca.key \
        -aes-128-cbc
      
    2. CAの証明書署名要求の作成

      # 適当に好きな値を設定(以下は私の設定例)
      # 最低限CommonNameさえあればあとは何でもいいらしい?
      
      CountryCode=JA # 国コードを指定するっぽいが多分何を指定してもいい
      Province=Hyogo # たぶん県を指定するっぽいが多分何を指定してもいい
      Location=Kobe # たぶん市区町村を指定するっぽいが多分何を指定してもいい
      Organization="Lycolia Rizzim" # 組織を設定を指定するっぽいが多分何を指定してもいい
      CommonName=lycolia.info # FQDNを指定するっぽいが多分何を指定してもいい
      
      # CA証明書署名要求作成
      
      openssl req \
        -new \
        -key ${file_prefix}ca.key \
        -out ${file_prefix}ca.csr \
        -subj "/C=${CountryCode}/ST=${Province}/L=${Location}/O=${Organization}/CN=${CommonName}-CA"
      
    3. CAの証明書の作成
      openssl req \
        -new \
        -x509 \
        -key ${file_prefix}ca.key \
        -out ${file_prefix}ca.crt \
        -subj "/C=${CountryCode}/ST=${Province}/L=${Location}/O=${Organization}/CN=${CommonName}-CA"
      
  3. クライアント証明書作成

    1. クライアントの秘密鍵の作成

      # -pass=pass:<PASSWORD>でもパスワードを掛けられるが平文になるらしいので-aes-128-cbcでパスワードを掛ける
      openssl genpkey \
        -algorithm EC \
        -pkeyopt ec_paramgen_curve:P-256 \
        -out ${file_prefix}client.key \
        -aes-128-cbc
      
    2. クライアントの証明書署名要求の作成

      openssl req \
        -new \
        -key ${file_prefix}client.key \
        -out ${file_prefix}client.csr \
        -subj "/C=${CountryCode}/ST=${Province}/L=${Location}/O=${Organization}/CN=${CommonName}-CLIENT"
      
    3. クライアント証明書の作成

      openssl x509 \
        -req \
        -in ${file_prefix}client.csr \
        -CA ${file_prefix}ca.crt \
        -CAkey ${file_prefix}ca.key \
        -CAcreateserial \
        -out ${file_prefix}client.crt \
        -subj "/C=${CountryCode}/ST=${Province}/L=${Location}/O=${Organization}/CN=${CommonName}-CLIENT"
      
  4. クライアントに食べさせる用の証明書を作る(PKCS12形式)
    openssl pkcs12 \
      -export \
      -out ${file_prefix}client.pfx \
      -inkey ${file_prefix}client.key \
      -in ${file_prefix}client.crt
    
  5. CA証明書の配置

    sudo mkdir /etc/nginx/ca
    sudo cp ${file_prefix}ca.crt /etc/nginx/ca
    
  6. nginxのsnippetsの作成

    cat <<EOF | sudo tee /etc/nginx/snippets/ssl_verify_client.conf
    ssl_verify_client on;
    ssl_client_certificate "ca/${file_prefix}ca.crt";
    EOF
    
  7. 各vhostの設定に埋め込む。https環境でないと設定しても意味ないので注意
    server {
      ...
      include snippets/ssl_verify_client.conf;
      ...
    }
    
  8. 設定を再読み込み
    sudo systemctl reload nginx
    
  9. 疎通確認
    curl -v \
      --cert ${file_prefix}client.crt \
      --key ${file_prefix}client.key \
      --cacert ${file_prefix}ca.crt \
      https://hoge.example.com/
    

WindowsのEdgeからアクセスする

  1. 作成したPKCS12形式の証明書をWindowsにもってきてダブルクリックする。保存場所→現在のユーザーで次へ
  2. 何もせず次へ
  3. パスワードを入力して次へ
  4. 何もせず次へ
  5. スマートカードを挿入をキャンセルする
  6. プライベートモードでEdgeを開き設定したvhostにアクセスして証明書を選択しなかったときに400エラーが出ることを確認
  7. プライベートモードを閉じて再度アクセスしたときに証明書を選択したときに正常にアクセスできることを確認

AndroidのEdgeから確認する

  1. 作成したPKCS12形式の証明書をAndroidにもってきて開く
  2. 適当にインポートする
  3. プライベートモードでEdgeを開き設定したvhostにアクセスして証明書を選択しなかったときに400エラーが出ることを確認
  4. プライベートモードを閉じて再度アクセスしたときに証明書を選択したときに正常にアクセスできることを確認

メモ

genrsaよりgenpkeyを使った方がいい

Generation of RSA Private Key. Superceded by genpkey.

https://linux.die.net/man/1/openssl

トラブルシューティング

証明書の選択画面が出ない

httpsになってないと出ない。

http://localhostとかhttp://dev.localみたいなアクセスをしていると出てこない。

HTTPSでアクセスしているのに400エラーが出る

CAの証明書とクライアントの証明書でCNの値が同じだと自己署名証明書扱いされて上手くいかないのでCNの値を変える。

今回手順に書いた内容ではCAとクライアント用でCNの値が相違するよう書いているので手順通りにしていれば起きない。

ED25519で証明書を作ったらなんか動かない

openssl genpkey-algorithm ed25519にするとEdgeは上手く解釈できないっぽいので-algorithm EC -pkeyopt ec_paramgen_curve:P-256として作る必要がある。

今回手順に書いた手順通りにしていれば起きない。

参考記事