うっかりrdsproxyadminから権限を剥奪してもRDS Proxyが正常動作するのか確認してみた

パスワード変更時と違って自動復旧してくれないようです
2022.06.13

MAD事業部@大阪の岩田です。

先日こんなブログを書きました。

rdsproxyadminのパスワードを手動変更してもRDS Proxyの基盤側でパスワードが再設定され、自動復旧することが確認できました。ここで新たな疑問が湧いてきました。rdsproxyadminからRDS Proxyの正常動作に必要な権限を剥奪するとどうなるのでしょうか?同じように自動復旧してくれるのでしょうか?気になったので検証してみました。

環境

今回利用したRDSの環境です

  • RDS for PostgreSQL
  • エンジンバージョン 13.6
  • インスタンスクラス db.t3.micro

やってみる

軽く事前準備と確認

前回のブログと同様にRDS & RDS Proxyの環境を構築して簡単なSQLの発行まで試しておきます。

適当なEC2からpsqlでRDS Proxy経由でRDSに接続してクエリを発行してみます

$ psql -h <RDSプロキシのエンドポイント> -U user01 db1
Password for user user01:
psql (13.3, server 13.4)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.

db1=> select now();
              now
-------------------------------
 2022-06-13 01:01:12.567261+00
(1 row)

db1=>

OKです。

RDSに直接接続したpsqlのセッションからRDS <-> RDS Proxy間の接続をクローズしておきます。

postgres=> select pid from pg_stat_activity where usename = 'user01';
  pid
-------
 24906
(1 rows)

postgres=> select pg_terminate_backend(24906);
 pg_terminate_backend
----------------------
 t
(1 row)

postgres=> select pid from pg_stat_activity where usename = 'user01';
 pid
-----
(0 rows)

rdsproxyadminからCONNECT権限をREVOKEしてみる

ウォームアップが完了したので、ここからがRDSのマスターユーザーを使ってrdsproxyadminかCONNECT権限をREVOKEしていきます。

CONNECT権限はpublicロールに付与されているので、publicロールからCONNECT権限をREVOKEする形になります。事前に通常のユーザーセッションで利用するDBユーザーにCONNECT権限を付与しておきます。

postgres=> grant connect on database db1 to user01;

ではpublicロールからCONNECT権限をREVOKEしてみましょう。RDSに直接接続しているpsqlセッションから以下のSQLを発行します。

postgres=> revoke connect on database postgres from public;
REVOKE

これでpublicロールからCONNECT権限が剥奪され、rdsproxyadminもCONNECT権限がなくなったはずです。すでに接続済のrdsproxyadmin のセッションをすべてCLOSEします、

postgres=> select 'select pg_terminate_backend(' || pid || ');' from pg_stat_activity where usename = 'rdsproxyadmin';
              ?column?
------------------------------------
 select pg_terminate_backend(5267);
 select pg_terminate_backend(5268);
(2 rows)

postgres=>  select pg_terminate_backend(5267);
 pg_terminate_backend
----------------------
 t
(1 row)

postgres=>  select pg_terminate_backend(5268);
 pg_terminate_backend
----------------------
 t
(1 row)

準備が整ったので、EC2からRDS Proxyに接続してSQLを発行してみましょう

$ psql -h pg13proxy.proxy-czo4ezbcwzku.ap-northeast-1.rds.amazonaws.com -U user01 db1
Password for user user01:
psql (13.3, server 13.4)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.

db1=> select now();
              now
-------------------------------
 2022-06-13 01:51:26.241751+00
(1 row)

普通に成功してしまいました。pg_stat_activityの状況を確認してみます。

postgres=> select usename,count(*) from pg_stat_activity group by usename;
    usename    | count
---------------+-------
               |     4
 user01        |     2
 rdsproxyadmin |     2
 postgres      |     1
 rdsadmin      |     2
(5 rows)

postgres=>

普通にrdsproxyadminのセッションが存在します。ログはどうでしょうか?まずRDS側のログです。

