わたねこコーリング

野良プログラマ発、日々のアウトプット

AWS Parameters and Secrets Lambda Extension の日本語文字化けに対応した話

AWS Lambda 関数に DB 接続アカウント等の秘匿情報を注入したい場合は、やっぱり環境変数とかじゃなく Secrets Manager を使いたいですよね。最近では Parameters and Secrets Lambda Extension という拡張機能が用意されていて、アプリケーションプログラム内で直にシークレットを取得するより低コストに処理できるようになっています。

docs.aws.amazon.com

dev.classmethod.jp

てな訳で、上記を参考に自分もやってみた(ランタイムは Python)のですが、シークレットに日本語を格納していると所謂文字化けが発生してしまいました。例えば nihongo-test というシークレットの値が {"value": "日本語です。文字化けしてませんか?"} だと、

secretId = 'nihongo-test'
headers = {"X-Aws-Parameters-Secrets-Token": os.environ.get('AWS_SESSION_TOKEN')}
url = f"http://localhost:2773/secretsmanager/get?secretId=" + urllib.parse.quote(secretId, safe='')
resp = requests.get(url, headers=headers)
print(resp.text)

というプログラムでの print() の出力は

{"ARN":"arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxxxx:secret:nihongo-test-PJyzkt","CreatedDate":"2023-10-13T01:06:42.784Z","Name":"nihongo-test","SecretBinary":null,"SecretString":"{\"value\": \"æ¥æ¬èªã§ããæå­åããã¦ã¾ããã?\"}","VersionId":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","VersionStages":["AWSCURRENT"],"ResultMetadata":{}}

のような有様に。キャッシュサーバからのレスポンスの Content-Type を確認したら 'text/plain' のみで charset 明示が無かったので、そのへんが原因みたいです。なので、

print(resp.content.decode(encoding='utf-8'))

のように resp.text ではなく、resp.content から body を取得してバイト列→文字列と変換してやれば OK ですた。