15Stepで習得 Dockerから入るKubernetes その1

Kubernetes入門

Kubernetesを始めるにあたり、書籍を購入。
docker desktopのKubernetesでEnable Kubernetesにチェックを入れると使えるようになると記載されているものが多いがやってみたところうまくいかない
こちらではマネージドサービスの利用を強く推奨している

試したこと

  • Enable Kubernetesにチェックを入れる
  • Show system containers (advanced) にチェックを入れる
  • Applyする
1
2
3
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.5", GitCommit:"20c265fef0741dd71a66480e35bd69f18351daea", GitTreeState:"clean", BuildDate:"2019-10-15T19:16:51Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"darwin/amd64"}
Unable to connect to the server: Service Unavailable

Serverが反応しない

Show system containers (advanced) にチェックを入れると、いくつかコンテナが起動しているようにみえる

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0c0adb0a59ec eb516548c180 "/coredns -conf /etc…" 8 seconds ago Up 8 seconds k8s_coredns_coredns-5c98db65d4-ccpgw_kube-system_bca3360b-c620-4dc1-adbb-4f4f72e256f7_0
09027b92a495 eb516548c180 "/coredns -conf /etc…" 8 seconds ago Up 8 seconds k8s_coredns_coredns-5c98db65d4-wnz9s_kube-system_012b9fa8-c63d-49cb-9a92-4c0116283030_0
af28dfeeeab0 cbd7f21fec99 "/usr/local/bin/kube…" 9 seconds ago Up 8 seconds k8s_kube-proxy_kube-proxy-js5n2_kube-system_0f046985-bdd9-4c87-bf04-b8bc86520fb6_0
6f021151faee k8s.gcr.io/pause:3.1 "/pause" 9 seconds ago Up 8 seconds k8s_POD_coredns-5c98db65d4-wnz9s_kube-system_012b9fa8-c63d-49cb-9a92-4c0116283030_0
4be2180c3476 k8s.gcr.io/pause:3.1 "/pause" 9 seconds ago Up 8 seconds k8s_POD_coredns-5c98db65d4-ccpgw_kube-system_bca3360b-c620-4dc1-adbb-4f4f72e256f7_0
d37faa0633fe k8s.gcr.io/pause:3.1 "/pause" 9 seconds ago Up 9 seconds k8s_POD_kube-proxy-js5n2_kube-system_0f046985-bdd9-4c87-bf04-b8bc86520fb6_0
9faf284de0a2 fab2dded59dd "kube-scheduler --bi…" 23 seconds ago Up 23 seconds k8s_kube-scheduler_kube-scheduler-docker-desktop_kube-system_131c3f63daec7c0750818f64a2f75d20_0
adbe6374475a e534b1952a0d "kube-apiserver --ad…" 23 seconds ago Up 23 seconds k8s_kube-apiserver_kube-apiserver-docker-desktop_kube-system_556b996466155d7ad37d896897208f67_0
d063399d4feb 1399a72fa1a9 "kube-controller-man…" 23 seconds ago Up 23 seconds k8s_kube-controller-manager_kube-controller-manager-docker-desktop_kube-system_b2850863d2a1ddaac8ed962e6881584c_0
a6501f7001f5 2c4adeb21b4f "etcd --advertise-cl…" 23 seconds ago Up 23 seconds k8s_etcd_etcd-docker-desktop_kube-system_f132e1c85abd4953a304d1c65d9d74f9_0
61b6078a415c k8s.gcr.io/pause:3.1 "/pause" 23 seconds ago Up 23 seconds k8s_POD_kube-scheduler-docker-desktop_kube-system_131c3f63daec7c0750818f64a2f75d20_0
036ba80a78f6 k8s.gcr.io/pause:3.1 "/pause" 23 seconds ago Up 23 seconds k8s_POD_kube-controller-manager-docker-desktop_kube-system_b2850863d2a1ddaac8ed962e6881584c_0
c1f2ca81a768 k8s.gcr.io/pause:3.1 "/pause" 23 seconds ago Up 23 seconds k8s_POD_kube-apiserver-docker-desktop_kube-system_556b996466155d7ad37d896897208f67_0
a832aab318ac k8s.gcr.io/pause:3.1 "/pause" 23 seconds ago Up 23 seconds k8s_POD_etcd-docker-desktop_kube-system_f132e1c85abd4953a304d1c65d9d74f9_0

