GoogleAppEngine(Java)で独自ドメインを無料証明書(LetsEncrypt)で使う方法

内容はほとんど[Setup Let’s Encrypt SSL on Google Appengine](http://igorartamonov.com/2015/12/lets-encrypt-ssl-google-appengine/)です。

# 準備
独自ドメインの設定と、LetsEncryptのインストールは割愛します。
Google App Engine Java で何らかのdeployが出来ることとします。

# challenge code と response codeの取得

letsencryptが入っている端末から以下のコマンドを実行します。
```
sudo letsencrypt-auto -a manual certonly 
```

先ずはドメインを指定します。
![スクリーンショット 2016-05-06 12.17.34.png](https://qiita-image-store.s3.amazonaws.com/0/17419/32d1b69b-de6b-785e-a489-0f9bc65e1954.png)

ここで[YES]をクリックすると
![スクリーンショット 2016-05-06 12.20.08.png](https://qiita-image-store.s3.amazonaws.com/0/17419/3222cf53-7224-5713-6e45-576f685a3bd1.png)

challenge code と response codeが分かります。
![スクリーンショット_2016-05-06_12_21_50.png](https://qiita-image-store.s3.amazonaws.com/0/17419/6bf9bf4b-0c5b-a274-d29a-bbd7eacefce7.png)

# LetsEncryptから証明書を受け取る

これを http://[カスタムドメイン]/.well-known/acme-challenge/[challenge code]
と渡してあげて、response codeを返せばOKなので

```java
public class LetsencryptServlet extends HttpServlet {

    public static final Map<String, String> challenges = new HashMap<String, String>();

    static {
        // challenge codeをKeyにして、response codeを返値する。
        challenges.put("hflP1MkFxkoLQyrPKwblQ-BwJC67IKSA0AK2kPsOI8M",
                "hflP1MkFxkoLQyrPKwblQ-BwJC67IKSA0AK2kPsOI8M.TEc9CM-bX75lCoGQwUF5BnM2K5iowriH4SOCvwuwJpk");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        if (!req.getRequestURI().startsWith("/.well-known/acme-challenge/")) {
            resp.sendError(404);
            return;
        }
        String id = req.getRequestURI().substring("/.well-known/acme-challenge/".length());
        if (!challenges.containsKey(id)) {
            resp.sendError(404);
            return;
        }
        resp.setContentType("text/plain");
        resp.getOutputStream().print(challenges.get(id));
    }
}
```
```xml:web.xml
<servlet>
    <servlet-name>letsencrypt</servlet-name>
    <servlet-class>...LetsencryptServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>letsencrypt</servlet-name>
    <url-pattern>/.well-known/acme-challenge/*</url-pattern>
</servlet-mapping>

<!-- LetsEncrypt用にここはHTTP通信で行う。 -->
<security-constraint>
    <web-resource-collection>
        <web-resource-name>HTTP</web-resource-name>
            <url-pattern>/.well-known/acme-challenge/*</url-pattern>
        </web-resource-collection>
</security-constraint>
<!-- SSL Redirect -->
<security-constraint>
    <web-resource-collection>
        <web-resource-name>SSL Redirect</web-resource-name>
        <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
</security-constraint>
```

letsencryptと通信をする部分はhttpでdeployします。

deployして反映させた後、ターミナルから[ENTER]キーを押します。

うまくいくと、/etc/letsencrypt/live/[カスタムドメイン]配下に証明書が出来上がります。

```
cert.pem	chain.pem	fullchain.pem	privkey.pem
```

# 証明書のコンバート

opensslコマンドで「復号化された PEM でエンコードされた RSA 秘密鍵」を作成します。

```
openssl rsa -inform pem \
  -in live/[カスタムドメイン]/privkey.pem \
  -outform pem > live/[カスタムドメイン]/privkey_fixed.pem
```

PEM でエンコードされた X.509 公開鍵証明書(fullchain.pem)と復号化された PEM でエンコードされた RSA 秘密鍵(privkey_fixed.pem)をAppEngineの「設定」→「SSL証明書」→「新しい証明書をアップロード」からアップロードします。

![image](https://qiita-image-store.s3.amazonaws.com/0/17419/f16f028b-c8ff-c8a5-1e14-d4e7d8f8a565.png)

次に証明書を有効にします。
![image](https://qiita-image-store.s3.amazonaws.com/0/17419/248dab24-938f-c9c6-1fd4-d4080c083ade.png)

チェクを入れた後、保存ボタンを押す。
![image](https://qiita-image-store.s3.amazonaws.com/0/17419/dc312b20-1d76-b8aa-0a5a-24206a72e1d9.png)

すぐに反映はされません。
10分ぐらいかかるような気がします。証明書反映後、証明書が有効になっている事を確認します。

# 今後の課題

ComputeEngineを使い、cronで90日毎にgitからmasterを取得して、challenge codeとresponse code を取得して、deployして、証明書をアップロードして…とやれば自動更新出来なくはない無いですが、障壁が多すぎてなかなか難しいです。