サーバ証明書を使ったApache TomcatのHTTPS設定方法|SSL/TLS導入手順を解説

はじめに

あなたのWebサイトがブラウザに「安全ではありません」と表示されたら、訪問者はどう感じるでしょうか。信頼性の欠如は、ユーザー離れや深刻なセキュリティリスクを招きます

本記事では、作成したサーバ証明書やルート証明書をApache/Tomcat、そしてブラウザに正しく配置し、サーバ認証を設定する手順を詳しく解説します。解説は実務でそのまま活用できる内容なので、記事を読みながら実際に設定を行い、安全なWebサイト運用スキルを習得しましょう。

なお、第三者機関による証明書発行が難しい場合や学習目的の場合は、以下の記事で紹介している「プライベートCA・中間CAの構築からサーバ証明書発行まで」の手順を参考に、自分で証明書を作成するところから挑戦してみるのもおすすめです。
初心者でもできる!OpenSSLでプライベートCAと中間CAを構築しサーバ証明書を発行する方法

検証環境

今回の手順は、以下の検証環境で実施しています。

クライアント(Windows)

  • OS: Windows 11
  • ブラウザ: Google Chrome

サーバ/クライアント(Linux)

  • OS: AlmaLinux 9.6
  • Java環境: OpenJDK 21.0.2
  • アプリケーションサーバ: Apache Tomcat 10
    ※Linuxサーバは、クライアントおよびサーバの両方の役割を1台で兼ねています。

Apacheへの証明書の配置

Apacheにサーバ証明書を配置し、サーバ認証が正しく動作するか確認していきます。前述の参考記事のように中間証明書を作成している場合は、事前に「中間証明書」と「サーバ証明書」を結合したチェインファイルを作成しておきます。

まず、ApacheでTLS通信を有効化するためのモジュールmod_sslをインストールします。以下のコマンドを実行してください。

[root@appserver-dev ~]# dnf install -y mod_ssl
Last metadata expiration check: 23:09:30 ago on Mon Jul 28 06:40:02 2025.
Dependencies resolved.
================================================================================================================
 Package                 Architecture           Version                         Repository                 Size
================================================================================================================
Installing:
 mod_ssl                 x86_64                 1:2.4.62-4.el9                  appstream                 109 k
Installing dependencies:
 sscg                    x86_64                 3.0.0-7.el9                     appstream                  45 k

Transaction Summary
================================================================================================================
Install  2 Packages

Total download size: 154 k
Installed size: 378 k
Downloading Packages:
(1/2): sscg-3.0.0-7.el9.x86_64.rpm                                              180 kB/s |  45 kB     00:00
(2/2): mod_ssl-2.4.62-4.el9.x86_64.rpm                                          245 kB/s | 109 kB     00:00
----------------------------------------------------------------------------------------------------------------
Total                                                                           133 kB/s | 154 kB     00:01
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                                                        1/1
  Installing       : sscg-3.0.0-7.el9.x86_64                                                                1/2
  Installing       : mod_ssl-1:2.4.62-4.el9.x86_64                                                          2/2
  Running scriptlet: mod_ssl-1:2.4.62-4.el9.x86_64                                                          2/2
  Verifying        : mod_ssl-1:2.4.62-4.el9.x86_64                                                          1/2
  Verifying        : sscg-3.0.0-7.el9.x86_64                                                                2/2

Installed:
  mod_ssl-1:2.4.62-4.el9.x86_64                             sscg-3.0.0-7.el9.x86_64

Complete!
[root@appserver-dev ~]#

続いて、mod_sslの設定ファイルであるssl.confを編集します。

[root@appserver-dev ~]# vi /etc/httpd/conf.d/ssl.conf
[root@appserver-dev ~]# grep -v '^#' /etc/httpd/conf.d/ssl.conf
Listen 443 https


SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog

SSLSessionCache         shmcb:/run/httpd/sslcache(512000)
SSLSessionCacheTimeout  300

SSLCryptoDevice builtin

################ Additional Setting 1 ##################
<VirtualHost *:443>
ServerName debug.quiz.eeengineer.com
ProxyRequests Off
ProxyPreserveHost On

ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/