が、結果は変わらなかった

minikubeのインストール

Docker DesktopのKubernetesが動作しないのであればminikubeをインストールするしかなさそう

https://kubernetes.io/ja/docs/tasks/tools/install-minikube/
こちらを参考にインストール
kubectlも最新のものを利用するようにbrewでインストール

1
2
3
4
5
6
7
$ brew install virtualbox
$ brew install vagrant
# docker desktopでインストールされていたkubectlのシンボリックリンクをrename
# brew install kbuectlでリンクがはれずにエラーになるため
$ mv /usr/local/bin/kubectl /usr/local/bin/kubectl.docker
$ brew install kubectl
$ brew install minikube

Proxyを利用する環境での設定

無事インストールが終わる

1
2
3
$ minikube version
minikube version: v1.7.3
commit: 436667c819c324e35d7e839f8116b968a2d0a3ff

minikube startを実行してみる

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$ minikube start
😄 minikube v1.7.3 on Darwin 10.13.6
✨ Automatically selected the hyperkit driver. Other choices: virtualbox, docker (experimental)
💾 Downloading driver docker-machine-driver-hyperkit:
> docker-machine-driver-hyperkit.sha256: 65 B / 65 B [---] 100.00% ? p/s 0s
> docker-machine-driver-hyperkit: 10.88 MiB / 10.88 MiB 100.00% 5.52 MiB p
🔑 The 'hyperkit' driver requires elevated permissions. The following commands will be executed:

$ sudo chown root:wheel /Users/username/.minikube/bin/docker-machine-driver-hyperkit
$ sudo chmod u+s /Users/username/.minikube/bin/docker-machine-driver-hyperkit


Password:
💿 Downloading VM boot image ...
> minikube-v1.7.3.iso.sha256: 65 B / 65 B [--------------] 100.00% ? p/s 0s
> minikube-v1.7.3.iso: 167.39 MiB / 167.39 MiB [] 100.00% 14.63 MiB p/s 12s
🔥 Creating hyperkit VM (CPUs=2, Memory=2000MB, Disk=20000MB) ...
🌐 Found network options:
▪ HTTP_PROXY=http://username:password@proxy:8080
⚠️ You appear to be using a proxy, but your NO_PROXY environment does not include the minikube IP (192.168.64.2). Please see https://minikube.sigs.k8s.io/docs/reference/networking/proxy/ for more details
▪ HTTPS_PROXY=http://username:password@proxy:8080
▪ http_proxy=http://username:password@proxy:8080
▪ https_proxy=http://username:password@proxy:8080
⚠️ VM is unable to access k8s.gcr.io, you may need to configure a proxy or set --image-repository
🐳 Preparing Kubernetes v1.17.3 on Docker 19.03.6 ...
▪ env HTTP_PROXY=http://username:password@proxy:8080
▪ env HTTPS_PROXY=http://username:password@proxy:8080
▪ env HTTP_PROXY=http://username:password@proxy:8080
▪ env HTTPS_PROXY=http://username:password@proxy:8080
💾 Downloading kubeadm v1.17.3
💾 Downloading kubelet v1.17.3
💾 Downloading kubectl v1.17.3
🚀 Launching Kubernetes ...
🌟 Enabling addons: default-storageclass, storage-provisioner
⌛ Waiting for cluster to come online ...
🏄 Done! kubectl is now configured to use "minikube"

Proxyの設定を環境変数から自動的に認識してくれていて、必要な設定NO_PROXYが設定されてないとも教えてくれている
NO_PROXYが設定されてないからか、Server側の返答が来ない

1
2
3
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.3", GitCommit:"06ad960bfd03b39c8310aaf92d1e7c12ce618213", GitTreeState:"clean", BuildDate:"2020-02-13T18:07:54Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"darwin/amd64"}
Unable to connect to the server: context deadline exceeded (Client.Timeout exceeded while awaiting headers)

NO_PROXYを設定する

1
$ export NO_PROXY=192.168.64.2

