VxRailなど、PowerEdge上にESXiをInstallしている場合、トラブルシューティングや初期構築などでiDRACの仮想コンソールに接続することはしばしばあると思います。
先日、ESXiのInstall用途で、iDRACの仮想コンソールにJavaで接続しようとしたら、エラーになって接続できないことがありました。
結論からいうと、iDRACのFWをUpdateするか、Javaのセキュリティファイルの設定を書き換えることで解決できました。
その時のトラブルシューティングを記します。
事象
キャプチャをとればよかったのですが、残念ながら取り損ねてしまいました。
英語でのキャプチャが欲しかったので後で事象を再現させて取ればよい、と楽観していたところ再現しなくなってしまったので取れずじまいです。
事象としては、idracの仮想コンソールにJavaで接続しようとした際に、Javaのアプレット(?)が起動した直後に「ビューワが切断された~」みたいなメッセージがでて接続できないという事象でした。
トラブルシューティング
Javaのコンソールやトレースを有効化する
Javaのエラーを見れば何かわかる、と思ったのでJavaのコンソールやロギングを有効化しました。
有効化は、コンパネからJavaのコントロールパネルを開き、AdvancedタブからConsoleやLoggingやTracingのチェックを入れればいいだけです。
事象を再現してログをみる
コンソールとロギング・トレーシングの設定をしたら、もう一度事象を再現させて、ログを見ればよいです。
実際に記録されていたログは以下です。
2020年2月19日
4:07
Java Web Start 11.241.2.07
Using JRE version 1.8.0_241-b07 Java HotSpot(TM) Client VM
JRE expiration date: 20/05/17 0:00
console.user.home = C:\Users\Administrator
----------------------------------------------------
c: clear console window
f: finalize objects on finalization queue
g: garbage collect
h: display this help message
m: print memory usage
o: trigger logging
p: reload proxy configuration
q: hide console
r: reload policy configuration
s: dump system and deployment properties
t: dump thread list
v: dump thread stack
0-5: set trace level to <n>
----------------------------------------------------
Missing Application-Name manifest attribute for: https://ip.ex.am.ple:443/software/avctKVM.jar
replace numpad
** Max Size: W = 1920 H = 1040
** Window Pref Size: W = 1040 H = 823
** Max Size: W = 1920 H = 1040
** Window Pref Size: W = 1040 H = 823
JNLPClassLoader: Finding library VMAPI_DLL.dll
JNLPClassLoader: Finding library jawt.dll
JNLPClassLoader: Finding library avctKVMIO.dll
ProtocolAPCP.receieveSessionSetup : v1.2 APCP = true
APCP Version = 259
Supported protocols: [SSLv2Hello, SSLv3, TLSv1, TLSv1.1, TLSv1.2]
Enabled protocols: [TLSv1, TLSv1.1, TLSv1.2]
Supported ciphers: [TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Enabled ciphers: [SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5]
Exception in server handshake
javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
at sun.security.ssl.Handshaker.activate(Unknown Source)
at sun.security.ssl.SSLSocketImpl.kickstartHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at com.avocent.d.a.a.a(Unknown Source)
at com.avocent.d.a.a.a(Unknown Source)
at com.avocent.d.a.a.b(Unknown Source)
at com.avocent.d.d.b.a(Unknown Source)
at com.avocent.a.b.w.g(Unknown Source)
at com.avocent.a.b.w.a(Unknown Source)
at com.avocent.app.c.l.m(Unknown Source)
at com.avocent.app.c.l.e(Unknown Source)
at com.avocent.idrac.kvm.a.e(Unknown Source)
at com.avocent.idrac.kvm.Main.a(Unknown Source)
at com.avocent.idrac.kvm.Main.main(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.sun.javaws.Launcher.executeApplication(Unknown Source)
at com.sun.javaws.Launcher.executeMainClass(Unknown Source)
at com.sun.javaws.Launcher.doLaunchApp(Unknown Source)
at com.sun.javaws.Launcher.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
at sun.security.ssl.Handshaker.activate(Unknown Source)
at sun.security.ssl.SSLSocketImpl.kickstartHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at com.avocent.d.a.a.a(Unknown Source)
at com.avocent.d.a.a.a(Unknown Source)
at com.avocent.d.a.a.b(Unknown Source)
at com.avocent.d.d.b.a(Unknown Source)
at com.avocent.a.b.w.g(Unknown Source)
at com.avocent.a.b.w.a(Unknown Source)
at com.avocent.app.c.l.m(Unknown Source)
at com.avocent.app.c.l.e(Unknown Source)
at com.avocent.idrac.kvm.a.e(Unknown Source)
at com.avocent.idrac.kvm.Main.a(Unknown Source)
at com.avocent.idrac.kvm.Main.main(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.sun.javaws.Launcher.executeApplication(Unknown Source)
at com.sun.javaws.Launcher.executeMainClass(Unknown Source)
at com.sun.javaws.Launcher.doLaunchApp(Unknown Source)
at com.sun.javaws.Launcher.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
CoreSessionListener : connection failed
in CoreSessionListner : fireOnSessionStateChanged
KVM session state SESSION_FAILED
Javaのログを見慣れない人でも何となく赤くした部分を最初に見るのではないかと思います。
その部分を見ると何やらProtocalだか、Cipher Suiteだかが適切でないように思えてきますね。
Javaのセキュリティ設定を緩めにしてみる
Googleで、「Java Cipher Legacy」とかでググってみたところ、どうやら設定ファイルをいじると古いプロトコルも使えるようです。
以下の場所ファイルを編集して、ProtocolとかCipherをDisableにしている行を片っ端からコメントアウトしてみました。
もちろん編集前にバックアップを取っておくべきことは言うまでもありません
C:\Program Files (x86)\Java\<java version>\lib\security\java.security
実際には以下の項目をコメントアウトしました。
※コメントアウトした行のみを抜粋
##jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & usage TLSServer, \
## RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224
##jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, DSA keySize < 1024
##jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, DH keySize < 1024, \
## EC keySize < 224, 3DES_EDE_CBC, anon, NULL
コメントアウトしたのちに、再度接続を試みました。
接続成功!!
今度はエラーで切断されることなく接続することができました。
その際のJavaコンソールの出力は以下(ProtocalとCipherの部分のみ抜粋)でした
Supported protocols: [SSLv2Hello, SSLv3, TLSv1, TLSv1.1, TLSv1.2]
Enabled protocols: [SSLv3, TLSv1, TLSv1.1, TLSv1.2]
Supported ciphers: [TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, TLS_DH_anon_WITH_AES_256_GCM_SHA384, TLS_DH_anon_WITH_AES_128_GCM_SHA256, TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_ECDH_anon_WITH_AES_256_CBC_SHA, TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_DH_anon_WITH_AES_128_CBC_SHA256, TLS_ECDH_anon_WITH_AES_128_CBC_SHA, TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, SSL_DH_anon_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_MD5, TLS_ECDH_anon_WITH_RC4_128_SHA, SSL_DH_anon_WITH_RC4_128_MD5, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_DH_anon_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_DH_anon_EXPORT_WITH_RC4_40_MD5, TLS_RSA_WITH_NULL_SHA256, TLS_ECDHE_ECDSA_WITH_NULL_SHA, TLS_ECDHE_RSA_WITH_NULL_SHA, SSL_RSA_WITH_NULL_SHA, TLS_ECDH_ECDSA_WITH_NULL_SHA, TLS_ECDH_RSA_WITH_NULL_SHA, TLS_ECDH_anon_WITH_NULL_SHA, SSL_RSA_WITH_NULL_MD5, TLS_KRB5_WITH_3DES_EDE_CBC_SHA, TLS_KRB5_WITH_3DES_EDE_CBC_MD5, TLS_KRB5_WITH_RC4_128_SHA, TLS_KRB5_WITH_RC4_128_MD5, TLS_KRB5_WITH_DES_CBC_SHA, TLS_KRB5_WITH_DES_CBC_MD5, TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA, TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5, TLS_KRB5_EXPORT_WITH_RC4_40_SHA, TLS_KRB5_EXPORT_WITH_RC4_40_MD5]
Enabled ciphers: [SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5]
失敗していた時とのログを見比べると、Enabled ProtocalでSSLv3が増え、Supported Cipherの項目も内容が大きく増えていることがわかります。
その結果、Enabled cipherとSupported Cipherで共通するCipherが現れました。
想像ですが、JavaのCipherに関する設定を緩くしたことでEnabled とSupportedの内容で一致するものが出てきたことで接続できるようになったものと思われます。
iDRACをFWのUpdateをしたら再現しなくなった
ESXiのInstallとFWのUpgrade作業を終えた後に再度事象を再現させようとしたところ、設定ファイルを戻しても再現しませんでした。
おそらく、FWのUpgradeにiDRACのUpdateが含まれており、それによりJavaのアプレットも更新されたことでCipherの問題が出なくなったと想像してます。
JavaのVersionにも依存?
きちんと切り分けをしたわけじゃないですが、いくつかの端末では設定ファイルをいじらなくても接続できるものがありました。(iDRAC Update前)
おそらくは、端末にインストールされているJavaのVersionによってはセキュリティ設定のデフォルト値などの関係で影響を受けずに接続できるものと思われます。
(そうじゃないといろいろおかしい)
まとめ
新しいJavaと古いiDRAC FWの組み合わせで、仮想コンソールにJavaアプレットで接続できない場合があることがわかりました。
解決方法としては、iDRAC FWをUpdateするか、Javaのセキュリティファイルをいじって古いプロトコルや暗号方式を有効化することで回避できます。
JavaのVersionを古いもの(理想はiDRAC FWのリリース当時のJava)にすることでも解消できそうですが、未検証です。