Jenkinsでデプロイしようとしてどん詰まりした話
初めてJenkins使って、ci/cd環境を作っていた。
dockerでjenkinsを立て、gitのリポジトリを登録して、ビルドして、いざデプロイの段階に進んだ。
デプロイの方法としてはmavenのtomcat7-maven-pluginを使う
しかし、そこで予想外のエラーに見舞われた。
com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
エラーの調査
エラーがでてしまったのでいつも通りgoogle先生に聞いてみた。
ざっくり言うと通信しようとしてるサイトのSSL証明書の信頼がないため、エラーを出してることが分かった。
オレオレ証明書とか証明書の有効期限が切れてるとでるらしい。
しかし、いま自分がデプロイしようとしたサーバーはオレオレ証明書でもなく、有効期限もまだ切れていなかった。
さらにブラウザでアクセスしてもしっかりとhttpsで通信できていた。
しかし、後々この「ブラウザでアクセスできた」ことが問題を複雑にしてしまった。
さらに詳細なエラーの調査
いろいろ調べてみたが、いまいち有力な情報はなかった。
どのサイトも証明書の信頼がないよ、だからkeytoolで信頼リストに追加してね、としか書かれていない。。。。
ただ自分のは、オレオレ証明書じゃないんだからそんな必要ないはず!と思い、いろいろほかの要因を考えた。
自分のSSL証明書はlet's encryptで発行していた。
まさかjavaはlet's encrypt自体を信頼いないんじゃないか?と思い、検索した。
ここに調査してくれてる人がいた。
なるほど、やはりlet's encrypt自体を信頼していなかったのか。
しかし、この記事を読み進めていくと以下の記述が、
Let’s Encryptの証明書はJava 8 Update101からサポートされているようです。
とあった。
JenkinsでつかってるjavaのversionがJava 8 Update101未満だからエラーがでるのか!
javaのversionを挙げれば解決や!
と思いました。。。。。
Jenkinsの調査
上に書いた通り、javaのversionが原因だと思い、jenkinsで使ってるversionを確認しにいった。
Jenkinsのシステム情報にjavaのversionが書いてあるとわかり、行ってみる。
java.version 1.8.0_171
・・・・・・・・・
きっとjenkinsのjavaと実際に実行するときのjavaのversionは違うんだと思い、jobのなかでjava -versionを実行してみた。
java -version
openjdk version "1.8.0_171"
OpenJDK Runtime Environment (build 1.8.0_171-8u171-b11-1~deb9u1-b11)
OpenJDK 64-Bit Server VM (build 25.171-b11, mixed mode)
・・・・・・・・・・・
なんでや?
javaのversionが原因じゃないなかったのか?
もうわからん
ローカル環境で実施してみる
ここで初めてローカルからデプロイしてみることにした。
jenkinsで実行していたコマンドをそのままローカルからやってみた。
com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
まじか。
httpsではなくhttpにしてデプロイしてみた
普段はhttpにきたリクエストはhttpsにリダイレクトされる
どこが原因だかわからなくなってきたから、問題を切り分けるためにhttpsではなくhttpでアクセスできるようにして、デプロイしてみた。
ちゃんとデプロイできる。
ここまでのまとめ
mavenのtomcat7-maven-pluginを使ったデプロイがうまくいかない。
ssl証明書が問題っぽいがブラウザからサイトにアクセスしても特に問題ない。
let's encriptはjavaのversionによってはエラーがでるが現状使ってるversionではでない。
ローカルからやっても同様のエラーがでるため、Jenkins自体に問題があるわけではない。
httpならできるのでコマンドが間違っていないし、クライアント側に問題がある可能性は低い
もう正直どこに問題があるのか皆目見当がつかない状態になってしまった。
この辺でkeytoolを使って証明書を登録したほうがはやいんじゃないと思い始めた。
のちにわかることだがkeytoolで登録してもエラーは解決しない。
だから結果的にはやんなくて正解だった。
半分諦めながら調査していると。。。
適当なワードで適当にgoogleで調べてるとあるサイトでこんなコメントを見つけた。
あんたの問題はjavaとは全く関係ないぜ!
あんたのサイトは不完全な証明書のチェーンを返してるぜ!
だから完全な証明書のチェーン(fullchain.pem)を返すよう変更する必要があるぜ!
なんだと。。。
たしかに自分は cert1.pem を読み込ませていた。
これをサイトに書いてあった通り、fullchain.pem を読み込ませみると。。。
エラーはたちまちに消えて、問題なくデプロイできるようになった!!!!
まとめ
読み込ませるSSLの証明書のファイルは cert1.pem から fullchain.pem に変更しただけ。
ブラウザからのアクセスは問題なく、javaからのアクセスでエラーがでる人はぜひとも確認してみてください。
終わりに
SSLの証明書の読み込んだファイルは、なんかのサイトにそう書いてあったし、問題なくSSL証明書と動いていたから問題ないと思い込んでいた。
その思い込みにより、SSLが問題ないかの確認を後回しにしてしまった。
ただいまだに思うのは fullchain1.pem があれば cert1.pem は必要ないとじゃないか?
fullchain1.pem しかなかったらこんなことにならなかったのに。。。
もし、cert1.pemが必要な理由がわかる人がいたら教えてください