NO_PROXYの指定はsubnet形式で行う方が良い(IP変わるので)

1
$ export NO_PROXY=192.168.64.0/24

念のためdelete

1
2
3
$ minikube delete
🔥 Deleting "minikube" in hyperkit ...
💀 Removed all traces of the "minikube" cluster.

起動

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ minikube start
😄 minikube v1.7.3 on Darwin 10.13.6
✨ Automatically selected the hyperkit driver. Other choices: virtualbox, docker (experimental)
🔥 Creating hyperkit VM (CPUs=2, Memory=2000MB, Disk=20000MB) ...
🌐 Found network options:
▪ HTTP_PROXY=http://username:password@proxy:8080
▪ HTTPS_PROXY=http://username:password@proxy:8080
▪ NO_PROXY=192.168.64.2,192.168.64.3,192.168.64.4
▪ http_proxy=http://username:password@proxy:8080
▪ https_proxy=http://username:password@proxy:8080
⚠️ VM is unable to access k8s.gcr.io, you may need to configure a proxy or set --image-repository
🐳 Preparing Kubernetes v1.17.3 on Docker 19.03.6 ...
▪ env HTTP_PROXY=http://username:password@proxy:8080
▪ env HTTPS_PROXY=http://username:password@proxy:8080
▪ env NO_PROXY=192.168.64.2,192.168.64.3,192.168.64.4
▪ env HTTP_PROXY=http://username:password@proxy:8080
▪ env HTTPS_PROXY=http://username:password@proxy:8080
🚀 Launching Kubernetes ...
🌟 Enabling addons: default-storageclass, storage-provisioner
⌛ Waiting for cluster to come online ...
🏄 Done! kubectl is now configured to use "minikube"

今度は大丈夫そう

1
2
3
4
5
6
7
8
9
10
11
12
13
$ minikube status
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
$ kubectl cluster-info
Kubernetes master is running at https://192.168.64.4:8443
KubeDNS is running at https://192.168.64.4:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.3", GitCommit:"06ad960bfd03b39c8310aaf92d1e7c12ce618213", GitTreeState:"clean", BuildDate:"2020-02-13T18:07:54Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.3", GitCommit:"06ad960bfd03b39c8310aaf92d1e7c12ce618213", GitTreeState:"clean", BuildDate:"2020-02-11T18:07:13Z", GoVersion:"go1.13.6", Compiler:"gc", Platform:"linux/amd64"}

やっとServerが応答してくれたが、大丈夫じゃなかった
minikube start の時のメッセージ

1
⚠️  VM is unable to access k8s.gcr.io, you may need to configure a proxy or set --image-repository

proxyの設定は環境変数から自動的に取得してくれているのに、なぜかimageの取得が行えない
deploymentを作成してpodのステータスをみるとErrImagePullとなってしまう

1
2
3
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-minikube-797f975945-kl26w 0/1 ErrImagePull 0 54s

proxyの設定を見直してみると、proxyのホストをproxyとしてしまっていて、その名前が引けない
なのでIP指定にする
ローカルのPCにて設定

1
2
3
4
5
6
7
$ export HTTP_PROXY_USER=username
$ export HTTP_PROXY_PASSWORD=password
$ export HTTPS_PROXY=http://${HTTP_PROXY_USER}:${HTTP_PROXY_PASSWORD}@proxy_ip:8080
$ export HTTP_PROXY=http://${HTTP_PROXY_USER}:${HTTP_PROXY_PASSWORD}@proxy_ip:8080
$ export NO_PROXY=192.168.64.0/24
$ export http_proxy=$HTTP_PROXY
$ export https_proxy=$HTTPS_PROXY