2022-06-13 01:46:29 UTC:172.31.9.117(42252):postgres@postgres:[698]:LOG:  statement: revoke connect on database db1 from public;
2022-06-13 01:46:30 UTC:172.31.59.48(37801):rdsproxyadmin@postgres:[5268]:LOG:  statement: SELECT current_setting('transaction_read_only') AS transaction_read_only, current_setting('max_connections') AS max_connections, EXTRACT(EPOCH F
ROM now() - pg_postmaster_start_time()) AS uptime;
...略

2022-06-13 01:51:08 UTC:172.31.9.117(42252):postgres@postgres:[698]:LOG:  statement: select pg_terminate_backend(5268);
2022-06-13 01:51:08 UTC:172.31.59.48(37801):rdsproxyadmin@postgres:[5268]:FATAL:  terminating connection due to administrator command
2022-06-13 01:51:08 UTC:172.31.30.94(33351):[unknown]@[unknown]:[26256]:LOG:  connection received: host=172.31.30.94 port=33351
2022-06-13 01:51:08 UTC:172.31.30.94(33351):rdsproxyadmin@postgres:[26256]:LOG:  connection authorized: user=rdsproxyadmin database=postgres
2022-06-13 01:51:08 UTC:172.31.30.94(33351):rdsproxyadmin@postgres:[26256]:LOG:  statement: SELECT current_setting('transaction_read_only') AS transaction_read_only, current_setting('max_connections') AS max_connections, EXTRACT(EPOCH FROM now() - pg_postmaster_start_time()) AS uptime;
2022-06-13 01:51:09 UTC:172.31.59.48(36381):[unknown]@[unknown]:[26257]:LOG:  connection received: host=172.31.59.48 port=36381
2022-06-13 01:51:09 UTC:172.31.59.48(36381):rdsproxyadmin@postgres:[26257]:LOG:  connection authorized: user=rdsproxyadmin database=postgres
2022-06-13 01:51:09 UTC:172.31.59.48(36381):rdsproxyadmin@postgres:[26257]:LOG:  statement: SELECT current_setting('transaction_read_only') AS transaction_read_only, current_setting('max_connections') AS max_connections, EXTRACT(EPOCH FROM now() - pg_postmaster_start_time()) AS uptime;
2022-06-13 01:51:09 UTC:172.31.30.94(33351):rdsproxyadmin@postgres:[26256]:LOG:  statement: SELECT current_setting('transaction_read_only') AS transaction_read_only, current_setting('max_connections') AS max_connections, EXTRACT(EPOCH FROM now() - pg_postmaster_start_time()) AS uptime;

普通にREVOKE完了後にも接続成功のログが上がってきています。特にRDS Proxyの基板側でGRANTし直したということも無いようです。

RDS Proxy側のログはどうでしょうか?

@timestamp @message
2022-06-13 01:51:14.434 2022-06-13T01:51:09.113Z [INFO] Database "pg13" at 172.31.20.74:5432 is now available for read/write access from 172.31.59.48.
2022-06-13 01:51:14.790 2022-06-13T01:51:08.796Z [INFO] Database "pg13" at 172.31.20.74:5432 is now available for read/write access from 172.31.30.94.
2022-06-13 01:51:20.915 2022-06-13T01:51:20.817Z [INFO] [proxyEndpoint=default] [clientConnection=256173523] A new client connected from 172.31.9.117:55630.
2022-06-13 01:51:23.417 2022-06-13T01:51:20.836Z [DEBUG] [proxyEndpoint=default] [clientConnection=256173523] Received Startup Message: [username="user01", database="db1", protocolMajorVersion=3, protocolMinorVersion=0, sslEnabled=true]
2022-06-13 01:51:23.417 2022-06-13T01:51:23.218Z [INFO] [proxyEndpoint=default] [clientConnection=4153722911] A new client connected from 172.31.9.117:42404.
2022-06-13 01:51:23.417 2022-06-13T01:51:23.232Z [DEBUG] [proxyEndpoint=default] [clientConnection=4153722911] Received Startup Message: [username="user01", database="db1", protocolMajorVersion=3, protocolMinorVersion=0, sslEnabled=true]
2022-06-13 01:51:26.419 2022-06-13T01:51:23.235Z [DEBUG] [proxyEndpoint=default] [clientConnection=4153722911] Proxy authentication with PostgreSQL native password authentication succeeded for user "user01" with TLS on.
2022-06-13 01:51:26.419 2022-06-13T01:51:26.225Z [INFO] [dbConnection=1921691738] A TCP connection was established from the proxy at 172.31.30.94:7547 to the database at 172.31.20.74:5432.
2022-06-13 01:51:26.419 2022-06-13T01:51:26.241Z [DEBUG] [dbConnection=1921691738] The new database connection successfully authenticated with TLS on.
2022-06-13 01:51:26.419 2022-06-13T01:51:26.241Z [DEBUG] [proxyEndpoint=default] [clientConnection=4153722911] The client connection borrowed the database connection [dbConnection=1921691738] for the next query/transaction.
2022-06-13 01:51:31.791 2022-06-13T01:51:26.242Z [DEBUG] [proxyEndpoint=default] [clientConnection=4153722911] The database connection [dbConnection=1921691738] borrowed from the connection pool is being released to the connection pool.