<Directory "/var/www/html">
    Require all denied
</Directory>

ServerAlias debug.quiz.eeengineer.com
################ Additional Setting 1 ##################

ErrorLog logs/ssl_error_log
TransferLog logs/ssl_access_log
LogLevel warn

SSLEngine on


SSLHonorCipherOrder on

SSLCipherSuite PROFILE=SYSTEM
SSLProxyCipherSuite PROFILE=SYSTEM


################ Additional Setting 2 ##################
SSLCertificateChainFile /etc/pki/tls/server/certs/server-chain.crt

SSLCertificateKeyFile /etc/pki/tls/server/private/server.key
################ Additional Setting 2 ##################



<FilesMatch "\.(cgi|shtml|phtml|php)$">
    SSLOptions +StdEnvVars
</FilesMatch>
<Directory "/var/www/cgi-bin">
    SSLOptions +StdEnvVars
</Directory>

BrowserMatch "MSIE [2-5]" \
         nokeepalive ssl-unclean-shutdown \
         downgrade-1.0 force-response-1.0

CustomLog logs/ssl_request_log \
          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

</VirtualHost>

[root@appserver-dev ~]#

ほとんどデフォルトで設定されていますので、追加設定や設定変更が必要な項目にしぼって解説します。

Additional Setting 1 にて、Apacheをリバースプロキシとして動作させ、debug.quiz.eeengineer.com への HTTPS リクエストをローカルの Tomcat (http://localhost:8080/) に中継させる設定としています。

<VirtualHost *:443>

  • 443 ポート(HTTPS)で受け付けるバーチャルホストの設定を開始します。
  • *は全てのIPアドレスで待ち受けることを意味します。

ServerName debug.quiz.eeengineer.com

  • このバーチャルホストの正規ホスト名を指定します。
  • HTTPSアクセス時、証明書の CN(Common Name)や SAN(Subject Alternative Name)と一致している必要があります

ProxyRequests Off

  • Apache をフォワードプロキシとして使う機能を無効化します。
    ※セキュリティ上、通常のWeb公開では必ずOFFにしてください。

ProxyPreserveHost On

  • Onにすることで、クライアントから送られたHostヘッダを、バックエンド(ここでは Tomcat)にそのまま渡します。

ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/

  • ProxyPass : クライアントが / にアクセスすると、そのリクエストを http://localhost:8080/ に転送します。
  • ProxyPassReverse : バックエンドから返される Location ヘッダやリダイレクト先のURLを書き換え、クライアントに正しいURLを返します。

<Directory “/var/www/html”>
Require all denied
</Directory>

  • /var/www/html ディレクトリへの直接アクセスを拒否します。

ServerAlias debug.quiz.eeengineer.com

  • このバーチャルホストの別名(エイリアス)を指定します。
    ※今回は ServerName と同じ値ですが、将来的にサブドメインや別名を追加する場合に使えます。

続いてAdditional Setting 2にて、 証明書関連の設定を追加します。

SSLCertificateChainFile /etc/pki/tls/server/certs/server-chain.crt

  • 中間証明書とサーバ証明書を結合したチェインファイルを指定してください。
    ※Apache 2.4.7以前であれば、SSLCertificateFileとSSLCertificateChainFileを分けて設定する必要がありましたが、2.4.8以降ではSSLCertificateChainFileのみを設定する方法が推奨されています。

SSLCertificateKeyFile /etc/pki/tls/server/private/server.key

  • サーバ証明書作成時に使った秘密鍵を指定してください。

設定ファイルの編集が終わったら、変更を適用するためにhttpdサービスを再起動します。ステータスを確認して、エラーが起きていないことを確認しましょう。

[root@appserver-dev ~]# systemctl restart httpd
[root@appserver-dev ~]#
[root@appserver-dev ~]# systemctl status httpd
● httpd.service - The Apache HTTP Server
     Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; preset: disabled)
     Active: active (running) since Wed 2025-07-30 15:03:50 JST; 5s ago
       Docs: man:httpd.service(8)
   Main PID: 2197 (httpd)
     Status: "Started, listening on: port 443, port 80"
      Tasks: 177 (limit: 23126)
     Memory: 22.8M
        CPU: 83ms
     CGroup: /system.slice/httpd.service
             ├─2197 /usr/sbin/httpd -DFOREGROUND
             ├─2198 /usr/sbin/httpd -DFOREGROUND
             ├─2199 /usr/sbin/httpd -DFOREGROUND
             ├─2200 /usr/sbin/httpd -DFOREGROUND
             └─2201 /usr/sbin/httpd -DFOREGROUND

