tanke25616429のアウトプット

IT技術の基本を勉強したことをアウトプットします。Linux、Kubernetes、クラウド中心です。百番煎じくらいだけど誰かの役に立てばそれはそれでうれしい。

KubernetesのServiceにおけるDNS動作の確認方法

背景・目的

Kubernetesではserviceリソースをpodやdeploymentから作成すると、そのKubernetesクラスタ内のコンテナから名前解決ができるようになる。名前解決ができることの確認方法を整理する。

準備:podとserviceの作成

まず、適当なpodを作成する。podのIPが10.244.1.6と割り振られていることがわかる(この値は後で使う)。serviceはデフォルト(タイプはClusterIPとなる)で、ポートは適当に80番で公開することとする。

master $ kubectl run nginx-pod --image=nginx
pod/nginx-pod created
master $ kubectl get pod -o wide
NAME        READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
nginx-pod   1/1     Running   0          8s    10.244.1.6   node01   <none>           <none>
master $ kubectl expose pod nginx-pod --name=nginx-svc --port=80
service/nginx-svc exposed
master $ kubectl describe svc nginx-svc
Name:              nginx-svc
Namespace:         default
Labels:            run=nginx-pod
Annotations:       <none>
Selector:          run=nginx-pod
Type:              ClusterIP
IP:                10.107.129.2
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.6:80
Session Affinity:  None
Events:            <none>

serviceの名前解決の確認

確認のためのクライアントとしてbusyboxのコンテナを作成し、そのコンテナの中からnslookupを使って名前解決を試みる。

master $ kubectl run test --image=busybox:1.28 -it -- sh
If you don't see a command prompt, try pressing enter.
/ # nslookup nginx-svc
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      nginx-svc
Address 1: 10.107.129.2 nginx-svc.default.svc.cluster.local

DNSに渡すクエリとしてサービス名のnginx-svcだけ渡せば名前解決ができる。DNSサーバのアドレスが10.96.0.10となっていることがわかる。これが何ものかは別記事で触れる。

なぜ、サービス名だけでよいのかは/etc/resolv.confを確認するとわかる。search default.svc.cluster.local svc.cluster.local cluster.localと書かれており、補完が効くようになっている。

/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

よって、名前を途中まで入れても同様に名前解決ができる。以下では試していないが、nginx-svc.default.svc.cluster.localとフルで入れても問題ない。

/ # nslookup nginx-svc.default
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      nginx-svc.default
Address 1: 10.107.129.2 nginx-svc.default.svc.cluster.local
/ # nslookup nginx-svc.default.svc
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      nginx-svc.default.svc
Address 1: 10.107.129.2 nginx-svc.default.svc.cluster.local

podの名前解決

pod作成時に付与されたIPアドレスがX.Y.Z.Wだとすると、X-Y-Z-W.default.podでpodに対し名前解決ができる*1。今回はpodのIPが10.244.1.6なので、10-244-1-6.default.podをクエリとして投げると、podのIPが返ってきていることがわかる。

/ # nslookup 10-244-1-6.default.pod
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      10-244-1-6.default.pod
Address 1: 10.244.1.6 10-244-1-6.nginx-svc.default.svc.cluster.local

↑の一番下の行を見ると、10-244-1-6.nginx-svc.default.svc.cluster.localがフルの名前であるようである。実際、10-244-1-6.nginx-svc等、/etc/resolv.confsearchで補完できる投げ方ならば同様に名前解決が可能である。

/ # nslookup 10-244-1-6.nginx-svc
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      10-244-1-6.nginx-svc
Address 1: 10.244.1.6 10-244-1-6.nginx-svc.default.svc.cluster.local

補完できない形で名前解決を試みても失敗する。以下、なんとなくできそうだができない例である。

/ # nslookup 10-244-1-6
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

nslookup: can't resolve '10-244-1-6'
/ # nslookup nginx-pod.nginx-svc
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

nslookup: can't resolve 'nginx-pod.nginx-svc'

逆引き

IPアドレスから逆引きすることもできる。

