上級 20分 Lesson 20

データベースセキュリティ — データの最後の砦

RDS IAM認証、暗号化、DynamoDB細粒度制御を講義形式で解説

AWS RDS DynamoDB SCS-C03 Security

みなさん、おはようございます。今日は、セキュリティの最終防線——データベースのセキュリティについて解説します。

ここまで、ネットワークセキュリティ、アクセス制御、エッジ防御などを学びました。これらすべての目的は何か。それはデータを守るためです。

では、データベース自体をどう守るのか。それが今日のテーマです。多層防御の最後の砦が、RDS や DynamoDB といったデータベースサービスのセキュリティ実装です。

RDS IAM 認証 — 「パスワード不要の認証」

従来の RDS 接続方法を思い出してください。RDS インスタンス(MySQL など)に接続するには、マスターユーザー名とパスワードが必要です。

mysqlコマンドで、RDSインスタンスのホスト名、ユーザー名adminを指定して、パスワードで認証するという方法です。ですが、このアプローチには複数のセキュリティ問題があります。第一に、パスワードが平文でアプリケーションサーバーのconfig.ymlや.envファイルに記録されます。第二に、インスタンスが侵害されたら、パスワードも流出します。第三に、チーム内でパスワードを共有する場合、伝播リスクが生じます。第四に、パスワード変更時にアプリケーション側の設定も変更が必要で、運用が複雑になります。

RDS IAM 認証はこれらを根本的に解決します。RDS へのログインも IAM ロールで制御され、パスワードは不要になります。代わりに一時的なトークンが使用されます。これにより、秘密情報の管理が完全に不要になり、CloudTrail による監査ログも自動取得されます。

IAM Database Authentication

では、どうするか?

IAM Database Authentication です。

これはね——

RDS へのログインも、IAM ロールで制御する。パスワード不要。

実装としては——

  1. RDS インスタンスで「IAM データベース認証を有効化」
  2. データベース内に「IAM ロール用のユーザー」を作成
  3. IAM ロールに「このユーザーでログイン可」という権限を与える
  4. アプリケーションがね、接続するとき——一時的なトークンを取得して、それでログイン

つまり、プロセスはこうなります。

プロセスとしては、アプリケーションがAWS IAM APIを呼んで、ユーザーadmin-role、ホストmy-instance.xyz、ポート3306で認証トークンを要求します。IAMが一時トークンを発行し、そのトークンは15分間有効です。アプリケーションがそのトークンをパスワードとして使ってRDSに接続します。RDSがトークンを検証し、それが有効なIAMトークンなら接続を許可するという流れです。

で、何が良いのか——

パスワードファイルが不要。トークンは毎回生成されるから、同じ値を保存する必要がない。

IAM ロール単位で制御できるから、「このアプリケーションはこのデータベースにだけ接続可」という制御が IAM ポリシーで一元化される。

CloudTrail に記録されるから、「誰がいつ何に接続したか」が全部ログに残る。

ただし——制限があります。

トークンの有効期限が 15 分です。

つまり、長時間接続が必要な場合——トークン更新ロジックが必要になります。

それと、接続プール(複数の接続をまとめて再利用する仕組み)との相性が少し微妙です。

RDS IAM 認証 = パスワード不要、IAM 一元管理、15 分トークン

暗号化 — 「転送中も保存中も守る」

では、認証は IAM で守られました。では、データ自体はどうするんですか?

暗号化です。

RDS のセキュリティには、2つの暗号化方式があります。

Encryption in Transit(転送中の暗号化)

ネットワーク上を流れるデータを暗号化します。

アプリケーション → RDS

その間のね、通信を HTTPS(TLS)で暗号化するってことです。

これは、RDS を起動するときに「暗号化を有効化」するだけで——自動的に有効になります。

ただし——注意があります。

RDS への接続文字列に「SSL を使う」って指定する必要があります。

例えば MySQL なら——

mysqlコマンドで、ホスト名を指定してssl-modeをREQUIREDに設定するということです。

アプリケーションコードでも——SSL 接続を指定することが大事です。

なぜなら——RDS がサーバー側で HTTPS をサポートしてても、クライアント側が「plain text で OK」と思ってたら——データは暗号化されずに流れるからです。

Encryption in Transit = 双方が TLS を強制する必要がある。

Encryption at Rest(保存中の暗号化)

では、RDS に保存されているデータ自体はどうするのか?

RDS のデータは、EBS(Elastic Block Store)ボリュームに保存されます。

そこを——KMS キーで暗号化することができます。

RDS インスタンスを作成するとき——「暗号化を有効化」を選択すると、自動的に EBS が KMS で暗号化されます。

すると何が起こるか——

MySQLがデータを書き込みます。それはEBSに到達する前にKMSで暗号化されて、暗号化されたままEBSに保存されます。MySQLがデータを読む際には、EBSから読み込まれた暗号化データをKMSで復号化して、平文でアプリケーションに返すという流れになります。

ユーザーからすると、特に何も意識する必要がない。でもね、EBS ボリュームには——暗号化されたデータしか存在しない。

重要な警告:「暗号化は後付けできない」

ここで——非常に大事な警告があります。

RDS を作った後に『あ、暗号化し忘れた』と気づいても——後から有効化できない。

なぜなら——暗号化は、EBS ボリューム単位の属性だから。

既存のボリュームを「暗号化してください」ってのは——技術的にできないんです。

では、どうするか?

方法1:スナップショットから新しいインスタンスを作成

既存の RDS のスナップショットを取ります。

そのスナップショットから——「暗号化有効」で新しい RDS インスタンスを立てます。

その新しいインスタンスにデータが復元される。その時点で、新しい EBS ボリュームが——KMS で暗号化されるわけです。