こちらも特にrdsproxyadminの接続が失敗したといったログは見当たりませんでした。rdsproxyadminロールの設定を見る限りpublic以外のロール(グループ)に所属しているということも無さそうですが、なぜCONNECTできたのかよく分かりませんでした...うーむ。。

                                                               List of roles
    Role name    |                         Attributes                         |                          Member of
-----------------+------------------------------------------------------------+-------------------------------------------------------------
 postgres        | Create role, Create DB                                    +| {rds_superuser}
                 | Password valid until infinity                              |
 rds_ad          | Cannot login                                               | {}
 rds_iam         | Cannot login                                               | {}
 rds_password    | Cannot login                                               | {}
 rds_replication | Cannot login                                               | {}
 rds_superuser   | Cannot login                                               | {pg_monitor,pg_signal_backend,rds_replication,rds_password}
 rdsadmin        | Superuser, Create role, Create DB, Replication, Bypass RLS+| {}
                 | Password valid until infinity                              |
 rdsproxyadmin   | Password valid until infinity                              | {}
 rdsrepladmin    | No inheritance, Cannot login, Replication                  | {}
 rdstopmgr       | Password valid until infinity                              | {pg_monitor}
 user01          | Create DB                                                  | {}

rdsproxyadminロールの属性をNOLOGINに変更してみる

SELECT権限のREVOKEでは予想に反してダウンタイムが発生しませんでした。今度はrdsproxyadminロールの属性をNOLOGINに変更するとどうなるかを確認してみます。

postgres=> alter role rdsproxyadmin with nologin;
ALTER ROLE
postgres=>

すでに接続済のrdsproxyadmin のセッションをすべてCLOSEします、

postgres=> select 'select pg_terminate_backend(' || pid || ');' from pg_stat_activity where usename = 'rdsproxyadmin';
              ?column?
-------------------------------------
 select pg_terminate_backend(26256);
 select pg_terminate_backend(26257);
(2 rows)

postgres=>  select pg_terminate_backend(26256);
 pg_terminate_backend
----------------------
 t
(1 row)

postgres=>  select pg_terminate_backend(26257);
 pg_terminate_backend
----------------------
 t
(1 row)

EC2からpsqlでRDS Proxyに接続し、SQLの発行を試みます

$ psql -h <RDS Proxyのエンドポイント> -U user01 db1
Password for user user01:
psql (13.3, server 13.4)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.

db1=> select now();
ERROR:  Timed-out waiting to acquire database connection.

select now()実行後にレスポンスが返却されず固まり、その後エラーが返却されました。待ち時間はきちんと計測した訳ではありませんが、体感としてはRDS Proxyの「接続借用タイムアウト」で指定された2分程度だった印象です。

RDSのログを確認してみましょう

2022-06-13 02:13:45 UTC:172.31.9.117(42252):postgres@postgres:[698]:LOG:  statement: alter role rdsproxyadmin with nologin;
2022-06-13 02:13:45 UTC:172.31.59.48(36381):rdsproxyadmin@postgres:[26257]:LOG:  statement: SELECT current_setting('transaction_read_only') AS transaction_read_only, current_setting('max_connections') AS max_connections, EXTRACT(EPOCH
FROM now() - pg_postmaster_start_time()) AS uptime;
...略

