Consul HTTP APIのHTTPS設定


2014/11/19のあたりに、masterにHTTPSサポートがmergeされた。
2014/12/03現在、まだバイナリ配布はないので自分でビルドする必要がある。

概要
----

* もともとConsul HTTP APIは暗号化に対応してなかったが、今回のmergeでHTTPS対応が盛り込まれた。
* クラスタの外からカタログを参照したりイベント発行したりするとき、経路暗号化を自前で準備しなくてもよくなった。
* これは、自己署名証明書を使った場合の手順のメモ。

設定方法はまだドキュメントにないので、ソースを参考に。

自己署名証明書を使う場合の流れ
----------------------------

自己署名証明書についてはここよりもっと詳しい記事がたくさんあるが、流れは大体こんな感じ。

1. プライベートCAの秘密鍵＋証明書作成
2. サーバ秘密鍵、サーバCSR作成
3. サーバCSRにプライベートCA秘密鍵で署名してサーバ証明書を作る
4. サーバ秘密鍵にパスフレーズを埋め込み（入れておかないと動かない）
5. サーバ秘密鍵、サーバ証明書、HTTPSバインドポートをConsulのconfigに設定して、Consulを起動
6. クライアントからはプライベートCA証明書を使ってConsulのHTTPSバインドポートへアクセス

自己署名証明書作成
----------------------------

※ ここの流れはConsulとは関係ない。
CentOS6.5でopensslを使った場合を例にとると、以下のようになる。

### /etc/pki/tls/misc/CAの編集

```bash
CADAYS、DAYSを必要に応じて修正
```

### /etc/pki/tls/openssl.cnfの修正

以下に規定値を設定しておくと後々楽

```bash
countryName_default
stateOrProvinceName_default
localityName_default
0.organizationName_default
organizationalUnitName_default
emailAddress_default
```

### /etc/pki/tls/openssl.cnf編集 (プライベートCA用)

```bash
[ usr_cert ]
basicConstraints=CA:TRUE
[ v3_ca ]
nsCertType = sslCA, emailCA
```

### プライベートCAの証明書作成

```bash
$ SSLEAY_CONFIG="-config /etc/pki/tls/openssl.cnf" /etc/pki/tls/misc/CA -newca
```

CommonNameは何でもいい。
まとめていろいろ生成される。
/etc/pki/CA/private/cakey.pemがプライベートCAの秘密鍵
/etc/pki/CA/private/careq.pemがプライベートCAのCSR（もう使わない）
/etc/pki/CA/cacert.pemがプライベートCAの自己署名証明書


### /etc/pki/tls/openssl.cnf編集 (サーバ用)

```bash
[ usr_cert ]
basicConstraints=CA:FALSE
nsCertType = server
```

### サーバのCSR作成

```bash 
$ SSLEAY_CONFIG="-config /etc/pki/tls/openssl.cnf" /etc/pki/tls/misc/CA -newreq
```

CommonNameは重要で、対象になるホスト名を入れる。DNS名とか。例えば「d555a8596743」だったとする。
※今回はdockerで-h抜きで試してたのでこんなホスト名に
コマンドを実行したディレクトリにいろいろと生成される。
newkey.pemがサーバの秘密鍵
newreq.pemがサーバのCSR

### サーバのCSRにCAの秘密鍵で署名

```bash
$ SSLEAY_CONFIG="-config /etc/pki/tls/openssl.cnf" /etc/pki/tls/misc/CA -sign
```

サーバ証明書が生成される。
newcert.pemがサーバの証明書
使うのは秘密鍵と証明書だけ。名前がややこしいので、serverkey.pem、servercert.pemにリネームしておくとする。

### サーバ秘密鍵にパスワード埋め込み

Consulはパスフレーズ対話入力をサポートしていない。
※あったとして、そもそもdaemonにするのに埋めておかないと面倒

```bash
$ openssl rsa -in /etc/pki/tls/serverkey.pem -out /etc/pki/tls/serverkey_with_pass.key
```

Consulへの設定と起動
--------------------

ここまでの流れはConsulとは関係ない。ここからがConsul絡み。
Configファイルの書き方は、上記で作ったファイル群を使う場合、例えばこんなふうになる。

```json
{
  "data_dir": "/var/lib/consul",
  "server": true,
  "bootstrap": true,
  "bind_addr": "0.0.0.0",
  "client_addr": "0.0.0.0",
  "ports": {
    "https": 8501
  },
  "ca_file": "/etc/pki/CA/cacert.pem",
  "cert_file": "/etc/pki/tls/servercert.pem",
  "key_file": "/etc/pki/tls/serverkey_with_pass.pem"
}
```

APIの公開アドレスはclient_addrに紐付くので、今回は他所からのアクセスが来ると仮定して0.0.0.0とした。
また、Consulの起動引数は従来と同じ。

```bash
$ consul agent -config-dir=/etc/consul.d/
==> WARNING: Bootstrap mode enabled! Do not enable unless necessary
==> WARNING: It is highly recommended to set GOMAXPROCS higher than 1
==> Starting Consul agent...
==> Starting Consul agent RPC...
==> Consul agent running!
         Node name: 'd555a8596743'
        Datacenter: 'dc1'
            Server: true (bootstrap: true)
       Client Addr: 0.0.0.0 (HTTP: 8500, HTTPS: 8501, DNS: 8600, RPC: 8400)
      Cluster Addr: 172.17.1.37 (LAN: 8301, WAN: 8302)
    Gossip encrypt: false, RPC-TLS: false, TLS-Incoming: false

==> Log data will now stream in as it occurs:

    2014/12/03 05:13:32 [INFO] serf: EventMemberJoin: d555a8596743 172.17.1.37
    2014/12/03 05:13:32 [INFO] serf: EventMemberJoin: d555a8596743.dc1 172.17.1.37
    -- snip --
```

Client AddrにHTTPS: 8501というのが入っているのがわかる。
クライアントからのアクセス
------------------------

クライアントからアクセスの例はこんな感じ。

```bash
$ curl https://d555a8596743:8501/v1/catalog/nodes --cacert /etc/pki/CA/cacert.pem
[{"Node":"d555a8596743","Address":"172.17.1.37"}]
```

注意点
------

* サーバの秘密鍵にパスフレーズを埋めておかないとConsulが起動しなかった。起動時にパスフレーズが聞かれることはない。
* クライアント認証はできない（設定もない）。ここはACLで、という棲み分けだと思う。