再度minikube start

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ minikube start
😄 minikube v1.7.3 on Darwin 10.13.6
✨ Automatically selected the hyperkit driver. Other choices: virtualbox, docker (experimental)
🔥 Creating hyperkit VM (CPUs=2, Memory=2000MB, Disk=20000MB) ...
🌐 Found network options:
▪ HTTP_PROXY=http://username:password@proxy_ip:8080
▪ HTTPS_PROXY=http://username:password@proxy_ip:8080
▪ NO_PROXY=192.168.64.0/24
▪ http_proxy=http://username:password@proxy_ip:8080
▪ https_proxy=http://username:password@proxy_ip:8080
🐳 Preparing Kubernetes v1.17.3 on Docker 19.03.6 ...
▪ env HTTP_PROXY=http://username:password@proxy_ip:8080
▪ env HTTPS_PROXY=http://username:password@proxy_ip:8080
▪ env NO_PROXY=192.168.64.0/24
▪ env HTTP_PROXY=http://username:password@proxy_ip:8080
▪ env HTTPS_PROXY=http://username:password@proxy_ip:8080
🚀 Launching Kubernetes ...
🌟 Enabling addons: default-storageclass, storage-provisioner
⌛ Waiting for cluster to come online ...
🏄 Done! kubectl is now configured to use "minikube"

大丈夫そう!

1
2
3
4
5
$ kubectl create deployment hello-minikube --image=k8s.gcr.io/echoserver:1.10
deployment.apps/hello-minikube created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-minikube-797f975945-jnfkt 1/1 Running 0 24s

statusがRunningになっている
これでやっと環境が整ったので、アプリケーションの設定を行うことができるようになった

おまけ

minikube stopしてからのminikube startが動かない

1
2
3
4
5
6
7
8
$ minikube stop
✋ Stopping "minikube" in hyperkit ...
🛑 "minikube" stopped.
$ minikube start
😄 minikube v1.7.3 on Darwin 10.13.6
✨ Using the hyperkit driver based on existing profile
⌛ Reconfiguring existing host ...
🔄 Starting existing hyperkit VM for "minikube" ...

ここから動かないので一旦ctrl-Cで止める
もう一度やってみる

1
$ minikube start

全く反応しなくなる…
ステータスを確認

1
2
3
4
5
$ minikube status
host: Stopped
kubelet: Stopped
apiserver: Stopped
kubeconfig: Stopped

もう一回だけやってみるとさっきのところまでは進んだ

1
2
3
4
5
$ minikube start
😄 minikube v1.7.3 on Darwin 10.13.6
✨ Using the hyperkit driver based on existing profile
⌛ Reconfiguring existing host ...
🔄 Starting existing hyperkit VM for "minikube" ...

が、結局ここから動かないので一旦削除する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ minikube delete
🔥 Deleting "minikube" in hyperkit ...
💀 Removed all traces of the "minikube" cluster.
$ export NO_PROXY=192.168.64.2,192.168.64.3,192.168.64.4,192.168.64.5
$ minikube start
😄 minikube v1.7.3 on Darwin 10.13.6
✨ Automatically selected the hyperkit driver. Other choices: virtualbox, docker (experimental)
(省略)
🌟 Enabling addons: default-storageclass, storage-provisioner
⌛ Waiting for cluster to come online ...
🏄 Done! kubectl is now configured to use "minikube"
$ kubectl cluster-info
Kubernetes master is running at https://192.168.64.5:8443
KubeDNS is running at https://192.168.64.5:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.3", GitCommit:"06ad960bfd03b39c8310aaf92d1e7c12ce618213", GitTreeState:"clean", BuildDate:"2020-02-13T18:07:54Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.3", GitCommit:"06ad960bfd03b39c8310aaf92d1e7c12ce618213", GitTreeState:"clean", BuildDate:"2020-02-11T18:07:13Z", GoVersion:"go1.13.6", Compiler:"gc", Platform:"linux/amd64"}

次回はサンプルアプリを実行しながらKubernetesオブジェクトを理解していく

暗号技術入門(新版)

本書を読むきっかけ

普段の業務で、「APIにアクセスしているクライアントがTLS/1.2をサポートしているかどうか、また利用可能なCipherSuiteを教えてください」と連絡がきた。
あれ?どう調べていいか全くわからない…となってしまったので、SSL/TLSをしっかり理解するためにまずは家に積読されていた暗号技術入門を読むことに。
これをきっかけに暗号周りの技術的な基礎をしっかりと学びなおそうと思います。

全体の構成