その後、アプリケーションを新しいインスタンスに切り替える。

ダウンタイムが発生します。

方法2:DMS(Database Migration Service)を使う

AWS DMS という専門ツールで、RDS 間のデータ移行をします。

その過程で——暗号化を有効化できます。

でもね——DMS も、お金がかかります。

暗号化は事前に決定する。後付けはコストが高い。本番立ち上げ前に、必ず決定する。

Aurora Activity Streams — 「データベース操作の全ログ」

では、データは暗号化で守られました。

でも——「誰がデータを見たのか」という監査ログはどうするのか?

これが、Aurora Activity Streams です。

Aurora(MySQL 互換、PostgreSQL 互換)のね——全ての SQL クエリと結果を——ほぼリアルタイムでログに記録するやつです。

例えば——

SQLのSELECT文でadmin@example.comというメールアドレスのユーザーを検索するようなクエリが実行された場合、そのクエリも結果もKinesisストリームに流されます。

そしたら——そのログを CloudWatch に流したり、S3 に保存したり、処理エンジンで分析したり——自由にできるわけです。

Activity Streams = 「誰がいつ何をデータベースに対してしたか」の完全な監査ログ

ただし——制限があります。

  1. パフォーマンスへの影響:Activity Streams を有効化すると、データベースのパフォーマンスが落ちることがあります。

  2. コスト:Activity Streams は有料サービスです。ログが大量に出たら、その分コストが増える。

だからね、金融機関みたいに「完全な監査ログが規制で必須」という要件がある場合にだけ——有効化するみたいな使い方が多いです。

DynamoDB 細粒度アクセス制御 — 「行・カラム単位での権限」

では、ここからは NoSQL データベースの話に移ります。

DynamoDB ですね。

DynamoDB もね、セキュリティが大事です。

DynamoDB は、アイテム(行)を保存するデータベース。

で——「誰がどのアイテムにアクセスできるか」を制御したいわけです。

例えば——

「ユーザー A は、自分のプロフィール情報しか見られない」 「ユーザー B は、自分のプロフィール情報しか見られない」

——こういう制御ですね。

リードバックテーブルとリーダー属性

実装としては——条件付き権限(IAM ポリシーの Condition)を使います。

例えば——

JSON形式のIAMポリシーで、dynamodb:GetItemアクションを許可し、リソースはUsersテーブルに指定して、Conditionではdynamodb:LeadingKeysが${aws:username}と一致する場合だけということが記述されています。

解読すると——

「ユーザー A がデータベースにアクセスするときは、LeadingKeys という属性が『A』のアイテムだけ見える」

つまり、アイテムテーブルに——LeadingKeys という属性(DynamoDB では「プロジェクション属性」)があって——そこにユーザー ID が入ってるわけです。

ユーザー A がアクセスすると——IAM がね、「ユーザー A は LeadingKeys=A のアイテムだけ見ていい」って制限をかける。

グローバルセカンダリインデックス(GSI)との組み合わせ

では、実際には——どう設計するのか?

DynamoDB のベストプラクティスとしては——

プライマリキー(partition key):アプリケーション共通のキー(例:UserId) グローバルセカンダリインデックス(GSI):ユーザー固有のキー(例:Email)

——こういう設計をします。

で、ユーザーが「自分のプロフィールを見たい」という要求をすると——

  1. IAM ポリシーで「このユーザーは、UserId = 自分の ID のアイテムだけ見える」
  2. DynamoDB はね、そのアイテムだけを返す
  3. 他のユーザーのデータには触られない

——こういう流れになるわけです。

DynamoDB 細粒度制御 = IAM 条件付きポリシー + LeadingKeys 属性での行レベル権限

Secrets Manager 自動ローテーション

では、最後に。データベースの認証情報の管理です。

RDS IAM 認証で——パスワード不要になったって言いました。

でも——マスターユーザーのパスワード自体は、どこかに保存されなきゃいけませんよね。

それがね——Secrets Manager です。

Secrets Manager は、先ほどちょっと出てきたやつなんですけど。

ここでの重要な機能は——自動ローテーションです。

設定としては——

「RDS のマスターユーザーパスワードを、30 日ごとに自動更新する」

——こんなふうに設定できるわけです。

そしたら——

  1. Secrets Manager が 30 日ごとに、新しいパスワードを生成する
  2. RDS のマスターユーザーのパスワードを更新する
  3. 新しいパスワードを Secrets Manager に保存
  4. アプリケーションは、Secrets Manager から最新のパスワードを読む

——全部、自動です。

アプリケーションが「パスワードを硬코딩」する必要がない。

アプリケーションが「30 日ごとにパスワード変更を忘れる」ってこともない。

自動化によって、セキュリティと運用が両立されるわけです。

Secrets Manager 自動ローテーション = 秘密情報の自動更新。人間の出番なし。

実務的なベストプラクティス

では、まとめます。

データベースセキュリティには——

  1. 認証:RDS IAM 認証でパスワード不要化
  2. 暗号化:転送中(TLS)と保存中(KMS)の両方を有効化。事前決定すること。
  3. 監査:Aurora Activity Streams で操作ログを記録
  4. 細粒度制御:DynamoDB なら IAM 条件付きポリシーで行単位のアクセス制御
  5. 秘密管理:Secrets Manager で認証情報を一元管理・自動ローテーション

これらが——全部、統合されるとき——

データベースは、金庫の中の金庫のような状態になるわけです。

外からの攻撃にも強いし、内部の不正アクセスにも強いし、秘密情報の漏洩にも強い。

それが——セキュリティの最後の砦、データベースを守るやり方なんです。

では、最後のテーマに行きましょう。