![[アップデート]Amazon RDS for PostgreSQLがTLS(v1.2)接続時に利用できる暗号スイートを制限できるようになりました](https://images.ctfassets.net/ct0aopd36mqt/wp-thumbnail-1ae9459a9164cd009c1564b2c0d294bd/538b644374647d5c4362c716c7c009f4/postgresql-1200x630.png)
[アップデート]Amazon RDS for PostgreSQLがTLS(v1.2)接続時に利用できる暗号スイートを制限できるようになりました
はじめに
先日Amazon RDS for PostgreSQLにTLS通信の際に利用できる暗号スイートを変更できるアップデートがありました。
PostgreSQLではTLS通信時に利用する暗号スイートをssl_ciphers
というパラメータで指定することが可能です。
RDSはこれまでこのパラメーターが変更できなかったためデフォルトの許可設定ではセキュリティ要件が合わない場合、各接続元側(クライアント側)で利用可能な暗号スイートを絞り込み所定の暗号スイートで通信させるような対応が必要でした。
今回のアップデートによりDB側(サーバ側)で利用できる暗号スイートが設定できるようになったため、クライアントの設定によらず一定以上の暗号化強度の保証をまとめてDB側で制御できるようになりました。
Amazon RDS for PostgreSQL 16.1 and later will support modification of the ssl_ciphers parameter.
今回の変更はPostgreSQL 16.1以上が対象となります。
デフォルトで利用可能な暗号スイート
ssl_cipher
が未指定(=RDSデフォルト)の値は本記事執筆時点(2025/04/03)では以下の通りです。
暗号スイートのレベルでの制御まで触らない方にはあまり馴染みがない文字列かもしれませんが、OpenSSL等の設定で利用される暗号化文字列です。
暗号文字列は、利用可能な具体的な暗号スイートもしくは特定の意味を持つセットや演算子をコロン区切りで列挙した文字列でとなっており、例えばHIGH:!aNULL:!3DES
の場合は「高強度な暗号スイート(現在は鍵帳128bit以上のアルゴリズム)」かつ「認証を提供しないアルゴリズムではない」かつ「3DESではない」暗号スイートを示します。
TLSv1.2の場合かつHIGH:!aNULL:!3DES
の場合、以下の文字列と同義です。
#openssl ciphers -s -tls1_2 'HIGH:!aNULL:!3DES'
ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-CCM:DHE-RSA-AES256-CCM:ECDHE-ECDSA-ARIA256-GCM-SHA384:ECDHE-ARIA256-GCM-SHA384:DHE-DSS-ARIA256-GCM-SHA384:DHE-RSA-ARIA256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-CCM:DHE-RSA-AES128-CCM:ECDHE-ECDSA-ARIA128-GCM-SHA256:ECDHE-ARIA128-GCM-SHA256:DHE-DSS-ARIA128-GCM-SHA256:DHE-RSA-ARIA128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA256:ECDHE-ECDSA-CAMELLIA256-SHA384:ECDHE-RSA-CAMELLIA256-SHA384:DHE-RSA-CAMELLIA256-SHA256:DHE-DSS-CAMELLIA256-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:DHE-DSS-AES128-SHA256:ECDHE-ECDSA-CAMELLIA128-SHA256:ECDHE-RSA-CAMELLIA128-SHA256:DHE-RSA-CAMELLIA128-SHA256:DHE-DSS-CAMELLIA128-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:DHE-RSA-CAMELLIA256-SHA:DHE-DSS-CAMELLIA256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:DHE-RSA-CAMELLIA128-SHA:DHE-DSS-CAMELLIA128-SHA:AES256-GCM-SHA384:AES256-CCM:ARIA256-GCM-SHA384:AES128-GCM-SHA256:AES128-CCM:ARIA128-GCM-SHA256:AES256-SHA256:CAMELLIA256-SHA256:AES128-SHA256:CAMELLIA128-SHA256:AES256-SHA:CAMELLIA256-SHA:AES128-SHA:CAMELLIA128-SHA
今回のアップデートはいくつかの暗号スイートからの選択式
本来のPostgreSQLであれば上記のように色々書き込んで幅広くカスタマイズできるのですが、実際にパラメータグループで設定画面開いてみると所定の値からの選択式となっていました。
本記事執筆時点(2024/04/03)では以下の5つが選択可能です。
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
この辺りあまり詳しくないですがTLSv1.3で利用可能な暗号スイート相当な気がします。
# openssl ciphers -s -tls1_3
TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/PostgreSQL.Concepts.General.SSL.html
By default, the value of ssl_max_protocol_version in RDS for PostgreSQL 16 and later is TLS v1.3. You must set the value of this parameter to TLS v1.2 as TLS v1.3 doesn't use the cipher configurations specified in the ssl_ciphers parameter. When you set the value as TLS v1.2, connections use only the ciphers that you define in ssl_ciphers.
また、ssl_cipher
はTLSv1.2のみに適用されTLSv1.3では適用されないためご注意ください。上記の選択肢から背景を想像するにTLSv1.2でもTLSv1.3相当の暗号スイートで通信させたいケースへのアップデートなのかもしれません。
https://www.postgresql.org/docs/17/runtime-config-connection.html#GUC-SSL-CIPHERS
ssl_ciphers (string)
Specifies a list of SSL cipher suites that are allowed to be used by SSL connections. See the ciphers manual page in the OpenSSL package for the syntax of this setting and a list of supported values. Only connections using TLS version 1.2 and lower are affected. There is currently no setting that controls the cipher choices used by TLS version 1.3 connections. The default value is HIGH:MEDIUM:+3DES:!aNULL. The default is usually a reasonable choice unless you have specific security requirements.
一応名誉のために書いておくとTLSv1.3の暗号スイートが制御できないのはRDS固有の制限ではなくPostgreSQL側の仕様です。
実際に試してみる
今回はPostgreSQL 17.4で試します。
確認はpsql
で、と行きたいところですが、psql
自体には暗号スイートの設定はないのでopenssl
コマンドで繋ぎに行きます(確認もこっちの方がしやすいんですよね)。
% openssl version
OpenSSL 3.2.2 4 Jun 2024 (Library: OpenSSL 3.2.2 4 Jun 2024)
opnenssl
コマンドで繋ぐ場合-starttls
オプションでpostgres
を指定すればOKです。
-starttls prot - use the STARTTLS command before starting TLS
for those protocols that support it, where
'prot' defines which one to assume. Currently,
only "smtp", "pop3", "imap", "ftp", "xmpp",
"xmpp-server", "irc", "postgres", "lmtp", "nntp",
"sieve" and "ldap" are supported.
デフォルト設定
まずはssl_ciphers
がデフォルトの状態で接続しに行きます。
後の確認とコマンドを合わせるために-cipher 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'
を指定しRDS側にはこのアルゴリズムのみが利用可能と伝達されるようにしておきます。
# openssl s_client -connect database-1.xxxxx.ap-northeast-1.rds.amazonaws.com:5432 -starttls postgres -tls1_2 -trace -cipher 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'
Connecting to 192.168.1.65
CONNECTED(00000003)
Sent TLS Record
Header:
Version = TLS 1.0 (0x301)
Content Type = Handshake (22)
Length = 188
ClientHello, Length=184
...
session_id (len=0):
cipher_suites (len=4)
{0xC0, 0x2F} TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
{0x00, 0xFF} TLS_EMPTY_RENEGOTIATION_INFO_SCSV
...
Received TLS Record
Header:
Version = TLS 1.2 (0x303)
Content Type = Handshake (22)
Length = 59
ServerHello, Length=55
...
session_id (len=0):
cipher_suite {0xC0, 0x2F} TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
...
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES128-GCM-SHA256
Session-ID:
Session-ID-ctx:
Master-Key: xxxxx
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1743672785
Timeout : 7200 (sec)
Verify return code: 19 (self-signed certificate in certificate chain)
Extended master secret: yes
---
OKです。ECDHE-RSA-AES128-GCM-SHA256
はHIGH:!aNULL:!3DES
に含まれるのでこの時点では通信できています。
絞り込み後(不一致パターン)
さて今回の本命、ssl_cipher
でTLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
のみを許可するようにし実行してみましょう。該当パラメータは動的なので再起動不要で適用されます。
% openssl s_client -connect database-1.xxxxx.ap-northeast-1.rds.amazonaws.com:5432 -starttls postgres -tls1_2 -trace -cipher 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'
Connecting to 192.168.1.65
CONNECTED(00000003)
Sent TLS Record
Header:
...
session_id (len=0):
cipher_suites (len=4)
{0xC0, 0x2F} TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
{0x00, 0xFF} TLS_EMPTY_RENEGOTIATION_INFO_SCSV
...
Received TLS Record
Header:
Version = TLS 1.2 (0x303)
Content Type = Alert (21)
Length = 2
Level=fatal(2), description=handshake failure(40)
OK!想定通りTLSハンドシェイクに失敗しました。
handshake_failure
Reception of a handshake_failure alert message indicates that the
sender was unable to negotiate an acceptable set of security
parameters given the options available. This is a fatal error.
ここで発生したhandshake_failure
はクライアント側が要求したセキュリティパラメータでサーバ側が対応できないエラーを示します。
今回ClientHelloでTLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
による暗号化が利用可能な旨をサーバ側に伝えていますが、先の設定においてRDSサイドではTLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
のみを許容しているためRDS側がエラーを返しました。
絞り込み後(一致パターン)
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
を要求するとこちらは許可されてるのでTLSセッションの確立に成功します。
$ openssl s_client -connect database-1.xxxx.ap-northeast-1.rds.amazonaws.com:5432 -starttls postgres -tls1_2 -trace -cipher 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384'
Connecting to 192.168.1.65
CONNECTED(00000003)
Sent TLS Record
Header:
Version = TLS 1.0 (0x301)
Content Type = Handshake (22)
Length = 188
ClientHello, Length=184
...
session_id (len=0):
cipher_suites (len=4)
{0xC0, 0x30} TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
{0x00, 0xFF} TLS_EMPTY_RENEGOTIATION_INFO_SCSV
...
Received TLS Record
Header:
Version = TLS 1.2 (0x303)
Content Type = Handshake (22)
Length = 59
ServerHello, Length=55
server_version=0x303 (TLS 1.2)
...
cipher_suite {0xC0, 0x30} TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
...
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
Session-ID:
Session-ID-ctx:
Master-Key: xxxxx
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1743674363
Timeout : 7200 (sec)
Verify return code: 19 (self-signed certificate in certificate chain)
Extended master secret: yes
---
TLSv1.3の場合
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
はTLSv1.3で利用できない暗号スイートとなっておりますが、オプションの仕様がTLSv1.3は影響を受けないはずなので一応見ておきましょう。
$ openssl s_client -connect database-1.xxxxx.ap-northeast-1.rds.amazonaws.com:5432 -starttls postgres -tls1_3 -trace
Connecting to 192.168.1.65
CONNECTED(00000003)
Sent TLS Record
Header:
Version = TLS 1.0 (0x301)
Content Type = Handshake (22)
Length = 292
ClientHello, Length=288
client_version=0x303 (TLS 1.2)
...
cipher_suites (len=8)
{0x13, 0x02} TLS_AES_256_GCM_SHA384
{0x13, 0x03} TLS_CHACHA20_POLY1305_SHA256
{0x13, 0x01} TLS_AES_128_GCM_SHA256
{0x13, 0x04} TLS_AES_128_CCM_SHA256
...
Received TLS Record
Header:
Version = TLS 1.2 (0x303)
Content Type = Handshake (22)
Length = 88
ServerHello, Length=84
...
cipher_suite {0x13, 0x02} TLS_AES_256_GCM_SHA384
...
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
This TLS version forbids renegotiation.
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 19 (self-signed certificate in certificate chain)
---
OK!TLS_AES_256_GCM_SHA384
が返却されそのままTLSセッションがはれたのでssl_cipher
の設定を無視してることがわかります。
一応厳密に指定して実行してみようとしましたがopenssl側でもTLSv1.3系の暗号スイートは指定対応してない?のかそもそもClientHello送る前に落ちました。TLSv1.3はわからない...。
openssl s_client -connect database-1.xxx.ap-northeast-1.rds.amazonaws.com:5432 -starttls postgres -tls1_3 -trace -cipher 'TLS_AES_128_GCM_SHA256'
Call to SSL_CONF_cmd(-cipher, TLS_AES_128_GCM_SHA256) failed
20B4C0B1FFFF0000:error:0A0000B9:SSL routines:SSL_CTX_set_cipher_list:no cipher match:ssl/ssl_lib.c:3329:
終わりに
今回はRDS for PostgreSQLでssl_cipher
の設定を触り強固な暗号スイートのみ利用可能にしてみました。
TLSv1.3出てらもう長く経っていますが、まだ結構TLSv1.3は使えないという環境も多いのではないかと思います。
身近なところだとAmazon Linux 2はOpenSSL 1.0系をメンテナンス続けてる形になりますので現状もTLSv1.3は使えないはずです。
# openssl version
OpenSSL 1.0.2k-fips 26 Jan 2017
# yum update openssl
Loaded plugins: changelog, extras_suggestions, langpacks, priorities, update-motd
229 packages excluded due to repository priority protections
No packages marked for update
# openssl s_client -connect database-1.xxx.ap-northeast-1.rds.amazonaws.com:5432 -starttls postgres -tls1_3
unknown option -tls1_3
そう言った中でセキュリティ要件等の兼ね合いでせめて暗号スイートだけでもとなった場合に今回の設定値を検討してみても良いでしょうか。
なお、適用前にクライアント側の利用可能な暗号スイートは十分ご確認上設定するようにしましょう。
※ 一応Amazon Linux2の場合はいずれも対応していそうではあります(記法の違いでgrepかけられないので目測の限り)。
ECDHE-RSA-AES256-GCM-SHA384
ECDHE-RSA-AES128-SHA256
ECDHE-RSA-AES128-GCM-SHA256
ECDHE-ECDSA-AES256-GCM-SHA384
ECDHE-ECDSA-AES128-GCM-SHA256