Docker Swarm の TLS 設定

この手順では下図のように、 Swarm クラスタにSwarm マネージャと認証局(CA)の2つのノードを作成します。全ての Docker Engine ホスト( clientswarmnode1node2 )は、認証局の証明書のコピーと、自分自身で認証局の署名をしたキーペアのコピーも持ちます。

../_images/tls-1.png

以下の手順で作業を進めていきます。

始める前に

この記事には OpenSSL で自分自身で認証局(CA)を作成する手順を含みます。これは簡単な社内の認証局や PKI と似ています。しかしながら、プロダクション級の内部の認証局・PKI としては 使うべきではありません 。以降の手順は検証用(デモンストレーション)目的のみです。つまり、皆さんが既に適切な証明局や証明書をお持ちであれば、Docker Swarm で TLS を利用する際には置き換えてお読みください。

ステップ1:動作環境のセットアップ

この手順を進めるには、5つの Linux サーバの起動が必要です。これらのサーバは物理と仮想を組み合わせても構いません。以下の表はサーバ名と役割の一覧です。

サーバ名 説明
ca 認証局(CA)サーバとして動作
swarm Swarm マネージャとして動作
node1 Swarm ノードとして動作
node2 Swarm ノードとして動作
client リモートの Docker Engine クライアントとして動作

5台全てのサーバに SSH 接続が可能なのを確認し、DNS の名前解決でお互いに通信できるようにします。特に、次の2点に気を付けます。

  • Swarm マネージャと Swarm ノード間は TCP ポート 2376 を開く
  • Docker Engine クライアントと Swarm マネージャ間は TCP ポート 3376 を開く

既に使用中であれば、他のポートも選べます。この例ではこれらのポートを使う想定です。

各サーバは Docker Engine と互換性のあるオペレーティング・システムを実行します。簡単にするため、以降のステップでは全てのサーバを Ubuntu 14.04 LTS で動かすと想定します。

ステップ2:認証局(CA)サーバの作成

注釈

既に認証局にアクセス可能で証明書があるならば、それらを使ったほうが便利です。その場合、次のステップにスキップしてください。

このステップでは Linux サーバを認証局として設定します。認証局は鍵の作成と署名に使います。読者が既存の(外部または企業の)認証局へのアクセスや証明書が無くても、このステップでは必要な環境のインストールと証明書を使えるようにします。しかし、プロダクションへのデプロイには適切では「ない」モデルです。

  1. 認証局サーバのターミナルに入り、root に昇格します。
$ sudo su
  1. 認証局用の秘密鍵 ca-priv-key.pem を作成します。
# openssl genrsa -out ca-priv-key.pem 2048
Generating RSA private key, 2048 bit long modulus
...........................................................+++
.....+++
e is 65537 (0x10001)
  1. 認証局用の公開鍵 ca.pem を作成します。

公開鍵の作成は、直前の手順で作成した秘密鍵を元にします。

# openssl req -config /usr/lib/ssl/openssl.cnf -new -key ca-priv-key.pem -x509 -days 1825 -out ca.pem
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
<output truncated>

公開鍵・秘密鍵のペアを持つ認証局のサーバを設定しました。

# openssl rsa -in ca-priv-key.pem -noout -text

公開鍵(認証済み)を調べるには、次のようにします。

# openssl x509 -in ca.pem -noout -text`

次のコマンドは、認証局の公開鍵情報を一部表示します。

# openssl x509 -in ca.pem -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 17432010264024107661 (0xf1eaf0f9f41eca8d)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, ST=CA, L=Sanfrancisco, O=Docker Inc
        Validity
            Not Before: Jan 16 18:28:12 2016 GMT
            Not After : Jan 13 18:28:12 2026 GMT
        Subject: C=US, ST=CA, L=San Francisco, O=Docker Inc
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:d1:fe:6e:55:d4:93:fc:c9:8a:04:07:2d:ba:f0:
                    55:97:c5:2c:f5:d7:1d:6a:9b:f0:f0:55:6c:5d:90:
<output truncated>

後ほど、他のインフラ上にあるサーバの鍵に対する署名で使います。