2022-06-13 02:14:03 UTC:172.31.9.117(42252):postgres@postgres:[698]:LOG:  statement: select pg_terminate_backend(26257);
2022-06-13 02:14:03 UTC:172.31.59.48(36381):rdsproxyadmin@postgres:[26257]:FATAL:  terminating connection due to administrator command
2022-06-13 02:14:03 UTC:172.31.30.94(38231):[unknown]@[unknown]:[8749]:LOG:  connection received: host=172.31.30.94 port=38231
2022-06-13 02:14:03 UTC:172.31.30.94(38231):rdsproxyadmin@postgres:[8749]:LOG:  connection authorized: user=rdsproxyadmin database=postgres
2022-06-13 02:14:03 UTC:172.31.30.94(38231):rdsproxyadmin@postgres:[8749]:FATAL:  role "rdsproxyadmin" is not permitted to log in
2022-06-13 02:14:03 UTC:172.31.59.48(44961):[unknown]@[unknown]:[8752]:LOG:  connection received: host=172.31.59.48 port=44961
2022-06-13 02:14:03 UTC:172.31.59.48(44961):rdsproxyadmin@postgres:[8752]:LOG:  connection authorized: user=rdsproxyadmin database=postgres
2022-06-13 02:14:03 UTC:172.31.59.48(44961):rdsproxyadmin@postgres:[8752]:FATAL:  role "rdsproxyadmin" is not permitted to log in
2022-06-13 02:14:04 UTC:172.31.30.94(52035):[unknown]@[unknown]:[8756]:LOG:  connection received: host=172.31.30.94 port=52035
2022-06-13 02:14:04 UTC:172.31.30.94(52035):rdsproxyadmin@postgres:[8756]:LOG:  connection authorized: user=rdsproxyadmin database=postgres
2022-06-13 02:14:04 UTC:172.31.30.94(52035):rdsproxyadmin@postgres:[8756]:FATAL:  role "rdsproxyadmin" is not permitted to log in

権限不足によるエラーログが大量出力されています。

RDS Proxy側のログはどうでしょうか?

@timestamp @message
2022-06-13 02:14:14.957 2022-06-13T02:14:14.709Z [INFO] [proxyEndpoint=default] [clientConnection=2841168921] A new client connected from 172.31.9.117:55652.
2022-06-13 02:14:19.011 2022-06-13T02:14:18.842Z [INFO] [proxyEndpoint=default] [clientConnection=42225156] A new client connected from 172.31.9.117:42426.
2022-06-13 02:14:19.011 2022-06-13T02:14:18.856Z [DEBUG] [proxyEndpoint=default] [clientConnection=42225156] Received Startup Message: [username="user01", database="db1", protocolMajorVersion=3, protocolMinorVersion=0, sslEnabled=true]
2022-06-13 02:14:20.434 2022-06-13T02:14:14.758Z [DEBUG] [proxyEndpoint=default] [clientConnection=2841168921] Received Startup Message: [username="user01", database="db1", protocolMajorVersion=3, protocolMinorVersion=0, sslEnabled=true]
2022-06-13 02:14:24.791 2022-06-13T02:14:18.858Z [DEBUG] [proxyEndpoint=default] [clientConnection=42225156] Proxy authentication with PostgreSQL native password authentication succeeded for user "user01" with TLS on.

こちらはpsql <-> RDS Proxy間の接続・認証成功などのログは出力されていますが、RDS Proxy<->RDS間の接続エラーに関するログは特に出力されていないようです。

ちなみにマネコンの表示もステータス:使用不可に変わっていました。

その後1時間ほど放置していましたが、rdsproxyadminのパスワード変更時とは違って特に自動復旧はしませんでした。

まとめ

うっかりrdsproxyadminロールの属性をNOLOGINに変更するとRDS Proxyが正常利用できなくなってしまうようです。基盤側でうまく自動復旧してくれるといったことも無い様なので気を付けましょう。

この記事が誰の役にも立たないことを願います。