2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RDS for PostgreSQL初期設計 マスターユーザーを避けRoleを用途別に分ける

2
Posted at

はじめに

RDS for PostgreSQLを作成したあと、アプリケーションからマスターユーザーで接続していないでしょうか。

マスターユーザーはRoleやデータベースを作成できる強い管理ユーザーです。通常のデータ読み書きに使うと、アプリケーションの不具合やSQLインジェクションが権限管理まで波及する可能性があります。

この記事では、RDS作成後に最初に決めたいRole設計と、SQLを実行する前のAWS側チェック、TLSを検証した接続方法を整理します。

長くなるため、次の3本に分けています。

  1. 本記事: Role設計と接続前の確認
  2. RDS for PostgreSQL権限設定 app_owner・app_user・app_readonlyを作る(今後公開予定)
  3. RDS for PostgreSQL権限テスト GRANT漏れと運用設定を確認する(今後公開予定)

先に結論

  • マスターユーザーは初期設定や管理作業に限定する
  • オブジェクト所有者、マイグレーション、アプリ接続、参照専用を分ける
  • ログインしないRoleへ権限をまとめ、ログインRoleへ付与する
  • RDSへ到達できる通信元をセキュリティグループで限定する
  • sslmode=verify-fullで証明書と接続先ホスト名を検証する
  • パスワードをSQLファイルやGitへ残さない

AWSも、RDSのマスターユーザーをアプリケーションから直接使用せず、アプリケーションに必要な最小権限のユーザーを作ることを推奨しています。

AWS公式: Master user account privileges

デフォルト設定とこの記事の推奨を先に整理

この記事では、設定を次の3種類に分けて説明します。

  • デフォルト: RDS、PostgreSQL、またはpsqlが初期状態で採用する値
  • この記事の推奨: セキュリティと運用を考慮し、明示的に採用する値
  • 環境ごとに確認: RDSの作成方法、コンソールのテンプレート、DBパラメータグループなどで変わる値

主な設定を先に整理すると、次のとおりです。

項目 デフォルト この記事の推奨・確認事項
RDSマスターユーザー名 RDSコンソールではpostgres 別名を指定でき、作成後は変更できない。実際の設定値を確認する
PostgreSQLのポート 5432 ポートを変更している可能性があるため、RDSの接続情報を確認する
CREATE ROLEのログイン属性 NOLOGIN 権限Roleと所有者RoleはNOLOGIN、接続用RoleだけLOGINを明示する
psql・libpqのsslmode prefer verify-fullを明示し、CA証明書と接続先ホスト名を検証する
rds.force_ssl RDS for PostgreSQL 15以降は1、14以前は0 バージョンと実値を確認する。15以降でもクライアント側の証明書検証は別途必要
password_encryption RDS for PostgreSQL 14以降はscram-sha-256、13はmd5 本記事の対象である15以降では通常デフォルトのままでよいが、実値を確認する
rds.accepted_password_auth_method md5+scram SCRAMだけに制限する場合は、既存Roleとドライバーの移行後に変更する
パブリックアクセス、Multi-AZ、削除保護など 作成方法や選択した設定で異なる デフォルトと思い込まず、対象DBインスタンスの実値を確認する

デフォルトは、すべてのシステムに最適な推奨値という意味ではありません。特にsslmode=preferはデフォルトですが、接続先の本人性を厳密に検証する設定ではないため、本記事ではverify-fullへ変更します。

前提

  • 対象読者: RDS for PostgreSQLを作成し、アプリケーション接続前の初期設定を行う人
  • 想定環境: RDS for PostgreSQL 15以降、psqlを利用できる端末
  • 認証方式: 本連載ではパスワード認証を扱う
  • 扱わない範囲: RDS Proxy、IAMデータベース認証、レプリケーション、監査ログの詳細
  • 実行場所: RDSへ接続可能なVPC内の端末、VPN接続端末、または管理用経路

サンプルの名前、タイムアウト、ネットワーク範囲をそのまま本番へ適用しないでください。対象システムの要件と変更手順に合わせ、検証環境で確認してから適用します。

PostgreSQLのRoleとは

PostgreSQLでは、ログインユーザーと権限グループをどちらも Role として扱います。

Roleという共通の仕組みにLOGIN属性が付いているかどうかで、使い方が変わります。PostgreSQLにRoleとは別の「ユーザー」や「グループ」が用意されているわけではありません。

