OpenSSL で作る Active Directory 証明書認証の検証環境

Active Directory の証明書認証は ADCS(Active Directory 証明書サービス)を使えば比較的簡単に導入できますが、その内部で何が起きているのかを理解する機会は多くありません。本稿では ADCS を使わず OpenSSL で認証局 (CA) を構築し、証明書認証の仕組みを学べる検証環境を作ります。

はじめに

本記事のゴールは、証明書認証の仕組みを自分で試して学べる「検証環境」を構築することです。 ここで構築する手順は、セキュリティや運用の観点から多くの重要な要素を簡略化しています。

⚠️この構成をそのまま本番環境で使用しないでください⚠️。

構築の概要

この記事全体の流れを把握するため、最初に概要を説明します。

事前準備

Active Directory や Linux サーバーの構築と基本的な操作をある程度理解している読者を想定しています。実際にやってみようかなという方は、以下の 3 台の仮想マシンを用意してください。

  • Linux サーバー 1台: Debian や Ubuntu など
  • Windows Server 1台: Active Directory ドメインコントローラーとして構築済み
  • Windows クライアント 1台: 上記ドメインに参加済み。TPM 2.0 が有効化されていること

本稿では VirtualBox 7.2.4 を使用して VM で次のように準備した環境で説明を進めます。タイムゾーンはすべて UTC に設定しました。各ホストの時刻は大きなずれがないように設定しておく必要があります。

  • Linux サーバー
    • OS: Ubuntu Server 24.04 LTS
    • ネットワークインターフェース
      • 内部ネットワーク: 192.168.50.10/24
      • NAT (インターネット接続用)
    • Minimal インストール
    • ホスト名: ca-server
  • Windows Server
    • OS: Windows Server 2025
    • ネットワークインターフェース
      • 内部ネットワーク: 192.168.50.20/24
    • ホスト名: dc1
    • ドメイン名 ad.example.com の Active Directory ドメインコントローラーとして構築
    • OU 名 ou の Organizational Unit を作成(OU=ou,DC=ad,DC=example,DC=com)
    • 上記 OU に user1 という名前のユーザーアカウントを作成(UPN=user1@ad.example.com
  • Windows クライアント
    • OS: Windows 11 Enterprise 25H2
    • ネットワークインターフェース
      • 内部ネットワーク: 192.168.50.30/24
    • ホスト名: cl1
    • ad.example.com ドメインに参加

検証環境の全体像

構成図

  1. (黄色) CA 証明書と CRL を HTTP で配布
  2. (緑色) Linux CA サーバーが KDC 証明書とユーザー証明書を発行
  • CSR と発行した証明書は HTTPS WebDAV (8443 番) でやり取り
  1. (赤色) クライアント PC とドメインコントローラー間で証明書認証
  • Kerberos PKINIT 認証

Windows クライアントで TPM を確認

管理者 PowerShell で次を実行し、TPM がアクティブか確認します。

Get-Tpm

TpmPresentTpmReady がともに True であれば準備完了です。False の場合は BIOS/UEFI で TPM を有効にしてください。

ステップ 1: Linux で OpenSSL CA を構築する

ここでは OpenSSL ベースのシンプルな CA を作成し、HTTP/HTTPS サービスで CRL、CSR、証明書をやり取りできるようにします。

1-1. パッケージのインストール

sudo apt update
sudo apt install openssl rclone wget

1-2. ディレクトリの初期化

mkdir -p ~/ca/{certs,crl,newcerts,private,http_public,webdav_share/uploads,webdav_share/certs_issued}
cd ~/ca
touch index.txt
openssl rand -hex 16 > serial
echo 1001 > crlnumber

主なディレクトリ:

  • private/: ルート CA 秘密鍵
  • http_public/: CA 証明書と CRL の公開場所
  • webdav_share/uploads/: Windows からアップロードされる CSR・メタデータ
  • webdav_share/certs_issued/: 発行済み証明書の保管場所

以降の OpenSSL コマンドで使用する環境変数を設定します。

export CA_SERVER_IP='192.168.50.10'

次に、設定ファイルとテンプレートをダウンロードします。

wget https://io.cyberdefense.jp/entry/openssl_ad_pkinit/openssl.cnf -O openssl.cnf
wget https://io.cyberdefense.jp/entry/openssl_ad_pkinit/kdc.ext.tpl -O kdc.ext.tpl
wget https://io.cyberdefense.jp/entry/openssl_ad_pkinit/user.ext.tpl -O user.ext.tpl
wget https://io.cyberdefense.jp/entry/openssl_ad_pkinit/request_kdc.inf -O http_public/request_kdc.inf
wget https://io.cyberdefense.jp/entry/openssl_ad_pkinit/request_sc.inf -O http_public/request_sc.inf

設定ファイルの解説は致しませんが、知りたくなった方のためにありがたい無償の電子書籍を紹介いたします(有償版の方の書籍もとてもオススメです)。

1-3. ルート CA と WebDAV サーバー証明書の発行

# ルート CA 証明書(CN=PKINIT Test CA)
openssl req -new -x509 -nodes \
  -keyout private/ca.key \
  -out ca.crt \
  -days 3650 \
  -config openssl.cnf \
  -extensions v3_ca

# WebDAV サーバー証明書(CN=webdav.example.com)
openssl req -new -nodes \
  -out webdav.csr \
  -keyout webdav.key \
  -subj "/CN=webdav.example.com" \
  -config openssl.cnf

openssl ca -batch -in webdav.csr \
  -out webdav.crt \
  -config openssl.cnf \
  -extensions v3_server

1-4. CA 証明書/CRL 配布と WebDAV サーバーの起動

アクセスログをリアルタイムで確認し、デバッグしやすくするために、これらのサーバーはフォアグラウンドで動作します。後続の作業は、別のターミナルを開いて実行してください。

# HTTP (8080) で CA 証明書と CRL を公開
cp ca.crt http_public/
openssl ca -gencrl -out http_public/crl.pem -config openssl.cnf
python3 -m http.server --directory http_public 8080
# HTTPS WebDAV (8443) で CSR アップロード、発行済み証明書の配布
rclone serve webdav ./webdav_share \
  --addr :8443 \
  --cert webdav.crt \
  --key webdav.key \
  --dir-cache-time 0s \
  --vfs-cache-mode off \
  --verbose

ステップ 2: ドメインコントローラーの証明書認証設定

ドメインコントローラーで CA を信頼させ、KDC 証明書を取得します。PowerShell は必ず管理者で実行してください。

2-1. CA 証明書のインポート

  1. http://192.168.50.10:8080/ca.crt をダウンロード
  2. ca.crt を右クリック → 「証明書のインストール」
  3. 「ローカル コンピューター」を選択し、「信頼されたルート証明機関」ストアへ配置

2-2. NTAuth ストアへの登録

次のコマンドを実行します。これは、Active Directoryドメインに対して、この CA が発行した証明書をログオン目的で信頼させるための重要な手順です。このストアに登録されていないCAからの証明書では、ドメインの認証はできません。

certutil -dspublish -f ca.crt NTAuthCA

実行例:

2-3. KDC CSR の作成とアップロード

http://192.168.50.10:8080/request_kdc.inf をダウンロードし、次のコマンドを実行します。

certreq -new -machine request_kdc.inf kdc.csr
Invoke-WebRequest -Uri "https://192.168.50.10:8443/uploads/kdc.csr" -Method PUT -InFile kdc.csr

実行例:

2-4. ドメインコントローラーの ObjectGUID 取得

KDC 証明書に埋め込む ObjectGUID を取得し、CA サーバーへアップロードします。

$kdcGuid = (Get-ADComputer -Identity $env:COMPUTERNAME).ObjectGUID.ToString() -replace '-',''
$kdcGuid | Out-File -Encoding ascii -NoNewline kdc_guid.txt
Invoke-WebRequest -Uri "https://192.168.50.10:8443/uploads/kdc_guid.txt" -Method PUT -InFile kdc_guid.txt

2-5. CA で KDC 証明書を署名

CA サーバーで次のコマンドを実行します。KDC 証明書(ドメイン コントローラー証明書)の要件の詳細については、Windows Server のドキュメント: サード パーティ CA からのドメイン コントローラー証明書の要件 を参照してください。証明書と Active Directory のオブジェクト(コンピューター)を紐付けるため、証明書の SAN(サブジェクト代替名)に ObjectGUID を含めるなどの要件が定められています。

cd ~/ca
export CA_SERVER_IP='192.168.50.10'
export KDC_GUID_HEX="$(cat webdav_share/uploads/kdc_guid.txt)"
export KDC_FQDN='dc1.ad.example.com'
export DOMAIN_NAME='ad.example.com'
openssl ca -batch -subj "/CN=${KDC_FQDN}" \
  -in webdav_share/uploads/kdc.csr \
  -out webdav_share/certs_issued/kdc.crt \
  -config openssl.cnf \
  -extensions v3_kdc \
  -extfile kdc.ext.tpl

実行例:

2-6. KDC 証明書のインストール

Invoke-WebRequest -Uri "https://192.168.50.10:8443/certs_issued/kdc.crt" -OutFile kdc.crt
certreq -accept -machine kdc.crt

実行例:

2-7. 再起動

ドメインコントローラーを再起動します。

ステップ 3: クライアント PC の証明書認証設定

Windows クライアントで仮想スマートカードを作成し、ユーザー証明書を格納していきます。証明書発行対象のドメインユーザーでログインして作業してください。時折、管理者権限が必要になります。原理的にはスマートカードがなくても証明書認証は可能ですが、Windows の証明書ベース認証機能はスマートカードなどのハードウェア利用を前提としているため、ここでは仮想スマートカードを使用します。

3-1. 仮想スマートカードを作成する

管理者権限で次のコマンドを実行してください。

tpmvscmgr.exe create /name PKINITVSC /pin default /puk default /adminkey default /generate
  • 上記コマンドは PIN=12345678、PUK=12345678、AdminKey=01020304... の既定値を設定します。
  • 以降の手順で PIN 入力を求められたら 12345678 を入力してください。

実行例:

3-2. CA 証明書のインポート

  1. http://192.168.50.10:8080/ca.crt をダウンロード
  2. ca.crt を右クリック → 「証明書のインストール」
  3. 「ローカル コンピューター」を選択し、「信頼されたルート証明機関」ストアへ配置

3-3. ユーザー CSR を作成してアップロードする

http://192.168.50.10:8080/request_sc.inf をダウンロードし、次のコマンドを実行します。

certreq -new -user request_sc.inf user.csr
Invoke-WebRequest -Uri "https://192.168.50.10:8443/uploads/user.csr" -Method PUT -InFile user.csr

実行時に仮想スマートカードの PIN 入力が求められます。

実行例:

3-4. ユーザー SID をアップロードする

ユーザーの証明書に埋め込む SID を取得し、CA サーバーへアップロードします。

$currentUserSid = [Security.Principal.WindowsIdentity]::GetCurrent().User.Value
$currentUserSid | Out-File -Encoding ascii -NoNewline user_sid.txt
Invoke-WebRequest -Uri "https://192.168.50.10:8443/uploads/user_sid.txt" -Method PUT -InFile user_sid.txt

user_sid.txt には S-1-5-... 形式の SID 文字列がそのまま保存されます。user.ext.tpl はこの文字列を拡張に埋め込みます。

実行例:

3-5. ユーザー証明書を署名する(CA サーバー)

CA サーバーで次のコマンドを実行します。証明書の要件の詳細については、Windows Server のドキュメント: 証明書の要件と列挙 および Microsoft Japan Windows Technology Support Blog: 2022 年 5 月 10 日の更新プログラムに含まれるドメイン コントローラーでの証明書ベースの認証の変更と対応の流れについて [KB5014754] を参照してください。証明書と Active Directory のオブジェクト(ユーザー)を紐付けるため、証明書の SAN(サブジェクト代替名)に SID を含めるなどの要件が定められています。

cd ~/ca
export CA_SERVER_IP='192.168.50.10'
export SID="$(cat webdav_share/uploads/user_sid.txt)"
export UPN='user1@ad.example.com'
openssl ca -batch -subj '/CN=user1' \
  -in webdav_share/uploads/user.csr \
  -out webdav_share/certs_issued/user.crt \
  -config openssl.cnf \
  -extensions v3_user \
  -extfile user.ext.tpl

実行例:

3-6. 発行済み証明書を仮想スマートカードにインポートする

Invoke-WebRequest -Uri "https://192.168.50.10:8443/certs_issued/user.crt" -OutFile user.crt
certreq -accept -user user.crt

実行例:

確認ポイント

  • certutil -scinfo に仮想スマートカード上の証明書が表示される
  • Get-ChildItem Cert:\CurrentUser\My で目的の証明書が確認できる

実行例:

ステップ 4: 証明書認証によるログオンを確認する

4-1. スマートカードでサインインする

  1. クライアントを再起動
  2. ログオン画面で「スマートカード」を選択
  3. PIN を入力
  4. 正常にデスクトップへサインインできれば成功🎉💐🎊

実行例:

うまくいかなかった方へ😔: できるだけ簡単に構築できるように心がけて書きましたが、それでも手順が複雑かもしれません。落とし穴は無数にあり、ポイントを絞ったトラブルシューティングの案内は難しく、困った時は各ホストのログ(イベントログ)と certutil コマンド、生成 AI などを駆使して原因を探ってみてください。グループポリシーの強制適用や再起動も試すとよいかもしれません。以下によくありそうな問題点をいくつか挙げておきます。

  • 時刻のずれ: Kerberos 認証は時刻に厳格です。CA、ドメインコントローラー、クライアントの時刻が 5 分以上ずれていないか確認してください。
  • CRL の失効確認エラー: ドメインコントローラーやクライアントが CA の CRL 配布ポイント (http://192.168.50.10:8080/crl.pem) にアクセスできないと認証に失敗します。certutil -url kdc.crt を実行して失効確認が成功するかテストしてみてください。
  • NTAuth ストアの登録漏れ: ドメインコントローラーで certutil -viewstore NTAuth を実行し、インポートした CA 証明書が表示されることを確認してください。

4-2. ドメインコントローラーのイベントログを確認

ドメインコントローラーでイベントビューアーを開き、Windows ログ → セキュリティ を選択します。イベント ID 4768(TGT 発行成功)が記録されていることを確認してください。

ネクストステップ

学習という意味では、以下のような追加の調査や実験をお勧めします。

  • Wireshark などで Kerberos 通信をキャプチャし、PKINIT のやり取りを詳細に観察する
  • 発行した証明書を読み解く
  • OpenSSL config の各種設定を読み解く
  • 各種変更を加えて動作を確認する

実運用を考える場合、非常に多くの検討事項があります。以下にいくつかピックアップします。

  • 手作業によるミス、運用負荷の高さ(自動化)
  • CA 秘密鍵の保護(HSM、オフライン運用)
  • 中間 CA の導入(ポリシー策定など)
  • CSR 提出時の認証(本人確認)
  • スマートカードの運用(PIN 管理、PIN ロック、紛失対応)
  • スマートカード(仮想スマートカード)デバイスの真正性確認(アテステーション)
  • 複数ドメインでの証明書認証基盤の共通化(altSecurityIdentities)
  • パスワード認証を駆逐する(一匹残らず)

PKI や証明書認証に関する過去記事もぜひ参考にしてください。

まとめ

ありそうでなかった OpenSSL ベースの Active Directory 証明書認証の検証環境構築手順を紹介しました。 ADCS を使うと構築が簡単な反面、内部で何が起きているのかを理解する機会は多くなく、また予期せぬセキュリティ上の問題を抱えがちかと思います。本稿の手順を通じて、証明書認証の仕組みを理解する一助となれば幸いです。

それでは、よい PKI ライフを👋

© 2016 - 2025 DARK MATTER / Built with Hugo / テーマ StackJimmy によって設計されています。