EC2 の OpenTelemetry Collector から API キー(ベアラートークン)で Amazon CloudWatch にトレースを送ってみた

EC2 の OpenTelemetry Collector から API キー(ベアラートークン)で Amazon CloudWatch にトレースを送ってみた

X-Ray の OTLP トレースエンドポイントで、IAM ユーザーから作成した API キーによる認証が使えるようになりました。東京リージョンで実際にトレースを送り、Logs Insights で検索できることを確認しました。
2026.11.15

はじめに

2026年11月3日、X-Ray の OTLP トレースエンドポイントで SigV4 に加えて API キー(ベアラートークン)認証がサポートされました。

https://aws.amazon.com/jp/about-aws/whats-new/2026/11/amazon-cloudwatch-api-keys-opentelemetry

この記事では、東京リージョンの EC2 上の OpenTelemetry Collector から API キーでトレースを送信し、CloudWatch Logs Insights と X-Ray の取得 API で参照できることを確認しました。

検証環境

項目 内容
リージョン ap-northeast-1
EC2 t3.small、Amazon Linux 2023.12.20261109(x86_64)
Collector otelcol-contrib 0.165.0(GitHub リリースの rpm でインストール)
送信元 Python 3.9.25、opentelemetry-sdk と opentelemetry-exporter-otlp-proto-http(どちらも 1.41.1)
Transaction Search 検証前から有効。インデックス率は 1%(設定は変更していない)

設定

IAM ユーザーと API キー

IAM ユーザーを作成して AWSXRayAPIKeyAccess ポリシーをアタッチし、サービス名に xray.amazonaws.com を指定して API キーを発行しました。キーの有効期間は 1 日にしました。

aws iam create-user --user-name xray-traces-api-key-user
aws iam attach-user-policy --user-name xray-traces-api-key-user --policy-arn arn:aws:iam::aws:policy/AWSXRayAPIKeyAccess
aws iam create-service-specific-credential --user-name xray-traces-api-key-user --service-name xray.amazonaws.com --credential-age-days 1

発行手順と必要な権限は、開発者ガイドに書かれています。

https://docs.aws.amazon.com/xray/latest/devguide/xray-opentelemetry-bearer-token.html

EC2 のロール

送信元の EC2 のロールについて、xray:PutTraceSegments と xray:CallWithBearerToken を simulate-principal-policy で評価すると、どちらも implicitDeny でした。

aws iam simulate-principal-policy --policy-source-arn arn:aws:iam::<ACCOUNT>:role/xray-apikey-verify-ec2 --action-names xray:PutTraceSegments xray:CallWithBearerToken --query 'EvaluationResults[].[EvalActionName,EvalDecision]'
[
    [
        "xray:PutTraceSegments",
        "implicitDeny"
    ],
    [
        "xray:CallWithBearerToken",
        "implicitDeny"
    ]
]

このロールの権限では、X-Ray にトレースを送信できません。

Collector と送信元

発行時の応答にある ServiceCredentialSecret の値を、末尾に改行を付けずに /etc/otelcol-contrib/xray-api-key へ保存しました。権限は 600、所有者は otelcol-contrib ユーザーです。Collector の bearertokenauth 拡張が、このファイルから API キーを読んで Authorization ヘッダーに設定します。

Collector の設定は /etc/otelcol-contrib/config.yaml に保存しました。

extensions:
  bearertokenauth:
    filename: "/etc/otelcol-contrib/xray-api-key"

receivers:
  otlp:
    protocols:
      http:
        endpoint: "127.0.0.1:4318"

processors:
  batch:

exporters:
  otlp_http/xray:
    compression: gzip
    traces_endpoint: "https://xray.ap-northeast-1.amazonaws.com/v1/traces"
    auth:
      authenticator: bearertokenauth

service:
  extensions: [bearertokenauth]
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp_http/xray]

送信元は、親スパン 1 つと子スパン 3 つを作成し、それぞれに test.run_id 属性を付けて、Collector の 127.0.0.1:4318 へ送る Python スクリプトです。

send_spans.py
import sys
import time
import uuid

from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

run_id = sys.argv[1] if len(sys.argv) > 1 else uuid.uuid4().hex[:8]

provider = TracerProvider(resource=Resource.create({"service.name": "apikey-demo"}))
provider.add_span_processor(
    BatchSpanProcessor(OTLPSpanExporter(endpoint="http://127.0.0.1:4318/v1/traces"))
)
trace.set_tracer_provider(provider)
tracer = trace.get_tracer("apikey-demo")

with tracer.start_as_current_span("parent-job") as parent:
    parent.set_attribute("test.run_id", run_id)
    for i in range(3):
        with tracer.start_as_current_span(f"child-step-{i}") as child:
            child.set_attribute("test.run_id", run_id)
            time.sleep(0.05)

provider.shutdown()
print(f"sent run_id={run_id}")

トレースの参照

Logs Insights

1 回目として、test.run_id に run092751 を指定して 1 トレース(4 スパン)を送りました。スパンは CloudWatch Logs の aws/spans ロググループに入り、次のクエリで検索できました。

fields @timestamp, name, spanId, parentSpanId, attributes.test.run_id | filter attributes.test.run_id = 'run092751' | sort @timestamp asc
name spanId parentSpanId
child-step-0 bfe4a2e476a8c5d6 9a91d3ebc50396e1
child-step-1 8c68c514137fa129 9a91d3ebc50396e1
child-step-2 4ace9b7ce01b29d5 9a91d3ebc50396e1
parent-job 9a91d3ebc50396e1

3 つの子スパンの parentSpanId が、parent-job の spanId と一致しています。

続けて、test.run_id を idx-092911 にして 1 トレースずつ 300 回送信し、300 トレース(1200 スパン)を追加しました。Collector の指標は次のとおりです。1204 は、1 回目の 4 スパンと 300 × 4 スパンの合計です。

指標 値
otelcol_receiver_accepted_spans 1204
otelcol_exporter_sent_spans 1204
otelcol_receiver_refused_spans 0

Logs Insights では、次のクエリでスパン数とトレース数を数えました。

filter attributes.test.run_id = 'idx-092911' | stats count(*) as spans, count_distinct(traceId) as traces

送信完了から約 2 分後の時点では spans が 1144 で、1200 に届いていませんでした。約 4 分後に再実行すると、spans が 1200、traces が 300 になりました。

X-Ray の取得 API

get-trace-summaries に --start-time 1794269290 --end-time 1794270790 を指定しました。この範囲には、送った 301 トレース(1 回目の 1 トレースと追加の 300 トレース)が含まれます。返ったのは 4 件でした。約 2 日 17 時間後に同じ範囲で取り直しても 4 件でした。

返った 4 件は、インデックス率 1% の設定と合う数です。

まとめ

X-Ray の OTLP トレースエンドポイントに、API キー(ベアラートークン)認証でトレースを送信できることを確認しました。

AWS 外の環境から X-Ray の OTLP トレースエンドポイントへ送信する場合、AWS 環境でも X-Ray 用の IAM ロールを付けにくい場合、別アカウントの X-Ray へ送りたい場合などに利用できそうです。

API キーを作成する IAM ユーザーには、必要最小限の権限だけを付けてください。可能であれば IP 制限をかけ、ローテーションの準備もしたうえで利用することをおすすめします。

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事