さくらのクラウド「ディスク暗号化機能」の設計と実装

この記事は [さくらインターネット Advent Calendar 2023](https://qiita.com/advent-calendar/2023/sakura) 8日目の記事です。

さくらインターネットの大久保です。

昨日(12/7)、さくらのクラウドにて「ディスク暗号化機能」のベータ版をリリースしました。本稿では、この機能をどういう風に設計し、実装したかを紹介しようと思います。

公式のリリース情報等は以下をご覧ください。

https://www.sakura.ad.jp/corporate/information/announcements/2023/12/07/1968214223/

# さくらのクラウド「ディスク暗号化機能」とは

機能概要については、下記にリリース文面より引用します。

========

「ディスク暗号化機能（β）」とは、お客さまがサーバーからストレージ領域に書き込まれるデータを、自動的に暗号化することができる機能です。これにより、情報漏洩などのリスクをより低減することができます。
データの読み込み時には自動的に復号されるため、お客さまは暗号化されていることを意識することなくサーバーを運用することが可能です。
本機能において、暗号鍵は対象のディスクごとに一意に生成され、利用中の保管、ディスク削除時の破棄など一連のライフサイクルはクラウド基盤上で自動的に行われます。

![ディスク暗号化機能の概念図](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108990/b22cc4fb-7912-3867-a1aa-bbe3c6b04f80.png)

機能の詳細については、マニュアルサイトに記載しておりますので、こちらをご覧ください。

https://manual.sakura.ad.jp/cloud/storage/disk-encryption.html

# 使い方

以下のように、[さくらのクラウドのコントロールパネル](https://secure.sakura.ad.jp/cloud/iaas/)より、サーバやディスクを作成する際に **「ディスクを暗号化する」にチェックを入れるだけ** で利用できます。

サーバ作成画面

![サーバ作成画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108990/39b46dbb-ed2c-e98f-cd27-ce788d23a95b.png)

ディスク作成画面

![ディスク作成画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108990/5bc41838-dba2-8831-ace9-6aa3df14a7ce.png)

ディスクの情報表示画面

![ディスクの情報表示画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108990/78c87be1-2f2b-fb02-75ee-018d10bc50a6.png)

言ってしまえばこれだけになるんですが、非常に簡単に利用できることが分かるかと思います。

:::note info
上記画面キャプチャにも表示されていますが、暗号化アルゴリズムは「AES256-XTS」を用いています。現状、十分な暗号化強度を持っていると考えられるため、これ一択となっています(アルゴリズムの選択や変更はできません)。もし将来、危殆化するような事態になった場合は、より強度の高い暗号化アルゴリズムをサポートすることになるかと思います。
:::

# 暗号鍵の扱いについて

ディスクの暗号化に用いられる暗号鍵は、**ディスクごとに独立して生成**されます。また、ディスクを解約(削除)された際には、**該当の暗号鍵は自動的に破棄**されます。

暗号鍵が破棄されることで元のデータは復号できなくなります。このように **論理的にデータの抹消を行ったとみなす方式は「暗号化消去」と呼ばれており**、本機能によってそれを実現することができます。

なお、暗号鍵のライフサイクル全般にわたってきちんと管理することは非常に重要です。この煩雑になりがちな **暗号鍵の管理に関する作業や運用は弊社にて行います。** お客様にて、暗号鍵を管理していただく必要はありません。

※ 詳細は、後ほど「暗号鍵管理システム」のパートで説明します。

# ディスクの暗号化は必要なのか？

そもそもの話になりますが、ディスクの暗号化は必要なのでしょうか？

まず最初にお伝えしますと、お客様データをお預かりしている弊社データセンターに設置しているストレージ装置は、データ漏洩の可能性を極力排除するための最大限の努力をもって対応しております。解約されたサービスのお客様データは、論理ディスク領域全体をゼロクリアにより消去しています。故障や退役に伴う物理メディアの廃棄時には、物理破壊によるセキュリティ対応を実施しています。

暗号化をしなければ危険、というわけではありませんのでご安心ください。詳しくはこちらをご覧ください。

https://cloud-news.sakura.ad.jp/2020/01/09/disk-data-erase/

# ディスクの暗号化を行う意義は？

前述の通り可能な限りの対策を実施していますが、セキュリティに100%安全ということはありません。ディスクの暗号化により、**物理的な攻撃や運用瑕疵によるデータ漏洩リスクを「より低減できる」** と考えられます。これは、単一の対策のみに頼るのではなく、複数の防御層を組み合わせることで安全性をより高めることを目指す、多層防御の考え方に基づくものです。

ところで、データ漏洩にまつわる象徴的な事件として、2019年に発生した神奈川県庁のHDD転売事件がありました。

https://www.nhk.or.jp/politics/articles/statement/27177.html

もっとも、これはデータの暗号化(と適切な暗号鍵管理)により防ぐことができた可能性が高いと言われています。この事件発生以降、日本国内でも「暗号化消去」の理解が広まりました。現在では、日本政府でも利用可能なデータ抹消方式の一つとして採用されています。

# 暗号化消去により他のデータ抹消方式の技術的困難を補完する

データ抹消方式の基準については、米国国立標準技術研究所(NIST)により発行されているNIST SP800-88により規定されています。このガイドラインでは、以下の3つのレベルが規定されています。

- Clear(消去)
- Purge(除去)
- Destroy(破壊)

暗号化消去は、このうち研究所レベルの攻撃にも耐えうる **Purge(除去)** に位置づけられています。一方、Clear(消去)やDestroy(破壊)によるデータ抹消には、以下のような技術的困難な事象が存在します。

- Clear(消去)レベルのデータ抹消
  一般的なデータ抹消ツールを用いてゼロやランダムデータでメディアを上書きする方式です。このとき、HDDの代替セクタや、SSDのウェアレベリング用の予備領域など、OSから見えない(LBAにマップされていない)領域に残ったデータを確実に抹消することは非常に困難です。
- Destroy(破壊)レベルのデータ抹消
  物理メディアの破砕、溶解、焼却などを行う方式です。しかし、HDDプラッタ上に磁気が完全に残留しないレベルまで破壊を行ったり、SSDやコントローラに内蔵されていたメモリチップに電荷が残留しないレベルまで破壊を行ったりするには非常にコストがかかります。地球環境にも負荷がかかり、サスティナブルではありません。

これら物理的なデータ抹消方式の技術的困難性を、暗号化消去を組み合わせることで補完でき、リスクをより低減できると考えられます。

# ディスクを暗号化しても防げないリスク

ディスクを暗号化しても、**物理的な攻撃や物理的な運用瑕疵以外のデータ漏洩リスク**を防ぐことはできません。具体的には、お客様サーバOSの設定やその上で実行されるミドルウェアやアプリケーション、またアクセス権の管理の不具合によって発生するデータ漏洩リスクは、ディスク暗号化によって守ることはできません。サーバ内からはディスクの内容が平文で読めてしまうためです。

責任共有モデルにより、サーバ内の脆弱性対応については、お客様自身に行っていただく必要があります。詳細は以下をご覧ください。

https://manual.sakura.ad.jp/cloud/support/user-support.html#user-support-responsibility-boundary-point

# 実装の概要とアーキテクチャ

さて、前置きが長くなりましたが、実装の話に入りたいと思います。

さくらのクラウドの物理基盤は、大きく以下の要素で構成されています。

- ストレージ装置
  - iSCSIを用いるネットワークストレージとなっています
- ホストサーバ
  - お客様サーバ(VM)を稼働させるもので、ハイパーバイザはLinux/KVMにて構成されています
- ストレージネットワーク
  - ストレージ装置とホストサーバ間のiSCSI通信を取り持ちます

このような構成において、暗号化処理を行う実装は、以下のようなパターンが考えられます。

![暗号化の実装パター](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108990/656824ee-598c-6198-ca6f-812a3d3eac93.png)

ストレージ機器が暗号化機能をサポートしている場合は、(2)ストレージコントローラにて暗号化処理を行うパターンや、(3)SSDやHDDなどのSED対応メディアで暗号化処理を行うパターンが自然な実装方法かと思います。

が、現在弊社で利用しているストレージ機器では暗号化機能をサポートしていません。必然的に、(1)ホストサーバにて暗号化処理を実装するパターンを採用することとなりました。

![アーキテクチャ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108990/7e85a2ba-faee-d97e-5b70-dc2095a4fbe9.png)

暗号鍵管理システム(KMS)は独立して構築することとし、暗号鍵の管理はここで厳重に行います。

なお、このアーキテクチャのメリット、デメリットは以下の通りです。

メリット
- ストレージ装置の機能や振る舞いに依存した実装を行う必要なく暗号化に対応できる
- 今後新たなストレージ装置の導入を検討する際に、暗号化の要件を緩和できる
- ソフトウェア実装のみで対応できるため、稼働中のストレージ機器の設定や運用を変える必要がない(ストレージ機器はダウンが許されない非常にクリティカルな装置であるため、稼働中の機器に手をいれるのは大変)
- 将来暗号アルゴリズムが危殆化した際に、ソフトウェア実装のみを変更することで、新しいアルゴリズムに対応できる
- ストレージ機器から暗号鍵の管理を分離することで、柔軟な鍵管理が可能になる(安全に運用しやすい方法をとることができる)
- お客様サーバ(VM)の直下で暗号化処理を行うため、ストレージネットワーク通信も含め暗号化できる

デメリット
- お客様サーバ(VM)の起動処理や、ディスクイメージ操作機能などのプロビジョニングが複雑になる
- ホストサーバにて暗号化処理に必要なCPU負荷が増える

# ホストサーバ上での暗号化/復号処理の実装について

さくらのクラウドのホストサーバはLinux/KVMで動作しています。Linuxではブロックデバイスの暗号化システムとして`dm-crypt`があり、一般的に広く用いられています。今回弊社でもこれを利用することにしました。

ホストサーバで暗号化/復号処理を行うにあたって、前述のデメリットに挙げた通り、**処理の負荷が気になる**ところです。パフォーマンスについては、検討段階よりサイボウズさんのブログを非常に参考にさせていただきました。ありがとうございます。

https://blog.cybozu.io/entry/2019/03/08/170000

弊社プロダクション環境でも、今回使用する暗号化アルゴリズムAES256-XTSで負荷測定を行いました。通常発生しうる程度のIO(最大数万IOPSを想定)ではCPU負荷は軽微で、IOパフォーマンスの低下(レイテンシの増加)もほとんど発生せず、**許容可能な範囲に収まることを確認**できました。最近のCPUにはAES-NIが実装されており、AESの暗号化処理を高速化できる恩恵が大きいと思われます。

# dm-cryptのプロビジョニングについて

さくらのクラウドでは、iSCSIを用いたストレージネットワークを構築しています。お客様サーバを起動する処理の中で、iSCSIデバイス(実際にはマルチパスを使っているのでdm-multipath)とqemuプロセスの間に、dm-cryptによる暗号化デバイスを挟み込むようなプロビジョニングを行います。

![dm-cryptのプロビジョニング](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108990/576d85ea-e9e2-bddf-1ce3-e994bd82ec4f.png)

dm-cryptにはいくつかのモードがあり、LUKS(Linux Unified Key Setup)を使用するのが一般的かと思います。が、弊社環境では、以下の理由によりLUKSを用いないPlainモードで動作させることとしました。
- 暗号鍵はKMSで集中管理するため、ディスク上で暗号鍵を管理する必要がない
- LUKSを用いる場合、ディスク領域内にLUKSヘッダを記録する分だけお客様が利用可能な容量が減ってしまう

特に、後者は互換性を保つうえで大きな問題となります。暗号化なしで提供している既存のディスク容量と異なる場合、パブリックアーカイブや、お客様にて既に作成済みのアーカイブを書き込むための容量が不足します。Plainモードで動作させることで、暗号化の有無にかかわらず、ゲストOSから同じ容量で見えるようにしました。

参考までに、以下のようなcryptsetupコマンドを用いてdm-cryptデバイスの設定を行っています。

```
/usr/sbin/cryptsetup open --type plain --cipher aes-xts-plain64 \
  --key-size 512 --key-file /dev/stdin /dev/mapper/mpatha encrypt-XXX
```

このコマンドを実行すると、iSCSIマルチパスデバイス`/dev/mapper/mpatha`を下位デバイスとした、暗号化デバイス `/dev/mapper/encrypt-XXX` が生成されます。これをqemuに渡すことになります。

cryptsetupコマンドには、暗号鍵を与えてあげる必要があります。暗号鍵は別途KMSから取得します。その際、ローカルディスクに一時的に暗号鍵を保存してしまうと、たとえそのファイルを削除したとしても、メディア上に残留してしまうおそれがあり、機密性が損なわれます(※)。そのため、プロビジョニングシステムからパイプでcryptsetupコマンドの標準入力に渡すようにしています。

※ 暗号化されたデータと暗号鍵の両方が漏洩すると、データが復元できてしまいます。平文の暗号鍵が、すべての箇所で永続ストレージに書き込まれることがないように、実装に十分な注意が必要です。

なお、暗号鍵のサイズが、256bitではなく512bitになっています。この理由は、XTSモードでは、ブロック暗号内部でAES256の暗号鍵が2つ必要なため、2倍の長さ(512bit)となっています。

参考: 
https://en.wikipedia.org/wiki/Disk_encryption_theory#XEX-based_tweaked-codebook_mode_with_ciphertext_stealing_(XTS)

# 暗号鍵管理システム(KMS)について

KMSは、NIST SP800-57やNIST SP800-130に則って厳格な管理が求められます。参考までに、CRYPTRECにより日本語訳されたドキュメントが以下にあります。

https://www.ipa.go.jp/security/crypto/guideline/ckms.html

鍵管理というその性質上、非常にたくさんのポリシーや運用について策定する必要があります。これらの運用を既存のAPIサーバやデータベースに適用するのは困難です。そのため、KMSは独立したシステムとして構築し、鍵管理に特化した運用を行えるようにしました。

今回、KMSに対する機能要件は以下のような事項がありました。
- 1つのディスクにつき、1つの暗号鍵を管理できること
- 暗号鍵の生成、保管、取得、ローテート、破棄ができること
- 暗号鍵の状態管理ができること
- 暗号鍵自体が平文で永続ストレージに記録されないこと
- KMSを利用するシステムからのアクセス制御、権限設定ができること
- 全ての操作を監査ログとして記録できること
- KMSをお客様データを格納するストレージから、地理的、オペレーション的に離れたところに設置できること(※1)
- KMSのセキュリティ(完全性、機密性、可用性の三要素)を自社でコントロールできること
- 高い可用性を実現できること(※2)

(※1) 暗号化されたデータと暗号鍵の両方が漏洩すると、元のデータが復号できてしまうため、データと暗号鍵は離れた場所に置いておくのがベストプラクティスである

(※2) KMSが停止すると、今回のケースではサーバの作成や起動ができない、ディスクイメージ操作ができない、といったサービス障害が発生する

これらを満たせるものを検討した結果、KMSのコア機能には、HashiCorp Vault(オープンソース版)を利用することになりました。1セットあたり3台でRaftクラスタを構成し、冗長化しています。また、障害の影響が波及しないために、アベイラビリティゾーン(さくらのクラウドだと、石狩第1ゾーン、石狩第2ゾーンのような単位)ごとに1セットずつ構築しています。

![KMSの構成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108990/e3bc0ced-d368-f42e-d5ba-4ee55bddbfce.png)

# 暗号鍵の種類と関係について

ここで暗号鍵の関係を、改めて整理しておきます。セキュリティを確保するため、ディスクの暗号鍵だけでなく、複数の暗号鍵を管理する必要があります。

![暗号鍵の関係](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108990/286722d8-d1e7-0308-9991-309b2d3e847c.png)

- DEK(Data Encryption Key)
  - お客様のディスクのデータを暗号化するための暗号鍵
  - 1つのディスクにつき、1つのDEKを生成する
  - KEKに対応するトランジットシークレットエンジンにてCSPRNGから生成
  - KEKにて暗号化し、Key Valueシークレットエンジンを利用して保管
- KEK(Key Encryption Key)
  - DEKを暗号化/復号するための暗号鍵
  - トランジットシークレットエンジンを利用
  - Vaultの外には取り出せない
- Vault Unseal Key
  - Vaultのストレージ全体を暗号化する暗号鍵(Vault Encryption Key)を復号するための暗号鍵(Vault Root Key)を秘密分散したもの

実は、HashiCorp Vaultについては、前回のブログでちょっと触れておりました。実際にどのようなコマンドを使用しているかについては、こちらに記載しています。

https://qiita.com/jh1vxw/items/b0e04b458f4b36efeb96

# KMS-APIについて

ホストサーバからKMSへのアクセスは、Vaultで直接リクエストを受けるのではなく、自社開発のKMS-APIでラッピングしています。これは、暗号鍵の管理方法を将来変更することになっても、アクセス元の実装を変更せずに済ませるためです。

例えば、将来HSMを導入したり(※)、Vaultを別のソフトウェアに変更しなければならない事情が発生したり、といったことを想定しています。抽象化レイヤーが存在することで、KMSサイドの実装変更を柔軟に行えます。

※ 初期リリース時点では、HSMはまだ導入していません。現在、導入に向けて準備を進めています。

また、KMSとの通信は暗号化する必要があり、HTTPSにて通信するようになっています。ネットワーク上を平文のDEKがそのまま流れないようにするためです。HTTPSの終端もKMS-APIが担っています。KMS-APIはステートレスに動作するため、証明書を更新するなどの際に、運用上のインパクトを最小限にできます。

# 今後の予定

まだ基本的なディスク暗号化機能をベータ版としてリリースしたばかりですが、今後以下を予定しています。

- ベータ版から正式サービスへの移行
  - 一定期間、実環境で安定性や運用面の確認を行った後、正式版に移行する予定です
- HSM(Hardware Security Module)の導入
  - 初期リリース時点では、VaultがRoot of Trustを担っていますが、HSMと連携することで、より暗号鍵保管の安全性を高める予定です
- BYOK(Bring Your Own Key)の対応
  - お客様が生成した暗号鍵を持ち込めるようにし、暗号鍵の操作が可能な機能をサポートする予定です
- ブロックストレージ以外の暗号化対応
  - アーカイブストレージ、オブジェクトストレージ、データベースアプライアンスなどの暗号化対応を順次行う予定です

ここまでお読みいただき、ありがとうございました。

# 参考文献

今回実装にあたって、様々なサイトやドキュメントを参考にさせていただきました。この場を借りてお礼申し上げます。

### ガイドライン関連

- ADEC:データ消去技術 ガイドブック
  https://adec-cert.jp/guidebook/index.html
- CRYPTREC:電子政府における調達のために参照すべき暗号のリスト
  https://www.cryptrec.go.jp/list.html
- CRYPTREC:暗号鍵管理ガイドライン
  https://www.ipa.go.jp/security/crypto/guideline/ckms.html
- CRYPTREC:暗号鍵設定ガイダンス〜暗号鍵の鍵長選択方法と運用方法〜
  https://www.ipa.go.jp/security/crypto/guideline/ckms_setting.html
- IPAによる日本語訳:NIST SP 800-57
  https://www.ipa.go.jp/security/reports/oversea/nist/ug65p90000019cp4-att/000090943.pdf
- NECセキュリティブログ:暗号鍵管理のガイドラインNIST SP800-57 part1のご紹介
  https://jpn.nec.com/cybersecurity/blog/210813/index.html
- NECセキュリティブログ:媒体のデータ抹消処理に関するガイドラインNIST SP800-88 rev.1のご紹介、およびクラウドサービスにおけるデータ抹消処理について
  https://jpn.nec.com/cybersecurity/blog/211224/index.html

### dm-crypt関連

- サイボウズエンジニアのブログ:ストレージデバイスの暗号化に用いる暗号スイート間の性能比較
  https://blog.cybozu.io/entry/2019/03/08/170000
- Arch Linux wiki
  https://wiki.archlinux.jp/index.php/保存データ暗号化
  https://wiki.archlinux.jp/index.php/Dm-crypt/デバイスの暗号化