Jul 30 15:03:50 appserver-dev systemd[1]: Starting The Apache HTTP Server...
Jul 30 15:03:50 appserver-dev httpd[2197]: AH00558: httpd: Could not reliably determine the server's fully qua>
Jul 30 15:03:50 appserver-dev systemd[1]: Started The Apache HTTP Server.
Jul 30 15:03:50 appserver-dev httpd[2197]: Server configured, listening on: port 443, port 80

※ファイアウォールが有効な環境では、HTTPS(443番ポート)での接続を許可する必要があります。
Linuxサーバにてファイアウォールを有効にしている場合は、下記の通り、接続許可ルールを追加してください。

[root@appserver-dev ~]# firewall-cmd --add-service=https --permanent
success
[root@appserver-dev ~]# firewall-cmd --reload
success
[root@appserver-dev ~]# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: enp0s3 enp0s8
  sources:
  services: cockpit dhcpv6-client https ssh
  ports: 5432/tcp 8080/tcp 80/tcp
  protocols:
  forward: yes
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
[root@appserver-dev ~]#

クライアント(Windows)によるサーバ認証の確認

サーバ認証の動作確認

サーバ側で証明書の配置とTLS認証の設定が完了したら、クライアントからWebサイトへアクセスし、サーバ認証が正しく動作しているか確認しましょう。

ブラウザにWebサイトのURLを入力してアクセスすると、「この接続ではプライバシーが保護されません」という警告画面が表示されます。これは、サーバ認証の仕組みが有効に働いていることを示しています。

※WebサイトのURLがDNSに登録されていない場合は、WindowsのhostsファイルにURLとIPアドレスの対応を追記しておいてください。

第三者機関が発行した正式な証明書を使用している場合、OSやブラウザにルート証明書があらかじめ格納されているため、クライアント側での追加設定は不要なことがほとんどです。一方、今回のように自己署名証明書を使用している場合や、サーバ証明書の有効期限が切れている場合には、上記のような警告が表示されます。この場合は、証明書の更新やルート証明書のインポートなど、適切な対応が必要です。

警告画面が出てきた場合は、Webサイトに登録されているサーバ証明書の内容を確認しましょう。「保護されていない通信」、「証明書の詳細」をクリックします。

下記の通り、証明書に関する情報が表示されます。発行元の期間が正当であるか、有効期限が切れていないか等を確認することができます。

「詳細(D)」タブをクリックすることで、より詳しい情報を参照することができますので、必要に応じて確認をしてください。

なお、通常運用では推奨しませんが、動作確認目的でサーバ認証を無視してアクセスすることも可能です。

「詳細設定」をクリックします。

WebサイトのURLにアクセスする(安全ではありません)」をクリックします。

自身がデプロイしているアプリケーションにアクセスできるはずです。

ルート証明書の配置

Webサイトの証明書をクライアント側で検証し、ブラウザの警告画面を出さないようにするために、ルート証明書をクライアント側に配置しましょう。Google Chromeにおける設定例をご説明します。

まず、Google Chromeを起動します。右上の設定ボタンをクリックし、「設定」を押下します。

「プライバシーとセキュリティ」の「セキュリティ」を押下します。

「証明書の管理」を押下します。

「Windowsからインポートした証明書を管理する」を押下する。

「信頼された証明機関」、「インポート」を押下します。

証明書のインポートウィザードが表示されます。「次へ」を押下します。

ルートCAが作成したルート証明書(pca.crt)を指定して、「次へ」を押下します。

