👮

AWS Identity Center下のIAMデータベース認証でも、トレーサビリティのある監査ログを記録する方法

2024/08/21に公開

tl;dr

AWS Identity Center下で普通にIAMデータベース認証を使うとどのクエリを誰が実行したのかがまったくわからなくなりますが、

  1. DB内で監査ログを取る(pgauditやMySQLの監査ログなど)
  2. DB内で各開発者ごとのユーザーを作る ( kazufumi-nishida など)
  3. 開発者ごとにそれぞれ対応したDB内ユーザーだけへのアクセスを許可する(AWS Identity CenterのABACにより)
  4. rds-db:connect アクションの対象リソースが無制限に許可されたアクセス権限セット(IAMロール)の普段使いを禁止する (AdministratorAccessやPowerUserAccessなど)

以上を行えば、DB内のあるユーザーを使えるのは唯一1名の開発者のみに限定されます。
これにより、以下のようなDB内監査ログからクエリの実行者を一意に特定することができます。

pgauditの監査ログ例
2017-06-12 19:09:49 UTC:...:kazufumi_nishida@postgres:[11701]:LOG: AUDIT:
OBJECT,1,1,READ,SELECT,TABLE,public.t1,select * from t1;
mysqlの監査ログ例
1484275314,aurora-audit,kazufumi_nishida,173.31.8.40,36,26057,QUERY,mydb,'select * from t1',0

( select * from t1 のクエリを実行したのが kazufumi_nishida という開発者であることが断定できる)

本記事の信頼性と注意書き

以下の内容は、適時AWSのサポートに問い合わせつつこれが現状最もベターな方法であることを裏取り確認しました。実際の動作チェックまで行っているため動作確認も取れています。
2024/08時点での最適解であるのはおそらく間違いないと思います。

ただ、将来的には機能改善によってもっと簡単に実現する方法が出てくるかもしれません。2024/08より大きく時間が経っている場合は末尾のAWSドキュメントやStack Overflowの質問回答などを参照する、もしくはAWSサポートに別解が増えていないか問い合わせてみるなどしてください。

長い説明

必要となる前提知識

以下の内容を理解するためには、以下のサービスの基本知識が必要です。

  • AWS Identity Center
  • AWS RDSのIAMデータベース認証
  • MySQLまたはPostgreSQLの監査ログ機能

これらについての知識が足りない場合は良い解説記事ややってみた記事がネット上にたくさんあるので、そちらを参照ください。

そもそも何が問題なのか

IAMデータベース認証はMySQLとPostgreSQLのDB内認証をAWS IAMと紐付けることができる便利なサービスです。寿命の長いパスワードを管理する必要もなくなりセキュリティも向上します。
ただし、このサービスには一つ欠点があります。それは、監査ログとの相性が良くないことです。
この問題は次の記事で非常にわかりやすく解説されています:

一言でまとめると、IAMデータベース認証を普通に使うと各クエリを誰が実行したのかがまったく特定できなくなります。監査ログにおいては誰がそれを行ったのかというのは中核となる要素ですので、それが記録されないとなると監査観点での価値はほとんどなくなるでしょう[1]

愚直な解決策

前述の記事に書かれている通り、この問題は基本的に次の方法で解決できます。

  1. 各開発者ごとに固有のDB内ユーザーを作成し、開発者はそのDB内ユーザーへのみログインできるようIAM権限を付ける (問題1への回答)
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Action": "rds-db:connect",
          "Resource": "arn:aws:rds-db:ap-northeast-1:*:dbuser:*/kazufumi_nishida",
          "Effect": "Allow"
        }
      ]
    }
    
  2. PowerUserAccessやAdministratorAccessのような、無制限に rds-db:connect アクションができる権限を開発者に付けない (問題2への回答)
  3. pgauditなどのDB内監査ログ機能を使う (問題3への回答)

ただし、AWS Identity Centerを使ってAWSアカウントと権限を管理しているとこれらの実行が難しくなります。

AWS Identity Center下での問題

AWS Identity Center下では前述の①について大きな問題が発生します。