次の図では、接続できないapp_rwへ読み書き権限をまとめ、そのRoleを接続用のapp_userへ付与しています。

  • app_rw: 自分ではログインできない。読み書き権限をまとめるRole
  • app_user: データベースへログインできる。付与されたapp_rwの権限を利用するRole

つまり、app_userへテーブル権限を一つずつ直接付与するのではなく、権限をまとめたapp_rwへ所属させる設計です。

設定 CREATE ROLEのデフォルト 意味
LOGIN / NOLOGIN NOLOGIN PostgreSQLへログインできるか
INHERIT / NOINHERIT INHERIT 所属Roleの権限を通常の操作で利用するか
CREATEDB / NOCREATEDB NOCREATEDB データベースを作成できるか
CREATEROLE / NOCREATEROLE NOCREATEROLE Roleを作成・管理できるか
SUPERUSER / NOSUPERUSER NOSUPERUSER PostgreSQL上の多くの権限制限を回避できるか
REPLICATION / NOREPLICATION NOREPLICATION レプリケーション接続やスロット管理を行えるか
BYPASSRLS / NOBYPASSRLS NOBYPASSRLS 行レベルセキュリティポリシーを回避できるか

CREATE USERは、LOGINを付けたCREATE ROLEとして扱えます。本連載では仕組みを統一して読みやすくするため、すべてCREATE ROLEを使います。

SQLでは、デフォルトと同じ属性もあえて明示します。たとえばapp_owner NOLOGINと書くことで、接続用ではないという設計意図をレビュー時に確認しやすくするためです。

なお、本記事の想定はPostgreSQL 15以降です。PostgreSQL 16以降では、RoleのINHERIT属性に加えて、Roleを付与するときのWITH INHERITオプションも権限継承に関係します。実際に利用するメジャーバージョンの仕様を確認してください。

PostgreSQL公式: CREATE ROLE

権限と所有権は別

PostgreSQLでは、SELECTINSERTなどの 権限 と、テーブルなどの 所有権 は別です。

テーブル所有者は、原則としてそのテーブルを変更・削除できます。アプリ接続ユーザーを所有者にすると、読み書きだけを許可したつもりでも、ALTER TABLEDROP TABLEまで実行できる設計になりかねません。

そこで、所有者用Roleはログイン不可にして分離します。

推奨するRole構成

この連載では、次の構成を使います。これはRDSがデフォルトで作る構成ではなく、この記事で明示的に作成する推奨構成です。

Role ログイン デフォルトで存在するか 用途 主な権限
RDSマスターユーザー あり あり 初期設定、Role作成、拡張管理 CREATEDBCREATEROLErds_superuserなど
app_owner なし なし データベース、スキーマ、テーブルの所有者 DDL対象の所有権
app_migrator あり なし Flyway、Liquibase、Prismaなどのマイグレーション 必要時にapp_ownerへ切り替える
app_rw なし なし 読み書き権限をまとめる SELECTINSERTUPDATEDELETE
app_user あり なし アプリケーション接続 app_rwを継承する
app_ro なし なし 参照権限をまとめる SELECT
app_readonly あり なし 調査、BI、サポート app_roを継承する

なぜRoleを6個も作るのか

Roleを分ける理由は、名前を増やすことではなく、権限の境界を明確にすることです。

起きたこと 分離していない場合 分離した場合
アプリにSQLインジェクションが発生 DDLやRole管理まで影響する可能性がある アプリ用権限の範囲へ影響を抑えやすい
マイグレーションに不具合がある 日常接続と同じ資格情報でDDLが動く マイグレーション用資格情報を停止できる
調査担当へ接続を許可する 更新操作もできてしまう 参照専用Roleだけを付与できる
担当者が増える ユーザーごとに個別GRANTが増える 権限Roleへの所属で管理できる

RDSマスターユーザーは完全なSUPERUSERではない

RDS作成時の管理ユーザー名は、コンソールではデフォルトでpostgresですが、別の名前も選べます。マスターユーザー名はDBインスタンス作成後に変更できないため、運用手順では「必ずpostgres」と決めつけず、RDSの設定値を確認します。

PostgreSQLのデフォルトポートは5432です。ただし、RDS作成時に変更できるため、接続コマンドへ固定値を書き込む前に、AWSコンソールの「接続とセキュリティ」でエンドポイントとポートを確認します。

AWS公式: Connecting to a DB instance running the PostgreSQL database engine

