SSL/TLS
TLSの機能
TLSは2者間(以降はクライアントーサーバ間の通信として記載する)で安全に通信できることが目的である。TLSの機能は大きく以下の2つがある。
- なりすましの防止
- 通信の暗号化
それぞれの機能について詳しく記述する。
なりすましの防止
クライアントがサーバにアクセスする際に、そのサーバが本物かどうかを確認したい。サーバ側から見ると、自分が本物であることを証明したい。そこで、サーバ証明書と呼ばれる電子証明書をクライアントに提示し、自身が本物であることを証明する。
そのためには、
の両方が必要である。さらにブレイクダウンして記述する。
1. アクセス先のサーバが本物である証明
現実世界と異なり、コンピュータの世界ではデータは電子的にコピーがいくらでも作られる。したがって、現実の身分証明書等と異なり「原本の証明書を提示しているから相手が本物」という判断はできない。あるサーバ証明書の妥当性は、そのサーバ証明書が電子的に検証できることで示される必要がある。
サーバ証明書には、サーバ独自の(ほかのサーバとは異なる)署名がなされている。この署名は秘密鍵(クライアント側が知らない鍵)によって実現される。サーバ証明書を提示されたクライアントは公開鍵(誰でも持っている)によって検証できる。この検証が失敗した場合は、相手がなりすましの可能性がある。
TLSにおいて、あるサーバと別のサーバを区別するキーはドメイン名である。サーバ証明書はドメインが真正であることを保証する。
2. サーバ証明書自体の保証
サーバ証明書によってドメインが真正であるだけでなく、サーバ証明書自体が正しいことを保証する必要がある。それをする仕組みとしてPKIがある(参考記事参照)。電子証明書(サーバ証明書を含む)では、電子署名とそれを検証するための公開鍵が含まれており、公開鍵は何らかのデータによって本人性が保証されているのだった(参考記事参照)。PKIにおいて、公開鍵の本人性はCA(Certificate Authority)と呼ばれる第三者の電子署名によって保証される。
PKIでは信頼できる第三者*1がサーバ証明書を発行する。サーバ証明書の発行者が前述したCAであり、具体的には、SymantecやGlobalSignなどの企業がそれにあたる。
サーバ証明書に付与されたCAの電子署名により、サーバの公開鍵がサーバ本人のものであることが示される*2。
なお、こうしたCAにサーバ証明書の発行を依頼せず、サーバ自信が自分で発行した証明書を利用することもできる(いわゆる、オレオレ証明書、自己証明書)。ちなみに自己証明書をサーバ証明書として使っているWebサイトにアクセスすると、ブラウザから警告が出る。
通信の暗号化
クライアントからサーバに対しTLSでの通信をリクエストすると上述したようにサーバの真正性がクライアントによって確認されるが、同時にTLSのやり取りの中で通信を暗号化するための鍵の交換が行われる*3。この鍵はTLS通信を行うサーバとクライアントの2者しか知らない。この鍵で通信内容を暗号化することにより、盗聴を防ぐことができる。
自己証明書を用いた場合でも通信の暗号化は実現できる。
参考にしたもの
関連記事
PKI
PKI
PKI(Public Key Infrastructure)とは、公開鍵暗号と電子証明書*1(以下、証明書)を用いて安全に通信ができるようにする仕組みのこと。
安全に通信を行うためには、まず通信相手が本物であることの保証が必要である。PKIにおける証明書は、現実世界の身分証明書と同じ役割を持つ。ここで、証明書そのものが信頼できない場合、意味がないので、証明書を信頼できる第三者(CA、Certificate Authority)が発行する。
参考にしたもの
デジタル証明書(電子証明書)とは - IT用語辞典 e-Words
関連記事
OpenSSLの仕組みとは?初歩から解説! | CodeCampus
*1:公開鍵証明書、デジタル証明書ともいう。
kubernetesのmanifestにおけるYAMLの配列、ハッシュについて
動機
kubernetesのmanifestファイルを書こうと思って、kubectl explainコマンドで調べるが、配列、ハッシュ周りの記法があやふやで間違えることがよくあった。具体的には
xxx: - yyy: YYY zzz: ZZZ
と書くべきか
xxx: - yyy: YYY - zzz: ZZZ
と書くべきか
xxx: yyy: YYY zzz: ZZZ
と書くべきかが迷うので整理する。
YAMLの配列とハッシュ
前提知識となるYAMLの構文を整理する。
配列
YAMLでは、インデントを揃えたうえで行頭に"- "(半角ハイフンスペース)をつけることで配列を表現する。
- aaa - bbb - ccc
この例は配列 [aaa bbb ccc]
(Go風に書くと*1)と同値である。
念のため、ハッシュと比較する意味で配列をちゃんと定義しておく。配列とは、0から始まる連続する自然数をキーとするオブジェクトの列のこと。
ハッシュ
ハッシュは、文字列をキーとしたオブジェクトの列のこと。文字列連想配列とかマップとかも呼ばれる。キーとバリュー(値)のペアで構成される。 YAMLでのハッシュは、インデントを揃えたうえで「キー: 値」の形式で並べて表現する。
A: aaa B: bbb C: ccc
この例をGoのmap風に書くと、map[A: aaa B: bbb C: ccc]
と同値である。
ネスト
ハッシュや配列はネストして入れ子構造にして使われることが多い。
ハッシュのネスト
半角スペースでインデントさせることでハッシュをネストさせる。
A: aaa B: B1: bbb1 B2: bbb2 C: ccc
この例の場合、B
というキーに対応するのは一個の値ではなく、
B1: bbb1 B2: bbb2
という、「キー: 値」のかたまりである。
配列のネスト
配列も半角スペースでインデントさせることでネストできる。
- aaa - - bbb1 - bbb2 - ccc
aaa
の次の行のハイフンの後には何もないが、この要素に対応するのは一個の値ではなく
- bbb1 - bbb2
という配列である*2。すなわち[aaa [bbb1 bbb2] ccc]
と同値である。
ハッシュと配列のネスト
ハッシュと配列のネストはどちらが外側に来るかで2通り考えられる。それぞれ示す。
ハッシュの中に配列
A: aaa B: - bbb1 - bbb2 C: ccc
この例ではB
というキーに対応する値は、
- bbb1 - bbb2
という配列である。
配列の中にハッシュ
- aaa - B1: bbb1 B2: bbb2 - ccc
この例ではaaa
の次の要素は、
B1: bbb1 B2: bbb2
というハッシュである。なお、ハイフンの次の行にハッシュを持ってこずにいきなりハイフンの後にハッシュを続けて書いてもよいことにYAMLの仕様上なっているため、以下の書き方ができる*3。
- aaa - B1: bbb1 B2: bbb2 - ccc
kubernetesのmanifestにおける実例
前提知識であるYAMLの構文を踏まえ、kuberntestのmanifestの記載と照らし合わせる。
RoleBindingのmanifest
RoleBindingのmanifestをYAML形式で表示すると下記のようになる。
# kubectl get rolebindings.rbac.authorization.k8s.io -n kube-system kube-proxy -o yaml apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding (中略) roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: kube-proxy subjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: system:bootstrappers:kubeadm:default-node-token
roleRef:
はハッシュにおけるキーとなっており、それと対応する値が、
apiGroup: rbac.authorization.k8s.io kind: Role name: kube-proxy
というハッシュである。
subjects:
もハッシュにおけるキーであるが、対応する値は配列である。この例だと配列には1つの要素だけがある。その要素に格納されている値が、
apiGroup: rbac.authorization.k8s.io kind: Group name: system:bootstrappers:kubeadm:default-node-token
というハッシュである。すなわち、ハッシュ-配列-ハッシュという入れ子になっている。わかりやすく書くと、
subjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: system:bootstrappers:kubeadm:default-node-token
ということである。
kubectl explain
コマンドで調べると、キーroleRef
に対応する値が<Object>
(オブジェクト)と書かれている。この場合のオブジェクトは単体の値もしくは、入れ子になったハッシュである。
一方、キーsubjects
に対応する値が<[]Object>
(配列)と書かれている。キーに対応する値が配列かどうかは、[]
があるかどうかでわかる。実行例を下記に示す。
# kubectl explain rolebindings KIND: RoleBinding VERSION: rbac.authorization.k8s.io/v1 (中略) roleRef <Object> -required- RoleRef can reference a Role in the current namespace or a ClusterRole in the global namespace. If the RoleRef cannot be resolved, the Authorizer must return an error. subjects <[]Object> Subjects holds references to the objects the role applies to.
キーsubjects
が配列を値に取るということがよりわかりやすいのは、複数のハッシュのかたまりを要素とする配列というケースである。
subjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: hogehoge - apiGroup: rbac.authorization.k8s.io kind: Group name: fugafuga
参考にしたもの
*1:参考にしたサイトはRubyなのだが、Goを勉強中なのでそちらの書き方を例として挙げた。
*2:なお体感であるが、配列の中に配列のパターンのネストはkubernetesのmanifestでの出現頻度が高くない気がする。
*3:kubernetesのmanifestではかなり多い書き方である。
ファイルとストレージのマッピング
この記事で整理したいこと
別の記事(ファイルシステム - Knのアウトプット)で
ファイルシステムがないと、人間やアプリケーションはデータが実際に記録されているストレージ上の位置を指定してデータにアクセスしなくてはならない。ストレージ上の位置は意味も文脈もないただの番地であり扱いにくい。
と書いた。これについて、実際のデータがどのように記録され、ファイルとマッピングされているかを整理する。
ファイルとストレージのマッピング
ざっくりとは、ストレージ上のビット列をある一定の塊として扱い、その塊とファイルがマッピングされている、と理解しておけばよい。
上述の「ある一定の塊」も階層的にまとめられている。小さいほうから順に追っていく。
ビットとバイト
コンピュータで扱うデータの最小単位はビットである。情報はビットの集合体、すなわち1と0の2種類の数字の列、で表現される。8ビットをまとめて1バイトと呼ぶ。記憶装置の容量はビットではなくバイト数で表すことが多い。
ビット/バイトのストレージ上での表現方法
ストレージ上のデータの実体もビット列として記録されている。ビットの表現方法はストレージを構成する記憶装置により異なる。記憶装置の物理的な特性を利用して1と0の2状態を表現する。例えば、HDDであれば磁性体の磁荷の向き、SSDやメモリであれば素子内の電化の状態によって1か0かが変わる。記憶装置上の物理的に連続した8ビットが1バイトとして表現される。
記憶装置への入出力単位
記憶装置への入出力は1ビットや1バイトごとに行うのではない。入出力の性能が落ちないようにまとまった固定長のデータの塊ごとに行う。以下にHDDの場合の入出力単位について説明する。SSDの場合は全く異なる。
HDD
HDDにおいては、この固定長の単位をセクタと呼ぶ*1。昔のセクタのサイズは512バイトが主流だったが、現在は4096バイト(4KiB)が主流である。入出力対象のセクタは物理的なアドレスで指定する。指定方法は複数ある(CHS方式、LBA方式)*2。
セクタとブロック
OSのファイルシステムから見た最小単位をブロックもしくはクラスタと呼ぶ*3。HDDにおいては、ブロック/クラスタはセクタをひとまとめにしたものとなる。セクタサイズとブロックサイズ/クラスタサイズが同一の場合は1対1にマッピングされる。
SSDの場合でもOS側から見ればブロックに対し入出力を行っている。ただし、OSから見たブロックとマッピングされる記憶装置側のデータの塊がセクタではない*4。
まとめ
記憶装置上の固定長バイトのデータの塊であるセクタと、OSのファイルシステムから見たブロックがマッピングされている。ファイルはファイルシステムにより複数のブロックとマッピングされている。
本記事で記載しなかったこと
AFT、ボリューム、LVM、エクステント、SSDにおける入出力単位(ページやブロックの話)等、関連する内容はまだあるが、改めて別記事に切り出して記載することとする。
参考にしたもの
ストレージ 進化するSSD(Solid State Drive) - 富士通
ISO9660 その2 物理セクタ、論理セクタ、論理ブロック: せんべえ焼き、もしくはコースターメーカー
HDDのセクタサイズ~512セクタと4Kセクタ【パソコン購入術】
Quora なぜコンピュータは1と0しか理解できないのですか?
オペレーティングシステム: 講義案内 ※スライド6 「ファイルシステムAPIとメモリマップドファイル」
「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典 セクタ
セクターサイズとクラスタサイズ(ブロックサイズ)の違い, 不良セクタとfsck/chkdsk について│SEの道標
関連記事
*1:ディスクセクタ、物理セクタ、ブロック、物理ブロックなどと呼ばれることもある
*2:CHS方式は磁気ディスクのどこにいるかをシリンダ、ヘッド、セクタの番号で一意に指定する。これだと記憶装置の種類や物理構造によって指定方法が異なってしまい不便だった。LBA方式は物理構造を気にせず、各セクタに通し番号を振る方式であり、前述の問題点を解消している。
*3:セクタをブロックと呼ぶこともあると別の脚注で書いている通り、ブロックという言葉は多義で使われる。そもそも、ブロックという言葉が一般的に固定長のデータの塊という意味と考えればいろいろな用語で使われるのはやむを得ない気はする。
*4:参考サイトによればSSDでもセクタを仮想的に提供できるらしい。
セクターサイズとクラスタサイズ(ブロックサイズ)の違い, 不良セクタとfsck/chkdsk について│SEの道標
SSD にはセクターという物理要素はありませんが、Advanced Format と同様、論理セクター(製品によっては仮想セクターと呼ぶ)を提供できますし、ものによっては設定でセクターサイズを変更できます。
コンピュータにおける記憶領域
執筆の動機
コンピュータの勉強をしているとデータの置き場所である記憶領域について、「XXへの入出力はYYに比べ遅い」「XXはYYに比べ安価」といった文章が出てくる。初学者からすると、同じような話が複数出てくるので混同しやすい。しかもそれらはたいてい別の文脈で現れるので「あのときのあれの話と同じだっけ? 違うっけ?」のようなことが起きる*1*2。そこで代表的なものを一覧して並べることでどのような概念があるかを明確にする。
記憶領域一覧
コンピュータの仕組みと照らし合わせながら登場人物を理解する。
- メモリからCPUのレジスタへプログラムやデータを読み出し、レジスタに対し演算を行い、演算結果をメモリに書き込む
- メモリアクセスを毎回することによる速度低下を防ぐため、CPU上にあるキャッシュメモリ上でデータを読み書きする
- プログラムは電源オン時やプログラム実行時などに補助記憶装置(HDD/SSD等)から読み込まれ、メモリ上にロードされる
メモリはメインメモリや主記憶装置とも呼ぶ。キャッシュはCPUの種類によって、L1からL3まで存在する(L2までしかないものもある)。電源をオフした際に情報が残る(=不揮発性)のは補助記憶装置だけである。 共通的な傾向として、高くて速い、安くて遅い、という風にまずは理解しておけばよい。したがってコンピュータ上では安い記憶装置ほど大容量で搭載されている。
これまでの話をまとめると以下の通り。
参考にしたもの
ファイルシステム
定義
ファイルとは
関連するデータを1つにまとめ、名前をつけて保存したもの。
記憶媒体にデータを保存、読み込み、移動、削除などする際に、ファイルを一つのまとまりとして取り扱う。OSの一部であるファイルシステムによって管理される。
ファイルシステムとは
ストレージ上のデータを、ファイルという単位でまとめ、名前をつけて管理する機能*1。
ファイルシステムはOSの機能として提供される。
ファイルシステムがあることによって、コンピュータを利用する人間やコンピュータ上で動作するアプリケーションがファイルパス(=ファイルの場所とファイル名の組み合わせ)*2という扱いやすい文字列でストレージ上のデータにアクセス(読み書き)できる。ファイルシステムがないと、人間やアプリケーションはデータが実際に記録されているストレージ上の位置を指定してデータにアクセスしなくてはならない。ストレージ上の位置は意味も文脈もないただの番地であり扱いにくい。ファイルパスは、意味のある(意味づけできる)ため扱いやすい。
参考にしたもの
ストレージはバイト列を格納できる大きな塊に見える。大きなバイナリファイルと思うこともできる。OSに搭載されたファイルシステムはストレージのバイト列を切り出し,「ファイル」という単位で小さなバイト列に名前を付ける機能だと言える。
— uchan (@uchan_nos) 2020年5月4日
仮想化
仮想化とは
コンピュータリソースを物理的な構成とは異なる構成に見せて動作させること。
平たく言うと、サーバー、OS、ネットワーク、メモリ等のコンピュータリソースに対して以下を行うこと。
- 1つのものを複数に見せる
- 複数のものを1つに見せる
- M個のものをN個に見せる
例
- VLAN(1つのネットワークを複数のブロードキャストドメインに分割)
- VSAN(複数のディスクを1つに見せる)
- サーバ仮想化(1台の物理サーバ上に複数のサーバを動作させる)
記事を書いた動機
製品に関する記事や宣伝を読んでいると、「~~仮想化技術」のような言い方をしているが、製品によって違う仮想化を指していることがあってモヤモヤするときがある。なので「1つのものを複数に」パターンか「複数のものを1つに」パターンかを意識しながら読むと、仮想化技術に関する文章を読んでいて混乱しにくい。