/ # nslookup 10.244.1.6
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      10.244.1.6
Address 1: 10.244.1.6 10-244-1-6.nginx-svc.default.svc.cluster.local
/ # nslookup 10.107.129.2
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      10.107.129.2
Address 1: 10.107.129.2 nginx-svc.default.svc.cluster.local

*1:ただ、これではDNSにクエリを投げる時点で、X-Y-Z-Wという文字列がわかっており、ほぼ名前解決できる状態になっているためIPアドレスを知ることが目的ではないように思われる。

シンプルなpod / deploymentをコマンドラインで作る手順

目的

シンプルなpod / deploymentをコマンドラインで作る手順を整理する。複雑なことをしたいときは-o yamlオプションでYAMLファイルに書き出して編集し、kubectl create -f 作成したYAMLファイル名*1したほうがやりやすいことが多い。

バージョン

Kubernetesの1.18で確認。

master $ kubectl version
Client Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.0", GitCommit:"9e991415386e4cf155a24b1da15becaa390438d8", GitTreeState:"clean", BuildDate:"2020-03-25T14:58:59Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.0", GitCommit:"9e991415386e4cf155a24b1da15becaa390438d8", GitTreeState:"clean", BuildDate:"2020-03-25T14:50:46Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"linux/amd64"}

kubectl runコマンド

普通にkubectl run ポッド名 --image=イメージ名でPodを作成できる。これも以前のバージョンではエラーが出たような気がする*2

master $ kubectl run mypod --image=nginx
pod/mypod created

master $ kubectl get po
NAME    READY   STATUS    RESTARTS   AGE
mypod   1/1     Running   0          50s

--generator=run-pod/v1をつけても同じことができる。ただし、将来的にdepricatedになる旨の警告が出る。

master $ kubectl run mypod-2 --generator=run-pod/v1 --image=nginx
Flag --generator has been deprecated, has no effect and will be removed in the future.
pod/mypod-2 created
master $ kubectl get po
NAME      READY   STATUS    RESTARTS   AGE
mypod     1/1     Running   0          3m39s
mypod-2   1/1     Running   0          88s

レプリカ数(deploymentに含まれるpodの数*3)をオプションで指定すれば自動でdeploymentにしてくれるかと思いきや、--replicasのオプション自体がないようである。

master $ kubectl run mydeploy --image=nginx --re(tabを押下)
--record            --recursive         --requests          --requests=         --request-timeout   --request-timeout=  --restart           --restart=

kubectl createコマンド

kubectl runではなくkubectl createを使う方法もある。これで作れるリソースは下記の通りである。podは作れない。

master $ kubectl create(tabを押下)
clusterrole          configmap            deployment           namespace            priorityclass        role                 secret               serviceaccount
clusterrolebinding   cronjob              job                  poddisruptionbudget  quota                rolebinding          service

いきなりレプリカ数が複数のdeploymentは作れないようである。

master $ kubectl create deployment mydeploy --image=nginx --replicas=2
Error: unknown flag: --replicas
See 'kubectl create deployment --help' for usage.

したがって、レプリカ数が1のdeploymentを作成し、しかるのちにレプリカ数をkubectl scaleコマンドで増やす等の二段階のやり方になる。

master $ kubectl create deployment mydeploy --image=nginx
deployment.apps/mydeploy created
master $ kubectl describe deployments.apps mydeploy
Name:                   mydeploy
Namespace:              default
CreationTimestamp:      Thu, 30 Jul 2020 03:32:06 +0000
Labels:                 app=mydeploy
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=mydeploy
Replicas:               1 desired | 1 updated | 1 total | 1 available | 0 unavailable
(略)
master $ kubectl scale deployment mydeploy --replicas=2
deployment.apps/mydeploy scaled
master $ kubectl describe deployments.apps mydeploy
Name:                   mydeploy
Namespace:              default
CreationTimestamp:      Thu, 30 Jul 2020 03:32:06 +0000
Labels:                 app=mydeploy
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=mydeploy
Replicas:               2 desired | 2 updated | 2 total | 1 available | 1 unavailable

