Linux
AWS
Elasticsearch
dm-crypt
crypto

Elasticsearchのデータ暗号化


はじめに

Elasticsearchのデータ暗号化について、検討する機会があったので、記事にまとめてみました^^:


利用した環境

product
version

cryptsetup
1.7.4

Elasticsearch
6.6.0

OS
Amazon Linux2 (4.14.88)

Instance Type
m5.2xlarge

EBS
ルート(8GB)、追加(30GB)

AMI
ami-04677bdaa3c2b6e24

【ディスクの状態】

nvme0n1が8GBのルートボリューム、nvme1n1が追加の30GBボリュームです。

※m5はNitro世代のEC2インスタンスでEBS NVMeボリュームのため、/dev/nvmeXnXという名称

[root@ip-172-31-34-49 ~]# lsblk

NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
nvme1n1 259:0 0 30G 0 disk
nvme0n1 259:1 0 8G 0 disk
├─nvme0n1p1 259:2 0 8G 0 part /
└─nvme0n1p128 259:3 0 1M 0 part

[root@ip-172-31-34-49 ~]# df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 16G 0 16G 0% /dev
tmpfs 16G 0 16G 0% /dev/shm
tmpfs 16G 388K 16G 1% /run
tmpfs 16G 0 16G 0% /sys/fs/cgroup
/dev/nvme0n1p1 8.0G 1.2G 6.9G 15% /
tmpfs 3.1G 0 3.1G 0% /run/user/1000


基本的な考え方

Elasticsearchのデータ(=Index)暗号化では、日立ソリューションズ社のCredeon Secure Full-text Searchがありますが、あくまで全文検索のためのIndex暗号化であって、Kibanaが利用するaggregation機能には対応していません。

Elastic Stackでは5.3.0から保存データの暗号化に対応しています。

サブスクリプションのPlatinum Editionで対応していますが、あくまでdm-cryptを用いたボリュームの暗号化を利用した場合でもElasticsearchとしてサポートするというものです。暗号化機能が付いている訳ではありません。


dm-cryptとは

Device-Mapperの機能の1つでLinuxにおけるブロックデバイス暗号の仕組みです。

Kernel 2.6以降のdevice-mapperモジュールに標準で組み込まれていて、cyptsetupという暗号化管理ツールを使ってストレージデバイスの暗号化を行います。

dmcrypt.PNG

【参考】

LUKSとは?


設定手順


  1. Java 1.8.0 インストール

  2. Elasticsearch 6.6.0 インストール

  3. JVMヒープサイズ設定

  4. Elasticsearch設定

  5. 暗号化ボリュームの設定

  6. Index保存領域の作成

  7. 設定確認


1. Java 1.8.0 インストール

Javaがインストールされていないことを確認した上でJava 1.8.0をインストールします。

[root@ip-172-31-34-49 ~]# java -version

-bash: java: command not found

[root@ip-172-31-34-49 ~]# yum install -y java-1.8.0-openjdk
<インストールの経過は省略>

[root@ip-172-31-34-49 ~]# java -version
openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)


2. Elasticsearch 6.6.0 インストール

Elastic社公式のリポジトリを登録し、Elasticsearch 6.6.0をインストールします。

[root@ip-172-31-34-49 ~]# vi /etc/yum.repos.d/elastic.repo

[root@ip-172-31-34-49 ~]# cat /etc/yum.repos.d/elastic.repo
[elasticsearch-6.x]
name=Elasticsearch repository for 6.x packages
baseurl=https://artifacts.elastic.co/packages/6.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md

[root@ip-172-31-34-49 ~]# yum install -y elasticsearch
<インストールの経過は省略>

[root@ip-172-31-34-49 ~]# systemctl status elasticsearch
● elasticsearch.service - Elasticsearch
Loaded: loaded (/usr/lib/systemd/system/elasticsearch.service; disabled; vendor preset: disabled)
Active: inactive (dead)
Docs: http://www.elastic.co


3. JVMヒープサイズ設定

Elasticsearchには物理メモリの半分を上限にJVMヒープを割り当てます。

m5.2xlargeのメモリは32GBなので、今回は15GBのメモリを割り当てます。

[root@ip-172-31-34-49 ~]# vi /etc/elasticsearch/jvm.options

-Xms15g
-Xmx15g
# 以下、設定の確認です。
[root@ip-172-31-34-49 ~]# cat /etc/elasticsearch/jvm.options | grep 15


4. Elasticsearch設定

ElasticsearchのIndex保存領域をpath.dataで指定します。今回は/mnt/es/elasticsearchとします。

[root@ip-172-31-34-49 ~]# vi /etc/elasticsearch/elasticsearch.yml

path.data: /mnt/es/elasticsearch
# 以下、設定の確認です。
[root@ip-172-31-34-49 ~]# cat /etc/elasticsearch/elasticsearch.yml | grep path.data


5. 暗号化ボリュームの設定

cryptsetupコマンドで/dev/nvme1n1にAES256/SHA1暗号化ボリューム(esvol)を作成し、/mnt/esにマウントします。

[root@ip-172-31-34-49 ~]# cryptsetup --key-size 512 --hash sha512 luksFormat /dev/nvme1n1

