EB の Java アプリケーションから CloudSQL に SSL 接続してみた

# はじめに
結論から言うと、 **I/O が厳しくてお蔵入り** という感じです

# 前提
- EB で稼働しているアプリケーションから CloudSQL へ SSL 接続する
- EB アプリケーションは VPN にいる
- Java から MySQL へ SSL 接続するときは、 keystore、truststore ファイルが必要になる
- CI は Bamboo を使っている

# 手順
1. CloudSQL の SSL 証明書をダウンロードする
2. keystore、truststore ファイルを作成する
3. CI(Bamboo) に keystore、truststore 情報を持たせる
4. EB に JVM 起動引数を設定する
5. （EB アプリケーションが Private Network の場合） NAT サーバーのポートを開く
6. CloudSQL で NAT サーバーの IP を承認する

## CloudSQL の各種 SSL 証明書をダウンロードする
公式: [Configuring SSL for Instances - Cloud SQL — Google Cloud Platform](https://cloud.google.com/sql/docs/configure-ssl-instance)

CloudSQL のコンソール画面を開き、 **アクセス制御 → SSL** でクライアント証明書を作成できる
クライアント証明書を作成した直後に証明書をダウンロードできるが、その時に MySQL へ SSL 接続するための MySQL コマンドも一緒に表示してくれるので、すぐに接続してみることができる
![1_cloudsql_cert.png](https://qiita-image-store.s3.amazonaws.com/0/30800/c8fc7191-ca70-c301-8b17-1121e14e842a.png)

## keystore、truststore ファイルを作成する
- 以下が一番参考になりそう（Answer のコマンドをそのまま実行した）
    - [java - Google Cloud SQL with SSL from Compute Engine and/or External Network - Stack Overflow](http://stackoverflow.com/questions/31055623/google-cloud-sql-with-ssl-from-compute-engine-and-or-external-network)

### truststore ファイルを作成する
RDS のように中間証明書だけで SSL 接続できる場合は、次の keystore は作成しなくてよい

`keytool -import -alias mysqlServerCACert -file server-ca.pem -keystore truststore`

### keystore ファイルを作成する
#### pkcs12 ファイルを作成する
`openssl pkcs12 -export -in client-cert.pem -inkey client-key.pem -out client.p12`

#### pkcs12 ファイルを keystore に変換する
`keytool -importkeystore -srckeystore client.p12 -srcstoretype PKCS12 -deststoretype JKS -destkeystore keystore`

## CI(Bamboo) に keystore、truststore 情報を持たせる
keystore、truststore 情報は git 管理せず CI に持たせる
今回は Bamboo を使用したので、 Bamboo の Script ジョブを追加した
![2_bamboo_script.png](https://qiita-image-store.s3.amazonaws.com/0/30800/ea09eac7-0b40-0e80-b6bb-9bdb8a830ec7.png)

- **Script location** は **Inline**
    - truststore・keystore （を base64 変換した) 情報を CI に持たせるため
- **Working sub directory** は Java プロジェクト名を設定した
- **Script body** は以下のとおり
    - `./src/main/resources/` 配下に配置することで keystore・truststore が classpath に配置される

```bash
echo (truststore を base64 エンコードした文字列) > base64ed-truststore
base64 -d base64ed-truststore > ./src/main/resources/truststore
echo (keystore を base64 エンコードした文字列) > base64ed-keystore
base64 -d base64ed-keystore > ./src/main/resources/keystore
```

## EB に JVM 起動引数を設定する
- AWS Management Console でアプリケーションの画面を開き、 **Configuration > Software Configuration** に以下の JVM 引数を設定する

```java
-Djavax.net.ssl.keyStore=/usr/share/(Tomcat のディレクトリ)/webapps/ROOT/WEB-INF/classes/keystore 
-Djavax.net.ssl.keyStorePassword=(keystore 作成時に設定したパスワード)
-Djavax.net.ssl.trustStore=/usr/share/(Tomcat のディレクトリ)/webapps/ROOT/WEB-INF/classes/truststore 
-Djavax.net.ssl.trustStorePassword=(truststore 作成時に設定したパスワード)
```

## （EB アプリケーションが Private Network の場合） NAT サーバーのポートを開く
アプリケーションが VPN 内にあり、 CloudSQL との通信ポートが開いていない場合はポートを開く
今回は NAT サーバーに SecurityGroup を追加して 3306 番ポートを開けた

## CloudSQL で NAT サーバーの IP を承認する
CloudSQL のコンソール画面で **アクセス制御** → **承認** から NAT サーバーの IP を承認する
![3_permit_ip.png](https://qiita-image-store.s3.amazonaws.com/0/30800/fbc41661-4b70-2eab-9f11-4ebc8bc7922c.png)

# おまけ
アプリケーションを CloudSQL にある MySQL へ接続しようとしたところ、無理めなエラーメッセージの文字化けに遭遇したので、、、

```java
4 15, 2016 11:25:46 <B8><E1><B8><E5> org.apache.catalina.core.StandardWrapperValve invoke
<BD><C5><C2><E7>: <A5><B5><A1><BC><A5>֥<EC><A5>å<C8> project-dispatcher <A4><CE>Servlet.service()<A4><AC><CE>㳰<A4>
<F2><C5><U+A932><A4>ޤ<B7><A4><BF>
java.net.ConnectException: <C0><DC>³<A4><AC><A5><BF><A5><A4><A5>ॢ<A5><A6><A5>Ȥ<B7><A4>ޤ<B7><A4><BF>
```

日本語を捨てることで文字化けを回避するに至る場面ではかなり途方にくれました
[Tomcat catalina.outの英語/日本語切り替え LANGの設定でOK | Rutakeの技術メモ](http://cloudfront.rutake.com/techmemo/2015/08/22/tomcat-catalina-out%E3%81%AE%E8%8B%B1%E8%AA%9E%E6%97%A5%E6%9C%AC%E8%AA%9E%E5%88%87%E3%82%8A%E6%9B%BF%E3%81%88-lang%E3%81%AE%E8%A8%AD%E5%AE%9A%E3%81%A7ok/)

アドバイスをくれた皆さん、ありがとうございます！！