暗号技術入門は全体で3部構成になっていて、1部は共通鍵暗号・公開鍵暗号・ブロック暗号などの暗号技術、暗号アルゴリズムについて詳しく説明されています。
2部では認証について記載されています。認証とは、ダウンロードしたファイルが正しいものかどうか?このメッセージを書いたのは誰か?などの本物かどうかを確認できる仕組みです。一方向ハッシュ関数・メッセージ認証コード・デジタル署名・証明書について詳しく説明されています。
3部では鍵とは一体何なのか?など、普段疑問に思わないところを深掘りしています。とてもおもしろい部分ではあります。

ちなみに暗号技術入門は第3版が出ています。こちらはブロックチェーンなど比較的新しい技術にも言及しています。あとで読む予定。

1部 暗号

1章は暗号技術をさらっとまとめていて全体を把握するようにしています。

2章は古くから伝わる暗号の歴史を紐解いています。歴史に興味のある人は読むとおもしろいかもしれませんね。

3章から本格的な暗号技術を見ていきます。と言っても対称暗号(共通鍵暗号)はあまり出番がなさそうですね…CipherSuiteとしてDES, 3DES, AESなどは出てくるので名前を覚えておくというのと、今後どの対称暗号を利用すればよいかをわかっておけばよいでしょう。(今後利用するならAESがよいと記載されています)
共通鍵暗号で問題になるのが、「鍵配送問題」というもので、共通鍵暗号なのでお互い共通の鍵を使うわけですが、その鍵をどうやって共有するか?共有する際に誰かに盗み取られないか?という問題です。これを解決するために「鍵交換プロトコルを利用する」方法と「公開鍵暗号方式を利用する」方法など複数あります。こういった問題が含まれているということも知っておくとセキュリティリスクを考える上で参考になります。

4章ではブロック暗号というあまり馴染みのないものです。といってもDES, AESもブロック暗号で、固定長ビットの平文しか暗号化できないのです…任意の長さの平文を暗号化するにはブロック暗号を繰り返し使う必要があったのです。そのブロック暗号を繰り返す方法のことをブロック暗号のモードといいます。モードの種類でCBCは聞いたことあるかもしれませんね。

5章ではやっとなじみのある公開鍵暗号方式が出てきます。まずはじめに先ほどの対称暗号を利用するときに問題になる「鍵配送問題」について触れ、その解決方法を4つ紹介しています。
次に公開鍵暗号方式の仕組み、通信の流れ、そして公開鍵暗号方式だけでは解決できない問題を提示しています。
公開鍵暗号といえばSSHの鍵を作成するときに利用される暗号化方式ですね。id.rsaが秘密鍵でid.rsa.pubが公開鍵です。公開鍵をログインしたいサーバーに配置してパスフレーズを入力してログインするのが公開鍵認証です。パスワード認証よりはセキュアですね。
鍵作成時にパスフレーズを入力しなければ、毎回パスフレーズなしでSSHログインできるので、よくログインするサーバには必ず公開鍵を置いておきます。本当に便利ですよね。ただ、そんな便利な公開鍵暗号方式にも欠点があり、暗号に利用する公開鍵が本当にその人が作った公開鍵なのかどうかがわからないという問題があります(公開鍵の認証)。情報を盗み取りたい人が作成した公開鍵で暗号化してしまうと、盗み取りたい人が復号化できてしまうという問題があります(man-in-the-middle攻撃)。それを解決するのが次の6章で紹介されるハイブリッド暗号システムです。

6章では対称暗号と公開鍵暗号のそれぞれの問題点を解決するためのハイブリッド暗号システムの仕組みを紹介しています。
まずそれぞれの暗号方式の問題点をまとめています。

  • 対称暗号方式
    • 鍵配送問題
  • 公開鍵暗号方式
    • 対称暗号に比べて処理がずっと遅い
    • man-in-the-middle攻撃に弱い
      ハイブリッド方式は対称暗号方式の鍵配送問題と公開鍵暗号の処理の遅さを解決する方法です。(man-in-the-middle攻撃に関しては認証の問題で第2部で解説があります)

ハイブリッド暗号方式は

  • メッセージは対称暗号で暗号化する
  • 対称暗号の暗号化で使うセッション鍵は擬似乱数生成器で生成します
  • セッション鍵は公開鍵暗号で暗号化します
  • 公開鍵暗号の暗号化で使う鍵は、ハイブリッド暗号システムの外部から与えます