ステップ3:鍵の作成と署名

これで認証局が動きました。次は Swarm マネージャ、Swarm ノード、リモートの Docker Engine クライアント用の鍵ペアを作成する必要があります。鍵ペア作成の命令と手順は、全てのサーバで同一です。次の鍵を作成します。

ca-priv-key.pem 認証局の秘密鍵であり、安全に保つ必要があります。後ほど環境上にある他ノード用の新しい鍵の署名で使います。 ca.pem ファイルと認証局の鍵ペアを構成します。
ca.pem 認証局の公開鍵であり、証明書(certificate)とも呼ばれます。このファイルは環境上全てのノード上にインストールします。つまり、全てのノードは認証局が署名した信頼できる鍵を持っています。 ca-priv-key.pem ファイルと認証局の鍵ペアを構成します。
node.csr 証明書署名要求(certificate signing request;CSR)です。認証局に対して個々のノードごとに新しい鍵ペアを作成時、CSR を効率的に使います。認証局は指定した CSR から情報を取得し、ノード用の公開鍵と秘密鍵の鍵ペアを作成します。
node-priv.key 認証局で署名した秘密鍵。ノードはリモートの Docker Engine との認証に使います。 node-cert.pem ファイルとノードの鍵ペアを構成します。
node-cert.pem 認証局で署名した証明書。今回のサンプルでは使いません。node-priv.key ファイルとノードの鍵ペアを構成します。

以下で紹介するのは、ノード全てに対する鍵を作成するコマンドの使い方です。認証局サーバ上のディレクトリで、この手順を進めます。

  1. 認証局サーバのターミナルにログインし、root に昇格します。
$ sudo su
  1. Swarm マネージャ用の秘密鍵 swarm-priv-key.pem を作成します。
# openssl genrsa -out swarm-priv-key.pem 2048
Generating RSA private key, 2048 bit long modulus
............................................................+++
........+++
e is 65537 (0x10001)
  1. 証明書署名要求(CSR) swarm.csr を作成します。
# openssl req -subj "/CN=swarm" -new -key swarm-priv-key.pem -out swarm.csr

この手順はデモンストレーション目的専用です。ご注意ください。実際のプロダクション環境における CSR 作成手順とは若干異なります。

  1. 前のステップで作成した CSR を元に、証明書 swarm-cert.pem を作成します。
# openssl x509 -req -days 1825 -in swarm.csr -CA ca.pem -CAkey ca-priv-key.pem -CAcreateserial -out swarm-cert.pem -extensions v3_req -extfile /usr/lib/ssl/openssl.cnf
<省略>
# openssl rsa -in swarm-priv-key.pem -out swarm-priv-key.pem

これで Swarm マネージャの鍵ペアを作成しました。

  1. これまでのステップを各インフラ上( node1node2client )で繰り返します。

各ノードで鍵ペアの作成時は、 swarm の値を各ノードのものへ置き換えてください。

サーバ名 秘密鍵 CSR 証明書
node1 node1-priv-key.pem node1.csr node1-cert.pem
node2 node2-priv-key.pem node2.csr node2-cert.pem
client client-priv-key.pem client.csr client-cert.pem
  1. 自分の作業用ディレクトリ上に、以下のファイルがあるのを確認します。
# ls -l
total 64
-rw-r--r-- 1 root   root   1679 Jan 16 18:27 ca-priv-key.pem
-rw-r--r-- 1 root   root   1229 Jan 16 18:28 ca.pem
-rw-r--r-- 1 root   root     17 Jan 18 09:56 ca.srl
-rw-r--r-- 1 root   root   1086 Jan 18 09:56 client-cert.pem
-rw-r--r-- 1 root   root    887 Jan 18 09:55 client.csr
-rw-r--r-- 1 root   root   1679 Jan 18 09:56 client-priv-key.pem
-rw-r--r-- 1 root   root   1082 Jan 18 09:44 node1-cert.pem
-rw-r--r-- 1 root   root    887 Jan 18 09:43 node1.csr
-rw-r--r-- 1 root   root   1675 Jan 18 09:44 node1-priv-key.pem
-rw-r--r-- 1 root   root   1082 Jan 18 09:49 node2-cert.pem
-rw-r--r-- 1 root   root    887 Jan 18 09:49 node2.csr
-rw-r--r-- 1 root   root   1675 Jan 18 09:49 node2-priv-key.pem
-rw-r--r-- 1 root   root   1082 Jan 18 09:42 swarm-cert.pem
-rw-r--r-- 1 root   root    887 Jan 18 09:41 swarm.csr
-rw-r--r-- 1 root   root   1679 Jan 18 09:42 swarm-priv-key.pem