「証明書をすべての次のストアに配置する(P)」を選択して「次へ」を押下します。

「完了」を押下します。

インストールの確認画面が出ますので、「はい(Y)」を押下します。

「正しくインポートされました。」の文言が出れば成功です。「OK」を押下して下さい。

ルート証明書のクライアント配置が完了しました。ブラウザを再び立ち上げて、Webサイトにアクセスしてみましょう。今後は警告出力なしで、Webサイトにアクセスできることを確認できるかと思います。

クライアント(Linux)によるサーバ認証

Windowsのブラウザ環境では、警告を無視して接続を続行する操作がGUI上で容易に行えますが、Linux環境ではそのような回避策は通常実装されていません。したがって、LinuxなどCUIベースのクライアントでは、事前に適切なルート証明書を配置しておくことが必須となります。

検証構成

今回は、Webサイトにアクセスして画面を取得するアプリケーションをtomcat上で起動させることで、サーバ認証が動作することを確認します。

Springで作成したサンプルアプリを参考までに記載しておきます。

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.boot.builder.SpringApplicationBuilder;

@SpringBootApplication
public class DemoApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(DemoApplication.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
package com.example.demo;

import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HttpClientSampleController {

    @GetMapping("/httpclient-sample")
    public String callExternalHttps() throws Exception {
        String url = "https://debug.quiz.eeengineer.com/quiz/public";

        try (CloseableHttpClient client = HttpClients.createDefault()) {
            HttpGet request = new HttpGet(url);
            try (CloseableHttpResponse response = client.execute(request)) {
                // レスポンスボディを文字列として取得
                String responseBody = EntityUtils.toString(response.getEntity(), "UTF-8");
                return responseBody;
            }
        }
    }
}

サーバ認証の動作確認

サーバ認証が動作していることを確認してみましょう。上記のサンプルアプリを動作させてWebサイトの情報取得を下記の通り試みると、ステータスコード500のInternal Server Errorが返却されました。

[root@appserver-dev ~]# curl http://localhost:8080/https-client-app-0.0.1-SNAPSHOT/httpclient-sample
{"timestamp":"2025-08-03T05:08:30.780+00:00","status":500,"error":"Internal Server Error","path":"/https-client-app-0.0.1-SNAPSHOT/httpclient-sample"}
[root@appserver-dev ~]#

tomcatのログを確認し、エラーとなっている原因の詳細を確認します。

[root@appserver-dev ~]# tail -f /opt/tomcat/logs/catalina.out
2025-08-03T14:10:42.960+09:00 ERROR 1905 --- [https-client-app] [nio-8080-exec-2] o.s.b.w.servlet.support.ErrorPageFilter  : Forwarding to error page from request [/httpclient-sample] due to exception [PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target]

javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:130) ~[na:na]
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:378) ~[na:na]
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:321) ~[na:na]
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:316) ~[na:na]
        at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1318) ~[na:na]
~~Omit~~
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:658) ~[tomcat-util.jar:10.1.41]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[tomcat-util.jar:10.1.41]
        at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:388) ~[na:na]
        at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:271) ~[na:na]
        at java.base/sun.security.validator.Validator.validate(Validator.java:256) ~[na:na]
        at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:230) ~[na:na]
        at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:132) ~[na:na]
        at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1302) ~[na:na]
        ... 79 common frames omitted
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:148) ~[na:na]
        at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:129) ~[na:na]
        at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297) ~[na:na]
        at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:383) ~[na:na]
        ... 84 common frames omitted

「unable to find valid certification path to requested target」のエラーが出ており、接続先サーバの証明書を検証するためのルート証明書が登録されていないことを意図するメッセージが出力されました。サーバ認証が適切に動作していると言えます。

続いて、ルート証明書をtruststoreに格納することで、本エラーが出力されることなくWebサイトにアクセスできることを確認しましょう。下記の通りkeytoolコマンドでpca.crtをインポートしてください。

[root@appserver-dev ~]# keytool -importcert \
  -cacerts \
  -alias my-root-ca \
  -file /etc/pki/tls/pca/certs/pca.crt \
  -storepass changeit