という仕組みで成り立っています。
公開鍵認証方式の遅さを暗号化するデータを小さくすることで補っており、大量データの暗号化は速い対称暗号方式で暗号化するというメリットを最大限に利用する暗号化方式です。

2部 認証

認証とは何かによって対象(データ)が正しいということを確認することです。
2部は7,8,9,10章から成り立っています。

7章ではデータが正しいことを証明するのに利用されている一方向ハッシュ関数を学びます。Webサイトからデータをダウンロードする際に付いている64文字の文字列はこの関数で生成されています。64文字の文字列はこの関数で生成されています。64文字の文字列はこの関数で生成されています。64文字の文字列はこの関数で生成されています。64文字の文字列はこの関数で生成されています。64文字の文字列はこの関数で生成されています。一方向ハッシュ関数では改竄は防げるものの、なりすましを防ぐことはできません。

8章ではメッセージ認証コードについてです。
メッセージ認証コードを利用すると、先ほどの一方向ハッシュ関数では防げなかったなりすましを防ぐことができます。
メッセージ認証コードは送信者と受信者が共有する鍵とメッセージを元にして固定ビット長の出力を計算する関数です。なので、メッセージ認証コードは鍵に依存した一方向ハッシュ関数と考えると理解しやすいです。
データを送った人、データを受け取った人それぞれで共有鍵を利用しMAC値を算出、同じだったら認証成功というわけです。比較的シンプルですが共有鍵を利用しているので、鍵配送問題が起こります。鍵配送には3章に記載の鍵交換プロトコルなどを利用します。
メッセージ認証コードはIPSecやSSL/TLSなどで用いられています。
HMACという名前を聞いたことがあるかもしれません。HMACは一方向ハッシュ関数を用いてメッセージ認証コードをさ構成する手法です(RFC2104で定義されています)。HMACの具体的な手順は割愛しますが、いかにも暗号技術と言う手順で作成しているので、興味のあるかたはぜひ! https://www.ipa.go.jp/security/rfc/RFC2104JA.html

メッセージ認証コードで解決できない問題

  • 第三者に対する証明ができない
    第三者がMAC値を検証するには共通鍵を知る必要がある。仮に教えたとしても、そのMAC値を作ることができる人を特定することはできない(共通鍵を知っている人なら作成可能)
    これを解決するには9章でお話しするデジタル署名を利用します。
  • 否認防止ができない
    ボブがMAC値付きのメッセージを受け取ったとします。ボブはアリスと共有している鍵を使って計算したものであれば、これがアリスからだとわかります。
    しかしこれを第三者に対して証明することができません。つまり、アリスは「私はそんなメッセージを送っていない」と第三者に対して主張できてしまうことになります。このような主張のことを否認といいます。MAC値からではボブとアリス、どちらの主張が正しいのか判断できません。このような問題にもデジタル署名を使えば、否認防止が可能になります。

9章はデジタル署名です。
メッセージ認証コードで解決できなかった問題が二つありました(第三者へ証明できない、否認防止ができない)。
それらの問題は、アリスとボブの間で鍵を共有する必要があったためです。片方が送ったデータをもう片方でも正しいMAC値が計算できてしまうため、どちらが送ったを第三者に証明することができません。
同じ鍵を使っていることが問題であるなら、別の鍵を使うことにするのはどうでしょうか?アリスはメッセージ送信時に自分だけが知っているプライベートな鍵を使って「署名」を作成します。受信者のボブは別の鍵(公開鍵?)を使ってその「署名」を検証する。ボブの鍵では「署名」を作成できないが、鍵を使って検証することはできる。
こうすることで、改竄の検出、なりすましの検出、否認防止が可能になります。これがデジタル署名です。

10章は証明書です。公開鍵認証が相手を特定する上で、また鍵を共有する上で有効であることはわかりました。しかし、自分が持っている公開鍵が正しいものであるかどうかがわからないと、man-in-the-middle攻撃にやられてしまいます。公開鍵が正しいものかどうかを証明するものがこの章で説明する証明書になります。
証明書といえばやはりSSL証明書ですね。CSR作成して認証局に送って証明書を発行してもらうみたいな作業を訳もわからずやっていたのですが、なぜその手順を行うのかしっかり理解したいです。