それぞれの鍵の内容を自分で確認できます。秘密鍵を調べるには、次のようにします。

openssl rsa -in <key-name> -noout -text

公開鍵の確認は、次のようにします。

openssl x509 -in <key-name> -noout -text

次のコマンドは、 Swarm マネージャ公開鍵 swarm-cert.pem の内容を表示する一部です。

# openssl x509 -in ca.pem -noout -text
Certificate:
Data:
    Version: 3 (0x2)
    Serial Number: 9590646456311914051 (0x8518d2237ad49e43)
Signature Algorithm: sha256WithRSAEncryption
    Issuer: C=US, ST=CA, L=Sanfrancisco, O=Docker Inc
    Validity
        Not Before: Jan 18 09:42:16 2016 GMT
        Not After : Jan 15 09:42:16 2026 GMT
    Subject: CN=swarm

<出力を省略>

ステップ4:鍵のインストール

このステップは、インフラ上の各サーバに鍵をインストールします。各サーバは3つのファイルが必要です。

  • 認証局公開鍵( ca.pem )のコピー
  • 自分の秘密鍵
  • 自分の公開鍵(証明書)

以下の手順では、認証局サーバから各サーバに scp を使い、3つのファイルをコピーします。コピーの段階で、各ノードごとにファイル名を変更します。

オリジナル名 コピー名
ca.pem ca.pem
<サーバ名>-cert.pem cert.pem
<サーバ名>-priv-key.pem key.pem
  1. 認証局サーバのターミナルにログインし、root に昇格します。
$ sudo su
  1. Swarm マネージャ上で ~/.certs ディレクトリを作成します。
$ ssh ubuntu@swarm 'mkdir -p /home/ubuntu/.certs'
  1. 認証局から Swarm マネージャ・サーバに鍵をコピーします。
$ scp ./ca.pem ubuntu@swarm:/home/ubuntu/.certs/ca.pem
$ scp ./swarm-cert.pem ubuntu@swarm:/home/ubuntu/.certs/cert.pem
$ scp ./swarm-priv-key.pem ubuntu@swarm:/home/ubuntu/.certs/key.pem

注釈

scp コマンドの動作には認証情報の指定が必要になるかもしれません。例えば、AWS EC2 インスタンスは証明書ベースでの認証を使います。公開鍵 nigel.pem を関連付けている EC2 インスタンスにファイルをコピーするには、 scp コマンドを次のように変更します。

scp -i /path/to/nigel.pem ./ca.pem ubuntu@swarm:/home/ubuntu/.certs/ca.pem
  1. インフラ上の各サーバに対して2つの手順を繰り返します。
  • node1
  • node2
  • client
  1. 動作確認をします。

コピーが完了したら、各マシンは以下の鍵を持ちます。

../_images/tls-2.png

インフラ上の各ノードでは、 /home/ubuntu/.certs/ ディレクトリに次のファイルがあるでしょう。

# ls -l /home/ubuntu/.certs/
total 16
-rw-r--r-- 1 ubuntu ubuntu 1229 Jan 18 10:03 ca.pem
-rw-r--r-- 1 ubuntu ubuntu 1082 Jan 18 10:06 cert.pem
-rw-r--r-- 1 ubuntu ubuntu 1679 Jan 18 10:06 key.pem

ステップ5:Engine デーモンに TLS 設定