RDS for PostgreSQLのマスターユーザーには、通常rds_superuserが付与されます。ただし、スタンドアロンPostgreSQLの完全なSUPERUSERではありません。

RDSマスターユーザー
├─ LOGIN
├─ CREATEDB
├─ CREATEROLE
├─ rds_superuser
└─ PostgreSQL本来のSUPERUSERではない

RDSはマネージドサービスです。ホストOSへのSSH接続や、本来のPostgreSQLスーパーユーザーによる操作はできません。OS管理や一部の管理処理はAWS側が担当します。

マスターユーザーの用途は、次のように限定します。

  • データベースとRoleの初期作成
  • 利用可能な拡張機能の導入
  • 初期権限設定
  • 障害調査や管理作業
  • 権限を失った場合の復旧

アプリケーションの接続文字列へ、RDSマスターユーザーの資格情報を設定しません。強い資格情報が漏えいすると、アプリ用データだけでなくRoleやデータベースの管理へ影響が広がります。

SQL実行前にAWS側を確認する

Roleを作る前に、RDSへの到達経路と保護設定を確認します。データベース内の権限を細かく分けても、インターネットから広く接続できる状態では防御が不十分です。

項目 デフォルトの扱い この記事の推奨・確認内容
パブリックアクセス 作成方法と選択内容で異なる 原則として無効。必要な場合は理由と接続元を明確にする
セキュリティグループ 選択したVPCとSGで異なる デフォルトポートは5432。実際のポートを、アプリのSG、VPN、管理経路など必要な通信元だけに許可する
保存時暗号化 RDS作成時に選択する 現在の暗号化状態とKMSキーを確認する
自動バックアップ 作成方法や指定値で保持期間が異なる 保持期間とポイントインタイムリカバリ要件を確認する
削除保護 作成方法や指定値で異なる 本番や重要環境では有効化を検討する
Multi-AZ 作成方法や選択した可用性設定で異なる 可用性要件とコストを踏まえて判断する
TLS強制 PostgreSQL 15以降はrds.force_ssl=1 実値を確認し、クライアント側でも証明書を検証する
パスワード保存方式 PostgreSQL 14以降はpassword_encryption=scram-sha-256 実値と既存Roleの保存方式を確認する
受け入れる認証方式 rds.accepted_password_auth_method=md5+scram SCRAMだけに制限する場合は、互換性確認と移行を先に行う
秘密情報 Roleを作るだけでは安全な保管先は決まらない SQL、Git、シェル履歴へパスワードを残さない

パブリックアクセス、バックアップ、削除保護、Multi-AZなどは、コンソールのテンプレートや作成方法によって初期選択が変わる可能性があります。「RDSのデフォルトだから有効なはず」と判断せず、対象DBインスタンスに保存されている値を確認します。

AWS公式: Settings for DB instances

セキュリティグループは送信元SGで絞る

アプリがECSやEC2上で動く場合、RDSのインバウンドルールは、可能であれば固定IPではなくアプリ側のセキュリティグループを送信元にします。

アプリのSecurity Group
        ↓ TCP 5432
RDSのSecurity Group

管理者が接続する場合は、VPN、踏み台、管理用VDIなど、現場で決めた経路からだけ到達できるようにします。

TLSを検証してRDSへ接続する

RDS for PostgreSQLはTLS接続に対応しています。psqlが利用するlibpqのデフォルトsslmode=preferは、まずTLSを試し、接続できなければ非TLS接続も試す設定です。また、デフォルトでは接続先ホスト名まで厳密に検証しません。接続先を確実に検証したい場合はverify-fullを明示します。

AWSが公開しているRDS用CA証明書バンドルを取得し、次のように接続します。

# 値は実際のRDSエンドポイント、管理ユーザー、証明書パスへ置き換えます。
psql "host=<RDSエンドポイント> \
port=5432 \
dbname=postgres \
user=<RDSマスターユーザー> \
sslmode=verify-full \
sslrootcert=/path/to/global-bundle.pem"

verify-fullでは、次の両方を検証します。

  • 証明書が信頼できるCAから発行されているか
  • 証明書のホスト名とRDSエンドポイントが一致するか

RDS for PostgreSQL 15以降では、rds.force_sslのデフォルトは1です。14以前はデフォルトが0のため、利用バージョンとDBパラメータグループを確認します。

rds.force_ssl=1はサーバー側で非TLS接続を拒否する設定です。一方、sslmode=verify-fullはクライアント側でCA証明書とホスト名を検証する設定です。役割が異なるため、RDS for PostgreSQL 15以降でもverify-fullを指定します。