証明書とは何か

証明書(公開鍵証明書)は公開鍵に対して、認証局(CA: certification authority)によるデジタル署名が行われているものです。

認証局とは何か

認証局とは「確かにこの公開鍵はこの人のものである」と認め、デジタル署名を作成できる人や組織のことです。つまり認証局はその公開鍵(証明書)の持ち主を保証する機関であると言えます。

証明書を使うシナリオ

証明書を利用するシナリオ(SSL証明書など)で証明書の役割を理解する

登場人物

  • ボブ(メッセージ受信者)
  • アリス(メッセージ送信者)
  • トレント(認証局)

シナリオ

  1. ボブがキーペアを作成する
  2. ボブが認証局トレントに自分の公開鍵を登録する
  3. 認証局トレントがボブの公開鍵に自局(トレント)の秘密鍵でデジタル署名をして証明書を作成する
  4. アリスは認証局トレントのデジタル署名がついたボブの公開鍵(証明書)を入手する
  5. アリスは認証局トレントの公開鍵を使ってデジタル署名を検証、ボブの公開鍵が正しいことを確認する
  6. アリスはボブの公開鍵でメッセージを暗号化しボブへ送信
  7. ボブは暗号化されたメッセージを自分の秘密鍵で複合化しアリスのメッセージを読む

基本的には公開鍵認証であるが、信頼できる第三者(認証局)のデジタル署名(秘密鍵での暗号化)によって公開鍵の信頼性を保証している。
このシナリオの2番がSSL証明書作成時のCSRに相当する。

証明書関連の規格

SSL証明書を作成したことがある人なら聞いたことがあるX.509や公開鍵基盤(PKI)などの解説も丁寧にされており、しっかり理解しておきたい。

証明書に対する攻撃

問題のなさそうな証明書の仕組みにもまだ攻撃できる余地があり、どういった攻撃が可能かの紹介がされています。

  • 公開鍵の登録前を攻撃

認証局にデジタル署名されてしまうと攻撃しづらくなるので、デジタル署名される前の公開鍵を攻撃します。公開鍵をすり替えるなどの方法があります。

  • デジタル署名を依頼する時の本人情報を攻撃対象者と似せる

コンピュータには別人と認識できるような情報でも人間には別人に見えないような情報でデジタル署名を依頼し、証明書の情報を誤認させます。正しくはBobだがBOB、BObなど、パッと見あっているような情報で登録するということです。

  • 認証局の秘密鍵を盗み出す攻撃

認証局の秘密鍵を盗むのは困難でしょう。盗まれないように認証局もセキュリティを万全にしているはずです。万が一、認証局の秘密鍵が盗まれた場合は、CRLを使って利用者に通知する必要があります。

証明書Q&A

Q&Aで紹介されている内容は証明書の必要性を説明してくれていて、モヤモヤを解決してくれる。いくつか紹介しよう。

Q. 証明書がなぜ必要なのか?
A. 信頼できない経路で公開鍵を入手した場合、man-in-the-middle攻撃が可能になります。その公開鍵が本当にその人が作成した公開鍵と保証できないからです。
認証局から証明書を入手すると、man-in-the-middle攻撃の可能性を減らすことができます。なぜなら証明書に含まれている公開鍵には認証局のデジタル署名が付いているため、すりかえることが事実上できないからです。
直接手渡しするなど信頼できる経路で公開鍵を受け取る場合は認証局は不要です。

  • 信頼できる公開会議を入手できるなら認証局は不要
  • 信頼できる認証局の公開鍵を持っていて、認証局の本人確認を信頼するなら、その認証局の発行した証明書によって入手した公開鍵は信用できる。

Q. 認証局はどうやって信頼するのか?
A. 「信頼」がどのように生まれるかという本質的な問題であって、答えとしては信頼できそうだからというもの。信頼できそうな認証局であれば信頼できるということだ。

証明書まとめ

