【Amazon Aurora】SSLによる通信の暗号化

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

藤本です。

先日、データベースのネットワーク暗号化を調べる機会があったのでご紹介します。

概要

データベースをセキュアに利用するために暗号化することは一般的にあります。暗号化は大きく分けてデータの暗号化、ネットワークの暗号化があります。データの暗号化はストレージ上に保管するデータを暗号化することによりデータを盗まれても鍵を盗まれない限り読み取られることはありません。ネットワークの暗号化はクライアントとデータベース間の通信を暗号化することにより盗聴されても読み取られることはありません。

今回は先日GAがリリースされたAmazon Auroraにおけるネットワークの暗号化の接続設定を実施します。Amazon Auroraにおけるネットワークの暗号化はSSLにより暗号化します。RDS for MySQLと同じ方法を利用できます。Amazon Auroraを展開すると既にSSLサーバ証明書や秘密鍵、CA証明書が既に登録されています。またそれに対応するクライアント証明書がAWSから提供されています。

RDS for MySQLと同じ方法をご紹介するだけでは面白みがないので、実際の暗号化の確認やいくつかのケースにおける接続設定をご紹介します。

  • Amazon Linuxコマンドラインによる接続
  • MariaDB Connector/Jによる接続
  • Django(Python)による接続

環境

クライアント

  • OS : Amazon Linux AMI 2015.03.1 (HVM)

  • コマンドラインによる接続

    • mysqlクライアント : mysql-5.5-1.6.amzn1.noarch
  • MariaDB Connector/Jによる接続
    • Driver : MariaDB Connector/J 1.2.0
  • Django(Python)による接続
    • Django (1.8.4)
    • MySQL-python (1.2.5)

データベース

  • Engine : Amazon Aurora

クライアント証明書ダウンロード

AWSから提供されるクライアント証明書を下記URLからダウンロードしてください。

http://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem

ちなみに公式ドキュメント(日本語)でリンクされている証明書は既に有効期限が切れているのでご注意ください。公式ドキュメント(English)は有効期限が更新された証明書がリンクされています。

[root@ip-172-31-15-94 ~]# wget https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem

Amazon Linuxコマンドラインによる接続

Amazon Linuxのmysqlクライアントを利用したコマンドラインによるSSL接続です。
mysqlクライアントを利用したSSL接続は、--ssl-caオプションにダウンロードしたクライアント(rds-combined-ca-bundle.pem)を指定します。

まずはAmazon AuroraのSSL設定を確認します。

[root@ip-172-31-15-94 ~]# mysql -h db-cluster-1.cluster-cp4ii35k0wcq.us-east-1.rds.amazonaws.com -u sfujimoto -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 5.6.10 MySQL Community Server (GPL)

Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use db

Database changed
mysql> show variables like '%ssl%';
+---------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Variable_name | Value                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
+---------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| have_openssl  | YES                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| have_ssl      | YES                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| ssl_ca        | /rdsdbdata/rds-metadata/ca-cert.pem                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| ssl_capath    |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ssl_cert      | /rdsdbdata/rds-metadata/server-cert.pem                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| ssl_cipher    | EXP1024-RC4-SHA:EXP1024-DES-CBC-SHA:AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA:EXP-DES-CBC-SHA:EXP-RC2-CBC-MD5:RC4-SHA:RC4-MD5:EXP-RC4-MD5:NULL-SHA:NULL-MD5:DES-CBC3-MD5:DES-CBC-MD5:EXP-RC2-CBC-MD5:RC2-CBC-MD5:EXP-RC4-MD5:RC4-MD5:KRB5-DES-CBC3-MD5:KRB5-DES-CBC3-SHA:ADH-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:ADH-AES256-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:ADH-AES128-SHA:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:EXP-KRB5-RC4-MD5:EXP-KRB5-RC2-CBC-MD5:EXP-KRB5-DES-CBC-MD5:KRB5-RC4-MD5:KRB5-DES-CBC-MD5:ADH-RC4-MD5:EXP-ADH-RC4-MD5:DHE-DSS-RC4-SHA:EXP1024-DHE-DSS-RC4-SHA:EXP1024-DHE-DSS-DES-CBC-SHA:EXP-KRB5-RC4-SHA:EXP-KRB5-RC2-CBC-SHA:EXP-KRB5-DES-CBC-SHA:KRB5-RC4-SHA:KRB5-DES-CBC-SHA:ADH-DES-CBC-SHA:EXP-ADH-DES-CBC-SHA:EDH-RSA-DES-CBC-SHA:EXP-EDH-RSA-DES-CBC-SHA:EDH-DSS-DES-CBC-SHA:EXP-EDH-DSS-DES-CBC-SHA |
| ssl_crl       |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ssl_crlpath   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ssl_key       | /rdsdbdata/rds-metadata/server-key.pem                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
+---------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
9 rows in set (0.00 sec)

