Amazon Bedrock のログをマスクしてみた

# はじめに
Amazon Bedrock ではAPIの呼び出しをログとして出力することができます。

https://aws.amazon.com/jp/blogs/news/amazon-bedrock_and_amazon-cloudwatch_integration_for_genai/

この機能を利用することで、実際に Bedrock をサービスで利用する上で問題が発生した時に調査しやすくすることができます。ただし、現状、Bedrock ログは 入力されたプロンプトと出力された結果をそのまま出力します。そのため、個人情報などを含むプロンプトを入力して利用する場合、ログにも個人情報が含まれてしまい、CloudWatchログなどを見れるユーザーが個人情報にアクセスできてしまう可能性があります。この問題を解決するにはログ上の個人情報の部分をマスクするなどの処理が必要です。しかし、現状、日本語の個人情報などをマスクしてログに出力するBedrockの機能は提供されていません。
この問題に対して、本記事では、CloudWatch Logs Data Protectionを利用し、プロンプトの全文マスクすることで対処します。

# Bedrock のログを CloudWatch Logs に出力する
まず、BedrockのログをCloudWatch Logsに出力する設定を行います。
Bedrockの画面の左メニューの下の方に[Settings]がありますので選択します。

![スクリーンショット 2024-09-14 16.37.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1005574/f4cfe49a-1050-f0e5-d046-463f994721e1.png)

[Model invocation logging]をオンにし、[Select the data types to include with logs]でログの出力種類を選択します。
[Select the logging destinations]では[CloudWatch Logs only]を選択します。
[Log group name]に ログの保存先のロググループ名を入力します。
[Choose a method to authorize Bedrock]ではログを配信するためのIAMロールを指定します。ここでは[Create and use a new role]を選択し、新しく作成します。

![スクリーンショット 2024-09-14 16.39.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1005574/7d95d4d8-7eb9-338b-b969-400c000155b2.png)

最後に[Save settings]を選択し、設定を保存します。
これで、以後はログが保存されるようになります。

試しにログを見てみましょう。
以下のようにログを有効化した後にプレイグラウンドでチャットをしてみます。

![スクリーンショット 2024-09-14 17.26.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1005574/55324d63-712a-3c5f-ddcc-7651de465782.png)


次に、CloudWatch Logs で先ほど指定したロググループを選択し、ログストリームの内容を確認します。

![名称未設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1005574/3ce206c7-3324-7829-a492-3de041906a79.png)


このように入力したプロンプトと出力内容が表示されていることが分かります。

# CloudWatch Logs の Data Protection を利用する
次に、CloudWatch Logs の Data Protection を設定します。
 Data Protectionでは大きく標準で用意されている「マネージドデータ識別子」と「カスタムデータ識別子」があります。

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/protect-sensitive-log-data-types.html

ただし。日本語の氏名などでは、「マネージドデータ識別子」は上手く動作しません。そのため、今回は「カスタムデータ識別子」を利用し、入出力全体をマスクします。
「カスタムデータ識別子」は正規表現を利用して、任意の文字列を指定することができます。 
Bedrockのログでは、ログの出力内容を確認するとシステムプロンプト、ユーザープロンプト、出力内容は共通して「content」キーが用いられていることが分かります。
そのため、今回は「"content:"」から「}]」までをマスクするように指定しました。
利用した正規表現は以下の通りです。
```
"content":\s*(\[(?:[^[\]]|\[(?:[^[\]]|\[(?:[^[\]]|\[[^[\]]*\])*\])*\])*\])
```
この正規表現は Bedrock Claude3.5 で作成してもらいました。（正規表現が苦手な当方でも簡単に作成できましいた。生成AIってすごい。）
これを CloudWatch Logs の該当のロググループの DataProtection に登録します。

![スクリーンショット 2024-09-14 17.02.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1005574/c28a116a-cde7-3774-ec56-b2f2f1c5b3d0.png)

さて、それでは実際にテストしてみます。
再度 Bedrock のプレイグラウドでチャットを行います。

![スクリーンショット 2024-09-14 17.05.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1005574/596efcb8-1abd-b666-1ad8-647066bf5758.png)

次に、CloudWatch Logs のログストリームを確認します。

![スクリーンショット 2024-09-14 17.06.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1005574/40115580-202f-ace4-8f0e-310b8005483d.png)

JSONが壊れてしまっていますが、入出力の内容がマスクされていることが分かります。
また、Data Protection は 「logs:Unmask」権限が付与されている場合、元の文字列を表示することができます。
「Display > Temporarily unmasked protected data」を選択します。

![スクリーンショット 2024-09-14 17.10.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1005574/532e14dd-6536-f2f4-a5c6-ea84dd07e490.png)

すると、下記図のようにマスクの無いログを確認することができます。

![スクリーンショット 2024-09-14 17.12.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1005574/34c10d71-436c-93ba-9031-d28e6034bd34.png)

通常はマスクありで調査を行い、どうしてもプロンプトの内容が必要な場合だけ 「logs:Unmask」権限を付与することで、個人情報を保護しつつ、Bedrock の問題を調査しやすくすることができます。

# まとめ
今回はBedrockのログの入出力テキストを CloudWatch Logs Data Protection を利用してマスクすることで個人情報に配慮しつつ、調査を行いやすくする方法を紹介しました。
その他にはCloudWatch Logs サブスクリプションフィルターを活用し、マスクした状態で保存されるようにする方法も考えられます。
もっとスマートな方法があればぜひご共有ください！！