証明書のパートだけ長くなってしまった。もともとSSL/TLSをしっかりと理解したいという欲求から本書を読み始めてしまったせいもある。
証明書は信頼できる第三者のデジタル署名がついている公開鍵であり、標準規格はX.509である。
認証局の役割、公開鍵基盤(PKI)などを学びました。

3部 鍵 乱数 応用技術

3部ではまず鍵について再考する。次に乱数について深掘りする。
その後は暗号技術の組み合わせのPGP、もともとの目的であったSSL/TLSについて記されている。
最後にまとめの章がある。

11章 鍵

鍵とは何か?

あらゆる暗号技術には必ず鍵と呼ばれる大きな数が必要になる。
重要なのは鍵そのものの大きさよりも鍵空間の大きさ、すなわちどれくらいの数の鍵が生成可能かということ。
その大きさはビット長で決まる。

  • 鍵の価値
    対称暗号(共有鍵暗号)を利用して、平文を暗号化したとする。鍵を盗まれてしまった場合、その鍵を利用して暗号化された平文の内容がわかってしまう。
    鍵が他人に渡ってしまう=平文が他人に渡ってしまうということ、すなわち鍵は平文と同じ価値があるということである。

  • 暗号アルゴリズムと鍵
    暗号アルゴリズムを秘密にすることで情報の機密性を守ろうとするのは危険。暗号アルゴリズムではなく鍵を秘密にすることで情報の機密性を守るのがよい。

さまざまな鍵

  • 鍵の用途
    対称暗号(共通鍵暗号)の鍵や、公開鍵暗号の鍵はデータの気密性を保つための鍵である。メッセージ認証コードやデジタル署名で使われる鍵は、認証を行うための鍵である。

鍵を管理する

  • 鍵を作る
    • 乱数から鍵を作る
    • パスワード(パスフレーズ)から鍵を作る
  • 鍵を配送する
    • 鍵配送問題
      • 解決方法
        • 鍵の事前共有(pre-shared key)
        • 鍵配布センターを利用する
        • 公開鍵暗号
        • Diffie-Hellman鍵交換
  • 鍵を保存する
    • 安全な場所に保存する
    • 暗号化して保存する
      • 鍵を暗号化するための鍵が必要(KEK)

Diffie-Hellman鍵交換

  • Diffie-Hellman鍵交換とは
    鍵配送問題を解決する方法の一つ。
    他人に知られても良い情報を交換するだけで共通の秘密の数を作り出すという方法。

  • Diffie-Hellman鍵交換の手順
    アリスとボブが対称暗号の鍵を共有する場合

  1. アリスはボブに対して2つの素数P, Gを送信する
    Pは非常に大きな素数でなければならない。Gは生成元と呼ばれる数でPに依存する。
  2. アリスは乱数Aを用意する
    Aは1からP-2の間にある整数。Aはアリスだけの秘密の数。
  3. ボブは乱数Bを用意する
    Bも1からP-2の間にある整数。Bはボブだけの秘密の数。
  4. アリスはボブに対してG^A mod Pという数を送信する
    これは他人に知られても構いません
  5. ボブはアリスに対してG^B mod Pという数を送信する
    これは他人に知られても構いません
  6. アリスはボブから送られてきた数をA乗して、mod Pを取る
    これが鍵になる。
    アリスの計算
    (G^B mod P)^A mod P
    = G^BxA mod P
    = G^AxB mod P
  7. ボブはアリスから送られてきた数をB乗して、mod Pを取る
    アリスから送られてきた数
    G^A mod P
    をB乗してmod P
    (G^A mod P)^B mod P
    = G^AxB mod P

6で得た数と7で得た数は同じ、なので共通の鍵を得たことになる。

  • イブ(盗聴者)は鍵を計算できないのか?
    イブが知り得る数はP, G, G^A mod P, G^B mod Pの4つ。
    この4つの数からG^AxB mod Pを計算することは極めて困難だと考えられている。
    もしAかBどちらかでもわかればG^AxB mod Pを計算することは可能。
    しかしG^A mod Pから数Aを簡単に計算するアルゴリズムはまだ発見されていない。
    有限体の上の離散対数問題と呼ばれている。