いきなりレプリカ数が複数のdeploymentを作る方法だが、kubectl Cheat Sheet | Kubernetes を見ても特になさそうである。

まとめ

  • podを作成する:kubectl run pod名 --image=イメージ名
  • deploymentを作成する:kubectl create deployment deployment名 --image=イメージ名

ほとんどのリソースはkubectl createで作れそうなので、podだけrunで作る、と覚えておけばよさそう。

*1:もしくはkubectl apply -f ファイル名

*2:Podを作成時は--generator=run-pod/v1をオプションでつけないといけない気がしたが、つけなくてもできるようである。逆につけないとDeploymentが作成された気もする。残念ながら前のバージョンのクラスタが手元にないので確認はしてない。

*3:普段意識することはないが、正確にはdeploymentの中にreplicasetがあり、そこに含まれるpodの数である。

KubernetesにおけるデフォルトのDockerレジストリ

コンテナイメージの取得元

背景

Kubernetesをインストールした状態で、pod(や、deployment)を作成することができる。このときに、コンテナのイメージは手動であらかじめダウンロードしていない。Kubernetesのインストールパッケージの中に膨大なコンテナイメージが含まれているはずもないので、インターネット越しに取ってきているはずである。どこから持ってきているのだろうか。

[root@master01 ~]# kubectl run nginx-pod --image=nginx
W0729 10:19:46.316434     519 helpers.go:535] --dry-run is deprecated and can be replaced with --dry-run=client.
pod/nginx-pod created

Docker Hub

結論から言うと、Docker Hubというレジストリ・サービスがあり、特に取得するレジストリを指定しない場合はそこから取ってくる*1

Docker Hub以外のレジストリから取得する場合は明示的に指定する。試しに適当なイメージでPodを作成してみたのが次に示す例である*2

[root@master01 ~]# kubectl run test-pod --image=quay.io/coreos/flannel:v0.12.0-amd64
pod/test-pod created
[root@master01 ~]# kubectl get pod test-pod -o wide
NAME       READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
test-pod   1/1     Running   0          31s   10.0.30.83   worker02   <none>           <none>

quay.io/coreos/というレジストリの場所を示す文字列が入っている。Docker Hubから取得する場合は--image=nginx等のレジストリの場所を示す文字列は省略可能である。

配置対象のワーカノードにもイメージがpullされているのがわかる。REPOSITORYの列を見るとquay.io/coreos/と取得元のレジストリがわかるようになっている。

[root@worker02 ~]# docker images
REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE
(略)
quay.io/coreos/flannel      v0.12.0-amd64       4e9f801d2217        4 months ago        52.8MB
(略)

参考にしたもの

  1. knowledge.sakura.ad.jp

  2. www.slideshare.net

*1:直接的に書かれているものが見つけられなかったので、傍証より確認した。参考リンクの1.より「kubectlコマンドでPodを作成するには、作成するPodの情報を記述したYAML形式ファイルを用意し、それを「kubectl create」コマンドの引数として与えれば良い。たとえば、「httpd」(DockerHubで公開されている、Docker公式のApache HTTP Serverを含んだコンテナイメージ)というイメージからコンテナを作成し、そのコンテナの80番ポートに外部からアクセスできるようにするには、以下のような設定ファイル(「pod-httpd.yaml」)を用意する。」という記載があった。直接的に調べるには、kubectl runの内部的な仕組みを知る必要があるが今回は割愛した。kubectl runがdocker runを呼び出し実行しているなら、ソースコードまで追わなくてもdocker側の仕様からわかる。参考リンク2.ではP.49にdocker pullを行うとDocker Hubからイメージを取ってくる図が記載されている

*2:実際にflannelをインストールする場合はflannelのイメージをただpodとして動かすのはダメなので注意。あくまでこれは適当なコンテナイメージを指定したかったためである。flannelを入れたければ、kurbenetes.io等にある手順に従い、manifestファイルをkubectl apply -fすることでインストールする必要がある。

KubernetesのServiceで出てくる各種ポートの意味

本記事の目的

KubernetesでServiceを作成するとPortTragetPortNodePortといろいろなポートが出てくる。忘れがちなのでメモする。