接続後に確認するSQL

接続できたら、現在の接続先とTLS状態を確認します。

-- 接続ユーザー、データベース、PostgreSQLバージョンを確認します。
SELECT
    current_user,
    current_database(),
    version();

-- 新しく設定するパスワードの暗号化方式を確認します。
SHOW password_encryption;

-- RDSがTLS接続を強制しているか確認します。
SHOW rds.force_ssl;

-- サーバーが受け入れるパスワード認証方式を確認します。
SHOW rds.accepted_password_auth_method;

-- 現在の接続で利用しているTLSバージョンと暗号スイートを確認します。
SELECT
    ssl,
    version,
    cipher
FROM pg_stat_ssl
WHERE pid = pg_backend_pid();

想定する確認結果は次のとおりです。

確認項目 期待する状態
current_database() 管理作業時はpostgresなど、意図したDB
password_encryption 本記事の対象であるRDS for PostgreSQL 15以降では、デフォルトのscram-sha-256
rds.force_ssl 本記事の対象であるRDS for PostgreSQL 15以降では、デフォルトのonまたは1
rds.accepted_password_auth_method デフォルトはmd5+scram。SCRAM限定へ変更済みならscram
pg_stat_ssl.ssl trueまたはt

RDS for PostgreSQL 14以降では、password_encryptionのデフォルトはscram-sha-256です。ただし、この値は 今後設定・変更するパスワードの保存方式 を決めるもので、既存RoleのMD5パスワードを自動でSCRAMへ変換するものではありません。

また、rds.accepted_password_auth_methodのデフォルトはmd5+scramで、MD5とSCRAMの両方を受け入れます。SCRAMだけに変更する場合は、利用中のドライバーがSCRAMへ対応していることを確認し、対象Roleのパスワードを再設定してから切り替えます。先にSCRAM限定へ変更すると、MD5形式のパスワードしか持たないRoleが接続できなくなります。

デフォルト値を変更する場合は、通常、カスタムDBパラメータグループが必要です。変更の適用方法や再起動の要否も、対象パラメータと環境で確認します。

AWS公式: Using SCRAM for PostgreSQL password encryption

psqlの確認コマンド

次はSQLではなく、psqlのメタコマンドです。

-- Roleと属性を表示する
\du+

-- データベース一覧を表示する
\l+

-- スキーマ一覧を表示する
\dn+

-- 現在の接続情報を表示する
\conninfo

パスワードを安全に扱う

サンプルSQLへ平文パスワードを書き、Gitで管理するのは避けます。psqlを使える場合は、次のように対話入力できます。

-- 入力したパスワードは画面へ表示されません。
\password app_user

RDSは、マスターユーザーの資格情報をSecrets Managerで生成・保存・ローテーションする機能を提供しています。一方、app_userなど自分で作ったRoleは別のシークレットとして管理し、アプリの取得権限やローテーション手順を設計します。

Secrets Managerには料金がかかります。また、秘密情報を保存するだけで安全になるわけではありません。取得できるIAM Role、アプリへの渡し方、監査、ローテーション後の接続更新まで確認します。

設計レビュー用チェックリスト

  • アプリケーションがマスターユーザーで接続していない
  • 所有者Roleとアプリ接続Roleを分離している
  • マイグレーション用Roleを通常接続から分離している
  • 参照専用の利用者へ更新権限を付けていない
  • RDSのパブリックアクセスとSecurity Groupを確認した
  • TLS証明書とRDSエンドポイントを検証している
  • パスワードをSQLファイルやGitへ保存していない
  • PostgreSQLとRDSのバージョンを記録した

参考・確認先

この記事は2026年8月20日に、次の公式資料を確認して作成しました。

関連記事

まとめ

RDS for PostgreSQLを作成したら、最初にアプリ用の接続ユーザーを作るだけでなく、所有者、マイグレーション、読み書き、参照専用の責任を分けます。

次の記事では、この設計をCREATE ROLEGRANTALTER DEFAULT PRIVILEGESへ落とし込み、データベースとスキーマを実際に構築します。

おわりに

データベースの権限設計は、Roleを作って終わりではなく、接続経路、秘密情報、検証方法まで決めておくと運用しやすくなります。
Wealthy Designでは、Webシステム開発、クラウド活用、AIを使った業務改善に取り組んでいます。

会社の取り組みは、会社サイトにまとめています。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?