AWS KMS プラグインによる暗号鍵の管理
MariaDB Server は バージョン 10.1 からデータ暗号化(Data-at-Rest Encryption)をサポートしていますが,暗号化鍵の管理(ローテーション等)において AWS KMS(Key Management Service)を利用することが可能となっています。
今回は Amazon EC2 インスタンスに MariaDB Server 10.4 をインストールし,AWS KMS で生成した暗号鍵を利用してデータの暗号化を行ってみます。
実行環境
AWS SDK C++, AWS KMS プラグインをソースからビルドする必要があるため,今回は 4 vCPU / 16 GB メモリのインスタンスタイプを利用しました。
- Amazon EC2 インスタンスタイプ: t2.xlarge
- OS: CentOS 7.6.10 (SELINUX=disabled)
- MariaDB : Community Server 10.4.7
cmake3 のインストール
AWS SDK C++ のビルドにバージョン 3.2 以降の cmake が必要となりますが,CentOS 7.6 標準の cmake は 2.8 ですので,cmake3 を事前にインストールします。
sudo yum -y install cmake3
AWS SDK C++ KMS クライアントのビルド事前準備
Setting Up the AWS SDK for C++ に従い AWS SDK C++ の依存パッケージをインストールします。
sudo yum -y install gcc gcc-c++ bison git sudo yum -y install libcurl-devel openssl-devel libuuid-devel pulseaudio-libs-devel
MariaDB Server aws_key_management プラグインのビルド
GitHub から MariaDB Community Server 10.4.7 を clone, AWS KMS プラグインのみビルドします。
sudo yum -y install ncurses-devel git clone -b mariadb-10.4.7 https://github.com/MariaDB/server.git mkdir build10.4 cd build10.4 cmake3 -DRPM=centos7 -DPLUGIN_AWS_KEY_MANAGEMENT=DYNAMIC -DAWS_SDK_EXTERNAL_PROJECT=1 -DNOT_FOR_DISTRIBUTION=1 ../server make -j4 aws_key_management
ビルドしたプラグインを MariaDB プラグインディレクトリにコピーします。
sudo cp -pf plugin/aws_key_management/aws_key_management.so /usr/lib64/mysql/plugin/
MariaDB Community Server 10.4.7 のインストール
レポジトリ設定を行い,MariaDB Community Server 10.4.7 をインストール,起動します。
curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash sudo yum -y install MariaDB-server sudo systemctl enable mariadb sudo systemctl start mariadb
IAM Role 作成,EC2 インスタンスへのアタッチ
AWS KMS Encryption Plugin Setup Guide には,/var/lib/mysql/.aws/credentials
に AWS Access Key ID と Secret Access Key を記述するよう記載されていますが,MariaDB Server を EC2 上で稼働させる場合は,IAM Role をアタッチすることで AWS アクセスキーをテキストファイルに平文(plain text)で記述する必要がなくなり,よりセキュアとなります。
IAM / KMS管理権限を持つ AWS アカウントにて AWS CLI を利用し,AWSKeyManagementServicePowerUser ポリシーを割り当てた IAM Role を作成します。
以下のような シェルスクリプトを作成,
#!/bin/sh if [ $# -lt 1 ] ; then echo -e "Usage: $0 role_name\n" exit 1 fi role_name=$1 managed_policy="arn:aws:iam::aws:policy/AWSKeyManagementServicePowerUser" aws iam create-role --role-name $role_name \ --assume-role-policy-document file://ec2-role-trust-policy.json \ --description "Allows EC2 instances to call AWS services on your behalf" aws iam attach-role-policy --role-name $role_name \ --policy-arn $managed_policy aws iam create-instance-profile --instance-profile-name $role_name aws iam add-role-to-instance-profile --instance-profile-name $role_name \ --role-name $role_name
ここで,ec2-role-trust-policy.json は以下のようなポリシードキュメントです。
{ "Version": "2012-10-17", "Statement": { "Effect": "Allow", "Principal": {"Service": "ec2.amazonaws.com"}, "Action": "sts:AssumeRole" } }
ここでは,kms-power-user
という Role を作成してみます。
./create-role.sh kms-power-user
EC2 ダッシュボードで EC2 インスタンスを選択,Actions – Instance Settings – Attach/Replace IAM Role から作成した Role を Apply します。
AWS KMS Key 作成
AWS CLI を用い,暗号鍵を作成します。
以下のようなシェルスクリプトを用い暗号鍵を作成,aliasを設定,ポリシーJSONドキュメントを作成,適用します。
#!/bin/sh key_id=`aws kms create-key | jq -r '.KeyMetadata.KeyId'` echo "AWS KMS KeyId: $key_id" echo -n "AWS KMS Master key alias: " read key_alias aws kms create-alias --alias-name "alias/$key_alias" --target-key-id $key_id echo -e "\nexisiting IAM Roles:" aws iam list-roles | jq -r '.Roles[] | .RoleName' echo echo -n "IAM Role name for KMS: " read role_name aws_id=`aws sts get-caller-identity | jq -r '.Account' ` echo "AWS Account ID: $aws_id" policy_file='kms-key-policy.json' cat <<EOF >$policy_file { "Version": "2012-10-17", "Id": "key-consolepolicy-3", "Statement": [ { "Sid": "Enable IAM User Permissions", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::${aws_id}:root" }, "Action": "kms:*", "Resource": "*" }, { "Sid": "Allow use of the key", "Effect": "Allow", "Principal": { "AWS": [ "arn:aws:iam::${aws_id}:role/$role_name" ] }, "Action": [ "kms:Encrypt", "kms:Decrypt", "kms:ReEncrypt*", "kms:GenerateDataKey*", "kms:DescribeKey" ], "Resource": "*" }, { "Sid": "Allow attachment of persistent resources", "Effect": "Allow", "Principal": { "AWS": [ "arn:aws:iam::${aws_id}:role/$role_name" ] }, "Action": [ "kms:CreateGrant", "kms:ListGrants", "kms:RevokeGrant" ], "Resource": "*", "Condition": { "Bool": { "kms:GrantIsForAWSResource": true } } } ] } EOF dos2unix $policy_file echo "AWS KMS KeyId: $key_id" aws kms put-key-policy --key-id $key_id \ --policy-name default \ --policy file://$policy_file
ここでは,alias/test-mariadb
という alias を設定し,kms-power-user
という IAM Role を割り当てます。
$ ./create-kms-key.sh AWS KMS KeyId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx AWS KMS Master key alias: test-mariadb exisiting IAM Roles: AWSServiceRoleForSupport kms-power-user IAM Role name for KMS: kms-power-user AWS Account ID: 012345678901
動作確認
暗号化(Data-at-Rest Encryption)無効の場合
まず比較のために Data-at-Rest Encryption 無効のままで,テストテーブルを作成,データを確認します。
MariaDB [test]> CREATE TABLE noencryption (note VARCHAR(10)); MariaDB [test]> INSERT INTO noencryption VALUES ('maria'),('monty'),('my'); MariaDB [test]> SELECT * FROM noencryption; +-------+ | note | +-------+ | maria | | monty | | my | +-------+
strings コマンドでテーブルデータに含まれている文字列を確認します。
sudo su - cd /var/lib/mysql/test strings noencryption.ibd infimum supremum maria monty
Data-at-Rest Encryption が無効にされている場合,テーブルデータ中の文字列が見えてしまいます。
暗号化(Data-at-Rest Encryption)有効の場合
暗号化を行う場合は /etc/my.cnf.d/server.cnf を以下のように設定し,
[mariadb] log_error plugin_load_add = aws_key_management aws-key-management aws-key-management-master-key-id = alias/test-mariadb aws-key-management-region = ap-northeast-1 !include /etc/my.cnf.d/enable_encryption.preset
mariadb service を再起動します。
sudo systemctl restart mariadb
エラーログに以下のようなログが記録されていれば,AMS KMS で作成された暗号鍵で正常に Data-at-Rest Encryption が行われています。
2019-08-01 10:04:07 0 [Note] mysqld: AWS KMS plugin: generated encrypted datakey for key id=2, version=1 2019-08-01 10:04:07 0 [Note] mysqld: AWS KMS plugin: loaded key 2, version 1, key length 128 bit 2019-08-01 10:04:07 0 [Note] Using encryption key id 2 for temporary files
MariaDB [(none)]> use test; MariaDB [test]> CREATE TABLE encrypted (note VARCHAR(10)); MariaDB [test]> INSERT INTO encrypted VALUES ('Maria'),('Monty'),('My'); Records: 3 Duplicates: 0 Warnings: 0 MariaDB [test]> SELECT * FROM encrypted; +-------+ | note | +-------+ | Maria | | Monty | | My | +-------+
暗号化なしの場合と同様に,/var/lib/mysql/test で strings コマンドを実行してみます。
0e#& ebt0 l +2: [(iRy o(lO 7c3>Z b`zY^ wqTV _Et2E`m Lh{? nsV- q@< 42-2 SX-x 2~16-c ?{MI no3W# @k / r lxru gV P=* (&=B ...
データが暗号化されていることが確認できました。
トラブルシューティング
エラーログに以下のようなエラーが記録されている場合は,SELinux が有効になっていると考えられますので,無効にするか,AWS API による KMS へのアクセスを許可してください。
2019-08-01 12:23:08 0 [ERROR] mysqld: AWS KMS plugin : KMS Client API 'Decrypt' failed : - Unable to connect to endpoint
まとめ
AWS KMS プラグインを用いて,MariaDB Server 10.4 のテーブルデータの暗号化を試しました。
今回 IAM Role 作成,KMS Key 作成に用いたシェルスクリプトは以下の GitHub レポジトリにあります。