[root@master01 ~]# kubectl describe svc nginx
Name:                     nginx
Namespace:                default
Labels:                   app=nginx
Annotations:              <none>
Selector:                 app=nginx
Type:                     NodePort
IP:                       10.108.101.153
Port:                     <unset>  8080/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30082/TCP
Endpoints:                10.0.1.21:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

NodePort

KuberntesのServiceにはいくつかType(種類)がある。NodePort Serviceはその一つである。NodePort Serviceを作成すると、NodePortというポート番号が設定できる。

このとき、Kubernetesの各ノードのIPにアクセスできるネットワークから、以下のURLでServiceにアクセスできる*1

http://<各ワーカノードのIP(複数ある場合、どのワーカでもよい)>:<NodePortのポート番号>

以下に例を示す。192.168.0.102192.168.0.103はそれぞれワーカノードのIPアドレスである。アクセス元はワーカノードへの疎通性があるところなら何でもよいので、ここではマスターノードからアクセスする。nginxのデフォルトページの応答が返ってきていることがわかる。

[root@master01 ~]# curl http://192.168.0.102:30082
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@master01 ~]# curl http://192.168.0.103:30082
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

それぞれのワーカノードで、NodePortとして設定されているポート番号(この場合は30082)の待ち受け状況を確認する。kube-proxという文字が見えるのでkube-proxyというプロセスがNodePortのポート番号で待ち受けているのが実態とわかる。

ワーカノード1で確認。

[root@worker01 ~]# ss -antu | grep 30082
tcp    LISTEN     0      128       *:30082                 *:*
[root@worker01 ~]# lsof -i :30082
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
kube-prox 3270 root    8u  IPv4  69766      0t0  TCP *:30082 (LISTEN)

ワーカノード2で確認。

[root@worker02 ~]# ss -antu |grep 30082
tcp    LISTEN     0      128       *:30082                 *:*
[root@worker02 ~]# lsof -i :30082
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
kube-prox 2369 root    8u  IPv4  43557      0t0  TCP *:30082 (LISTEN)

Port

KubernetesでServiceを作成するとデフォルトではClusterIP*2というIPが生成される。Portは作成したServiceへClusterIP経由でアクセスする際のポート番号である。ClusterIPはKubernetesクラスター内のコンテナからアクセスできる。以下のURLでアクセス可能。

http://<ClusterIP>:<Portで指定のポート番号>

以下に例を示す。コンテナ内に入り、コンテナ内からnginxの応答が返ってきていることがわかる。この例だとServiceのアクセス先とアクセス元のコンテナが同じなのでわかりにくいが、別に他のコンテナでも同じ方法でアクセスできる。

[root@master01 ~]# kubectl get service
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          119d
nginx        NodePort    10.108.101.153   <none>        8080:30082/TCP   11h
[root@master01 ~]# kubectl get pod nginx-f89759699-pksbl
NAME                    READY   STATUS    RESTARTS   AGE
nginx-f89759699-pksbl   1/1     Running   0          2d22h
[root@master01 ~]# kubectl exec nginx-f89759699-pksbl -it -- /bin/sh
# curl http://10.108.101.153:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

TargetPort

Serviceとして公開されたアプリケーションの処理の実体を担うコンテナがアクセスを待ち受けているポート番号である。このポートは外部からアクセスするためのURLになるものではない。http://<ClusterIP>:<Portで指定のポート番号>でアクセスを受けたとき、コンテナから見るとTargetPortでアクセスを受けたものとして処理される*3

確認するには、コンテナに入りhttp://localhost:<TargetPortで指定のポート番号>にアクセスしてみればよい。

[root@master01 ~]# kubectl exec nginx-f89759699-pksbl -it -- /bin/sh
# curl http://localhost:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

なお、アプリケーション側の設定も正しい必要がある。例えばnginxではnginxのアプリケーションが待ち受けるポートの設定が記述されている。以下の通り、80番ポートでリッスンしており、KubernetesのServiceのTargetPortと一致していることがわかる。