AWS Identity Centerを使っている多くのケースでは、1つのアクセス権限セット(IAMロール)を開発者(= ワークフォースユーザー)につけていると思います。
このとき、複数のワークフォースユーザーにはまったく同じIAM権限が付きます。
しかし、問題1に対処するためには1人1人のワークフォースユーザーに Resource のみ異なるIAM権限をアタッチする必要があります。
もしこれを愚直にやる場合、ワークフォースユーザーが増えるたびにその人専用のアクセス権限セットが必要になります。アクセス権限セットが増えるということはAWSアカウント内のIAMロールも増えるということであり、AWS Identity Center内のワークフォースユーザー ⇔ アクセス権限セットの紐付けも複雑化することになります。特に、グループによる一括管理は使えなくなってしまい、管理がとても大変になります。

もう少しマシな解決策はないのでしょうか。

スマートな解決策

結論から書くとあります。IAMにはポリシー変数という、権限主体の属性に合わせて変わる変数が使えます。

ただし、こちらはポリシー内での使える場所や加工にかなりの制約があります。
特に正規表現による置換なども一切できないため、以下のようにDB内ユーザー名のところを変数化したい場合、予め変数にちょうどDB内ユーザーの名前と全く同じ文字列を入れておく必要があります。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "rds-db:connect",
      "Resource": "arn:aws:rds-db:ap-northeast-1:*:dbuser:*/${ここを変数化したい}",
      "Effect": "Allow"
    }
  ]
}

${aws:username} が一見使えそうなのですが、先程のページに書かれている通り、これはIAMユーザーを使っている場合しか値がありません。AWS Identity Centerの場合は値が入っていないことになります。
${aws:userid}roke-id というロールごとの固有IDが含まれており(例: AROADBQP57FF2AEXAMPLE:kazufumi-nishida)、そのままDB内ユーザーの名前として使うのは少々不便です。前述の理由でこの文字列の加工もできません[2]
また、他の値 (${aws:SourceIdentity} など)も利用できるケース(記事中で可用性と書かれている項目)が限定されており、今回の目的には使えない物が多いです。

では、使える変数はないのでしょうか?

あります。 ${aws:PrincipalTag} です。

${aws:PrincipalTag} とAWS Identity Centerの属性を活用する (= ABAC)

AWS Identity Centerには属性という機能があります。
これを設定すると、アクセス権限セット内のポリシー変数として参照できるようになります。
これがいわゆるABAC(Attribute-Based Access Control)です。

例えばGoogle WorkspaceをIdentity Providerとして使用している場合、次の手順で属性を設定し、

  1. IAM Identity Center のコンソールの設定を開く
  2. アクセスコントールの属性 にて「属性の管理」を選択
  3. 「属性を追加」より下記の値を設定

    キー:username
    値:${path:userName}

その後、アクセス権限セットに次のIAMポリシーを設定すると、

{
    "Version": "2012-10-17",
    "Id": "rdsdb",
    "Statement": [
        {
            "Action": [
                "rds-db:connect"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:rds-db:*:*:dbuser:*/${aws:PrincipalTag/username}"
            ]
        }
    ]
}

Identity Centerのユーザーに設定されているメールアドレスと同じ文字列のDB内ユーザー名へログインできるようになります。

この属性で使える値はIdentity Providerなどにもより、性や名、その気になれば社員番号なども使えます。非常に柔軟なため、好きなDB内ユーザー名を指定できるでしょう。

参考: AWS IAM Identity Center において ABAC で EC2 インスタンスの操作を許可してみる | DevelopersIO

※注意書き: このABACの部分については実際に動くことは確認したものの、私からは担当部署への依頼で上記設定を実行してもらっており、いろいろと試していないです。そのため、より良い方法など改善の余地はあるかもしれません。

まとめ

というわけで、tl;drにも書いた以下をすべて実行することで、DB内の各クエリを実行した人が誰かを常に一意に特定できるようになります。

  1. DB内で監査ログを取る(pgauditやMySQLの監査ログなど)
  2. DB内で各開発者ごとのユーザーを作る ( kazufumi-nishida など)
  3. 開発者ごとにそれぞれ対応したDB内ユーザーだけへのアクセスを許可する(AWS Identity CenterのABACにより)
  4. rds-db:connect アクションの対象リソースが無制限に許可されたアクセス権限セット(IAMロール)の普段使いを禁止する (AdministratorAccessやPowerUserAccessなど)