SSL通信が有効となっていることや、証明書、秘密鍵が設定されています。

テーブルは適当に作成します。

mysql> create table Users (username varchar(16),password varchar(16));
Query OK, 0 rows affected (0.04 sec)

まずSSLなしで接続した状態でtcpdumpしながらINSERT文を実行します。

[root@ip-172-31-15-94 ~]# mysql -h db-cluster-1.cluster-cp4ii35k0wcq.us-east-1.rds.amazonaws.com -u sfujimoto -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 5.6.10 MySQL Community Server (GPL)

Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use db

Database changed
mysql> insert into Users values ('user01','password');
Query OK, 1 row affected (0.01 sec)

----------------------------
13:20:45.512153 IP ip-172-31-15-94.ec2.internal.50152 > ip-172-31-58-135.ec2.internal.mysql: Flags [P.], seq 2713646016:2713646068, ack 2832149442, win 278, options [nop,nop,TS val 114513 ecr 19962], length 52
    0x0000:  4508 0068 0682 4000 4006 91e2 ac1f 0f5e  E..h..@.@......^
    0x0010:  ac1f 3a87 c3e8 0cea a1be f3c0 a8cf 2bc2  ..:...........+.
    0x0020:  8018 0116 a27e 0000 0101 080a 0001 bf51  .....~.........Q
    0x0030:  0000 4dfa 3000 0000 0369 6e73 6572 7420  ..M.0....insert.
    0x0040:  696e 746f 2055 7365 7273 2076 616c 7565  into.Users.value
    0x0050:  7320 2827 7573 6572 3031 272c 2027 7061  s.('user01',.'pa
    0x0060:  7373 776f 7264 2729                      ssword')
----------------------------

mysql> select * from Users;
+----------+----------+
| username | password |
+----------+----------+
| user01   | password |
+----------+----------+
1 row in set (0.00 sec)

あちゃー、passwordが丸見えですね。INSERT文がそのまま平文で流れていることが分かります。

次にSSL接続した状態でtcpdumpしながらINSERT文を流します。

[root@ip-172-31-15-94 ~]# mysql -h db-cluster-1.cluster-cp4ii35k0wcq.us-east-1.rds.amazonaws.com -u sfujimoto -p --ssl-ca=/root/rds-combined-ca-bundle.pem
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 5.6.10 MySQL Community Server (GPL)

Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use db

Database changed
mysql> insert into Users values ('user02','password');
Query OK, 1 row affected (0.01 sec)

----------------------------
14:03:28.741641 IP ip-172-31-15-94.ec2.internal.35162 > ip-172-31-55-9.ec2.internal.mysql: Flags [P.], seq 662:784, ack 772, win 300, options [nop,nop,TS val 755321 ecr 57594], length 122
    0x0000:  4508 00ae 7110 4000 4006 2a8c ac1f 0f5e  E...q.@.@.*....^
    0x0010:  ac1f 3709 895a 0cea 6bd5 3933 24f1 837a  ..7..Z..k.93$..z
    0x0020:  8018 012c 9f46 0000 0101 080a 000b 8679  ...,.F.........y
    0x0030:  0000 e0fa 1703 0100 208f c664 c222 31c3  ...........d."1.
    0x0040:  fd2b 2e10 3314 90b3 1999 ed8b 17d4 12fd  .+..3...........
    0x0050:  642d 5df8 1dc4 e69b d117 0301 0050 2751  d-]..........P'Q
    0x0060:  3e76 8cb5 8742 17c3 4189 69ea 5c88 733e  >v...B..A.i.\.s>
    0x0070:  5fb6 b7a3 4b71 5a03 1155 2aba 471f 594b  _...KqZ..U*.G.YK
    0x0080:  f60b df05 4429 cf64 cf4b 8255 6a65 76f4  ....D).d.K.Ujev.
    0x0090:  c255 fb50 7854 16cf 70fe 283f f521 7e94  .U.PxT..p.(?.!~.
    0x00a0:  d0cb a271 d30d bddd e34d bb60 7e4f       ...q.....M.`~O
----------------------------

mysql> select * from Users;
+----------+----------+
| username | password |
+----------+----------+
| user01   | password |
| user02   | password |
+----------+----------+
2 rows in set (0.00 sec)

暗号化されていますね。オプション一つで暗号化できます。簡単ですね。

またユーザー単位でSSL接続を強制することも出来ます。

GRANT USAGE ON *.* TO 'encrypted_user'@'%' REQUIRE SSL 

encrypted_userをSSL接続を強制したいDBユーザー名に置き換えてください。

MariaDB Connector/Jにおける接続

MariaDB Connector/Jについては下記エントリを参照ください。
MariaDB Connector/JによるAmazon RDS for Auroraの高速フェイルオーバー

公式ページに習って、serverSslCertオプションにクライアント証明書を指定します。
About MariaDB Connector/J

tcpdumpしながらJavaプログラムを実行します。

[root@ip-172-31-15-94 java]# cat AuroraSample.java
import java.sql.*;

public class AuroraSample {
    public static void main (String[] args) {
        Connection conn = null;
        try {
            Class.forName("org.mariadb.jdbc.Driver");
            conn = DriverManager.getConnection(
                "jdbc:mysql:aurora://"
                + "db-cluster.cluster-cp4ii35k0wcq.us-east-1.rds.amazonaws.com:3306,"
                + "db-replica.cp4ii35k0wcq.us-east-1.rds.amazonaws.com:3306"
                + "/db?user=sfujimoto&password=password&useSSL=true&serverSslCert=rds-combined-ca-bundle.pem"
            );

            Statement stmt = conn.createStatement();
            String sql = "insert into users values ('user03','password')";
            stmt.executeUpdate(sql);
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

[root@ip-172-31-15-94 java]# javac -cp ./mariadb-java-client-1.3.0-SNAPSHOT.jar AuroraSample.java
[root@ip-172-31-15-94 java]# java -cp .:mariadb-java-client-1.3.0-SNAPSHOT.jar:slf4j-api-1.7.12.jar AuroraSample

----------------------------
04:28:36.592835 IP ip-172-31-15-94.ec2.internal.49247 > ip-172-31-28-58.ec2.internal.mysql: Flags [P.], seq 627:749, ack 1843, win 264, options [nop,nop,TS val 1904731 ecr 1906772], length 122
    0x0000:  4500 00ae d72a 4000 4006 df48 ac1f 0f5e  E....*@.@..H...^
    0x0010:  ac1f 1c3a c05f 0cea 1ab8 c991 52bf 0254  ...:._......R..T
    0x0020:  8018 0108 8477 0000 0101 080a 001d 105b  .....w.........[
    0x0030:  001d 1854 1703 0100 20cf d4c7 ce54 8e12  ...T.........T..
    0x0040:  8ea7 1ad8 1f6b 1010 01f3 b7f5 c0a8 1f1d  .....k..........
    0x0050:  dc1f b498 ab7e 2eba 2017 0301 0050 d638  .....~.......P.8
    0x0060:  c25a 67f7 49e5 ca48 1cb7 52d8 fd9c 49b3  .Zg.I..H..R...I.
    0x0070:  bd03 541c 4d73 dad8 5ee8 1ccf a1d2 db8b  ..T.Ms..^.......
    0x0080:  bced 2532 5b69 cba9 544e 2842 7bcc 52ad  ..%2[i..TN(B{.R.
    0x0090:  e774 e63e 7dcd cdb7 e129 444e 2cfd 9989  .t.>}....)DN,...
    0x00a0:  4cae 6922 d405 dff6 35af 589a ad8c       L.i"....5.X...
----------------------------

[root@ip-172-31-15-94 ~]# mysql -h db-cluster.cluster-cp4ii35k0wcq.us-east-1.rds.amazonaws.com -u sfujimoto -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 535
Server version: 5.6.10 MySQL Community Server (GPL)

Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use db

Database changed
mysql> select * from users;
+----------+-----------+
| username | passwordd |
+----------+-----------+
| user01   | password  |
| user02   | password  |
| user03   | password  |
+----------+-----------+
3 rows in set (0.00 sec)

Django(Python)による接続

次はWebアプリケーションを例にした実装です。やっぱりDjangoですよね。settings.pyのデータベース設定にオプションを付け加えます。 こちらの設定は公式ドキュメントで見つけられず、stackoverflowからDjangoのソースを確認して、知ることが出来ました。

tcpdumpしながらWebリクエストを送信します。

[root@ip-172-31-15-94 ~]# cat ./project/settings.py
(略)
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': 'db-cluster-1.cluster-cp4ii35k0wcq.us-east-1.rds.amazonaws.com',
        'PORT': 3306,
        'NAME': 'db',
        'USER': 'sfujimoto',
        'PASSWORD': 'password',
        'OPTIONS':  {
            'ssl': {
                'ca': '/root/rds-combined-ca-bundle.pem',
            }
        }
    }
}

[ec2-user@ip-172-31-15-94 ~]# cat ./app/views.py
from django.http import HttpResponse
from app.models import Users
import json

# Create your views here.
def register(request):
  req_body = json.loads(request.body)
  u = Users(req_body['username'], req_body['password'])
  u.save()
  return HttpResponse("Success")

[ec2-user@ip-172-31-15-94 ~]$ ./manage.py runserver &
[ec2-user@ip-172-31-15-94 ~]$ curl -d '{"username":"user04", "password":"password"}' -X POST http://localhost:8000/register/
Success

----------------------------
14:43:14.057632 IP ip-172-31-15-94.ec2.internal.35252 > ip-172-31-55-9.ec2.internal.mysql: Flags [P.], seq 1038:1192, ack 1602, win 228, options [nop,nop,TS val 1351650 ecr 656019], length 154
    0x0000:  4508 00ce 24f8 4000 4006 7684 ac1f 0f5e  E...$.@.@.v....^
    0x0010:  ac1f 3709 89b4 0cea 1006 bf45 ffe2 dd41  ..7........E...A
    0x0020:  8018 00e4 9f66 0000 0101 080a 0014 9fe2  .....f..........
    0x0030:  000a 0293 1703 0100 20a5 8b95 6c8a 1356  ............l..V
    0x0040:  558c afac 6c24 a9f0 385a aabb f634 1bee  U...l$..8Z...4..
    0x0050:  4544 eb19 1d2e 9b32 ea17 0301 0070 61e6  ED.....2.....pa.
    0x0060:  f005 bc97 868b 7ee3 4cdb 4419 3270 c15e  ......~.L.D.2p.^
    0x0070:  e925 3fa0 71d5 9ef3 9a7c c66e 1cf6 ba99  .%?.q....|.n....
    0x0080:  69cf 6484 abd1 42aa 1fd4 e6ac 036d d206  i.d...B......m..
    0x0090:  8a67 1817 4d97 0e2b b3b1 abc8 ff9c 967e  .g..M..+.......~
    0x00a0:  09a5 ceeb 9dc0 ffe7 c04f d826 5e97 31ce  .........O.&^.1.
    0x00b0:  34e4 c324 cb8b da96 8dc3 c926 01ac c184  4..$.......&....
    0x00c0:  8f1c 77d8 f5f0 73e2 d5c6 9bae 8bac       ..w...s.......
----------------------------

[ec2-user@ip-172-31-15-94 ~]$ ./manage.py dbshell

mysql> select * from app_users;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  9 | user04   | password |
+----+----------+----------+
1 row in set (0.00 sec)

まとめ

いかがでしたでしょうか?
Amazon Auroraのネットワーク暗号化はクライアント証明書さえダウンロードしていれば、オプション一つで設定可能です。データベース側は何も設定しなくとも全てAWS側が準備してくれています。クラウドの推進により物理環境がブラックボックスとなりセキュリティ対策が当たり前となっている状況でこの導入のハードルの低さはありがたいです。