# cat /etc/nginx/conf.d/default.conf
server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

*1:マスターノードもワーカノードとして使う場合はマスターノードのIPからでもアクセス可能。

*2:ClusterIPはServiceのTypeでもある。

*3:NodePortでサービスを公開している場合、実際にはClusterIPのサービスがその裏で動いている。http://<各ワーカノードのIP>:<NodePortのポート番号>でアクセスを受けた後、いったんClusterIPでアクセスを受ける形になる。

電子証明書

電子証明書の必要性

(https://tanke25616429.hatenablog.com/entry/2020/07/24/221419)[電子署名の記事]では、公開鍵を用いて文書に付与された電子署名を検証し、本人性や改ざんがなされていないことを記した。 tanke25616429.hatenablog.com

しかし、検証を行うための公開鍵自体が送信者本人のものでない場合、電子署名の検証に成功したとしても、文書の本人性や改ざんがないことは保証できない。

f:id:tanke25616429:20200724224114p:plain
公開鍵が正しいことの保証が必要

そこで、公開鍵が送信者本人であることを保証する情報*1が必要となる。この情報と公開鍵をセットで電子証明書と呼ぶ。

f:id:tanke25616429:20200724225609p:plain
電子証明書による公開鍵の本人性証明

現実世界との対比

押印した文書に印鑑証明書をつけることに似ている。公開鍵が押印に対応し、公開鍵の本人性を保証するデータが印鑑証明書である*2

f:id:tanke25616429:20200724230424p:plain
印鑑証明書と電子証明書の対比(https://www.infraexpert.com/study/security6.htmlより引用)

x.509

電子証明書の規格の一つ。ITU-Tが定めている。現在、広く普及しているもの*3PKI(Public Key Infrastructure)の仕組みの中で使われる。

参考にしたもの

デジタル証明書の仕組み

公開鍵証明書 - Wikipedia

www.atmarkit.co.jp

*1:デジタル証明書、公開鍵証明書とも呼ぶ。

*2:電子証明書=印鑑証明書のほうが対比はわかりやすいが、電子証明書といった場合は通例公開鍵そのものも含む。また、押印=電子署名ではないかという気もしてしまうところで(実際は公開鍵=押印)、若干アナロジーには限界がある。

*3:x509という文字列は、例えばOpenSSLコマンドのオプションの指定で出てくる。OpenSSLはSSL/TLSを実装したオープンソースのライブラリ

電子署名

電子署名とは

電子署名*1とは電子化された文書に対して行われる電子的な署名のこと電子署名が行われることで以下を保証する。

  1. 署名対象の文書に署名者が承認の意志を示すこと*2
  2. 署名対象の文書が改ざんされていないこと

電子的な文書の送信者、電子署名を付与することによって上記1.と2.を保証する。受信者の目線からすると、その電子署名付きの文書は確かに送り主が承認したものでかつ改ざんされていないことがわかる*3

現実世界との対比

電子署名は、現実世界でいうと署名(サイン)や印鑑に対応する。契約書や申請書に印鑑やサインをすると、1. 署名対象の文書を署名者が承認していることが示される。2.署名対象の文書が改ざんされていないことは契約書等だと対応がつかないので封緘をイメージするとよい*4

現実世界と異なり、コンピュータの世界ではデータは電子的にコピーがいくらでも作られる。したがって、現実の文書と異なり「原本を提示していること」をもって妥当だと判断はできない。電子署名の妥当性は、電子的に検証できる必要がある。

電子署名の要件

上記の1.と2.(ここでは特に1.について。以降、1.の条件を短く「本人性」の証明と呼ぶこととする。)を保証するためには、電子署名には以下の要件がある。以降、「文書」は電子的なデータを指す言葉として使う。

  • (a) 署名者本人にしかその電子署名が生成できないこと
  • (b) (a)が誰にでも検証できること

(a)は言わずもがなで、別人がある文書に対し同じ電子署名を生成できてしまっては、電子署名から本人かどうかを判断できない。これは署名者本人しか知りえない情報を用いて行う(具体的には後述する)。(b)の「誰にでも」は「公開されている情報から」と言い換えたほうがわかりやすいかもしれない。(a)の事実を検証するために、署名者しか知りえない情報を必要とするならば、第三者は誰もそれを検証しえない。秘密の情報を検証のために誰かに渡しては、その時点で秘密ではなくなる。

実現方法

公開鍵暗号における、公開鍵と秘密鍵の鍵ペアによって実現する。電子署名では秘密鍵電子署名の生成に利用し、公開鍵を電子署名の検証に利用する。

f:id:tanke25616429:20200724220438p:plain
電子署名の生成と検証

送信者は受信者に対し以下のデータを送る。秘密鍵は送信者の手元にしかない。

受信者は公開鍵を用いて電子署名が送信者本人にしか生成できないことを検証する。文書から電子署名を生成するのには秘密鍵が必要であるため、文書に対応した電子署名を生成できるのは送信者だけである。数学的な性質により、電子署名の生成自体は秘密鍵なしにはできないが、その文書から電子署名が生成されていることの検証は公開鍵があればできる*5。この非対称性により、要件の(a)と(b)が達成される。

また、電子署名の値は署名対象の文書から生成されるため、文書が異なれば電子署名の値も変わる。つまり、電子署名の検証が成功すれば、文書が改ざんされていないことも保証される。文書を悪意の第三者が改ざんした場合、電子署名の値と整合が取れなくなる。さりとて、悪意の第三者電子署名の値を文書の改ざんに合わせて改ざんすることはできない。電子署名の生成には送信者しか知らない秘密鍵が必要だからである。

参考にしたもの

電子署名の基礎知識|電子認証局会議

デジタル署名の仕組み

qiita.com

*1:デジタル署名ともいう。

*2:最初にこの記事を公開したとき「署名対象の文書が確かに署名者本人によるものであること」と記載していたが、著作権の所在を示すようにも解釈できる、と指摘をいただきそれを反映し記載を改めた。

*3:「承認」というのは、自身が作成した文書にもできるし、他者の文書に対してもできる。現実世界のアナロジーで考えると、申請者が署名をして稟議にかける行為や、決裁者が署名してOKを出す行為があり、どちらも文書に対し承認をする行為といえる。これを逆に言えば、署名した文書(=承認した文書)は後から「知らない」としらばっくれることはできないということである。

*4:現実の封緘では文書が秘匿されていることも目的となるが(将棋の封じ手など)、電子署名では文書秘匿の目的はない。

*5:なぜか、は著者にとって難しい話でよくわかっていないので省略する。

SSL/TLS関連ファイルの意味

執筆の動機

SSL/TLS関連で様々なファイルがホスト上にあり、どれが何なのか混乱しがちなので整理する。個人的にはKuberntesを扱っていると /etc/kubernetes/pkiフォルダの配下にたくさんあるので、それを整理することを最終目的としている(KuberntesにおけるTLSは別途記事にする予定)。

関連ファイル

電子証明書、通信暗号化のための秘密鍵CSR、の3種のファイルがある。

電子証明書

サーバ証明書やクライアント証明書*1などがこれにあたる。慣例的に拡張子は*.crt*.pem の形になっている。*.crtはCertificateの略だろう*2

server.crt
server.pem
client.crt
client.pem

通信暗号化のための秘密鍵

通信暗号化するためのファイルで、慣例的に*.key*-key.pemの形になっている。

server.key
server-key.pem
client.key
client-key.pem

CSR

CSR(Certificate Signing Request)はCAに提出するサーバ証明書をリクエストするファイルである。CSRにはサーバのドメイン等の情報が含まれている。CAはCSRを入力として電子証明書を生成する。慣例的に*.csrの形になっている。

server.csr

参考にしたもの

install-memo.hatenadiary.org

booth.pm

CSRの生成方法|マニュアル|サポート|SSLサーバ証明書 ジオトラスト

www.udemy.com

関連記事

tanke25616429.hatenablog.com

tanke25616429.hatenablog.com

*1:TLSにおいてはクライアント証明はオプションである。

*2:*.pemは不明