
AWS プライベートサブネットにある OpenSearch ドメインに AWS SigV4 で認証する
今回ちょっとマイナーなネタになってしまうのですが、たまに表題の作業をする時に手順を忘れてしまうので備忘録として残しておきます。
内容は表題の通り、 AWS VPC のプライベートサブネット上に配置された OpenSearch Service のドメインに対して SigV4 認証をする方法になります。

SigV4 認証について
AWS Signature Version 4 (SigV4) は、AWS API におけるリクエスト認証の方式で、IAM クレデンシャル (アクセスキーやシークレットキー、セッショントークンなど) に基づいてリクエストに署名を付与することで、送信者の識別 (認証) をする事ができます。
S3 でよく見る奴ですが、 OpenSearch Service ではこの機能を使って OpenSearch ドメイン内のユーザーに特定の IAM ロール (※) を backend role として紐づける事ができ、そのクレデンシャルに基づいて SigV4 による認証を行う事ができます。要するにユーザー名/パスワード方式の Basic 認証を経なくても良くなり、セキュリティの向上に繋がると言うことです。
AWS SigV4 support for OpenSearch clients
https://opensearch.org/blog/aws-sigv4-support-for-clients/
※おそらく IAM ユーザーでも認証できると思いますが最近は IAM ユーザーを使うことが推奨されていないので検証はしていません。
例えば、 “my-app” と言うユーザーが OpenSearch ドメインにあるとして、これに arn:aws:iam::000000000000:role/OpenSearchMyAppRole と言うロールを backend role として紐づけると、このロールのクレデンシャルを使って SigV4 で署名をする事で “my-app” ユーザーとして認証が可能になります。また OpenSearch Service の機能として master ユーザーそのものに IAM ロールを紐づける事も可能です。
今回やりたい事
本題に戻りまして、プライベートサブネット上にあるサーバーに対して踏み台サーバーを経由するなどしてローカルから何か作業をしたい事がたまにあると思います。その場合以下の様にして ssh コマンドのトンネル機能を使って踏み台のサーバーを経由して localhost からアクセス可能にしたりすると思います:
ssh -i ~/.ssh/test-key-pair.pem -L 4443:vpc-my-os-domain-xxx.ap-northeast-1.es.amazonaws.com:443 ec2-user@i-asdf1234asdf
上記の例では curl --insecure https://localhost:4443 でプライベートサブネット上にある OpenSearch のドメイン vpc-my-os-domain-xxx.ap-northeast-1.es.amazonaws.com に接続可能になります。このままでは、通常であれば何かしらのユーザーで認証が必要ですが、 arn:aws:iam::000000000000:role/OpenSearchMyAppRole で SigV4 署名する事で認証が可能になります。
AWS SigV4 Proxy を使う
簡単に SigV4 署名を実現するツールが AWS Labs から提供されています。
HTTP プロキシサーバーになっていて、受け取ったリクエストに対して SigV4 署名を付けた状態で指定したホストに転送してくれます。ちなみに OpenSearch だけでなく、HTTP リクエストに対応している S3, SQS, API Gateway などにも対応しています。
まずは arn:aws:iam::000000000000:role/OpenSearchMyAppRole に assume-role してセッション情報を取得しましょう:
aws sts assume-role --role-arn arn:aws:iam::000000000000:role/OpenSearchMyAppRole --role-session-name oss-sigv4-session
出力された情報を使って AWS SigV4 Proxy を起動します。公式の Docker イメージが提供されているのでそちらを使ってコンテナを起動します:
docker run --rm -ti --network=bridge -p 8080:8080 \
-e AWS_ACCESS_KEY_ID=先ほど取得したAccessKeyId \
-e AWS_SECRET_ACCESS_KEY=先ほど取得したSecretAccessKey \
-e AWS_SESSION_TOKEN=先ほど取得したSessionToken \
public.ecr.aws/aws-observability/aws-sigv4-proxy \
--verbose --log-failed-requests --log-signing-process --no-verify-ssl \
--name es --region ap-northeast-1 \
--host host.docker.internal:4443 \
--sign-host ap-northeast-1.es.amazonaws.com
リージョン等は適宜調整してください。これで Proxy サーバーが 8080 で listen するので、リクエストを http://localhost:8080 に送りましょう。署名は Proxy がするので素のリクエストで問題ないです:
curl http://localhost:8080
{
"name" : "asdf1234asdf123",
"cluster_name" : "000000000000:my-os-domain",
"cluster_uuid" : "xxxxxxxx-ZZZZ1234",
"version" : {
"distribution" : "opensearch",
"number" : "2.17.0",
"build_type" : "tar",
"build_hash" : "unknown",
"build_date" : "2025-06-09T10:25:23.765511018Z",
"build_snapshot" : false,
"lucene_version" : "9.11.1",
"minimum_wire_compatibility_version" : "7.10.0",
"minimum_index_compatibility_version" : "7.0.0"
},
"tagline" : "The OpenSearch Project: https://opensearch.org/"
}
SSL リクエストは Proxy に委譲するのでこちらでは (直接トンネル経由でリクエストした時とは違い) http で通信している点に注意してください。
おまけ:ワンライナー版
assume-role して取得したセッション情報を使って AWS SigV4 Proxy を起動するワンライナーです:
( set -- $(aws sts assume-role --role-arn arn:aws:iam::000000000000:role/OpenSearchMyAppRole --role-session-name oss-sigv4-session \
--query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' --output text) && \
AWS_ACCESS_KEY_ID=$1 AWS_SECRET_ACCESS_KEY=$2 AWS_SESSION_TOKEN=$3 \
docker run --rm -ti --network=bridge -p 8080:8080 \
-e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN \
public.ecr.aws/aws-observability/aws-sigv4-proxy \
--verbose --log-failed-requests --log-signing-process --no-verify-ssl \
--name es --region ap-northeast-1 \
--host host.docker.internal:4443 \
--sign-host ap-northeast-1.es.amazonaws.com )
※ bash でのみ動作確認しています。