Owner: EMAILADDRESS=pca@example.com, CN=My Root CA, OU=Root CA Unit, O=My Root CA Org, L=Chiyoda, ST=Tokyo, C=JP
Issuer: EMAILADDRESS=pca@example.com, CN=My Root CA, OU=Root CA Unit, O=My Root CA Org, L=Chiyoda, ST=Tokyo, C=JP
Serial number: 532155400fc1718e23239f96c0163ee6e6dab02c
Valid from: Wed Jul 30 14:19:51 JST 2025 until: Sat Jul 28 14:19:51 JST 2035
Certificate fingerprints:
         SHA1: 92:E0:FA:7A:E8:58:30:BC:C5:56:DC:41:15:EF:7E:42:A9:CC:04:A1
         SHA256: 35:32:3F:A9:C1:D5:C0:D0:EA:66:12:01:B4:04:5B:4E:0B:84:8A:78:2E:A8:80:B0:7C:C7:A5:D9:78:3F:42:5E
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 4096-bit RSA key
Version: 3

Extensions:

#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: DB 11 C4 ED 3E C2 EE C4   F7 9D B3 F8 ED 4A D4 98  ....>........J..
0010: E1 BA ED 58                                        ...X
]
]

#2: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
  CA:true
  PathLen: no limit
]

#3: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
  DigitalSignature
  Key_CertSign
  Crl_Sign
]

#4: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: DB 11 C4 ED 3E C2 EE C4   F7 9D B3 F8 ED 4A D4 98  ....>........J..
0010: E1 BA ED 58                                        ...X
]
]

Trust this certificate? [no]:  yes
Certificate was added to keystore
[root@appserver-dev ~]#

<コマンド解説>
-importcert
証明書を keystore(この場合は truststore)にインポートするモードを指定
-cacerts
Java のデフォルト truststore($JAVA_HOME/lib/security/cacerts)を対象にするショートカット指定
-alias my-root-ca
証明書を登録するときの識別名。後で削除や確認するときにこの名前で操作する。
-file /etc/pki/tls/pca/certs/pca.crt
インポートする証明書ファイルのパス
-storepass changeit
keystore(truststore)のパスワード。デフォルトの cacerts は多くのJava環境でchangeitだが、必要に応じて変更する。

ルート証明書が適切にtruststoreに配置されていることを確認するには、keytool -listコマンドを使います。-vオプションをつけることで、詳細情報を表示させることも可能です。

[root@appserver-dev ~]# keytool -list -cacerts -storepass changeit -alias my-root-ca -v
Alias name: my-root-ca
Creation date: Aug 14, 2025
Entry type: trustedCertEntry

Owner: EMAILADDRESS=pca@example.com, CN=My Root CA, OU=Root CA Unit, O=My Root CA Org, L=Chiyoda, ST=Tokyo, C=JP
Issuer: EMAILADDRESS=pca@example.com, CN=My Root CA, OU=Root CA Unit, O=My Root CA Org, L=Chiyoda, ST=Tokyo, C=JP
Serial number: 532155400fc1718e23239f96c0163ee6e6dab02c
Valid from: Wed Jul 30 14:19:51 JST 2025 until: Sat Jul 28 14:19:51 JST 2035
Certificate fingerprints:
         SHA1: 92:E0:FA:7A:E8:58:30:BC:C5:56:DC:41:15:EF:7E:42:A9:CC:04:A1
         SHA256: 35:32:3F:A9:C1:D5:C0:D0:EA:66:12:01:B4:04:5B:4E:0B:84:8A:78:2E:A8:80:B0:7C:C7:A5:D9:78:3F:42:5E
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 4096-bit RSA key
Version: 3

Extensions:

#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: DB 11 C4 ED 3E C2 EE C4   F7 9D B3 F8 ED 4A D4 98  ....>........J..
0010: E1 BA ED 58                                        ...X
]
]

#2: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
  CA:true
  PathLen: no limit
]

#3: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
  DigitalSignature
  Key_CertSign
  Crl_Sign
]

