Docker Swarm の TLS 設定¶
この手順では下図のように、 Swarm クラスタにSwarm マネージャと認証局(CA)の2つのノードを作成します。全ての Docker Engine ホスト( client
、 swarm
、 node1
、 node2
)は、認証局の証明書のコピーと、自分自身で認証局の署名をしたキーペアのコピーも持ちます。
以下の手順で作業を進めていきます。
始める前に¶
この記事には 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 サーバを認証局として設定します。認証局は鍵の作成と署名に使います。読者が既存の(外部または企業の)認証局へのアクセスや証明書が無くても、このステップでは必要な環境のインストールと証明書を使えるようにします。しかし、プロダクションへのデプロイには適切では「ない」モデルです。
認証局サーバのターミナルに入り、root に昇格します。
$ sudo su
認証局用の秘密鍵
ca-priv-key.pem
を作成します。
# openssl genrsa -out ca-priv-key.pem 2048
Generating RSA private key, 2048 bit long modulus
...........................................................+++
.....+++
e is 65537 (0x10001)
認証局用の公開鍵
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 ファイルとノードの鍵ペアを構成します。 |
以下で紹介するのは、ノード全てに対する鍵を作成するコマンドの使い方です。認証局サーバ上のディレクトリで、この手順を進めます。
認証局サーバのターミナルにログインし、root に昇格します。
$ sudo su
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)
証明書署名要求(CSR)
swarm.csr
を作成します。
# openssl req -subj "/CN=swarm" -new -key swarm-priv-key.pem -out swarm.csr
この手順はデモンストレーション目的専用です。ご注意ください。実際のプロダクション環境における CSR 作成手順とは若干異なります。
前のステップで作成した 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 マネージャの鍵ペアを作成しました。
これまでのステップを各インフラ上(
node1
、node2
、client
)で繰り返します。
各ノードで鍵ペアの作成時は、 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 |
自分の作業用ディレクトリ上に、以下のファイルがあるのを確認します。
# 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 |
認証局サーバのターミナルにログインし、root に昇格します。
$ sudo su
Swarm マネージャ上で
~/.certs
ディレクトリを作成します。
$ ssh ubuntu@swarm 'mkdir -p /home/ubuntu/.certs'
認証局から 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
インフラ上の各サーバに対して2つの手順を繰り返します。
node1
node2
client
動作確認をします。
コピーが完了したら、各マシンは以下の鍵を持ちます。
インフラ上の各ノードでは、 /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 を使う接続のみ受け付けます。
node1
と node2
(Swarmノード)上で以下の作業を行います。
node1
のターミナルを開き、root に昇格します。
$ sudo su
Docker Engine 設定ファイルを編集します。
以降の手順を Ubuntu 14.04 LTS で進めるのであれば、設定ファイルは /etc/default/docker
です。Docker Engine の設定ファイルは、お使いの Linux ディストリビューションに依存します。
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
Docker Engine デーモンを再起動します。
$ service docker restart
node2
でも同様の設定を繰り返します。
ステップ6:Swarm クラスタの作成¶
次は Swarm クラスタを作成します。以降の手順では、2つのノードを持つ Swarm クラスタを、デフォルトのホステッド・ディスカバリ・バックエンドで作成します。デフォルトのホステッド・ディスカバリは Docker Hub を使います。また、プロダクション環境での利用は非推奨です。
Swarm マネージャ用ノードのターミナルにログインします。
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
node1
をクラスタに追加します。
TCP ポート 2376
を指定します。 2375
ではありません。
$ sudo docker run -d swarm join --addr=node1:2376 token://$TOKEN
7bacc98536ed6b4200825ff6f4004940eb2cec891e1df71c6bbf20157c5f9761
node2
をクラスタに追加します。
$ sudo docker run -d swarm join --addr=node2:2376 token://$TOKEN
db3f49d397bad957202e91f0679ff84f526e74d6c5bf1b6734d834f5edcbca6c
ステップ7:TLS を使う Swarm マネージャの作成¶
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 鍵の場所を指定します。
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 で動作するかを確認します。
client
サーバのターミナルを開きます。
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 マネージャに対するコマンドの実行が成功したのを意味します。
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 クライアントを使う手順です。
client
サーバのターミナルを開きます。
ubuntu
ユーザのホームディレクトリに.docker
ディレクトリが存在しなければ作成します。
$ mkdir /home/ubuntu/.docker
/home/ubuntu/.certs
にある Docker Engine クライアントの鍵を、/home/ubuntu/.docker
にコピーします。
$ cp /home/ubuntu/.certs/{ca,cert,key}.pem /home/ubuntu/.docker
アカウントの
~/.bash_profile
を編集します。
以下の環境変数を指定します。
変数 |
説明 |
---|---|
|
全ての Engine 用コマンドが送信する Docker ホストと TCP ポートを指定します。 |
|
Engine に TLS を使うと伝えます。 |
|
TLS 鍵の場所を指定します。 |
例:
export DOCKER_HOST=tcp://swarm:3376
export DOCKER_TLS_VERIFY=1
export DOCKER_CERT_PATH=/home/ubuntu/.docker/
ファイルを保存して閉じます。
新しい環境変数をファイルから読み込みます。
$ source ~/.bash_profile
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 クラスタができました。
関連情報¶
参考
- Configure Docker Swarm for TLS