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 します。

既存EC2インスタンスにIAMロールをアタッチ

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 レポジトリにあります。

https://github.com/goto-satoru/create-aws-kms-key