WARNING!
========
This will overwrite data on /dev/nvme1n1 irrevocably.

Are you sure? (Type uppercase yes): YES
Enter passphrase: #パスワードを設定
Verify passphrase: #パスワードの確認

[root@ip-172-31-34-49 ~]# cryptsetup luksOpen /dev/nvme1n1 esvol
Enter passphrase for /dev/nvme1n1: #上記で設定したパスワードを入力

[root@ip-172-31-34-49 ~]# ls /dev/mapper
control esvol

[root@ip-172-31-34-49 ~]# mkfs.ext4 /dev/mapper/esvol
mke2fs 1.42.9 (28-Dec-2013)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
1966080 inodes, 7863808 blocks
393190 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=2155872256
240 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000

Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

[root@ip-172-31-34-49 ~]# mount /dev/mapper/esvol /mnt/es
[root@ip-172-31-34-49 ~]# ll /mnt
total 4
drwxr-xr-x 3 root root 4096 Feb 10 18:29 es

暗号化ボリュームが作成されていることを確認します。

[root@ip-172-31-34-49 ~]# lsblk

NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
nvme1n1 259:0 0 30G 0 disk
└─esvol 253:0 0 30G 0 crypt /mnt/es
nvme0n1 259:1 0 8G 0 disk
├─nvme0n1p1 259:2 0 8G 0 part /
└─nvme0n1p128 259:3 0 1M 0 part

[root@ip-172-31-34-49 ~]# df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 16G 0 16G 0% /dev
tmpfs 16G 0 16G 0% /dev/shm
tmpfs 16G 392K 16G 1% /run
tmpfs 16G 0 16G 0% /sys/fs/cgroup
/dev/nvme0n1p1 8.0G 1.5G 6.6G 19% /
/dev/mapper/esvol 30G 45M 28G 1% /mnt/es
tmpfs 3.1G 0 3.1G 0% /run/user/1000


6. Index保存領域の作成

/mnt/es配下にelasticsearchディレクトリを作成し、適切な権限を付与します。

[root@ip-172-31-34-49 elasticsearch]# cd /mnt/es

[root@ip-172-31-34-49 es]# mkdir elasticsearch
[root@ip-172-31-34-49 es]# chown elasticsearch:elasticsearch elasticsearch/
[root@ip-172-31-34-49 es]# chmod 750 elasticsearch/
[root@ip-172-31-34-49 es]# ll
total 20
drwxr-x--- 2 elasticsearch elasticsearch 4096 Feb 10 21:47 elasticsearch
drwx------ 2 root root 16384 Feb 10 18:29 lost+found

Elasticsearchをサービス起動し、path.data配下にNodeIDファイル(node-0.st)が生成されていることを確認します。

[root@ip-172-31-34-49 es]# systemctl start elasticsearch

[root@ip-172-31-34-49 es]# cat elasticsearch/nodes/0/_state/node-0.st
?lstate:)
node_idUWTgg6zqmS2Cq72YdCOdCpA(


7. 設定確認


  • 暗号化した30GBの追加EBSボリュームのSnapshotを作成します。

  • 作成したSnapshotから別途EBSボリュームを作成し、別EC2にアタッチします。

EBSをアタッチしたEC2にログインし、追加EBSとしてnvme1n1が存在していることを確認します。

[root@ip-172-31-6-22 ~]# lsblk

NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
nvme0n1 259:0 0 100G 0 disk
├─nvme0n1p1 259:1 0 100G 0 part /
└─nvme0n1p128 259:2 0 1M 0 part
nvme1n1 259:3 0 30G 0 disk

[root@ip-172-31-6-22 ~]# df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 3.8G 0 3.8G 0% /dev
tmpfs 3.8G 0 3.8G 0% /dev/shm
tmpfs 3.8G 380K 3.8G 1% /run
tmpfs 3.8G 0 3.8G 0% /sys/fs/cgroup
/dev/nvme0n1p1 100G 2.2G 98G 3% /
tmpfs 763M 0 763M 0% /run/user/1000

/mnt/esにマウントし、内容を確認してみます。

[root@ip-172-31-6-22 ~]# mkdir /mnt/es

[root@ip-172-31-6-22 ~]# mount -o discard /dev/nvme1n1 /mnt/es
mount: /mnt/es: unknown filesystem type 'crypto_LUKS'.


まとめ

LUKSで暗号化したボリュームを他マシンにマウントしても認識しませんでした。

これでElasticsearchノードにログインされない限り、OSレベルでのIndexデータの機密性は確保できました。

ElasticsearchのData Nodeをi3系インスタンスで構築し、NVMe SSDにIndexを配置することで暗号化することも可能です。


NVMe インスタンスストレージのデータは、インスタンスのハードウェアモジュールに実装されている XTS-AES-256 ブロック暗号を使用して暗号化されます。暗号化キーは、ハードウェアモジュールで作成され、NVMe インスタンスストレージデバイスごとに固有です。すべての暗号化キーは、インスタンスが停止または終了して復元できないときに破棄されます。この暗号化を無効にしたり、独自の暗号キーを指定したりすることはできません。


以上、いかがでしたでしょうか。

不明な点、誤植などありましたら、コメントをお願いします!!