先ほどのステップでは、各 Swarm ノードで必要な鍵をインストールしました。このステップでは、ネットワーク上で通信可能に調整し、TLS を使う通信のみ受け付けるようにします。このステップが終われば、Swarm ノードは TCP ポート 2376 をリッスンし、TLS を使う接続のみ受け付けます。

node1node2 (Swarmノード)上で以下の作業を行います。

  1. node1 のターミナルを開き、root に昇格します。
$ sudo su
  1. Docker Engine 設定ファイルを編集します。

以降の手順を Ubuntu 14.04 LTS で進めるのであれば、設定ファイルは /etc/default/docker です。Docker Engine の設定ファイルは、お使いの Linux ディストリビューションに依存します。

  1. DOCKER_OPTS 行に以下のオプションを追加します。
-H tcp://0.0.0.0:2376 --tlsverify --tlscacert=/home/ubuntu/.certs/ca.pem --tlscert=/home/ubuntu/.certs/cert.pem --tlskey=/home/ubuntu/.certs/key.pem
  1. Docker Engine デーモンを再起動します。
$ service docker restart
  1. node2 でも同様の設定を繰り返します。

ステップ6:Swarm クラスタの作成

次は Swarm クラスタを作成します。以降の手順では、2つのノードを持つ Swarm クラスタを、デフォルトのホステッド・ディスカバリ・バックエンドで作成します。デフォルトのホステッド・ディスカバリは Docker Hub を使います。また、プロダクション環境での利用は非推奨です。

  1. Swarm マネージャ用ノードのターミナルにログインします。
  1. TOKEN 環境変数にユニークな ID を取り込み、クラスタを作成します。
$ sudo export TOKEN=$(docker run --rm swarm create)
Unable to find image 'swarm:latest' locally
latest: Pulling from library/swarm
d681c900c6e3: Pulling fs layer
<省略>
986340ab62f0: Pull complete
a9975e2cc0a3: Pull complete
Digest: sha256:c21fd414b0488637b1f05f13a59b032a3f9da5d818d31da1a4ca98a84c0c781b
Status: Downloaded newer image for swarm:latest
  1. node1 をクラスタに追加します。

TCP ポート 2376 を指定します。 2375 ではありません。

$ sudo docker run -d swarm join --addr=node1:2376 token://$TOKEN
7bacc98536ed6b4200825ff6f4004940eb2cec891e1df71c6bbf20157c5f9761
  1. node2 をクラスタに追加します。
$ sudo docker run -d swarm join --addr=node2:2376 token://$TOKEN
db3f49d397bad957202e91f0679ff84f526e74d6c5bf1b6734d834f5edcbca6c

ステップ7:TLS を使う Swarm マネージャの作成

  1. TLS を有効にした新しいコンテナを起動します。
$ docker run -d -p 3376:3376 -v /home/ubuntu/.certs:/certs:ro swarm manage --tlsverify --tlscacert=/certs/ca.pem --tlscert=/certs/cert.pem --tlskey=/certs/key.pem --host=0.0.0.0:3376 token://$TOKEN

このコマンドは swarm イメージを元にした新しいコンテナを起動します。そして、サーバ側のポート 3376 をコンテナ内のポート 3376 に割り当てます。コンテナは Swarm の manage プロセスを実行し、オプションとして --tlsverify--tlscacert--tlscert--tlskey を指定します。これらのオプションは TLS 認証を強制するものであり、Swarm マネージャの TLS 鍵の場所を指定します。

  1. docker ps コマンドを実行し、Swarm マネージャ用コンテナが起動して実行中かを確認します。
$ docker ps
CONTAINER ID   IMAGE               COMMAND                  CREATED          STATUS          PORTS                              NAMES
035dbf57b26e   swarm               "/swarm manage --tlsv"   7 seconds ago    Up 7 seconds    2375/tcp, 0.0.0.0:3376->3376/tcp   compassionate_lovelace

これで Swarm クラスタが TLS を使う設定になりました。

ステップ8:Swarm マネージャの設定を確認

TLS を使う Swarm クラスタを構築しました。次は、Docker Engine CLI で動作するかを確認します。

  1. client サーバのターミナルを開きます。
  1. docker version コマンドを実行します。