以下個人的な所感です。
IAMデータベース認証に出会ってからこの問題を解決できず5年ほど戦い続けてきて、この度やっと解決の目処が立ったので、かなりの満足感です(最後の鍵である PrincipalTag を見つけたときは、本当にこれで解決できるのかかなり疑いました)。
というわけで、私と同様にIAMデータベース認証を使いたいけど監査ログの問題がなーと思っている人は、ぜひこれで解決してください。

備考: どれくらいAdministratorAccessなどが使われていなければ、なりすましはされていないと証明できるか

AdministratorAccessの利用をやめることを原則としたほうがよいですが、緊急時もしくは意図せず使ってしまう場合もあると思います。
そのようなとき、それらの利用からどれくらい時間が経てば、なりすましは絶対に不可能なのか考察してみました。

以下はあくまで机上の計算であり、実際の検証もしていません。なので参考情報として見てください。

1. DBコネクションについて

まず、DBインスタンスへのコネクションは基本的に自動的には切れません。
かつ、パスワードのチェックはコネクション開始時のみに行われます。
このことから、一度DBインスタンスへ接続した場合、IAMデータベース認証の権限が剥奪されたり、AWS Identity Centerのセッション時間を超えたとしてもDBへクエリを実行することができます。
これはなんらかの問題やDBインスタンス再起動でコネクションが切断されない限り、事実上半永久にクエリを実行できるはずです(MySQLではそう。PostgreSQLは裏取りしていないがたぶんそう)。

もしコネクションがずっと残っている場合、常になりすましの可能性があるので、以下の話はコネクションがないことを確認できている前提で話します。

2. AWS Identity Centerのセッション時間

AWS Identity Centerには権限セットごとにセッション継続時間が設定されています( セッション期間の設定 - AWS IAM Identity Center )。
例えばAdministratorAccessアクセス権限セットのセッション時間が8時間の場合、最初のログインから8時間後まではIAMデータベース認証でパスワードを取得できることになります。

3. IAMデータベース認証の認証トークンの有効期限

生成された認証トークンには有効期限があります。

この15分という有効期限の間はいつでもこのパスワードを使ってDBへログインすることができます。

理論上の最大なりすまし可能時間のまとめ

前述の通り、AWS Identity Centerのセッション時間と認証トークンの有効期限という2つのセッション時間があります。
そのため、理論上はAdministratorAccessなどへのログインから AWS Identity Centerのセッション時間 + IAMデータベース認証の認証トークンの有効期限 の時間後まではDBへログインできます。それ以降は新たなログインが不可能なので、その時間が経った後、コネクションがなければなりすましはないと判断できます。

例: AdministratorAccessアクセス権限セットのセッション時間が8時間だった場合
朝9時にある開発者がAdministratorAccessでログインしたとすると、そこから8時間15分後の17時15分、これ以降はなりすましが不可能になります。

※ なりすましと何度も書きましたが、同じDB内ユーザーへログインしたとしてもログイン元のIPアドレスは監査ログに記録されるため、痕跡が一切残らないわけではありません。あくまで、あるクエリの実行者を一意に特定できない可能性がある、という意味でなりすまし可能と表現しました

参考リンク

関連したAWS公式ドキュメント

脚注
  1. 監査ログには接続元のIPアドレスが記録されるので、ある日時のIPアドレスとエンジニアの対応が完璧に把握できているならある程度はわかるのですが、多くの会社であまり現実的な仮定ではないでしょう ↩︎

  2. それでもなんとか ${aws:userid} を使おうとしているのが How to Setup IAM Database Authentication with IAM Identity Center | by Christopher Scholz | Mediumですが、反動としてアクセス権限セットのIAMポリシーがどんどん増えていく欠点を抱えています ↩︎

株式会社エス・エム・エス

Discussion