#4: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: DB 11 C4 ED 3E C2 EE C4   F7 9D B3 F8 ED 4A D4 98  ....>........J..
0010: E1 BA ED 58                                        ...X
]
]

[root@appserver-dev ~]#

証明書をtruststoreに格納できたら、再度クライアントアプリを動作させてみましょう。下記の通りエラーなくWebサイトの情報が表示できたら成功です。

[root@appserver-dev ~]# curl  http://localhost:8080/https-client-app-0.0.1-SNAPSHOT/httpclient-sample
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ITインフラエンジニア向けスキルアップクイズ</title>

    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head>
<body>

<div class="container">

    <h3>ITインフラエンジニア向けスキルアップクイズ</h3>
        <a href= "/login" >ユーザ登録/ログイン</a>
        <H6>ユーザ登録してログインすることで、クイズの学習ステータスを管理することができます。ぜひ登録して使ってみてください。</H6>

エラー時のトラブルシュート方法

truststoreにルート証明書を登録したのにもかかわらず、エラーが解消されない場合のトラブルシュート方法をご紹介します。

原因の切り分けをするために、まずは直接Webサイトにアクセスしてみましょう。この際、truststoreに格納されているルート証明書ではなく、OS上に格納されているルート証明書を直接指定してアクセスしてみてください。下記の通り、curlコマンドに–cacertオプションをつけて実行します。

[root@appserver-dev ~]# curl --cacert /etc/pki/tls/pca/certs/pca.crt https://debug.quiz.eeengineer.com/quiz/public
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ITインフラエンジニア向けスキルアップクイズ</title>

    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head>
<body>

<div class="container">

    <h3>ITインフラエンジニア向けスキルアップクイズ</h3>

上記のとおり、問題なくWebサイトにアクセスできた場合は、ルート証明書自体は正しいファイルである可能性が高いと考えられます。この場合は、ルート証明書が truststore に適切に登録されていない、またはアプリケーションの不具合といった別の要因を疑い、調査を進めてください。

一方、ルート証明書を直接指定してもエラーが発生する場合は、サーバ証明書およびルート証明書の正当性を改めて確認しましょう。証明書の確認には、curl コマンドの -v オプションが有効です。これを使うと、Webサイトに登録されているサーバ証明書の詳細情報を取得できます。取得した証明書が想定どおりのものであるか確認してください。

以下は一例として、Netflix の Web サイトに登録されている証明書情報を取得する方法です。
取得結果をもとに、適切なルート証明書が配置されているか確認してください。

[root@appserver-dev ~]# curl -v https://www.netflix.com
~~Omit~~
* Server certificate:
*  subject: C=US; ST=California; L=Los Gatos; O=Netflix; CN=www.netflix.com
*  start date: Sep 23 00:00:00 2024 GMT
*  expire date: Sep 24 15:49:08 2025 GMT
*  subjectAltName: host "www.netflix.com" matched cert's "www.netflix.com"
*  issuer: C=US; O=DigiCert Inc; OU=www.digicert.com; CN=DigiCert Secure Site ECC CA-1
~~Omit~~

過去のトラブル事例として、Webサイトのサーバ証明書が知らないうちに更新され、それに対応するルート証明書を追加インストールしなければならなかったケースがあります。特に最近では、クラウド環境でサーバ証明書の自動更新を利用しているサイトが増えているため、運用設計や証明書管理手順も含めて定期的に確認することを推奨します。

上記の調査を行ってもエラーが解消しない場合は、パケットキャプチャを用いて通信の到達範囲や異常箇所を詳細に確認してください。パケットキャプチャの解析方法については、別記事で解説予定です。

さいごに

サーバ証明書を用いた Apache Tomcat の HTTPS 設定方法の解説は以上です。サーバ認証に関するエラーは、現場でも発生しやすいトラブルです。仕組みを理解し、落ち着いて迅速にトラブルシュートできるよう、日頃から備えておくことを推奨します。

参考文献

HTTPS Client Authentication (The Java EE 6 Tutorial, Volume I)
Install mod_ssl on Apache – CentOS | IT Blog

コメント