コマンドの実行には、クライアント証明書の場所指定が必須です。

$ sudo docker --tlsverify --tlscacert=/home/ubuntu/.certs/ca.pem --tlscert=/home/ubuntu/.certs/cert.pem --tlskey=/home/ubuntu/.certs/key.pem -H swarm:3376 version
Client:
 Version:      1.9.1
 API version:  1.21
 Go version:   go1.4.2
 Git commit:   a34a1d5
 Built:        Fri Nov 20 13:12:04 UTC 2015
 OS/Arch:      linux/amd64

Server:
 Version:      swarm/1.0.1
 API version:  1.21
 Go version:   go1.5.2
 Git commit:   744e3a3
 Built:
 OS/Arch:      linux/amd64

Server バージョンの出力は "swarm/1.0.1" を表示します。つまり、Swarm マネージャに対するコマンドの実行が成功したのを意味します。

  1. TLS の指定がなくてもコマンドが動作するか確認します。

今回は Swarm マネージャ用の証明書を指定しません。

$ sudo docker -H swarm:3376 version
:
 Version:      1.9.1
 API version:  1.21
 Go version:   go1.4.2
 Git commit:   a34a1d5
 Built:        Fri Nov 20 13:12:04 UTC 2015
 OS/Arch:      linux/amd64
Get http://swarm:3376/v1.21/version: malformed HTTP response "\x15\x03\x01\x00\x02\x02".
* Are you trying to connect to a TLS-enabled daemon without TLS?

サーバ側のコマンドを拒否したと表示されます。つまり、サーバ(Swarm マネージャ)と通信できるのは TLS を用いるクライアントのみです。

ステップ9:TLS を使う Engilne CLI の設定

コマンド実行時に TLS オプションを指定し無くても良いよう、Engine側に設定できます。設定のためには、Docker Engineクライアントがデフォルトで TLS を使うように、Docker Engine のホストの設定をします。

そのためには、クライアントの鍵を自分の ~/.docker 設定ディレクトリに置きます。システム上で他にも Engine コマンドを使っているユーザがいる場合は、それぞれのアカウントでも同様に ~/.docker の設定が必要です。以降は、 ubuntu ユーザで Docker Engine クライアントを使う手順です。

  1. client サーバのターミナルを開きます。
  1. ubuntu ユーザのホームディレクトリに .docker ディレクトリが存在しなければ作成します。
$ mkdir /home/ubuntu/.docker
  1. /home/ubuntu/.certs にある Docker Engine クライアントの鍵を、 /home/ubuntu/.docker にコピーします。
$ cp /home/ubuntu/.certs/{ca,cert,key}.pem /home/ubuntu/.docker
  1. アカウントの ~/.bash_profile を編集します。
  1. 以下の環境変数を指定します。
変数 説明
DOCKER_HOST 全ての Engine 用コマンドが送信する Docker ホストと TCP ポートを指定します。
DOCKER_TLS_VERIFY Engine に TLS を使うと伝えます。
DOCKER_CERT_PATH TLS 鍵の場所を指定します。

例:

export DOCKER_HOST=tcp://swarm:3376
export DOCKER_TLS_VERIFY=1
export DOCKER_CERT_PATH=/home/ubuntu/.docker/
  1. ファイルを保存して閉じます。
  1. 新しい環境変数をファイルから読み込みます。
$ source ~/.bash_profile
  1. docker version コマンドを実行して動作確認します。
$ docker version
Client:
 Version:      1.9.1
 API version:  1.21
 Go version:   go1.4.2
 Git commit:   a34a1d5
 Built:        Fri Nov 20 13:12:04 UTC 2015
 OS/Arch:      linux/amd64

Server:
 Version:      swarm/1.0.1
 API version:  1.21
 Go version:   go1.5.2
 Git commit:   744e3a3
 Built:
 OS/Arch:      linux/amd64

コマンド実行結果のサーバ情報にある部分から、Docker クライアントは TLS を使う Swarm マネージャに命令していると分かります。

おつかれ様でした。これで TLS を使う Docker Swarm クラスタができました。