CTO室の岩本 (iwamot) です。
4月7日のプレスリリースでご案内の通り、ENECHANGEでは、ChatGPTを活用した業務効率化を進めています。
私も寄与したく、SlackへのChatGPT bot導入を提案し、実際に導入しました。結果、70名以上に利用されており、多少は貢献できたと思っています。
導入に際しては、安全性を高めるため、いくつか手を打ちました。具体的には「入力内容の保全・機密情報のマスキング・Azure OpenAI Serviceの利用」です。
以下、詳しくご紹介します。
入力内容の保全
まず、入力内容の保全についてです。何らかの事故が起こった場合、後から入力内容の精査が求められるかもしれません。そのため保全が必要です。
私が導入したChatGPT in SlackのDEBUGログには、ユーザの入力内容が含まれています。そこでFluent Bitを使ってログをフィルタリング・加工し、CloudWatch LogsとS3に出力する仕組みにしました。
Fluent Bitの設定は下記の通りです。ECSのFireLensで使う前提としています。
/fluent-bit/etc/parsers_chatgpt.conf
[PARSER] Name chatgpt_post_details Format regex Regex ^DEBUG:openai:api_version=\S+ data='(?<data>.*)' message='Post details'$ Decode_Field_as escaped_utf8 data do_next Decode_Field_as json data
/fluent-bit/etc/chatgpt.conf(後述のマスキングに関わる部分は省略)
[SERVICE] Parsers_File parsers_chatgpt.conf # https://aws.amazon.com/jp/blogs/news/under-the-hood-firelens-for-amazon-ecs-tasks/ Flush 1 Grace 30 # OpenAI APIへのPOSTログのみに絞り込み [FILTER] Name rewrite_tag Match app-firelens-* Rule $log ^DEBUG:openai:api_version=\S+\sdata='.*'\smessage='Post\sdetails'$ chatgpt.post_details.$TAG true # dataの内容をUTF-8デコードしてJSONに変換 [FILTER] Name parser Match chatgpt.post_details.* Key_Name log Parser chatgpt_post_details Reserve_Data On # ユーザ入力のみに絞り込み [FILTER] Name grep Match chatgpt.post_details.* Exclude data['user'] system # data JSONの内容をlift [FILTER] Name nest Match chatgpt.post_details.* Operation lift Nested_under data [OUTPUT] Name cloudwatch_logs Match chatgpt.post_details.* region ${AWS_DEFAULT_REGION} log_group_name ${POST_DETAILS_LOG_GROUP_NAME} log_stream_template $TAG[2] log_stream_prefix fallback-stream Retry_Limit 5 [OUTPUT] Name kinesis_firehose Match chatgpt.post_details.* region ${AWS_DEFAULT_REGION} delivery_stream ${POST_DETAILS_DELIVERY_STREAM} time_key date Retry_Limit 5
機密情報のマスキング
次に、機密情報のマスキングについてです。入力内容にメールアドレス・電話番号・クレジットカード番号が含まれる場合、漏洩事故を防ぐため、マスキングしてからOpenAI APIにPOSTするのが安全です。
ChatGPT in Slackにはマスキングの機能があるため、環境変数を指定するだけで実現できます。
私はECSのタスク定義で下記のように指定しました。
{ "name": "REDACTION_ENABLED", "value": "true" }, { "name": "REDACT_CREDIT_CARD_PATTERN", "value": "(?<![0-9-])((?:\\d{4}(?:[ -]\\d{4}){3})|(?:\\d{4}[ -]\\d{6}[ -]\\d{4,5}))(?![0-9-])" }, { "name": "REDACT_EMAIL_PATTERN", "value": "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}" }, { "name": "REDACT_PHONE_PATTERN", "value": "(?<!\\d)\\d{1,5}-\\d{1,4}-\\d{4}(?!\\d)" }, { "name": "REDACT_SSN_PATTERN", "value": "(?!)" },
また、マスキングを検知してSlackに通知したく、Fluent Bitに下記の設定も加えています。
/fluent-bit/etc/filters_chatgpt.lua
function add_redaction_fields(tag, timestamp, record) local system_slack_id = string.match(record["messages"][1]["content"], "<@(U[%w]-)>") local new_record = record new_record["redacted_contents"] = {} for _, message in ipairs(record["messages"]) do local content = message["content"] if string.find(content, "^<@" .. system_slack_id .. ">: ") == nil then if string.find(content, "%[EMAIL%]") ~= nil or string.find(content, "%[PHONE%]") ~= nil or string.find(content, "%[CREDIT CARD%]") then content = string.gsub(content, "<@(U[%w]-)>", "<%1>") table.insert(new_record["redacted_contents"], content) end end end if #new_record["redacted_contents"] > 0 then new_record["redacted"] = "true" end return 2, timestamp, new_record end
/fluent-bit/etc/chatgpt.conf(マスキングに関わる部分のみ抜粋)
# マスキング情報を追加 [FILTER] Name lua Match chatgpt.post_details.* script filters_chatgpt.lua call add_redaction_fields # マスキングされたログに別のタグを付与 [FILTER] Name rewrite_tag Match chatgpt.post_details.* Rule $redacted true chatgpt.redacted.$TAG[2] true # マスキング情報を削除 [FILTER] Name record_modifier Match chatgpt.post_details.* Remove_key redacted Remove_key redacted_contents # マスキングされたメッセージのみ出力 [FILTER] Name record_modifier Match chatgpt.redacted.* Allowlist_key redacted_contents [OUTPUT] Name slack Match chatgpt.redacted.* webhook ${REDACTED_WEBHOOK}
Azure OpenAI Serviceの利用
最後に、Azure OpenAI Serviceの利用についてです。Azure OpenAI Serviceはアクセス元を制限できるため、APIキーの漏洩リスクが軽減できます。OpenAI APIにはないメリットです。
ChatGPT in SlackはAzure OpenAI Serviceを未サポートだったため、サポートできるようpull requestを作成したところ、マージしていただけました。Azure OpenAI Serviceで必要となるdeployment_id
等をopenai.Completion.create
のパラメータに追加し、環境変数で指定できるようにしたものです。
その後、ECSのタスク定義に下記の環境変数を追加し、gpt-3.5-turbo版のエンドポイントをAzure OpenAI Serviceに変更済みです。gpt-4版は利用申請が受理され次第、変更したいと思っています。
{ "name": "OPENAI_API_TYPE", "value": "azure" } { "name": "OPENAI_API_BASE", "value": "https://enechange-chatgpt-in-slack.openai.azure.com" }, { "name": "OPENAI_API_VERSION", "value": "2023-05-15" }, { "name": "OPENAI_DEPLOYMENT_ID", "value": "example-deployment-id" },
さらに、AWS側のIPアドレスをNATゲートウェイで固定し、当該IPアドレスからのアクセスのみをAzure側で許可することで、APIキーの漏洩リスクを軽減できました。
まとめ
以上の工夫により、運用の手軽さは損なわず、ChatGPT botの安全性を高められました。
日進月歩の状況なので、導入したbotがいつまで使われるのか分からないのが正直なところですが、現時点では適切な手が打てたのではないかと思っています。