Open Agent Management Protocol
この記事は英語の原文を日本語に翻訳したものです。原文: https://opentelemetry.io/docs/specs/opamp/
翻訳元: open-telemetry/opamp-spec v0.17.0(コミット 06ff6ef)
ステータス: Beta
はじめに
Open Agent Management Protocol(OpAMP)は、データ収集を行う大規模なAgent群をリモートで管理するためのネットワークプロトコルです。
OpAMPを使うと、AgentはServerにステータスを報告し、Serverから設定を受け取り、Serverからエージェントインストールパッケージの更新を受け取れます。このプロトコルはベンダーに依存しないため、ServerはOpAMPを実装する異なる種類のAgent群(異なるベンダーの混在したAgent群を含む)をリモートで監視・管理できます。
OpAMPは次の機能をサポートします。
- Agentのリモート設定。
- ステータスレポート。このプロトコルにより、Agentは自身の種類やバージョン、稼働しているOSの種類やバージョンといったプロパティを報告できます。ステータスレポートはまた、管理Serverが個々のAgentやAgentの種類に応じてリモート設定を調整することも可能にします。
- OTLP互換のバックエンドへのAgent自身のテレメトリーのレポート。CPUやRAM使用率といったAgentのプロセスメトリクスや、データ処理のレートといったAgent固有のメトリクスを監視するために使われます。
- Agentのハートビート。
- ダウンロード可能なAgent固有パッケージの管理。
- セキュアな自動更新機能(Agentのアップグレードとダウングレードの双方)。
- クライアント側のTLS証明書の失効やローテーションを含む、接続クレデンシャルの管理。
上記の機能によって、混在した大規模なAgent群(OpenTelemetry Collector、Fluentdなど)に対する「単一の管理画面」が実現します。
通信モデル
OpAMP Serverは、OpAMPプロトコルのクライアント側実装を提供するAgentを管理します。以降、このクライアント側実装をOpAMP Client、あるいは単にClientと呼びます。OpAMPは、AgentとClientの間に特定の関係を前提としません。Clientは、Agentとは異なるライフサイクルを持つ別プロセスとして動作することも、サイドカーやプラグインとして動作することも、Agentのコードに完全に統合されることもできます。
Agentは、OpAMP Serverから指示された場合にオプションで自身のテレメトリーをOTLPの宛先に送信できます。Agentはおそらく他の宛先にも接続し、収集したデータをそこに送信します。
┌────────────┬────────┐ ┌─────────┐
│ │ OpAMP │ OpAMP │ OpAMP │
│ │ ├──────────►│ │
│ │ Client │ │ Server │
│ └────────┤ └─────────┘
│ │
│ ┌────────┤ ┌─────────┐
│ │OTLP │ OTLP/HTTP │ OTLP │
│ Agent │ ├──────────►│ │
│ │Exporter│ │ Receiver│
│ └────────┤ └─────────┘
│ │
│ ┌────────┤
│ │Other ├──────────► Other
│ │Clients ├──────────► Destinations
└────────────┴────────┘
この仕様書は、OpAMPネットワークプロトコルと、OpAMP AgentおよびServerに期待される振る舞いを定義します。OTLP/HTTPプロトコルの仕様についてはOTLPを参照してください。Agentが他の宛先に接続する際に使うプロトコルはAgentの種類ごとに異なり、この仕様書の対象外です。
OpAMPプロトコルは、プレーンHTTP接続とWebSocket接続という2つのサポート対象トランスポートのいずれかで動作します。Server実装はプレーンHTTP接続とWebSocket接続の両方を受け付けるべき(SHOULD)です。OpAMP Client実装は、それぞれの必要に応じてプレーンHTTPまたはWebSocketのいずれかのトランスポートのみをサポートすることを選んでもかまいません。
OpAMP ClientはAgentの代わりにOpAMP Serverに接続します。通常、1つのServerが多数のClientからの接続を受け付けます。Agentは、自己割り当てまたはServer割り当てのグローバルに一意なインスタンス識別子(instance_uid、以下同様)で識別されます。instance_uidは、Client経由でAgentからServerへ送られる各メッセージ、およびServerからAgentへ送られる各メッセージに記録されます。
接続のデフォルトのURLパスは/v1/opampです。URLパスはClient側・Server側で設定可能でもよい(MAY)ものとします。
OpAMPエンドポイントのデフォルトのポートは4320です。OpAMP Server実装は、デフォルトでこのポートをリスンするべき(SHOULD)です。
Agent側でOpAMPを実装する典型的な方法の一つは、Agentプロセスを制御する補助的なSupervisorプロセスを持つことです。Supervisorは、通常OpAMP Serverとの通信も担います。
┌───────────────────┐
│ Supervisor │
│ │
│ ┌────────┤ ┌────────┐
│ │ OpAMP │ OpAMP │ OpAMP │
│ │ ├──────────►│ │
│ │ Client │ │ Server │
└────┬─────┴────────┘ └────────┘
│
│
▼
┌──────────┐
│ │
│ Agent │
│ │
└──────────┘
OpAMPの仕様書は、Supervisorの使用を必須とはしておらず、SupervisorとAgentがどのように通信するかも定義していません。
この仕様書の以降の記述では、_Agent_という語を、Supervisorがその一部を構成しているかどうかに関わらず、OpAMPのクライアント側を実装しているエンティティを指す語として使います。
WebSocketトランスポート
OpAMPプロトコルがサポートするトランスポートの1つがWebSocketです。OpAMP ClientはWebSocketクライアントであり、ServerはWebSocket Serverです。ClientとServerは、バイナリデータのWebSocketメッセージを使って通信します。各WebSocketメッセージの内容は、エンコードされたheaderに続けてバイナリエンコードされたProtobufのdataメッセージが続く形になります(WebSocketメッセージのフォーマットを参照)。
Agentの代わりに、ClientはAgentToServerメッセージデータを送信し、ServerはServerToAgentのProtobufメッセージデータを送信します。
┌────────────\ \────────┐ ┌──────────────┐
│ / / │ Data:AgentToServer │ │
│ \ \ OpAmp ├───────────────────────►│ │
│ Agent / / │ │ Server │
│ \ \ Client │ Data:ServerToAgent │ │
│ / / │◄───────────────────────┤ │
└────────────\ \────────┘ └──────────────┘
WebSocketメッセージのフォーマット
各WebSocketメッセージのフォーマットは以下のとおりです。
┌────────────┬────────────────────────────────────────┬───────────────────┐
│ header │ Varint encoded unsigned 64 bit integer │ 1-10 bytes │
├────────────┼────────────────────────────────────────┼───────────────────┤
│ data │ Encoded Protobuf message, │ 0 or more bytes │
│ │ either AgentToServer or ServerToAgent │ │
└────────────┴────────────────────────────────────────┴───────────────────┘
デコード前のheaderは64ビットの符号なし整数です。WebSocketメッセージの中では、この64ビットのheader値はBase 128 Varint形式でバイト列にエンコードされます。エンコードされたheaderが使うバイト数は、デコード前のheaderの値によって決まり、1バイトから10バイトの間になります。
この版の仕様書では、デコード前のheaderの値は0に固定されています。それ以外のheaderの値はすべて将来の使用のために予約されています。そのような値は将来のOpAMP仕様書のバージョンで定義されます。この仕様書に準拠したOpAMP WebSocketメッセージデコーダーは、headerの値が0であることを確認するべき(SHOULD)であり、0でない場合はそのWebSocketメッセージが不正な形式であると見なすべき(SHOULD)です。
dataフィールドには、ProtobufバイナリワイヤーフォーマットでエンコードされたAgentToServerまたはServerToAgentメッセージを表すバイト列が含まれます。
headerとdataの両フィールドとも、可変長のバイト列を含むことに注意してください。headerをデコードするBase 128 Varintアルゴリズムは、読み取ったバイト列から自分がいつ停止すべきかを判断できます。
dataフィールドをProtobufのデコードロジックでデコードするには、実装はdataフィールドのバイト数を知る必要があります。これを算出するために、実装はWebSocketメッセージ全体のバイト数からheaderのバイト数を差し引く必要があります(MUST)。
Protobufワイヤーフォーマットの設計上、エンコードされたAgentToServerまたはServerToAgentメッセージが空(すべてのフィールドが未設定)である場合、dataのバイト数は0になることがあります。これは有効な状態です。
WebSocketメッセージの交換
OpAMP over WebSocketは、非同期・全二重のメッセージ交換プロトコルです。OpAMP ClientとServerが交換するメッセージの順序とシーケンスは、この仕様書内の各ケーパビリティに対応する節でそれぞれ定義されています。
シーケンスは通常、何らかの外部イベントによって発生する起点メッセージから開始されます。例えば、接続が確立された後にClientがAgentToServerメッセージを送信する場合、「接続の確立」が起点イベントであり、AgentToServerが起点メッセージとなります。
ClientとServerのどちらも、起点メッセージを送信してシーケンスを開始できます。
起点メッセージは、受信者に1つ以上のメッセージを返信させることがあり、それがさらに反対方向のメッセージを引き起こす、という形で続いていきます。この双方向のメッセージ交換は、交換の目標が達成されるか、シーケンスがエラーで失敗するまで続きます。
同一のメッセージが、あるケースではシーケンスの起点メッセージとなり、別のケースでは他のメッセージへの応答として発生することがある点に注意してください。OpAMPの他のプロトコルとは異なり、「リクエスト」と「レスポンス」というメッセージ種別の間に厳密な区別はありません。メッセージの役割は、そのシーケンスがどのように開始されたかに依存します。
例えばAgentToServerメッセージは、Clientが初めてServerに接続する際にClientが送信する起点メッセージとなることがあります。また、AgentToServerメッセージは、Serverがリモート設定のオファーをAgentに送り、Agentがその設定を受け入れたことを報告する際の応答として送信されることもあります。
Clientがハートビートを送信できる場合、ClientはReportsHeartbeatケーパビリティを設定するべき(SHOULD)です。ReportsHeartbeatケーパビリティが設定されている場合、Clientは定期的にハートビートを送信するべき(SHOULD)です。ハートビートの間隔は、Client側で別の値が設定されていない限り、あるいはServerがOpAMPConnectionSettings.heartbeat_interval_secondsフィールドを通じて別の間隔を提示していない限り、30秒であるべき(SHOULD)です。
メッセージシーケンスの詳細は、動作節以下の各節を参照してください。
WebSocketトランスポートは、HTTPトランスポート使用時のようにClientがServerをポーリングするのを待たずに、ServerからAgentへ即座に通信する能力が必要な場合に典型的に使われます(詳細は後述)。
プレーンHTTPトランスポート
OpAMPプロトコルがサポートする2つ目のトランスポートは、プレーンHTTP接続です。OpAMP ClientはHTTPクライアントであり、ServerはHTTPサーバーです。ClientはServerに対してPOSTリクエストを送ります。POSTリクエストとレスポンスのボディは、バイナリシリアライズされたProtobufメッセージです。ClientはリクエストボディにAgentToServerのProtobufメッセージを送信し、ServerはレスポンスボディにServerToAgentのProtobufメッセージを送信します。
OpAMP over HTTPは、同期的・半二重のメッセージ交換プロトコルです。Clientは、配送すべきAgentToServerメッセージがあるときにHTTPリクエストを開始します。ServerはAgentに配送したいServerToAgentメッセージを、各HTTPリクエストへの応答として返します。Agentが配送するものを何も持たない場合、Clientはinstance_uidフィールドのみを設定したinstance_uidのAgentToServerメッセージを送信して、Serverを定期的にポーリングしなければなりません(MUST)。これにより、Serverが(新しいリモート設定などの)配送したいメッセージをレスポンスとして返す機会を得られます。
Agentが配送するものを持たない場合のデフォルトのポーリング間隔は30秒です。このポーリング間隔はClient側で設定可能であるべき(SHOULD)です。Clientが以前にOpAMP接続設定を受け取り、それを受け入れている場合は、OpAMPConnectionSettings.heartbeat_interval_secondsの値がポーリング間隔として使われるべき(SHOULD)です。
HTTPトランスポートを使う場合のメッセージのシーケンスは、WebSocketトランスポートを使う場合とまったく同じです。唯一の違いはタイミングにあります。
- Serverがメッセージをagentに送信したい場合、Serverは、Clientがサーバーをポーリングし、Serverのメッセージをレスポンスとして返せるHTTPリクエストを確立するまで待つ必要があります。
- Agentがメッセージをサーバーに送信したいが、すでに応答されていないリクエストをServerに送信済みの場合、Clientはそのレスポンスを受け取るまで新しいリクエストの送信を待たなければなりません(MUST)。なお、この場合の新しいリクエストは、直前のレスポンスを受け取った直後に送信できます。Clientはリクエストの間のポーリング期間を待つ必要はありません。
プレーンHTTPトランスポートを使う場合、Clientは「Content-Type: application/x-protobuf」というリクエストヘッダーを設定しなければなりません(MUST)。Serverはこのヘッダーが設定されたHTTPリクエストを受信した場合、それをプレーンHTTPトランスポートのリクエストと見なすべき(SHOULD)であり、そうでなければWebSocketトランスポートの開始要求と見なすべき(SHOULD)です。
Clientは、リクエストボディをgzipメソッドで圧縮してもよく(MAY)、その場合は「Content-Encoding: gzip」を指定しなければなりません(MUST)。Server実装は「Content-Encoding」ヘッダーを尊重し、gzip圧縮されたリクエストボディと非圧縮のリクエストボディの両方をサポートしなければなりません(MUST)。
Clientは、instance_uidフィールドの値を、UUIDの標準的な文字列表現にエンコードして「OpAMP-Instance-UID」リクエストヘッダーに設定するべき(SHOULD)です(例:「OpAMP-Instance-UID: f81d4fae-7dec-11d0-a765-00a0c91e6bf6」)。この値は、AgentToServerメッセージのinstance_uidフィールドの値と等しくなります。
Clientが「Accept-Encoding」ヘッダーで圧縮されたレスポンスを受け入れられることを示した場合、Serverはレスポンスを圧縮するべき(SHOULD)です。
AgentToServerとServerToAgentのメッセージ
AgentToServer Message
OpAMPのWebSocketメッセージの本体、またはHTTPリクエストのボディは、以下のように定義されるバイナリシリアライズされたProtobufメッセージAgentToServerです(この文書中のすべてのメッセージはProtobuf 3言語で定義されています)。
message AgentToServer {
bytes instance_uid = 1;
uint64 sequence_num = 2;
AgentDescription agent_description = 3;
uint64 capabilities = 4;
ComponentHealth health = 5;
EffectiveConfig effective_config = 6;
RemoteConfigStatus remote_config_status = 7;
PackageStatuses package_statuses = 8;
AgentDisconnect agent_disconnect = 9;
uint64 flags = 10;
ConnectionSettingsRequest connection_settings_request = 11; // Status: [Development]
CustomCapabilities custom_capabilities = 12; // Status: [Development]
CustomMessage custom_message = 13; // Status: [Development]
AvailableComponents available_components = 14; // Status: [Development]
ConnectionSettingsStatus connection_settings_status = 15; // Status: [Development]
}
Serverは、動作節で対応する記述に従って各フィールドを処理するべきです。
AgentToServer.instance_uid
instance_uidフィールドは、稼働中のAgentインスタンスをグローバルに一意に識別する識別子です。Agentはこの識別子を自己生成するべき(SHOULD)であり、他のAgentが生成する識別子と競合しないよう最善を尽くすべきです。instance_uidは、Agentプロセスの生存期間を通じて変わらないままであるべき(SHOULD)です。instance_uidは16バイトでなければならず(MUST)、UUID v7仕様を使って生成されるべき(SHOULD)です。
Agentが、Serverによって生成された識別子を使いたい場合、このフィールドには一時的な値を設定するべき(SHOULD)で、かつRequestInstanceUidフラグを設定しなければなりません(MUST)。
AgentToServer.sequence_num
シーケンス番号は、Clientが送信するAgentToServerメッセージごとに1ずつ増加します。これにより、sequence_numが直前に受信した値より正確に1大きくなっていないことにServerが気付いた場合、Serverはメッセージを取り損なったことを検出できます。詳細はエージェントステータスの圧縮を参照してください。
AgentToServer.agent_description
Agentの種類や稼働場所などを記述するデータです。詳細はAgentDescriptionメッセージを参照してください。このフィールドは、直前のAgentToServerメッセージ以降この情報が変化していない場合は未設定であるべき(SHOULD)です。
AgentToServer.capabilities
AgentCapabilities列挙型で定義されたフラグのビットマスクです。AgentCapabilities列挙型に定義されていないビットはすべて、Clientによって0に設定されなければなりません(MUST)。これにより、将来AgentCapabilities列挙型を拡張してプロトコルを拡張しても、古いAgentは自動的に新しいケーパビリティをサポートしていないと報告することになります。このフィールドは常に設定されなければなりません(MUST)。
Agentは、最初のメッセージ以降いつでも自身のケーパビリティを更新してもよい(MAY)ものとします。Serverは、以降のメッセージが正しく送信されるように、Agentの変更を尊重しなければなりません(MUST)。Serverが、Agentがサポートしないケーパビリティに対応するメッセージの一部を送信した場合、Agentはそれを無視するべき(SHOULD)です。
enum AgentCapabilities {
// The capabilities field is unspecified.
UnspecifiedAgentCapability = 0;
// The Agent can report status. This bit MUST be set, since all Agents MUST
// report status.
ReportsStatus = 0x00000001;
// The Agent can accept remote configuration from the Server.
AcceptsRemoteConfig = 0x00000002;
// The Agent will report EffectiveConfig in AgentToServer.
ReportsEffectiveConfig = 0x00000004;
// The Agent can accept package offers.
// Status: [Beta]
AcceptsPackages = 0x00000008;
// The Agent can report package status.
// Status: [Beta]
ReportsPackageStatuses = 0x00000010;
// The Agent can report own trace to the destination specified by
// the Server via ConnectionSettingsOffers.own_traces field.
// Status: [Beta]
ReportsOwnTraces = 0x00000020;
// The Agent can report own metrics to the destination specified by
// the Server via ConnectionSettingsOffers.own_metrics field.
// Status: [Beta]
ReportsOwnMetrics = 0x00000040;
// The Agent can report own logs to the destination specified by
// the Server via ConnectionSettingsOffers.own_logs field.
// Status: [Beta]
ReportsOwnLogs = 0x00000080;
// The can accept connections settings for OpAMP via
// ConnectionSettingsOffers.opamp field.
// Status: [Beta]
AcceptsOpAMPConnectionSettings = 0x00000100;
// The can accept connections settings for other destinations via
// ConnectionSettingsOffers.other_connections field.
// Status: [Beta]
AcceptsOtherConnectionSettings = 0x00000200;
// The Agent can accept restart requests.
// Status: [Beta]
AcceptsRestartCommand = 0x00000400;
// The Agent will report Health via AgentToServer.health field.
ReportsHealth = 0x00000800;
// The Agent will report RemoteConfig status via AgentToServer.remote_config_status field.
ReportsRemoteConfig = 0x00001000;
// The Agent can report heartbeats.
// This is specified by the ServerToAgent.OpAMPConnectionSettings.heartbeat_interval_seconds field.
// If this capability is true, but the Server does not set a heartbeat_interval_seconds field, the
// Agent should use its own configured interval, which by default will be 30s. The Server may not
// know the configured interval and should not make assumptions about it.
// Status: [Development]
ReportsHeartbeat = 0x00002000;
// The agent will report AvailableComponents via the AgentToServer.available_components field.
// Status: [Development]
ReportsAvailableComponents = 0x00004000;
// The agent will report ConnectionSettingsOffers status via AgentToServer.connection_settings_status field.
// Status: [Development]
ReportsConnectionSettingsStatus = 0x00008000;
// Add new capabilities here, continuing with the least significant unused bit.
}
AgentToServer.health
ステータス: Beta
Agentおよびサブコンポーネントの現在のヘルスです。トップレベルのComponentHealthは、Agent全体のヘルスを表します。直前のAgentToServerメッセージ以降変化がない場合は省略してもよい(MAY)ものとします。詳細はComponentHealth messageを参照してください。
AgentToServer.effective_config
Agentの現在の実効設定です。実効設定とは、Agentが現在実際に使用している設定です。実効設定は、Agentがローカル設定を代わりに(または加えて)使用しているなどの理由で、以前にServerから受け取ったリモート設定とは異なる場合があります。詳細はEffectiveConfigメッセージを参照してください。このフィールドは、直前のAgentToServerメッセージ以降この情報が変化していない場合は未設定であるべき(SHOULD)です。
AgentToServer.remote_config_status
以前にServerから受け取ったリモート設定のステータスです。詳細はRemoteConfigStatusメッセージを参照してください。このフィールドは、直前のAgentToServerメッセージ以降この情報が変化していない場合は未設定であるべき(SHOULD)です。
AgentToServer.package_statuses
ステータス: Beta
パッケージステータスを含む、Agentのパッケージの一覧です。このフィールドは、直前のAgentToServerメッセージ以降この情報が変化していない場合は未設定であるべき(SHOULD)です。
AgentToServer.agent_disconnect
AgentDisconnectは、ClientからServerへ送信される最後のAgentToServerメッセージで設定されなければなりません(MUST)。
AgentToServer.flags
AgentToServerFlagsのビットマスクで定義されるビットフラグです。
enum AgentToServerFlags {
FlagsUnspecified = 0;
// Flags is a bit mask. Values below define individual bits.
// The Agent requests Server go generate a new instance_uid, which will
// be sent back in ServerToAgent message
RequestInstanceUid = 0x00000001;
}
AgentToServer.connection_settings_request
ステータス: [Development]
接続設定の作成を要求するフィールドです。Agentが接続設定の作成を開始するフローにおいて、このフィールドが設定されます。
詳細はConnectionSettingsRequestメッセージを参照してください。
AgentToServer.custom_capabilities
ステータス: [Development]
Agentがサポートするカスタムケーパビリティを示すメッセージです。
詳細はCustomCapabilitiesメッセージを参照してください。
AgentToServer.custom_message
ステータス: [Development]
Agentからserverへ送信されるカスタムメッセージです。
詳細はCustomMessageメッセージを参照してください。
AgentToServer.available_components
ステータス: [Development]
Agent内で利用可能なコンポーネントを列挙するメッセージです。このフィールドは、ReportsAvailableComponentsケーパビリティが設定されている場合に限り報告されるべき(SHOULD)です。
詳細はAvailableComponentsメッセージを参照してください。
AgentToServer.connection_settings_status
ステータス: [Development]
以前にServerから受信した接続設定のステータスです。詳細はConnectionSettingsStatusメッセージを参照してください。このフィールドは、直前のAgentToServerメッセージ以降この情報が変化していない場合は未設定であるべき(SHOULD)です。このフィールドは接続設定の管理ワークフローの一部です。
ServerToAgent Message
WebSocketメッセージの本体、またはHTTPレスポンスのボディは、バイナリシリアライズされたProtobufメッセージServerToAgentです。
ServerToAgentメッセージは、AgentToServerメッセージへの応答として、あるいはServerがAgentに配送すべきデータを持っているときに、ServerからAgentへ送信されます。
ServerがAgentToServerメッセージを受信し、Agentに送り返すデータを何も持っていない場合でも、ServerToAgentメッセージは送信されますが、instance_uid以外のフィールドはすべて未設定になります(この場合、ServerToAgentは単純に受信確認として機能します)。
ServerToAgentメッセージを受信すると、Agentはそれを処理しなければなりません(MUST)。必要な処理は、メッセージ内のどのフィールドが設定されているかによって決まります。詳細は、以下のフィールドの説明からこの仕様書の対応する節へのリンクを参照してください。
この処理の結果として、AgentはServerにステータスレポートを送信する必要が生じることがあります。Agentは、ServerToAgentメッセージの処理を完全に終えてから1つのステータスレポートを送信してもよく、あるいはServerToAgentメッセージの各部分を処理する都度、複数のステータスレポートを送信して進行状況を示してもかまいません(例えばパッケージのダウンロードを参照)。処理に長い時間がかかる場合、複数回のステータスレポートによってServerが状況を把握し続けられるようにするのが望ましいことがあります。
Serverは各ステータスレポートに対して、ServerToAgentメッセージ(または何か問題が起きた場合はServerErrorResponse)で応答することに注意してください。これらのServerToAgentメッセージは、以前に受信したものと同じ内容の場合もあれば、Server側の状況が変化していれば異なる内容になる場合もあります。Agentは、これらの追加のServerToAgentメッセージが届いたときにそれを処理する準備をしておくべき(SHOULD)です。
Clientは、Agentのステータスが処理の結果として変化しなかった場合、ステータスレポートを一切送信するべきではありません(SHOULD NOT)。
ServerToAgentメッセージの構造は以下のとおりです。
message ServerToAgent {
bytes instance_uid = 1;
ServerErrorResponse error_response = 2;
AgentRemoteConfig remote_config = 3;
ConnectionSettingsOffers connection_settings = 4; // Status: [Beta]
PackagesAvailable packages_available = 5; // Status: [Beta]
uint64 flags = 6;
uint64 capabilities = 7;
AgentIdentification agent_identification = 8;
ServerToAgentCommand command = 9; // Status: [Beta]
CustomCapabilities custom_capabilities = 10; // Status: [Development]
CustomMessage custom_message = 11; // Status: [Development]
}
ServerToAgent.instance_uid
Agentのインスタンス識別子です。直前にAgentToServerメッセージで受信したinstance_uidフィールドと一致しなければなりません(MUST)。(終端プロキシが使われている場合など)複数のAgentとの通信が1つのWebSocket接続に多重化されている場合、instance_uidフィールドによって、そのServerToAgentメッセージがどのAgentに宛てられているかを区別できます。
注: この値は、AgentIdentificationフィールドで新しい値を送信することでServerによって上書きされることがあります。これが発生した場合、Agentは自身のinstance_uidを提供された値に更新し、以降のすべての通信でその値を使わなければなりません(MUST)。
ServerToAgent.error_response
error_responseは、AgentToServerメッセージの処理中に何か問題が起きたことをServerが示したい場合に設定されます。error_responseが設定されている場合、以下の他のフィールドはすべて未設定でなければならず、逆に以下のフィールドのいずれかが設定されている場合、error_responseは未設定でなければなりません。
ServerToAgent.remote_config
このフィールドは、Serverが該当Agentに対するリモート設定オファーを持っている場合に設定されます。詳細は設定を参照してください。
ServerToAgent.connection_settings
ステータス: Beta
このフィールドは、Serverが(宛先、ヘッダー、証明書などの)クライアント接続設定の1つ以上をAgentに変更してほしい場合に設定されます。詳細は接続設定の管理を参照してください。
ServerToAgent.packages_available
ステータス: Beta
このフィールドは、ServerがAgentに提供するパッケージを持っている場合に設定されます。詳細はパッケージを参照してください。
ServerToAgent.flags
ServerToAgentFlagsのビットマスクで定義されるビットフラグです。
Report*フラグは、Clientが直前のAgentToServerメッセージに該当データの一部を含めなかった(これは許容される圧縮のやり方です)にもかかわらず、Serverがそのデータを持っていない場合(例えばServerが再起動してAgentのステータスを失った場合、この節を参照)に、Serverが使用できます。
enum Flags {
FlagsUnspecified = 0;
// Flags is a bit mask. Values below define individual bits.
// ReportFullState flag can be used by the Server if the Client did not include
// some sub-message in the last AgentToServer message (which is an allowed
// optimization) but the Server detects that it does not have it (e.g. was
// restarted and lost state). The detection happens using
// AgentToServer.sequence_num values.
// The Server asks the Agent to report the full status again by sending
// a new, full AgentToServer message.
ReportFullState = 0x00000001;
// ReportAvailableComponents flag can be used by the server if the Agent did
// not include the full AvailableComponents message, but only the hash.
// If this flag is specified, the agent will populate available_components.components
// with a full description of the agent's components.
// Status: [Development]
ServerToAgentFlags_ReportAvailableComponents = 0x00000002;
}
ServerToAgent.capabilities
ServerCapabilities列挙型で定義されたフラグのビットマスクです。ServerCapabilities列挙型に定義されていないビットはすべて、Serverによって0に設定されなければなりません(MUST)。これにより、将来ServerCapabilities列挙型を拡張してプロトコルを拡張しても、古いServerは自動的に新しいケーパビリティをサポートしていないと報告することになります。このフィールドは、Serverが送信する最初のServerToAgentメッセージで設定されなければならず(MUST)、以降のServerToAgentメッセージではUnspecifiedServerCapability値を設定することで省略してもよい(MAY)ものとします。
enum ServerCapabilities {
// The capabilities field is unspecified.
UnspecifiedServerCapability = 0;
// The Server can accept status reports. This bit MUST be set, since all Server
// MUST be able to accept status reports.
AcceptsStatus = 0x00000001;
// The Server can offer remote configuration to the Agent.
OffersRemoteConfig = 0x00000002;
// The Server can accept EffectiveConfig in AgentToServer.
AcceptsEffectiveConfig = 0x00000004;
// The Server can offer Packages.
OffersPackages = 0x00000008;
// The Server can accept Packages status.
// Status: [Beta]
AcceptsPackagesStatus = 0x00000010;
// The Server can offer connection settings.
// Status: [Beta]
OffersConnectionSettings = 0x00000020;
// The Server can accept ConnectionSettingsRequest and respond with an offer.
// Status: [Development]
AcceptsConnectionSettingsRequest = 0x00000040;
// Add new capabilities here, continuing with the least significant unused bit.
}
ServerToAgent.agent_identification
必要に応じてServerが上書きできる、Agentの識別に関するプロパティです。new_instance_uidが設定されている場合、Agentは自身のinstance_uidを提供された値に更新し、以降のすべての通信でその値を使わなければなりません(MUST)。new_instance_uidは16バイトでなければならず(MUST)、UUID v7仕様を使って生成されるべき(SHOULD)です。
message AgentIdentification {
bytes new_instance_uid = 1;
}
ServerToAgent.command
ステータス: Beta
このフィールドは、ServerがAgentに再起動を行わせたい場合に設定されます。このフィールドは、instance_uidまたはcapabilities以外のフィールドと同時に設定してはなりません。それ以外のフィールドはすべて無視され、Agentはコマンドを実行します。詳細はServerToAgentCommand Messageを参照してください。
ServerToAgent.custom_capabilities
ステータス: [Development]
Serverがサポートするカスタムケーパビリティを示すメッセージです。
詳細はCustomCapabilitiesメッセージを参照してください。
ServerToAgent.custom_message
ステータス: [Development]
ServerからAgentへ送信されるカスタムメッセージです。
詳細はCustomMessageメッセージを参照してください。
ServerErrorResponse Message
このメッセージの構造は以下のとおりです。
message ServerErrorResponse {
enum Type {
UNKNOWN = 0;
BAD_REQUEST = 1;
UNAVAILABLE = 2
}
Type type = 1;
string error_message = 2;
oneof Details {
RetryInfo retry_info = 3;
}
}
ServerErrorResponse.type
このフィールドは、Agentのリクエストを処理しようとした際にServerが遭遇したエラーの種類を定義します。取り得る値は以下です。
UNKNOWN: 不明なエラー。何か問題が発生しましたが、それが正確に何であるかは分かりません。error_messageフィールドに問題の説明が含まれることがあります。
BAD_REQUEST: 直前に受信したAgentToServerメッセージへの応答としてのみ送信され、そのAgentToServerメッセージが不正な形式であったことを示します。不正なリクエストの処理を参照してください。
UNAVAILABLE: Serverが過負荷状態にあり、リクエストを処理できません。スロットリングを参照してください。
ServerErrorResponse.error_message
エラーメッセージです。通常は人間が読める形式です。
ServerErrorResponse.retry_info
type==UNAVAILABLEの場合の、再試行に関する追加のRetryInfoメッセージです。
ServerToAgentCommand Message
ステータス: Beta
このメッセージの構造は以下のとおりです。
// ServerToAgentCommand is sent from the Server to the Agent to request that the Agent
// perform a command.
message ServerToAgentCommand {
enum CommandType {
// The Agent should restart. This request will be ignored if the Agent does not
// support restart.
Restart = 0;
}
CommandType type = 1;
}
ServerToAgentCommandメッセージは、ServerがAgentに再起動してほしいときに送信されます。このメッセージには、command、instance_uid、capabilitiesフィールドのみを含めなければなりません。それ以外のフィールドはすべて無視されます。
動作
ステータスレポート
Clientは以下の場合にステータスレポートを送信しなければなりません(MUST)。
- Serverへの接続直後の初回。このステータスレポートは、Clientが送信する最初のメッセージでなければなりません(MUST)。WebSocket Clientが以前の接続が閉じられた後に再接続する場合、そのステータスレポートは、前回の接続で送信されたメッセージ以降変化していないステータスフィールドを省略してもよい(MAY)ものとします。
- その後は、Agentのステータスが変化するたびに。
ステータスレポートは、AgentToServerメッセージとして送信されます。このメッセージ内の次のフィールドは、対応するステータスの部分を反映するために設定できます。agent_description、capabilities、health、effective_config、remote_config_status、package_statusesです。
Serverは、ServerToAgentメッセージを送信することでAgentToServerメッセージに応答しなければなりません(MUST)。
ステータスレポートの処理が失敗した場合、error_responseフィールドがServerErrorResponseメッセージに設定されなければなりません(MUST)。
ステータスレポートがServerによって正常に処理された場合、error_responseフィールドは未設定でなければならず(MUST)、他のフィールドは必要に応じて設定できます。
以下は、(サーバー側の処理が成功したと仮定した場合の)ステータスレポートの動作を示すシーケンス図です。
Client Server
│ │
│ │
│ WebSocket Connect │
├──────────────────────────────────────►│
│ │
│ AgentToServer │ ┌─────────┐
├──────────────────────────────────────►├──►│ │
│ │ │ Process │
│ ServerToAgent │ │ Status │
│◄──────────────────────────────────────┤◄──┤ │
│ │ └─────────┘
. ... .
│ AgentToServer │ ┌─────────┐
├──────────────────────────────────────►├──►│ │
│ │ │ Process │
│ ServerToAgent │ │ Status │
│◄──────────────────────────────────────┤◄──┤ │
│ │ └─────────┘
│ │
Agentのステータスは、Serverからのメッセージを受信した結果として変化することがある点に注意してください。例えば、ServerがAgentにリモート設定を送信したとします。Agentがそのようなリクエストを処理すると、Agentのステータスが変化します(例えば、Agentの実効設定が変わります)。そのようなステータス変化があれば、Clientはそれに応じてServerにステータスレポートを送信するべきです。
したがって、このような場合のメッセージのシーケンスは、基本的に以下のようになります。
Agent Client Server
│ │ ServerToAgent │
┌───────┤◄──────────────────────────────────────┤
│ │ │
▼ │ │
┌────────┐ │ │
│Process │ │ │
│Received│ │ │
│Data │ │ │
└───┬────┘ │ │
│ │ │
│Status │ │
│Changed│ AgentToServer │ ┌─────────┐
└──────►├──────────────────────────────────────►├──►│ │
│ │ │ Process │
│ ServerToAgent │ │ Status │
│◄──────────────────────────────────────┤◄──┤ │
│ │ └─────────┘
Clientは、ServerToAgentメッセージを受信した際、Serverから受信したメッセージの処理がAgentのステータスの実際の変化(例えばAgentの設定変更)をもたらさない限り、ステータスレポートを送信してはなりません(MUST NOT)。この場合のシーケンス図は以下のようになります。
Agent Client Server
│ │ ServerToAgent │
┌──────┤◄──────────────────────────────────────┤
│ │ │
▼ │ │
┌────────┐ │ │
│Process │ │ │
│Received│ │ │
│Data │ │ │
└───┬────┘ │ │
│ │ │
▼ │ │
No Status │ │
Changes │ │
│ │
│ │
重要: Clientがこれらの規則に従わない場合、ClientとServerの間で無限にメッセージが往復するループが発生する可能性があります。
エージェントステータスの圧縮
Clientは、AgentToServerメッセージを送信することでAgentのステータスをServerに通知します。ステータスには、例えばAgentの記述、実効設定、Serverから受信したリモート設定のステータス、パッケージのステータスなどが含まれます。Serverは、AgentToServerメッセージから参照されるサブメッセージ内のデータを使って、Agentのステータスを追跡します。
Clientは、その特定のデータが前回報告されて以降変化していないサブメッセージを省略することで、AgentToServerメッセージを圧縮してもよい(MAY)ものとします。この圧縮の対象となり得るサブメッセージは、AgentDescription、ComponentHealth、EffectiveConfig、RemoteConfigStatus、PackageStatuses、CustomCapabilities、AvailableComponents、ConnectionSettingsStatusです。
圧縮は、AgentToServerメッセージ内でサブメッセージを省略することによって行われます。サブメッセージ内のいずれかのフィールドが変化した場合、その特定のサブメッセージには圧縮を使用できず、関連するすべてのフィールドを含むサブメッセージが存在しなければなりません(MUST)。
すべてのAgentToServerメッセージがServerに確実に配送され、Serverがそれらを正しく処理する場合、この圧縮は安全であり、Serverは常にAgentの正しい最新ステータスを保持しているはずです。
しかし、ClientとServerが同期を失い、Clientは自分が送信したデータをServerが持っていると思い込んでいるが実際にはServerが持っていないという状況が発生することがあります。これは例えば、Clientは動作を継続しつつServerが再起動され、その間にClientが送信したAgentToServerメッセージをServerが一時的にダウンしていて受信できなかった場合に発生し得ます。
この状況を検出して復旧するために、AgentToServerメッセージにはsequence_numフィールドが含まれます。このフィールドは、Clientが新しく送信するAgentToServerメッセージができるたびに増加する整数です。
Serverが受信したAgentToServerメッセージのsequence_numフィールドの値が、直前に受信したsequence_numの値より正確に1大きくない場合、Serverはそれによって、AgentToServerメッセージの完全なステータスを持っていないことを認識します。
この状況が発生した場合、失われたステータスを復旧するために、Serverは省略されたデータをAgentに報告させるよう要求しなければなりません(MUST)。この要求を行うために、ServerはServerToAgentメッセージのflagsフィールドにReportFullStateビットを設定して、AgentにServerToAgentメッセージを送信しなければなりません(MUST)。
AgentDescription Message
AgentDescriptionメッセージの構造は以下のとおりです。
message AgentDescription {
repeated KeyValue identifying_attributes = 1;
repeated KeyValue non_identifying_attributes = 2;
}
AgentDescription.identifying_attributes
Agentを識別する属性です。
キーと値は、OpenTelemetryのresourceセマンティック規約に従います。
Agentは、これらの属性を自身のテレメトリーのResourceにも含めるべき(SHOULD)です。識別属性の組み合わせは、Agentが自身のテレメトリーを送信する宛先システムにおいて、そのAgent自身のテレメトリーを一意に識別できるだけの十分な情報を持つべき(SHOULD)です。
AgentDescription.non_identifying_attributes
Agentを必ずしも識別するわけではないが、Agentがどこで動いているかを説明する助けとなる属性です。
以下は、非識別属性として適した属性の例です。
- Agentがどこで動作しているかを表すos.*。
- Agentが動作しているホストを表すhost.*。
- ホストが配置されているクラウドを表すcloud.*。
- このAgentとその実行環境を記述するその他の関連するResource属性。
- エンドユーザーがこのAgentに関連付けたいと考える任意のユーザー定義属性。
ComponentHealth Message
ステータス: Beta
ComponentHealthメッセージの構造は以下のとおりです。
message ComponentHealth {
bool healthy = 1;
fixed64 start_time_unix_nano = 2;
string last_error = 3;
string status = 4;
fixed64 status_time_unix_nano = 5;
map<string, ComponentHealth> component_health_map = 6;
}
ComponentHealth.healthy
Agentが起動しており正常であればtrueに設定します。
ComponentHealth.start_time_unix_nano
Agentが起動している間、すなわちAgentが起動した時点からのタイムスタンプです。値は1970年1月1日00:00:00 UTCからのUNIXエポック時間(ナノ秒)です。Agentが動作していない場合は0に設定されなければなりません(MUST)。
ComponentHealth.last_error
Agentがエラー状態にある場合の、人間が読めるエラーメッセージです。healthy==falseの場合に設定されるべき(SHOULD)です。
ComponentHealth.status
文字列として表現されたコンポーネントのステータスです。ステータス値は、プロトコルレベルではなく、Agent固有のセマンティクスによって定義されます。
ComponentHealth.status_time_unix_nano
コンポーネントのステータスが観測された時刻です。値は1970年1月1日00:00:00 UTCからのUNIXエポック時間(ナノ秒)です。
ComponentHealth.component_health_map
より粒度の細かいサブコンポーネントのヘルスを格納するマップです。基盤となるシステムを記述するために必要な深さでネストできます。
EffectiveConfig Message
EffectiveConfigメッセージの構造は以下のとおりです。
message EffectiveConfig {
AgentConfigMap config_map = 1;
}
EffectiveConfig.config_map
Agentの実効設定です。
AgentConfigMapメッセージの定義については、設定節を参照してください。
RemoteConfigStatus Message
RemoteConfigStatusメッセージの構造は以下のとおりです。
message RemoteConfigStatus {
bytes last_remote_config_hash = 1;
enum Status {
// The value of status field is not set.
UNSET = 0;
// Remote config was successfully applied by the Agent.
APPLIED = 1;
// Agent is currently applying the remote config that it received earlier.
APPLYING = 2;
// Agent tried to apply the config received earlier, but it failed.
// See error_message for more details.
FAILED = 3;
}
Status status = 2;
string error_message = 3;
}
RemoteConfigStatus.last_remote_config_hash
このAgentがAgentRemoteConfig.config_hashフィールドで最後に受信したリモート設定のハッシュです。Serverは、このハッシュを自身が保持するそのAgent向けの設定ハッシュと比較するべき(SHOULD)であり、ハッシュが異なる場合はServerはServerToAgentメッセージのレスポンスにremote_configフィールドを含めなければなりません(MUST)。
RemoteConfigStatus.status
以前に受信したリモート設定を適用しようとしたAgentの試みのステータスです。
RemoteConfigStatus.error_message
status==FAILEDの場合の任意のエラーメッセージです。
ConnectionSettingsStatus Message
ConnectionSettingsStatusメッセージの構造は以下のとおりです。
message ConnectionSettingsStatus {
bytes last_connection_settings_hash = 1;
enum Status {
// The value of status field is not set.
UNSET = 0;
// offered connection settings were successfully applied by the Agent.
APPLIED = 1;
// Agent is currently applying the offered connection settings that it received earlier.
APPLYING = 2;
// Agent tried to apply the offered connection settings recieved earlier, but it failed.
// See error_message for more details.
FAILED = 3;
}
Status status = 2;
string error_message = 3;
}
ConnectionSettingsStatus.last_connection_settings_hash
このAgentがconnection_settings.hashフィールドで最後に受信した、提示された接続設定のハッシュです。Serverは、このハッシュを自身が保持するそのAgent向けの設定ハッシュと比較するべき(SHOULD)であり、ハッシュが異なる場合はServerはServerToAgentメッセージのレスポンスにconnection_settingsフィールドを含めなければなりません(MUST)。
ConnectionSettingsStatus.status
以前に受信した接続設定を適用しようとしたAgentの試みのステータスです。
ConnectionSettingsStatus.error_message
status==FAILEDの場合の任意のエラーメッセージです。
PackageStatuses Message
ステータス: Beta
PackageStatusesメッセージは、Agentが持っている、または提示されたすべてのパッケージのステータスを記述します。このメッセージの構造は以下のとおりです。
message PackageStatuses {
map<string, PackageStatus> packages = 1;
bytes server_provided_all_packages_hash = 2;
string error_message = 3;
}
PackageStatuses.packages
PackageStatusメッセージのマップです。キーはパッケージ名です。キーはPackageStatusメッセージのnameフィールドと一致しなければなりません(MUST)。
PackageStatuses.server_provided_all_packages_hash
このAgentが以前にPackagesAvailableメッセージを通じてServerから受信した全パッケージの集約ハッシュです。
Serverは、このハッシュを、このAgentについて自身が保持する全パッケージの集約ハッシュと比較するべき(SHOULD)であり、ハッシュが異なる場合はServerはAgentにPackagesAvailableメッセージを送信するべき(SHOULD)です。
PackageStatuses.error_message
このフィールドは、AgentがPackagesAvailableメッセージを処理する際にエラーに遭遇し、そのエラーが特定の単一のパッケージに関連しない場合に設定されます。
処理エラーがなかった場合、このフィールドは未設定でなければなりません(MUST)。
PackageStatus Message
ステータス: Beta
PackageStatusの構造は以下のとおりです。
message PackageStatus {
string name = 1;
string agent_has_version = 2;
bytes agent_has_hash = 3;
string server_offered_version = 4;
bytes server_offered_hash = 5;
enum Status {
INSTALLED = 0;
INSTALL_PENDING = 1;
INSTALLING = 2;
INSTALL_FAILED = 3;
DOWNLOADING = 4;
}
Status status = 6;
string error_message = 7;
PackageDownloadDetails download_details = 8;
}
PackageStatus.name
パッケージ名です。常に設定されなければならず(MUST)、PackageStatusesメッセージのpackagesフィールド内のキーと一致しなければなりません(MUST)。
PackageStatus.agent_has_version
Agentが持っているパッケージのバージョンです。
Agentがこのパッケージを持っている場合は設定されなければなりません(MUST)。
Agentがこのパッケージを持っていない場合は空でなければなりません(MUST)。これは例えば、パッケージがServerによって提示されたがインストールに失敗し、Agentが以前このパッケージを持っていなかった場合に該当します。
PackageStatus.agent_has_hash
Agentが持っているパッケージのハッシュです。
Agentがこのパッケージを持っている場合は設定されなければなりません(MUST)。
Agentがこのパッケージを持っていない場合は空でなければなりません(MUST)。これは例えば、パッケージがServerによって提示されたがインストールに失敗し、Agentが以前このパッケージを持っていなかった場合に該当します。
PackageStatus.server_offered_version
Serverからagentに提示されたパッケージのバージョンです。
このパッケージのインストールが、以前にServerから受けたインストールのオファーによって開始されたものである場合は設定されなければなりません(MUST)。
Agentがこのパッケージを持っているが、それがローカルにインストールされたものでServerから提示されたものではない場合は空でなければなりません(MUST)。
agent_has_versionとserver_offered_versionの両方のフィールドが設定され、かつ異なる値を持つことがある点に注意してください。これは例えば、Agentがすでにパッケージのあるバージョンを正常にインストール済みで、Serverが別のバージョンを提示したが、Agentがそのバージョンのインストールに失敗した場合に発生し得ます。
PackageStatus.server_offered_hash
Serverからagentに提示されたパッケージのハッシュです。
このパッケージのインストールが、以前にServerから受けたインストールのオファーによって開始されたものである場合は設定されなければなりません(MUST)。
Agentがこのパッケージを持っているが、それがローカルにインストールされたものでServerから提示されたものではない場合は空でなければなりません(MUST)。
agent_has_hashとserver_offered_hashの両方のフィールドが設定され、かつ異なる値を持つことがある点に注意してください。これは例えば、Agentがすでにパッケージのあるバージョンを正常にインストール済みで、Serverが別のバージョンを提示したが、Agentがそのバージョンのインストールに失敗した場合に発生し得ます。
PackageStatus.status
このパッケージのステータスです。取り得る値は以下です。
INSTALLED: パッケージがAgentによって正常にインストールされています。error_messageフィールドは設定してはなりません(MUST NOT)。
INSTALLING: Agentが現在パッケージをダウンロードおよびインストール中です。Agentがインストール中のバージョンを示すため、server_offered_hashフィールドが設定されなければなりません(MUST)。error_messageフィールドは設定してはなりません(MUST NOT)。
INSTALL_FAILED: Agentがパッケージのインストールを試みましたが失敗しました。Agentがインストールを試みたバージョンを示すため、server_offered_hashフィールドが設定されなければなりません(MUST)。error_messageには、失敗に関する詳細が含まれることもあります。
PackageStatus.error_message
ステータスがエラーの場合のエラーメッセージです。
PackageStatus.download_details
ステータス: [Development]
download_detailsには、パッケージのダウンロードを記述する追加の詳細情報が含まれます。statusがDOWNLOADINGの場合にのみ設定されるべきです。
message PackageDownloadDetails {
double download_percent = 1;
double download_bytes_per_second = 2;
}
接続設定の管理
ステータス: Beta
OpAMPには、Agentが接続するすべての宛先の接続設定、およびOpAMP Client自身の接続設定をServerが管理できるようにする機能が含まれています。
以下の図は、OpAMP Serverによって管理され、自身のテレメトリーをOTLPバックエンドに送信し、さらに自身の作業のために他の宛先にも接続する典型的なAgentを示しています。
┌────────────┬────────┐ ┌─────────┐
│ │ OpAMP │ OpAMP │ OpAMP │
│ │ ├──────────►│ │
│ │ Client │ │ Server │
│ └────────┤ └─────────┘
│ │
│ ┌────────┤ ┌─────────┐
│ │OTLP │ OTLP/HTTP │OTLP │
│ Agent │ ├──────────►│Telemetry│
│ │Client │ │Backend │
│ └────────┤ └─────────┘
│ │
│ ┌────────┤
│ │Other ├──────────► Other
│ │ ├──────────►
│ │Clients ├──────────► Destinations
└────────────┴────────┘
OpAMP Serverや他の宛先に接続する際、Agent(またはAgentの代わりに接続するOpAMP Client)は、通常、ヘッダーベースの認可メカニズム(例えば「Authorization」HTTPヘッダーやカスタムヘッダー内のアクセストークン)を使い、オプションでTLS接続のためのクライアント側証明書(相互TLSとも呼ばれます)も使うことが期待されます。
OpAMPプロトコルでは、Serverはこれらの各接続についての設定を提示でき、Agentはそのオファーを受け入れるか拒否できます。このメカニズムは、Agentを特定の宛先に誘導すること、およびアクセストークンやTLS証明書の登録・失効・ローテーションのために使えます。
Serverは、以下の3つのクラスの宛先について接続設定を提示できます。
- OpAMP Server自身。これは通常、TLS証明書や認可に使うリクエストヘッダーといったクレデンシャルを管理するために使われます。Serverは、OpAMP Clientに別のOpAMP Serverへ接続するよう指示するために、異なる宛先エンドポイントを提示してもよい(MAY)ものとします。
- Agentが自身のテレメトリー(メトリクス、トレース、ログ)をOTLP/HTTPプロトコルで送信するための宛先。
- 文字列名がそれぞれに関連付けられた、その他の追加接続設定の集合。Agentの種類がこれらをどう使うかはAgent固有です。通常、名前はAgentが認識している接続先の名前を表します。例えばOpenTelemetry Collectorは、それぞれ対応する名前を持つエクスポーターに対して、名前付き接続設定を1つずつ使えます。
Serverは、特定の接続クラスに対応するケーパビリティが、AgentToServer.capabilitiesフィールドを通じてAgentから報告されている場合に限り、その接続クラスに対するオファーを提示できます。
- ReportsOwnTracesケーパビリティビットが設定されている場合、Serverはown_tracesフィールドを使ってトレース用の接続設定を提示してもよい(MAY)ものとします。
- ReportsOwnMetricsケーパビリティビットが設定されている場合、Serverはown_metricsフィールドを使ってメトリクス用の接続設定を提示してもよい(MAY)ものとします。
- ReportsOwnLogsケーパビリティビットが設定されている場合、Serverはown_logsフィールドを使ってログ用の接続設定を提示してもよい(MAY)ものとします。
- AcceptsOpAMPConnectionSettingsケーパビリティビットが設定されている場合、Serverはopampフィールドを使ってOpAMP接続用の接続設定を提示してもよい(MAY)ものとします。
- AcceptsOtherConnectionSettingsケーパビリティビットが設定されている場合、Serverはother_connectionsフィールドを使ってその他の宛先向けの接続設定を提示してもよい(MAY)ものとします。
さらに、ReportsConnectionSettingsStatusケーパビリティは、提示された接続設定が期待どおりに適用されたかをAgentがServerに報告できることを示すために使われます。
どの接続設定が提示されるかによって、操作のシーケンスはわずかに異なります。自身のテレメトリー用の接続設定の扱いは自身のテレメトリーのレポートで説明されています。「その他」の宛先向けの接続設定の扱いはその他の宛先向け接続設定で説明されています。OpAMP接続設定の扱いは以下で説明します。
また、Agentから接続設定の作成を開始するようServerにリクエストすることも可能です。このプロセスはエージェント起動のCSRフロー節で説明されています。
OpAMP接続設定オファーのフロー
Server起動によるOpAMP接続設定の変更は、以下のように行われます。
Client Server
│ │ Initiate
│ Connect │ Settings
├──────────────────────────────────────►│ Change
│ ... │ │
│ │◄───────┘
│ │ ┌───────────┐
│ ├─────────►│ │
│ │ Generate │Credentials│
┌───────────┐ │ServerToAgent{ConnectionSettingsOffers}│ and Save │ Store │
│ │◄───────┤◄──────────────────────────────────────┤◄─────────┤ │
│Credentials│ Save │ │ └───────────┘
│ Store │ │ Disconnect │
│ ├───────►├──────────────────────────────────────►│
└───────────┘ │ │
│ Connect, New settings │ ┌───────────┐
├──────────────────────────────────────►├─────────►│ │
│ │ Delete │Credentials│
┌───────────┐ │ Connection established │ old │ Store │
│ │◄───────┤◄─────────────────────────────────────►│◄─────────┤ │
│Credentials│Delete │ │ └───────────┘
│ Store │old │ │
│ ├───────►│ │
└───────────┘ │ │
- Serverは新しい接続設定を生成し、Agentインスタンスの UIDと関連付けてServerのクレデンシャルストアに保存します。
- Serverは、ConnectionSettingsOffersメッセージを含むServerToAgentメッセージを送信します。opampフィールドには、提示される新しいOpAMPConnectionSettingsが含まれます。
- Clientは設定オファーを受信し、更新された接続設定をローカルストアに保存し、「候補」としてマークします(Clientがクラッシュした場合、手順5〜9の候補検証を再試行します)。
- Clientは Serverから切断します。ClientがReportsConnectionSettingsStatusケーパビリティを持っている場合、Clientは新しい接続設定を適用中であることを示すべき(SHOULD)です。
- Clientは新しい設定を使ってServerに接続します。
- 接続が正常に確立され、必要なTLS検証がすべて通過し、Serverが認可の成功を示します。
- Serverは、(Agentインスタンス UIDを使って)このAgentの古い接続設定をクレデンシャルストアから削除します。
- Clientは古い設定をクレデンシャルストアから削除し、新しい接続設定を「有効」としてマークします。ClientがReportsConnectionSettingsStatusケーパビリティを持っている場合、接続設定が適用されたことを報告しなければなりません(MUST)。
- 手順6が失敗した場合、Clientは新しい設定を削除し、古い設定に戻して再接続します。ClientがReportsConnectionSettingsStatusケーパビリティを持っている場合、接続設定が失敗したことを報告しなければなりません(MUST)。
注: 新しい接続設定を永続化できず、一時的なストレージしか使えないClientは、証明書オファーを拒否するべき(SHOULD)です。そうしないと、再起動後にアクセスを失い、提示された証明書も失う可能性があります。
Trust On First Use
TLSをクライアント証明書とともに使いたいが、最初は証明書を持っていないOpAMP Clientは、Trust On First Use(TOFU)フローを使えます。このシーケンスは以下のとおりです。
- Clientは、クライアント証明書なしで(Serverの識別情報を検証する)通常のTLSを使ってServerに接続します。Clientは、自身を識別できるようにAgentのステータスレポートを送信します。
- Serverは接続とステータスを受け入れ、OpAMP Client用のクライアント証明書を生成する承認を待ちます。
- Serverは人間による手動の承認を待つか、あるいはServerがそのように設定されている場合はTOFUリクエストをすべて自動的に承認します(Server側のオプションにできます)。
- 承認されると、以降のフローはOpAMP接続設定オファーのフローの手順と基本的に同一ですが、削除すべき古いクライアント証明書が存在しない点が異なります。
TOFUフローによって、証明書のクライアント側インストールを行う必要なく、セキュアな環境をブートストラップできます。
まったく同じTOFUの手法は、Serverにアクセスするための認可ヘッダーを持たないOpAMP Clientにも使えます。Serverはそのようなアクセスを検出し、承認後にClientへ認可ヘッダーを送信できます。
Registration On First Use
一部のユースケースでは、新しくインストールされたAgentに初回使用に適した初期の接続設定を装備させ、最初の接続が確立された後に新しい接続クレデンシャルの組を生成することが望ましい場合があります。
これは、TOFUフローの仕組みと非常に似た方法で実現できます。唯一の違いは、最初の接続は適切に認証されますが、Serverは接続直後に新しい接続設定を生成してAgentに提示することです。Clientはその設定を永続化し、以降のすべての操作でそれを使います。
これにより、事前に定義した1組の接続クレデンシャル(認可ヘッダー、証明書など)を使って多数のAgentをデプロイしつつ、接続に成功した直後に各Agentが独自の一意な接続クレデンシャルを取得できます。これにより、他のすべてのAgentへのアクセスを妨げることなく、個々のAgentのクレデンシャルを失効させられます。
エージェント起動のCSRフロー
ステータス: [Development]
これは、Certificate Signing Request(CSR)をServerに送信し、以降のOpAMP接続で使うクライアント証明書(自己署名または CA署名)を取得できる、Agent起動のフローです。
このフローは現在、OpAMP接続に対してのみサポートされています。Agentが自身のテレメトリー用の接続や他の接続種別に対してCSRリクエストを送ることはできません。
Client Server
│ (1) Connect │
├──────────────────────────────────────►│
│ ... │
┌───────────┐ │ │ ┌───────────┐
│ Generate │ (2) │ (3) AgentToServer{CSR} │(4) │ │
│ Keypair ├───────►├──────────────────────────────────────►├─────────►│ Approve │
│ and CSR │ │ ... │ │ │
└───────────┘ │ │ └─────┬─────┘
│ │ │(5)
│ │ │
│ │ ▼
│ │ ┌───────────┐
┌───────────┐ │ServerToAgent{ConnectionSettingsOffers}│ (7) │Create │
│ │◄───────┤◄──────────────────────────────────────┤◄─────────┤Certificate│
│Credentials│ Save │ │ │ (6) │
│ Store │ │ Disconnect │ └───────────┘
│ ├───────►├──────────────────────────────────────►│
└───────────┘ │ │
│ Connect, New settings │ ┌───────────┐
├──────────────────────────────────────►├─────────►│ │
│ │ Delete │Credentials│
┌───────────┐ │ Connection established │ old │ Store │
│ │◄───────┤◄─────────────────────────────────────►│◄─────────┤ │
│Credentials│Delete │ │ └───────────┘
│ Store │old (8) │ │
│ ├───────►│ │
└───────────┘ │ │
このシーケンスは以下のとおりです。
- (1) Clientは Serverに接続します。Clientは通常のTLSを使い、Serverの識別情報を検証するべき(SHOULD)です。Agentは、Serverによってすでに信頼されているブートストラップ用のクライアント証明書を使うこともできます(注: このブートストラップ証明書の配布とインストール方法は、この仕様書の対象外です)。
- (2) Agentは鍵ペアとCertificate Signing Request(CSR)を生成します。CSRには、Clientが以降の認証に使いたい情報が含まれます。
- (3) ClientはCSRを含むAgentToServerメッセージを送信します。
- (4) ブートストラップ証明書が提供されている場合、Serverはそれを(信頼されたCAなどで)検証し、Agent用のクライアント証明書を生成する承認を待ちます。
- (5) Serverは人間による手動の承認を待つか、あるいはServerがそのように設定されている場合はTOFUリクエストをすべて自動的に承認します(Server側のオプションにできます)。
- (6) 承認されると、Serverはクライアント証明書を作成します。Serverはこれを、自己署名証明書を発行(ローカルCAとして動作)するか、CSRをCAにプロキシしてCAからクライアント証明書を取得するかのいずれかで行います。
- (7) CAからクライアント証明書を取得した後のフローは、OpAMP接続設定オファーのフローの手順と基本的に同一で、作成されたクライアント証明書を運ぶ接続設定の提示から始まります。OpAMPConnectionSettings.certificateメッセージには、certフィールドにクライアント証明書が設定されます。CAが使われる場合はca_certフィールドにCAの証明書が設定されます。private_keyフィールドは設定されません。このフローでは、Agentが秘密鍵を保持しており、Serverはそれを保持していないためです。
- (8) 提示された新しいクライアント証明書の検証に成功すると、Agentは(使われていた場合)ブートストラップ証明書を削除し、以降の接続には新しい証明書を使います。
ServerはAgentにOpAMPConnectionSettingsを送信する際、certificate以外のフィールドも含めてもよい(MAY)ものとし、これによりServerはAgentの証明書、接続ヘッダー、その他の設定を一度に置き換えられます。
手順4〜6のいずれかが失敗した場合、ServerはtypeフィールドをServerErrorResponseType_BadRequestに設定したServerErrorResponseでAgentに応答しなければなりません(MUST)。
まったく同じフローは、Agentがいつでも新しい証明書を再リクエストするために使えます。例えば、現在の証明書の有効期限が近づいたときにAgentがこれを行うことがあります。
CSRにおけるinstance_uidの利用
ステータス: [Development]
実装は、AgentのinstanceUidをCSRフィールドの1つ(またはその一部)として使うことを選んでもよく、そのような実装では、接続してきたAgentのペイロード内のinstance_uidが証明書の内容と一致することをServerが検証してもよい(MAY)ものとします。これにより、Agentが他のAgentになりすますことを防げます。
CSRフィールドにinstance_uidを含むCSRを受信した場合、ServerはAgentToServerメッセージ内のinstance_uidフィールドが、CSRフィールド内のinstance_uidと一致することを検証しなければなりません(MUST)。これにより、Agentが自分自身の証明書しかリクエストできないことが強制されます。
instance_uidがCSRおよび発行されたクライアント証明書の一部である場合、instance_uidの変更があればクライアント証明書の再生成が必要になります。そのような変更は、例えばServerがnew_instance_uidフィールドを通じてAgentに新しいinstance_uidを使うよう指示した場合に発生し得ます。
Serverからinstance_uidの変更を指示されたAgentは、今回は新しいinstance_uidをCSRフィールドの1つとして使って、エージェント起動のCSRフローを再度実行しなければなりません。Serverは、Agentが古いinstance_uidを含む古い証明書をまだ使用している間にCSRを受信する準備をしておかなければなりません。
言い換えると、受信したCSRが、その同じ着信接続で使われているクライアント証明書内で参照されているinstance_uidとは異なるinstance_uidに対する新しい証明書をリクエストすることがあります。これは有効な状況であり、Serverによって拒否されてはなりません(MUST NOT)。この状況では、Serverは、接続してきたクライアント証明書内のinstance_uidを見て、それを既知の古いinstance_uidと比較し、Agentが実際にServerの指示どおりinstance_uidの変更を行っていることを確認してもよい(MAY)ものとします。
アクセスの取り消し
ServerはClientが使うアクセスヘッダーとクライアント証明書を知っているため、対応する接続設定を「失効」としてマークしてClientを切断することで、個々のAgentへのアクセスを取り消せます。失効したクレデンシャルを使った以降の接続は、Serverによって拒否され、実質的にそのClientによるServerへのアクセスが禁止されます。
Serverは、Agentの3種類の宛先すべての接続設定を管理できるため(接続設定を提示できるため)、この取り消しは、Serverが以前提示し、Agentが受け入れた宛先種別であれば、3種類のいずれについても実行できます。
自身のテレメトリーと「その他」の宛先については、Serverは、失効したクレデンシャルを使う接続を拒否できるように、失効した事実を対応する宛先にも伝達しなければなりません(MUST)。
証明書の生成
Serverが生成するクライアント証明書は、自己署名、プライベートなCertificate Authorityによる署名、あるいはパブリックなCertificate Authorityによる署名のいずれでもかまいません。Serverは、証明書が意図した宛先によって信頼されるようにクライアント証明書を生成する責任を負います。これには、宛先が個々の自己署名クライアント証明書を直接記憶して信頼するか、あるいは信頼チェーンを検証できるように、クライアント証明書の署名に使われたCertificate Authorityを信頼している必要があります。
クライアント証明書がどのように生成されるかは、OpAMP仕様書の対象外です。
その他の宛先向け接続設定
未定。
ConnectionSettingsRequest Message
ステータス: [Development]
ConnectionSettingsRequestは、Agentの接続設定のオファーを作成して応答するようServerに求める、Agentからのリクエストです。
message ConnectionSettingsRequest {
OpAMPConnectionSettingsRequest opamp = 1;
}
opampフィールドは、OpAMP接続設定のリクエストを示すために設定されます。このフィールドが未設定の場合、ConnectionSettingsRequestメッセージは空であり、Serverにとって対応不要です。
OpAMPConnectionSettingsRequest Message
ステータス: [Development]
OpAMPConnectionSettingsRequestは、レスポンス内にOpAMPConnectionSettingsを生成するようServerに求めるリクエストです。
エージェント起動のCSRフローで使われます。
message OpAMPConnectionSettingsRequest {
CertificateRequest certificate_request = 1;
}
certificate_requestは、Agentがクライアント証明書の作成をServerにリクエストする場合に設定されます。このフィールドは必須です。
CertificateRequest Message
ステータス: [Development]
message CertificateRequest {
bytes csr = 1;
}
csrフィールドは、クライアントの秘密鍵で署名された、PEMエンコードされたClient Certificate Signing Request(CSR)です。
Serverはリクエストを検証するべき(SHOULD)であり、certificate.certに発行された証明書を含むOpAMPConnectionSettingsで応答するべき(SHOULD)です。
ConnectionSettingsOffers Message
ConnectionSettingsOffersメッセージは、Agentが使うべき接続設定を記述します。
message ConnectionSettingsOffers {
bytes hash = 1;
OpAMPConnectionSettings opamp = 2;
TelemetryConnectionSettings own_metrics = 3;
TelemetryConnectionSettings own_traces = 4;
TelemetryConnectionSettings own_logs = 5;
map<string,OtherConnectionSettings> other_connections = 6;
}
ConnectionSettingsOffers.hash
このメッセージから変化がないために省略されている設定も含めた、すべての設定のハッシュです。
ConnectionSettingsOffers.opamp
OpAMP Serverに接続するための設定です。このフィールドが設定されていない場合、Clientは設定が変化していないと見なし、既存の設定を使い続けるべきです。Clientは、無効な設定によってOpAMP Serverへのアクセスを失わないよう、実際に接続してみることで提示された接続設定を検証しなければなりません(MUST)。
ConnectionSettingsOffers.own_metrics
Agent自身のメトリクスを送信するOTLPメトリクスバックエンドに接続するための設定です。このフィールドが設定されていない場合、Agentは設定が変化していないと見なすべきです。
ConnectionSettingsOffers.own_traces
Agent自身のトレースを送信するOTLPトレースバックエンドに接続するための設定です。このフィールドが設定されていない場合、Agentは設定が変化していないと見なすべきです。
ConnectionSettingsOffers.own_logs
Agent自身のログを送信するOTLPログバックエンドに接続するための設定です。このフィールドが設定されていない場合、Agentは設定が変化していないと見なすべきです。
ConnectionSettingsOffers.other_connections
文字列名がそれぞれに関連付けられた、もう1つの接続設定の集合です。Agentがこれらをどう使うかはAgent固有です。通常、名前はAgentが認識している接続先の名前を表します。このフィールドが設定されていない場合、Agentはother_connections設定が変化していないと見なすべきです。
OpAMPConnectionSettings
OpAMPConnectionSettingsメッセージは、OpAMP接続に指定された設定を使うようServerからOpAMP Clientへのオファーを構成するフィールドの集合です。
message OpAMPConnectionSettings {
string destination_endpoint = 1;
Headers headers = 2;
TLSCertificate certificate = 3;
uint64 heartbeat_interval_seconds = 4;
TLSConnectionSettings tls = 5;
ProxyConnectionSettings proxy = 6;
}
OpAMPConnectionSettings.destination_endpoint
OpAMP ServerのURLです。これはWebSocketまたはHTTPのURLでなければならず(MUST)、空であってはなりません(MUST)。例: wss://example.com:4320/v1/opamp。
OpAMPConnectionSettings.headers
接続時に使う任意のヘッダーです。通常、アクセストークンや他の認可ヘッダーを設定するために使われます。HTTPベースのプロトコルでは、Clientはこれらをリクエストヘッダーに設定するべきです。例: key=“Authorization”, Value=“Basic YWxhZGRpbjpvcGVuc2VzYW1l”。
OpAMPConnectionSettings.certificate
Clientは、以降その宛先に接続するために提示された証明書を使うべきです。Clientが提示された証明書を検証して接続できた場合、この接続についての以前のクライアント証明書はすべて忘れるべき(SHOULD)です。このフィールドは任意です。省略された場合、Clientはクライアント側証明書を使うべきではありません(SHOULD NOT)。このフィールドは、クライアント証明書の失効やローテーションを行うために使えます。
OpAMPConnectionSettings.heartbeat_interval_seconds
ステータス: [Development]
ReportsHeartbeatケーパビリティがtrueの場合、Clientは提示されたハートビート間隔を使ってAgentToServerメッセージを定期的に送信しなければなりません(MUST)。このケーパビリティがtrueで、Serverがheartbeat_interval_secondsを0に設定した場合、Agentのハートビートは無効化されるべきです。少なくともAgentToServer.instance_uidフィールドはハートビートに設定されなければなりません(MUST)。HTTPベースのクライアントは、ハートビート間隔をポーリング間隔として使わなければなりません(MUST)。
instance_uidフィールドが設定されているAgentToServerメッセージは、有効なハートビートとみなされます。他のデータを含む別のAgentToServerメッセージがちょうど送信された場合、ハートビートのためだけに別途AgentToServerメッセージを送信する必要はないことに注意してください。Agentは、直前に送信したAgentToServerメッセージからハートビート間隔を数えなければなりません。
ハートビートは、接続をアクティブに保ち、Agentがまだ生存かつアクティブであることをServerに知らせるために使われます。Serverはハートビートを使って、接続中のAgentの生存に関する判断を行うことができます。
ハートビートの調整のフローは以下のように説明されます。
┌──────────┐ ┌──────────┐
│ │ (1) Connect │ │
│ ├──────────────────────►│ │
│ │ │ │
│ │ (2) Set Heartbeat │ │
│ │◄──────────────────────┤ │
│ │ Interval │ │
│ │ │ │
│ Agent │ (3) Send Heartbeat │ Server │
│ ├──────────────────────►│ │
│ │ │ │
│ │ ... heartbeat │ │
│ │ interval │ │
│ │ │ │
│ │ (4) Send Heartbeat │ │
│ ├──────────────────────►│ │
│ │ │ │
└──────────┘ └──────────┘
- Agentはserverに接続し、オプションでReportsHeartbeatケーパビリティを設定します。Agentがこのケーパビリティを設定しない場合、Serverはハートビートを受信することを期待しないべきです。
- AgentがReportsHeartbeatケーパビリティを設定した場合、ServerはOpAMPConnectionSettingsメッセージ内のheartbeat_interval_secondsフィールドに間隔を設定して応答してもよい(MAY)ものとします。この値は、希望する間隔か、
0(Clientがハートビートを送信すべきでないことを示す)のいずれかです。推奨されるデフォルトの間隔は30秒です。 - AgentがReportsHeartbeatケーパビリティを設定しており、かつServerがハートビートを無効化していない場合、Agentは、Serverが設定した間隔、またはAgent自身の設定されたハートビート間隔で指定される周期ごとにハートビートメッセージを送信しなければなりません(MUST)。
- Agentは、生存している間、設定された間隔でハートビートを送信し続けます。
Agentは、ReportsHeartbeatケーパビリティを設定しないことで、ハートビートを送信しないことを選べます。Serverは、OpAMPConnectionSettings.heartbeat_interval_secondsフィールドに0秒の値を設定して応答することで、ハートビートを受信しないことを選べます。
OpAMPConnectionSettings.tls
ステータス: [Development]
任意のOpAMP固有のTLS設定です。
OpAMPConnectionSettings.proxy
ステータス: [Development]
任意のOpAMP固有のプロキシ設定です。
TelemetryConnectionSettings
TelemetryConnectionSettingsメッセージは、自身のテレメトリーを報告するためのネットワーク接続に指定された設定を使うようServerからAgentへのオファーを構成するフィールドの集合です。
message TelemetryConnectionSettings {
string destination_endpoint = 1;
Headers headers = 2;
TLSCertificate certificate = 3;
TLSConnectionSettings tls = 4;
ProxyConnectionSettings proxy = 5;
}
TelemetryConnectionSettings.destination_endpoint
この値は、パスを含むOTLP/HTTP/ProtobufレシーバーへのフルURLでなければなりません(MUST)。スキーマはhttps://で始まるべき(SHOULD)です。例: https://example.com:4318/v1/metrics。URLがhttp://で始まる場合、Agentはテレメトリーの送信を拒否してもよい(MAY)ものとします。
TelemetryConnectionSettings.headers
接続時に使う任意のヘッダーです。通常、アクセストークンや他の認可ヘッダーを設定するために使われます。HTTPベースのプロトコルでは、Agentはこれらをリクエストヘッダーに設定するべきです。例: key=“Authorization”, Value=“Basic YWxhZGRpbjpvcGVuc2VzYW1l”。
TelemetryConnectionSettings.certificate
Agentは、以降その宛先に接続するために提示された証明書を使うべきです。Agentが提示された証明書を検証して接続できた場合、この接続についての以前のクライアント証明書はすべて忘れるべき(SHOULD)です。このフィールドは任意です。省略された場合、クライアントはクライアント側証明書を使うべきではありません(SHOULD NOT)。このフィールドは、クライアント証明書の失効やローテーションを行うために使えます。
TelemetryConnectionSettings.tls
ステータス: [Development]
任意のテレメトリー固有のTLS設定です。
TelemetryConnectionSettings.proxy
ステータス: [Development]
任意のテレメトリー固有のプロキシ設定です。
OtherConnectionSettings
OtherConnectionSettingsメッセージは、ネットワーク接続に指定された設定を使うようServerからAgentへのオファーを構成するフィールドの集合です。このメッセージのすべてのフィールドが指定されている必要はありません。Serverは一部のフィールドのみを指定でき、その場合はServerがそれらのフィールドのみを変更するようAgentに提示し、残りのフィールドは変更しないままにすることを意味します。
例えば、Serverはcertificateフィールドのみが設定され、他のすべてのフィールドが未設定のConnectionSettingsメッセージを送信することがあります。これは、Serverが Agentに新しい証明書を使ってほしいが、現在のヘッダーやその他の設定を使って現在送信中の宛先への送信を継続してほしいことを意味します。
他のメッセージを参照するフィールドについては、その参照が未設定の場合にそのフィールドは未設定とみなされます。
プリミティブなフィールド(string)については、フィールドが未設定であることを示すために「flags」に頼ります(これは、古いprotocコンパイラがフィールドの存在を確認できるメソッドを生成しないという制約を克服するためです)。
message OtherConnectionSettings {
string destination_endpoint = 1;
Headers headers = 2;
TLSCertificate certificate = 3;
map<string, string> other_settings = 4;
TLSConnectionSettings tls = 5;
ProxyConnectionSettings proxy = 6;
}
OtherConnectionSettings.destination_endpoint
URL、host:port、またはその他の宛先指定子です。
OtherConnectionSettings.headers
接続時に使う任意のヘッダーです。通常、アクセストークンや他の認可ヘッダーを設定するために使われます。HTTPベースのプロトコルでは、Agentはこれらをリクエストヘッダーに設定するべきです。例: key=“Authorization”, Value=“Basic YWxhZGRpbjpvcGVuc2VzYW1l”。
OtherConnectionSettings.certificate
Agentは、以降その宛先に接続するために提示された証明書を使うべきです。Agentが提示された証明書を検証して接続できた場合、この接続についての以前のクライアント証明書はすべて忘れるべき(SHOULD)です。このフィールドは任意です。省略された場合、クライアントはクライアント側証明書を使うべきではありません(SHOULD NOT)。このフィールドは、クライアント証明書の失効やローテーションを行うために使えます。
OtherConnectionSettings.other_settings
その他の接続設定です。これらはAgent固有であり、Agentが解釈します。
OtherConnectionSettings.tls
ステータス: [Development]
任意の接続固有のTLS設定です。
OtherConnectionSettings.proxy
ステータス: [Development]
任意の接続固有のプロキシ設定です。
TLSConnectionSettings Message
ステータス: [Development]
このメッセージは、クライアントの接続を構成するために使われる任意のTLS設定を運びます。Agentが接続設定を検証できた場合、Agentは以前のTLS設定をすべて忘れるべき(SHOULD)です。このメッセージが含まれていない場合、クライアントは設定が変化していないと見なして既存の設定を使い続けるべき(SHOULD)です。
message TLSConnectionSettings {
string ca_pem_contents = 1;
bool include_system_ca_certs_pool = 2;
bool insecure_skip_verify = 3;
string min_version = 4;
string max_version = 5;
repeated string cipher_suites = 6;
}
TLSConnectionSettings.ca_pem_contents
ca_pem_contents属性は、TLS設定の一部としてCAの公開証明書を提供するために使うことができます。
TLSConnectionSettings.include_system_ca_pool
include_system_ca_poolは、TLS設定を構築する際にシステムのデフォルトCAプールを使うようAgentに求めます。
TLSConnectionSettings.insecure_skip_verify
この設定は、接続のすべてのTLS検証を無効にします。
TLSConnectionSettings.min_version
これは、クライアントが使う最小サポートTLSバージョンを設定します。例: 1.2、TLSv1.2。
TLSConnectionSettings.max_version
これは、クライアントが使う最大サポートTLSバージョンを設定します。例: 1.2、TLSv1.2。
TLSConnectionSettings.ciper_suites
これは、接続で使用できるサポート対象の暗号スイートを設定します。例: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA。
ProxyConnectionSettings Message
ステータス: [Development]
このメッセージは、クライアントの接続を構成するために使われる任意のプロキシ設定を運びます。Agentが接続設定を検証できた場合、Agentは以前のプロキシ設定をすべて忘れるべき(SHOULD)です。このメッセージが含まれていない場合、クライアントは設定が変化していないと見なして既存の設定を使い続けるべき(SHOULD)です。
プロキシがmTLS証明書やその他のTLS設定を必要とする場合、Clientは関連する接続の設定を使うべき(SHOULD)です。
message ProxyConnectionSettings {
string url = 1;
Headers connect_headers = 2;
}
ProxyConnectionSettings.url
urlは空であってはならず(MUST)、例えばhttps://example.com:8443や127.0.0.1:8443のようになります。
ProxyConnectionSettings.connect_headers
HTTPベースのプロキシの最初のCONNECTリクエストに対してClientが設定すべき任意のヘッダーです。SOCKS5などの他のプロキシ種別は、これらのヘッダーを無視することがあります。例: key=“Authorization”, Value=“Basic YWxhZGRpbjpvcGVuc2VzYW1l”。
Headers Message
message Headers {
repeated Header headers = 1;
}
message Header {
string key = 1;
string value = 2;
}
TLSCertificate Message
このメッセージは、クライアント側証明書として使えるTLS証明書を運びます。
(cert、private_key)の組は、宛先Serverが認識するCertificate Authority(CA)によって発行・署名されるべきです。
あるいは、Serverが証明書を検証できる限り、証明書は自己署名でもかまいません。この場合、ca_certフィールドは省略できます。
message TLSCertificate {
bytes cert = 1;
bytes private_key = 2;
bytes ca_cert = 3;
}
TLSCertificate.cert
PEMエンコードされた証明書です。必須です。
TLSCertificate.private_key
証明書のPEMエンコードされた秘密鍵です。必須です。
TLSCertificate.ca_cert
署名を行ったCAのPEMエンコードされた証明書です。任意ですが、証明書がCA署名の場合は指定されなければなりません(MUST)。将来、接続してきたクライアントの証明書を検証できるように、中間のTLS終端プロキシによって保存されることがあります。
自身のテレメトリーのレポート
ステータス: Beta
自身のテレメトリーのレポートは、OpAMPプロトコルの任意のケーパビリティです。Serverは、Agentが自身のテレメトリー(メトリクス、トレース、ログ)を送信できる宛先をAgentに提示できます。Agentがテレメトリーを生成でき、かつそうしたい場合、Agentは自身のテレメトリーをOTLP/HTTPプロトコルで提示された宛先に送信すべきです。
┌────────────┬────────┐ ┌─────────┐
│ │ OpAMP │ OpAMP │ OpAMP │
│ │ ├──────────►│ │
│ │ Client │ │ Server │
│ └────────┤ └─────────┘
│ Agent │
│ ┌────────┤ ┌─────────┐
│ │OTLP │ OTLP/HTTP │ OTLP │
│ │ ├──────────►│ Metric │
│ │Exporter│ │ Backend │
└────────────┴────────┘ └─────────┘
Serverは、own_metrics、own_traces、own_logsのいずれか1つ以上のフィールドが設定されたconnection_settingsフィールドを持つServerToAgentメッセージを送信することでオファーを行います。これらのフィールドはそれぞれ、OTLPプロトコルでテレメトリーを受信できる宛先を記述します。
Serverは、使用できるOTLPバックエンドが存在しない場合を除き、特定のAgentに最初のServerToAgentメッセージを送信する際(通常はClientからの最初のステータスレポートへの応答として)にconnection_settingsフィールドを設定すべき(SHOULD)です。Serverは、宛先が変化した場合、以降のServerToAgentでもこのフィールドを設定するべき(SHOULD)です。宛先が変化していない場合、connection_settingsフィールドは設定されるべきではありません(SHOULD NOT)。connection_settingsフィールドが未設定のServerToAgentを受信した場合、Agentは以前に提示された宛先へのテレメトリー送信を続けるべき(SHOULD)です。AgentがReportsConnectionSettingsStatusケーパビリティを持つ場合、新しい設定を受信した際にconnection_settings_statusを適宜設定するべき(SHOULD)です。
Agentは、own_metricsフィールドで提示された宛先に定期的にメトリクスを報告するべき(SHOULD)です。推奨されるレポート間隔は10秒です。以下は、操作のシーケンスを示す図です。
Agent Client Server
Metric
│ │ │ Backend
│ │ServerToAgent{ConnectionSettingsOffer}│
┌─────────│◄─────────────────────────────────────┤ │
│ │ │
▼ │
┌────────┐ │
│Collect │ OTLP Metrics │ ──┐
│Own ├───────────────────────────────────────────────►│ │
│Metrics │ │ │
└────────┘ ... . │ Repeats
│ │
┌────────┐ │ │ Periodically
│Collect │ OTLP Metrics │ │
│Own ├───────────────────────────────────────────────►│ │
│Metrics │ │ ──┘
└────────┘ │
Agentは、Agentプロセス(または複数プロセス)のメトリクスと、Agentの状態を記述する任意のカスタムメトリクスを報告すべき(SHOULD)です。報告されるプロセスメトリクスは、OpenTelemetryのプロセスに関する規約に従わなければなりません(MUST)。
同様に、Agentは、own_tracesフィールドで提示された宛先にトレースを、own_logsフィールドで提示された宛先にログを報告すべき(SHOULD)です。
AgentDescriptionメッセージのidentifying_attributesフィールドで指定されたすべての属性は、報告されるOTLPテレメトリーのResourceにも指定されるべき(SHOULD)です。
AgentDescriptionメッセージのnon_identifying_attributesフィールドで指定された属性は、報告されるOTLPテレメトリーのResourceにも指定してもよい(MAY)ものとし、その場合はまったく同じ値を持つべき(SHOULD)です。
設定
Agentの設定は、OpAMPプロトコルの任意のケーパビリティです。リモート設定のケーパビリティは、必要に応じて(例えばKubernetesのようなオーケストレーションシステムの既存の設定機能を使う場合など)無効化できます。
Serverは、ServerToAgentメッセージ内のremote_configフィールドを設定することで、Agentにリモート設定を提示できます。ServerToAgentメッセージは通常ステータスレポートへの応答として送信されるため、ServerはAgentの記述を把握しており、必要に応じて提示する設定を特定のAgentに合わせて調整できます。
OpAMP Clientは、AgentがリモートConfigurationを受け入れられる場合、AgentToServer.capabilitiesのAcceptsRemoteConfigビットを設定しなければなりません(MUST)。このビットが設定されていない場合、Serverはリモート設定をAgentに提示してはなりません(MUST NOT)。
Agentが実際の稼働に使う設定は、Serverから提示されるリモート設定とは異なることがあります。この実際の設定はAgentの実効設定(Effective Configuration)と呼ばれます。実効設定は通常、リモート設定とAgentが利用可能な他の入力(例えばローカルに利用可能な設定)をマージした後にAgentによって形成されます。
実効設定が形成されると、Agentはそれを自身の動作に使い、Clientはステータスレポートのeffective_configフィールドを通じて実効設定もOpAMP Serverに報告します。Serverは通常、Clientから報告されるステータス内の他のデータと並んで、実効設定をエンドユーザーが確認できるようにします。
Clientは、Agentが実効設定を報告できる場合、AgentToServer.capabilitiesのReportsEffectiveConfigビットを設定しなければなりません(MUST)。このビットが設定されていない場合、ServerはAgentToServer.effective_configフィールドが設定されることを期待するべきではありません。
以下は典型的な設定シーケンスの図です。
Agent Client Server
│ │ AgentToServer{} │ ┌─────────┐
│ ├──────────────────────────────────►├──►│ Process │
│ │ │ │ Status │
Local │ Remote │ │ │ and │
Config │ Config │ ServerToAgent{AgentRemoteConfig} │ │ Fetch │
│ │ ┌────────┤◄──────────────────────────────────┤◄──┤ Config │
▼ │ ▼ │ │ └─────────┘
┌─────────┐ │ │
│ Config │ │ │
│ Merger │ │ │
└─────┬───┘ │ │
│ │ │
│Effective │ │
│Config │ AgentToServer{} │
└──────────►├──────────────────────────────────►│
│ │
│ │
EffectiveConfigとRemoteConfigStatusのフィールドは、変化があった場合にAgentToServerメッセージに含まれます。
注: AgentToServerメッセージで報告される実効設定やその他のフィールドが変化していない場合、Clientはそのメッセージを送信するべきではありません(SHOULD NOT)。Clientがこの規則に従わない場合、ClientとServerの間で無限にメッセージが往復するループが発生する可能性があります。
Serverは、Clientからのステータスレポートを待たずに、自身の判断でリモート設定の送信を開始することもできます。これは、接続中だが報告すべき新しい情報がないAgentを再設定するために使えます。この場合のシーケンス図は以下のようになります。
Agent Client Server
│ │ │
│ │ │
│ │ │ ┌────────┐
Local │ Remote │ │ │Initiate│
Config │ Config │ ServerToAgent{AgentRemoteConfig} │ │and │
│ │ ┌────────┤◄──────────────────────────────────┤◄──┤Send │
▼ │ ▼ │ │ │Config │
┌─────────┐ │ │ └────────┘
│ Config │ │ │
│ Merger │ │ │
└────┬────┘ │ │
│ │ │
│Effective │ │
│Config │ AgentToServer{} │
└──────────►├──────────────────────────────────►│
│ │
│ │
Agentは、自身の設定をServerによってリモートで制御させたくない場合、リモート設定のオファーを無視してもよい(MAY)ものとします。
Configuration Files
Agentの設定は、名前付きの設定ファイル群の集合です(これはリモート設定と実効設定の両方に当てはまります)。
ファイル名は、その集合の中で一意でなければなりません(MUST)。リモート設定とローカル設定に同じ名前だが異なる内容のファイルが含まれる可能性があります。これらのファイルがどのようにマージされて実効設定を形成するかはAgentの種類ごとに異なり、OpAMPプロトコルの一部ではありません。
集合内に設定ファイルが1つしかない場合、ファイル名は空でもよい(MAY)ものとします。
設定ファイルの集合は、AgentConfigMapメッセージを使って表現されます。
message AgentConfigMap {
map<string, AgentConfigFile> config_map = 1;
}
AgentConfigSetメッセージのconfig_mapフィールドは、キーがファイル名である設定ファイルのマップです。
単一の設定ファイルを使うAgentの場合、config_mapフィールドは単一のエントリを含むべき(SHOULD)で、キーは空文字列でもよい(MAY)ものとします。
AgentConfigFileメッセージは、1つの設定ファイルを表し、以下の構造を持ちます。
message AgentConfigFile {
bytes body = 1;
string content_type = 2;
}
bodyフィールドには、設定ファイルの生バイト列が含まれます。生バイト列の内容、フォーマット、エンコーディングはAgentの種類ごとに異なり、OpAMPプロトコルの関心の外にあります。
content_typeは任意のフィールドです。bodyフィールドに含まれるものを記述するMIME Content-Type(例:「text/yaml」)です。Agentのステータスレポート内の実効設定で報告されるcontent_typeは、例えばServerが報告された設定をUIで適切に可視化するために使えます。
セキュリティに関する考慮事項
リモート設定は、悪意のある攻撃者に悪用される可能性のある、潜在的に危険な機能です。例えばAgentがローカルファイルを収集してネットワーク経由で送信できる場合、侵害されたOpAMP Serverが悪意のあるリモート設定をAgentに提示し、機密性の高いローカルファイルを収集して特定のネットワーク宛先に送信するようAgentに強制する可能性があります。
一般的な推奨事項については一般的な推奨事項を、特にリモート再設定のケーパビリティに関する推奨事項については設定の制限のセキュリティ節を参照してください。
AgentRemoteConfig Message
このメッセージの構造は以下のとおりです。
message AgentRemoteConfig {
AgentConfigMap config = 1;
bytes config_hash = 2;
}
パッケージ
ステータス: Beta
各Agentは1つ以上のパッケージから構成されます。パッケージには名前があり、内容はファイルに格納されます。ファイルの内容、パッケージが提供する機能、それらがどのように保存・使用されるかはAgentの種類ごとに異なり、OpAMPプロトコルの関心の外にあります。
パッケージには、トップレベルパッケージとサブパッケージの2種類があります。
通常、トップレベルパッケージはAgentの主要機能を実装する1つだけです。トップレベルパッケージが1つだけの場合、名前は空でもかまいません。
サブパッケージはアドオンやプラグインとも呼ばれます。サブパッケージは、機能追加のためにAgentにインストールできます(そのためアドオンという名前がついています)。
Agentは1つ以上のパッケージをインストールしていることがあります。各パッケージには名前があります。Agentは、同じ名前のパッケージを2つ以上持つことはできません。
異なるパッケージは同じ名前のファイルを持つことがあります。ファイル名はグローバルに一意ではなく、特定のパッケージのスコープ内でのみ一意です。
パッケージは、(ローカルユーザーなどによって)ローカルに提供・インストールされることもあれば、Serverによってリモートで提示され、その場合はAgentがそのパッケージをダウンロードしてインストールすることもあります。
Serverは、Agentからのステータスレポートへの応答として、あるいはパッケージをAgentにプッシュしたいというServer側の判断によって送信されるServerToAgentメッセージ内のpackages_availableフィールドを設定することで、Agentにパッケージを提示します。
PackagesAvailableメッセージは、このAgent向けにServer上で利用可能なパッケージを記述します。各パッケージについて、このメッセージは、パッケージの内容を持つファイルを記述し、HTTP GETリクエストを使ってそのファイルをダウンロードできるURLを提供します。これらのURLは、(OpAMP Serverと同じホスト上、または別のホスト上にあり得る)ダウンロードServer上のパッケージファイルを指します。
このプロトコルは、パッケージごとに1つのダウンロード可能なファイルのみをサポートします。Agentのパッケージが概念的に複数のファイルから構成されている場合、Agentとサーバーは、zipやtarファイルのように、複数のファイルを1つのファイルに格納できる任意のファイル形式で保存することに同意できます。単一のパッケージファイルをダウンロードした後、Agentはその中に含まれるファイルを展開してもよい(MAY)ものとします。これがどのように行われるかはAgent固有であり、プロトコルの範囲外です。
OpAMP Clientが、AgentToServer.capabilitiesのAcceptsPackagesビットを通じてAgentがパッケージを受け入れられることを示した場合に限り、Serverはパッケージのオファーを提示できます。
パッケージのダウンロード
PackagesAvailableメッセージを受信した後、Agentは以下のダウンロード手順に従うべき(SHOULD)です。
ステップ1
自分が持っている全パッケージの集約ハッシュと、Serverがall_packages_hashフィールドで提示した集約ハッシュを比較します。
集約ハッシュが同一であれば、Agent上のすべてのパッケージがServerによって提示されたものと同一であることを意味するため、ダウンロード手順は完了したものと見なします。そうでない場合はステップ2に進みます。
ステップ2
Serverが提示した各パッケージについて、Agentはその特定のパッケージをダウンロードすべきかどうかを確認すべき(SHOULD)です。
- Agentが指定された名前のパッケージを持っていない場合、そのパッケージをダウンロードすべき(SHOULD)です。各パッケージファイルのダウンロード方法についてはステップ3を参照してください。
- Agentがそのパッケージを持っている場合、Agentは、自分が持っているパッケージのハッシュを、PackageAvailableメッセージ内のhashフィールドで提示されたパッケージのハッシュと比較すべき(SHOULD)です。ハッシュが同一であればパッケージは同一であり、そのパッケージの処理は完了したものとして次のパッケージに進みます。ハッシュが異なる場合は、ステップ3で説明されるようにパッケージファイルを確認します。
最後に、Agentが持っているパッケージの中にServerから提示されなかったものがある場合、そのパッケージはAgentによって削除されるべき(SHOULD)です。
ステップ3
Serverから提示されたパッケージのファイルについて、Agentはそのファイルをダウンロードすべきかどうかを確認すべき(SHOULD)です。
- Agentが指定された名前のファイルを持っていない場合、そのファイルをダウンロードすべき(SHOULD)です。
- Agentがそのファイルを持っている場合、Agentは、ローカルに持っているファイルのハッシュを、DownloadableFileメッセージ内のhashフィールドと比較すべき(SHOULD)です。ハッシュが同一であれば、このファイルの処理は完了です。そうでなければ、提示されたファイルは異なるものであり、DownloadableFileメッセージのdownload_urlフィールドで指定された場所からファイルをダウンロードすべき(SHOULD)です。Agentは、ファイルをダウンロードするためにHTTP GETメッセージを使うべき(SHOULD)です。Agentは、GETリクエストにheadersフィールドで提供されたHTTPヘッダーを含めるべき(SHOULD)です。
上記の手順によって、Agentは新規または変更されたパッケージのみを効率的にダウンロードし、かつ新規または変更されたファイルのみをダウンロードできます。
パッケージをダウンロードした後、Agentは(例えばパッケージを何らかの形で「インストール」または「有効化」するといった)Agentの種類ごとの追加処理を実行できます。
Package Status Reporting
ダウンロードとインストールの過程で、Agentはその処理のステータスを定期的に報告してもよい(MAY)ものとします。これを行うために、OpAMP ClientはAgentToServerメッセージを送信し、package_statusesフィールドを適宜設定するべき(SHOULD)です。
すべてのパッケージのダウンロードとインストールが(成功または失敗にかかわらず)完了したら、ClientはすべてのパッケージのステータスをServerに報告するべき(SHOULD)です。
以下は、パッケージのダウンロードとステータスレポートの典型的なシーケンス図です。
Download Agent/Client OpAMP
Server Server
│ │ │
│ │ ServerToAgent{PackagesAvailable}│
│ │◄─────────────────────────────────┤
│ HTTP GET │ │
│◄────────────────┤ │
│ Download file #1│ │
├────────────────►│ │
│ │ AgentToServer{PackageStatuses} │
│ ├─────────────────────────────────►│
│ HTTP GET │ │
│◄────────────────┤ │
│ Download file #2│ │
├────────────────►│ │
│ │ AgentToServer{PackageStatuses} │
│ ├─────────────────────────────────►│
│ │ │
. . .
│ HTTP GET │ │
│◄────────────────┤ │
│ Download file #N│ │
├────────────────►│ │
│ │ AgentToServer{PackageStatuses} │
│ ├─────────────────────────────────►│
│ │ │
Clientは、(ダウンロードまたはインストール中の)Agentが持っている、または処理中のすべてのパッケージを、PackageStatusesメッセージに常に含めなければなりません(MUST)。
Clientは、Serverから提示されてダウンロードしたパッケージだけでなく、Agentがローカルにインストールしたパッケージのステータスも報告してもよい(MAY)ものとします。
ハッシュの算出
Agentとサーバーは、Agentがどのファイルとパッケージをダウンロードする必要があるかを判断できるように、ハッシュを使ってファイルとパッケージの内容を識別します。
ハッシュの算出はServerによって行われます。Serverは衝突確率が最小になる強力なハッシュ算出方式を選ばなければならず(MUST)(実装がそのような保証を必要とする場合、ハッシュの一意性を保証するために乱数値を算出にシードしてもよい(MAY)ものとします)。
ハッシュはAgentにとって不透明であり、Agentはハッシュを算出することはなく、保存と比較のみを行います。
ハッシュには3つのレベルがあります。
File Hash
パッケージファイルの内容のハッシュです。これはDownloadableFileメッセージのcontent_hashフィールドに格納されます。この値は、Agentが持っている特定のファイルがServer上のものと異なり、再ダウンロードが必要かどうかを判断するために使われるべき(SHOULD)です。
Package Hash
パッケージ全体(パッケージ名とファイル内容)を識別するパッケージハッシュです。このハッシュはPackageAvailableメッセージのhashフィールドに格納されます。
この値は、Agentが持っている特定のパッケージがServer上のものと異なり、再ダウンロードが必要かどうかを判断するために使われるべき(SHOULD)です。
All Packages Hash
全パッケージハッシュは、特定のAgentのすべてのパッケージの集約ハッシュです。このハッシュは、すべてのパッケージ名と内容の集約として算出されます。このハッシュは、PackagesAvailableメッセージのall_packages_hashフィールドに格納されます。
この値は、Agentが持っているパッケージのいずれかがServer上で利用可能なものと異なり、再ダウンロードが必要かどうかを判断するために使われるべき(SHOULD)です。
集約ハッシュには、Agent上でローカルに利用可能で、ダウンロードServerからダウンロードされなかったパッケージは含まれない点に注意してください。
セキュリティに関する考慮事項
パッケージをリモートでダウンロードすることは、悪意のある攻撃者に悪用される可能性のある、潜在的に危険な機能です。パッケージに実行可能コードが含まれる場合、侵害されたOpAMP Serverが悪意のあるパッケージをAgentに提示し、任意のコードを実行するようAgentに強制する可能性があります。
一般的な推奨事項については一般的な推奨事項を、特にコード署名のケーパビリティに関する推奨事項についてはセキュリティ節を参照してください。
PackagesAvailable Message
このメッセージの構造は以下のとおりです。
message PackagesAvailable {
map<string, PackageAvailable> packages = 1;
bytes all_packages_hash = 2;
}
PackagesAvailable.packages
パッケージのマップです。キーはパッケージ名です。
PackagesAvailable.all_packages_hash
リモートでインストールされたすべてのパッケージの集約ハッシュです。
Clientはこの値を、以降のPackageStatusesメッセージに含めるべき(SHOULD)です。これにより、Agentに利用可能なパッケージの集合が変化したことをServerが識別し、次のServerToAgentメッセージで利用可能なパッケージを指定できます。
Serverがパッケージのagentへの送信をサポートし、かつAgentがパッケージを受け入れられることを示している場合、このフィールドは常に設定されなければなりません(MUST)。
PackageAvailable Message
このメッセージは、Agentがすでに持っているパッケージの新規インストール、あるいはアップグレードまたはダウングレードを開始するための、Serverからのオファーです。このメッセージの構造は以下のとおりです。
message PackageAvailable {
PackageType type = 1;
string version = 2;
DownloadableFile file = 3;
bytes hash = 4;
}
PackageAvailable.type
パッケージの種類です。アドオンまたはトップレベルパッケージのいずれかです。
enum PackageType {
TopLevelPackage = 0;
AddonPackage = 1;
}
PackageAvailable.version
Server側で利用可能なパッケージのバージョンです。Agentは例えば、以前にダウンロード済みでインストールに失敗したパッケージの再ダウンロードを避けるためにこの情報を使うことができます。
PackageAvailable.file
パッケージのダウンロード可能なファイルです。
PackageAvailable.hash
パッケージのハッシュです。PackageAvailableメッセージの他のすべてのフィールドとパッケージのファイル内容に基づいて算出されるべき(SHOULD)です。このハッシュは、Agentが持っているパッケージがServerが提示しているパッケージと異なるかどうかをAgentが判断するために使われます。
DownloadableFile Message
このメッセージの構造は以下のとおりです。
message DownloadableFile {
string download_url = 1;
bytes content_hash = 2;
bytes signature = 3;
Headers headers = 4; // Status: [Development]
}
DownloadableFile.download_url
HTTP GETリクエストを使ってファイルをダウンロードできるURLです。指定されたURLのServerは、ダウンロードの再開ができるよう、範囲リクエストをサポートするべき(SHOULD)です。
DownloadableFile.content_hash
ファイル内容のSHA256ハッシュです。ファイルが正しくダウンロードされたことをAgentが検証するために使えます。
DownloadableFile.signature
ファイル内容の任意の署名です。ダウンロードされたファイルの真正性をAgentが検証するために使えます。例えばdetached GPG signatureにできます。正確な署名方式と検証方式はAgent固有です。推奨事項についてはコード署名を参照してください。
DownloadableFile.headers
ステータス: [Development]
HTTP GETリクエストで使う任意のヘッダーです。通常、アクセストークンや他の認可ヘッダーを設定するために使われます。HTTPベースのプロトコルでは、Agentはこれらをリクエストヘッダーに設定するべきです。例: key=“Authorization”, Value=“Basic YWxhZGRpbjpvcGVuc2VzYW1l”。
カスタムメッセージ
ステータス: [Development]
目的
OpAMPプロトコルは、Agentのリモート管理と設定のあらゆる側面をカバーすることを意図しています。このコア機能の中でさらに要件が識別された場合、プロトコルは将来のリリースでこの追加の振る舞いをサポートするために拡張されることが期待されます。しかし、OpAMPプロトコルではサポートされない、Agentとの通信が必要なユースケースも一部存在します。これらは、Agentのリモート管理の範囲外であるか、1つのAgentに高度に固有で他のAgentの種類に一般化できないためです。CustomCapabilitiesとCustomMessageは、別の接続を開いたり、まったく新しいプロトコルを定義したりせずに、ServerとAgentの間でカスタムの振る舞いを実装できるようにします。
多くのAgentとAgent Management Serverの間の相互運用性はOpAMPの目標ですが、追加のカスタム機能は特定のAgentとServerのみでサポートされる場合があります。適切な場合、実装者はCustomMessageの使用方法を文書化し、追加のプラットフォームへのサポート追加を促すことが推奨されます。適切な場合、ServerとAgentの実装で広くサポートされているカスタムケーパビリティは、将来標準のOpAMPケーパビリティとして採用されることがあります。
CustomCapabilities
AgentとServerはどちらも、このメッセージを使って特定のカスタムケーパビリティをサポートすることを示すべきです。これはServerToAgentとAgentToServerの両方でサポートされます。このメッセージは、サポートされるカスタムケーパビリティの一覧が変化したときにのみ送信されるべきです。このメッセージが送信されたとき、サポートされるカスタムケーパビリティの一覧はこの一覧に一致するよう更新されるべきです。このメッセージが一度も送信されない場合、カスタムケーパビリティはサポートされていないと見なされます。
ケーパビリティは、オプションのバージョン情報を伴う逆順FQDNで識別されなければなりません。これにより、異なる組織によって導入されるケーパビリティ間の衝突を避けられます。ケーパビリティ名は、そのカスタムケーパビリティを作成した組織の逆順FQDN、ピリオド、そしてケーパビリティを識別する短い名前で構成されます。バージョンは任意であり、ケーパビリティ名とはスラッシュで区切られます。
例えば、「com.company.capability/v2」は、「company.com」によって作成された「capability」のバージョン2を識別します。
サポートされていないケーパビリティを持つCustomMessageを受信した場合、そのメッセージは無視できます。あるケーパビリティのサポートは、そのケーパビリティに対応するすべてのCustomMessageがサポートされることを意味します。正確な振る舞いはカスタムケーパビリティごとに固有です。
message CustomCapabilities {
repeated string capabilities = 1; // Status: [Development]
}
CustomCapabilities.capabilities
サポートされているカスタムケーパビリティの一覧です。各ケーパビリティは、オプションのバージョン情報を伴う逆順FQDNであり、そのカスタムケーパビリティを一意に識別し、サポートされているCustomMessage内で指定されたケーパビリティと一致するべきです。
CustomMessage
CustomMessageは、AgentとServerの間でカスタムメッセージを送信できるようにします。双方向のカスタム通信を可能にするため、ServerToAgentとAgentToServerの両方でサポートされます。これには、AgentとServerの両方がメッセージの内容とエンコーディングについて合意していることが必要です。ケーパビリティがサポートされていない場合、またはメッセージの種類が認識されない場合、そのメッセージは無視できます。
CustomMessageは、メッセージの種類を識別し、メッセージの内容を持つバイナリデータを含みます。データのフォーマットはメッセージの種類によって決まり、OpAMPプロトコルの範囲外です。
message CustomMessage {
string capability = 1;
string type = 2;
bytes data = 3;
}
CustomMessage.capability
ケーパビリティを一意に識別し、CustomCapabilitiesメッセージ内のいずれかのケーパビリティと一致する逆順FQDNです。
CustomMessage.type
ケーパビリティ内でのメッセージの種類です。ケーパビリティは、そのケーパビリティを実装するために使われるカスタムメッセージの種類を定義します。typeは、そのケーパビリティ内でのみ一意である必要があります。
CustomMessage.data
メッセージのバイナリデータです。ケーパビリティは、それが定義する各カスタムメッセージ種別について、dataの内容のフォーマットを指定しなければなりません。
例
以下の例は、CustomCapabilitiesとCustomMessageの可能な使用方法を説明していますが、仕様書の一部となることを意図したものではありません。これらの例では、メッセージ種別のFQDNを作るために「io.opentelemetry.」が使われていますが、各ベンダーは自身のFQDNを使うことが期待されます。
一時停止/再開の例
Agentがテレメトリー収集の一時停止と再開をサポートしている場合を考えます。一時停止中は、テレメトリーデータの収集も送信も行われません。この振る舞いをServerが制御できるようにするために、CustomMessageを使うCustomCapabilityを導入できます。
エージェントの接続
接続時、Agentは「io.opentelemetry.pause」を含むCustomCapabilitiesを含むAgentToServerメッセージを送信します。それに応じて、Serverは「io.opentelemetry.pause」を含むCustomCapabilitiesメッセージを含むServerToAgentメッセージを送信します。
CustomCapabilities {
capabilities: ["io.opentelemetry.pause"]
}
Pause
Serverは、type「pause」の以下のCustomMessageを含むServerToAgentメッセージを送信します。これは追加情報を持たない単純なコマンドであるため、データは送信されません。
CustomMessage {
capability: "io.opentelemetry.pause"
type: "pause"
}
Agentがこのメッセージをサポートしており、一時停止に成功した場合、type「status」のCustomMessageを含み、新しい一時停止状態を示すバイナリのJSONエンコードされたレスポンスをdataに含むAgentToServerメッセージを返します。
CustomMessage {
capability: "io.opentelemetry.pause"
type: "status"
data: {
"paused": true
}
}
Agentがこのメッセージをサポートしているが一時停止しようとしてエラーに遭遇した場合、type「error」のCustomMessageを含み、エラーメッセージを含むバイナリのJSONエンコードされたレスポンスをdataに含むAgentToServerメッセージを返します。
CustomMessage {
capability: "io.opentelemetry.pause"
type: "error"
data: {
"error": "Unable to pause"
}
}
Resume
Pauseと同様ですが、ServerToAgentメッセージにはtype「resume」のCustomMessageが含まれ、成功時の新しいステータスは{ "paused": false }になります。
CustomMessage {
capability: "io.opentelemetry.pause"
type: "resume"
}
サービスディスカバリの例
サービスディスカバリは、Agentがテレメトリーを収集できる、Agentからアクセス可能な稼働中のサービスを発見することを含みます。この例では、Serverが利用可能なサービスを問い合わせるメッセージをAgentに送信します。Agentからは、利用可能なサービスに関する情報を含む応答が期待されます。
エージェントの接続
接続時、Agentはケーパビリティ「io.opentelemetry.discovery」を含むCustomCapabilitiesメッセージを送信します。それに応じて、Serverはケーパビリティ「io.opentelemetry.discovery」も含むCustomCapabilitiesメッセージを送信します。このケーパビリティがAgentとServerの両方でサポートされているため、このケーパビリティに関連するメッセージをディスカバリのサポートのために送信できます。
FindServices
Serverは、以下のCustomMessageを含むServerToAgentメッセージを送信します。これは追加情報を持たない単純なリクエストであるため、データは送信されません。
CustomMessage {
capability: "io.opentelemetry.discovery"
type: "find_services"
}
FindServicesResponse
サービスを発見した後、Agentは、発見したすべてのサービスに関する情報を含む複雑なデータ構造のJSONエンコーディングをバイナリデータに含むCustomMessageを含むAgentToServerメッセージを送信します。このデータ構造には、ディスカバリ中に発生したエラーのための任意のフィールドも含まれます。
CustomMessage {
capability: "io.opentelemetry.discovery"
type: "available_services"
data: { ... }
}
AvailableComponents Message
ステータス: [Development]
各Agentは複数のサブコンポーネントから構成されることがあります。これらのコンポーネントは、それぞれ関連するメタデータを持つことがあります。AvailableComponentsメッセージによって、Agentが自身が持つコンポーネントについてOpAMP serverに知らせることができます。
AvailableComponentsメッセージの構造は以下のとおりです。
message AvailableComponents {
map<string, ComponentDetails> components = 1;
bytes hash = 2;
}
AvailableComponents.components
componentsフィールドには、一意なIDからComponentsDetailsメッセージへのマップが含まれます。直前のServerToAgentメッセージでOpAMP serverがReportAvailableComponentsフラグを設定して明示的にリクエストしていない場合、このフィールドはメッセージから省略されることがあります。
例
OpenTelemetry Collector
OpenTelemetry Collectorのカスタムビルドに含まれるコンポーネントに関する情報を、ComponentDetailsがどのように保持できるかの例を示します。
{
"receivers": {
"sub_component_map": {
"hostmetrics": {
"metadata": {
"code.namespace": "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver@v0.107.0",
}
}
}
},
"processors": {
"sub_component_map": {
"batch": {
"metadata": {
"code.namespace": "go.opentelemetry.io/collector/processor/batchprocessor@v0.107.0"
}
},
"transform": {
"metadata": {
"code.namespace": "github.com/open-telemetry/opentelemetry-collector-contrib/processor/transformprocessor@v0.107.0"
}
},
}
},
"exporters": {
"sub_component_map": {
"nop": {
"metadata": {
"code.namespace": "go.opentelemetry.io/collector/exporter/nopexporter@v0.107.0"
}
}
}
}
// ... Component list continues for extensions and collectors ...
}
Fluent Bit
Fluent Bitが利用可能なコンポーネントをどのように報告できるかの例を示します。
{
"input": {
"sub_component_map": {
"tail": {}
}
},
"parser": {
"sub_component_map": {
"json": {}
}
},
"filter": {
"sub_component_map": {
"lua": {},
"modify": {}
}
},
"output": {
"sub_component_map": {
"null": {},
"file": {},
}
}
}
AvailableComponents.hash
componentsフィールドのagent側で算出されたハッシュです。Agentは、自身が利用可能なコンポーネントを報告できる能力を持つ場合、このハッシュを含めなければなりません(MUST)。フォーマットはagentによって決められます。同じコンポーネントの集合を持つAgentであれば、ハッシュは同一であるべき(SHOULD)です。
初回のハンドシェイク
送信されるデータ量を減らすため、AvailableComponentsメッセージは最初からコンポーネントの完全なマップを含みません。代わりに、AvailableComponentsメッセージは、componentsを空のマップにしたまま、agent側で算出されたハッシュのみを設定します。
最初のAgentToServerメッセージには、agent側で算出されたハッシュのみが設定されたAvailableComponentsメッセージを含めるべき(SHOULD)です。
OpAMP serverは、このハッシュを使って、AvailableComponentsの集合を記憶しているかどうかを判断できます。ハッシュがOpAMP server上に見つからない場合、serverはServerToAgentメッセージ内にReportAvailableComponentsフラグを設定することで、コンポーネントの完全なマップの報告をリクエストできます。このフラグが指定された場合、Agentはcomponentsフィールドに利用可能なコンポーネントの完全な記述を設定します。
serverはその後、任意でそのハッシュに対応するコンポーネントを永続化してもよく、それによって以降の接続で再度リクエストする必要がなくなります。
AvailableComponentsメッセージもステータスの圧縮の対象であり、ハッシュが以前の値から変化していない場合は省略できます。
ComponentDetails Message
ComponentDetailsメッセージはAgentのコンポーネントを記述します。
ComponentDetailsの構造は、ComponentHealthの構造と1対1で一致する必要はありません。ComponentHealthは一般に現在稼働中のコンポーネントのインスタンスを指しますが、ComponentDetailsは、現在必ずしも稼働しているとは限らない、利用可能なコンポーネントの種類を指します。同じコンポーネント種別が複数の稼働中インスタンスを持つこともあります。
ComponentDetailsメッセージの構造は以下のとおりです。
message ComponentDetails {
repeated KeyValue metadata = 1;
map<string, ComponentDetails> sub_component_map = 2;
}
ComponentDetails.metadata
コンポーネントを記述するために使える追加のキー/値の組です。
キー/値の組は、該当する場合はセマンティック規約に準拠するべき(SHOULD)です。詳細はOpenTelemetry Semantic Conventionsを参照してください。
ComponentDetails.sub_component_map
一意なコンポーネントIDからサブコンポーネントの詳細へのマップです。基盤となるシステムを記述するために必要な深さでネストできます。
接続管理
接続の確立
ClientはHTTP(S)接続を確立してServerに接続します。
WebSocketトランスポートが使われる場合、接続はWebSocket標準で定義されているようにWebSocketにアップグレードされます。
接続が確立された後、Clientは最初のステータスレポートを送信し、それへの応答を待たなければなりません(MUST)。
ClientがServerへの接続を確立できない場合、Serverを過負荷にしないよう、ジッターを伴う指数バックオフ戦略を使って接続の再試行を行うべき(SHOULD)です。
接続の再試行を行う際、Clientは、Serverから受信するスロットリングのレスポンスを尊重するべき(SHOULD)です。
接続のクローズ
OpAMPクライアントによるWebSocket接続のクローズ
接続をクローズするために、Clientはまずagent_disconnectフィールドが設定されたAgentToServerメッセージを送信しなければなりません(MUST)。その後、ClientはWebSocketのClose制御フレームを送信し、WebSocket標準で定義された手順に従わなければなりません(MUST)。
サーバーによるWebSocket接続のクローズ
接続をクローズするために、ServerはWebSocketのClose制御フレームを送信し、WebSocket標準で定義された手順に従わなければなりません(MUST)。
プレーンHTTPトランスポート
OpAMPのHTTPレスポンスが完了した時点で、Clientは論理的に切断されたと見なされます。Client接続は常にHTTPレスポンスの完了後に失われるものと暗黙的に見なされるため、Clientがagent_disconnectフィールドを設定したAgentToServerメッセージを送信する必要はありません。
ClientとServerはHTTPキープアライブを使ってもかまいませんが、これはOpAMPプロトコルの論理的な動作には影響しません。
Serverは、何をアクティブなAgent(例えば継続的にポーリングしているClient)と見なし、何を非アクティブなAgent(例えば特定の期間HTTPリクエストを行っていないClient)と見なすかを、自身のビジネスロジックで判断してもかまいません。このビジネスロジックはOpAMP仕様書の対象外です。
WebSocket接続の復旧
確立済みのWebSocket接続が予期せず切断された場合、Clientは直ちに再接続を試みるべき(SHOULD)です。再接続が失敗した場合、Clientは接続の確立で説明されたバックオフを使って接続の試行を続けるべき(SHOULD)です。
重複するWebSocket接続
各Clientインスタンスは、Serverに対して同時に1回を超えて接続するべきではありません(SHOULD NOT)。ClientがServerに再接続する必要がある場合、Clientはまずagent_disconnectメッセージを送信し、既存の接続をクローズし、その後にのみ再接続を試みなければなりません(MUST)。
Serverは、同じClientインスタンスが複数の同時接続を持っている、あるいは複数のAgentインスタンスが同じinstance_uidを使っていることを検出した場合、切断するかリクエストへの応答を拒否してもよい(MAY)ものとします。
Serverは(例えばAgentが不良なUID生成器を使っている場合や、Agentが動作しているVMの複製によって)重複するinstance_uidを検出するべき(SHOULD)です。重複するinstance_uidが検出された場合、Serverは新しいinstance_uidを生成し、AgentIdentificationのnew_instance_uidの値として送信するべき(SHOULD)です。
重複するinstance_uidの検出
Serverは、重複するinstance_uidの値で接続してくるAgentを検出できることがあります。検出メカニズムは実装固有です。重複の検出は、Serverがinstance_uidの再利用やなりすましを防ぎたい場合に望ましいものです。
これが発生した場合、Serverは重複したインスタンスからのリクエストを切断するか拒否してもよい(MAY)ものとします。Serverは新しいinstance_uidを生成し、ServerToAgentレスポンスのAgentIdentificationのnew_instance_uidの値として送信するべき(SHOULD)です。
認証
ステータス: Beta
ClientとServerは、Basic認証やBearer認証といった、HTTPがサポートする認証方式を使ってもよい(MAY)ものとします。認証は、HTTP接続が確立され、WebSocket接続にアップグレードされる前に行われます。
Client認証が失敗した場合、Serverは401 Unauthorizedで応答しなければなりません(MUST)。
不正なリクエスト
Serverが不正な形式のAgentToServerメッセージを受信した場合、Serverはerror_responseを適宜設定したServerToAgentメッセージで応答するべき(SHOULD)です。typeフィールドはBAD_REQUESTに設定されなければならず(MUST)、error_messageは、AgentToServerメッセージの問題を説明する人間が読める記述であるべき(SHOULD)です。
BAD_REQUEST応答を受信したAgentToServerメッセージについて、Clientは再送するべきではありません(SHOULD NOT)。
メッセージの再送
Clientは、以下の場合にAgentToServerメッセージを再送してもよい(MAY)ものとします。
- 応答を必要とするAgentToServerメッセージを送信したが、合理的な時間内に応答が受信されなかった場合(このタイムアウトは設定可能でもよい(MAY)ものとします)。
- 応答を必要とするAgentToServerメッセージを送信したが、応答を受信する前に接続が失われた場合。
- スロットリング節で説明されているように、ServerからUNAVAILABLE応答を受信した後。
応答を必要とするメッセージについて、Serverが同じメッセージを複数回受信した場合、Serverが重複を検出して1回だけ処理する場合でも、Serverは最初のメッセージだけでなく各メッセージに応答しなければなりません(MUST)。
接続が利用できない場合でも、Clientは、Serverに送信したいメッセージの増大するキューを保持する必要はない点に注意してください。Clientは通常、Serverに送信したい各種類のメッセージについて、最新の1つのメッセージだけを保持し、接続が利用可能になった時点で送信すればよいのです。
例えば、Clientは Agentのステータスを追跡し、最初の機会に送信できるAgentToServerメッセージを組み立てておくべきです。Clientが(例えば接続がまだ利用できないなどの理由で)AgentToServerメッセージを送信できない場合、Clientは、Agentのステータスが変化するたびに新しいAgentToServerメッセージを作成し、送信待ちのキューにこれらすべてのAgentToServerメッセージを保持する必要はありません。Clientは、単に最新の1つのAgentToServerメッセージを保持し、最初の機会に送信すればよいのです。これには当然、AgentToServerメッセージが、直前に報告された以降のすべての変更を含み、Agentの現在(最新)の状態を正しく反映している必要があります。
同様に、アドオンステータスレポートやエージェントパッケージインストールステータスレポートといった、他のすべてのAgentレポート機能についても、Clientは最新の1つのステータスメッセージだけを保持し、最初の機会に送信すればよいことが求められます。
逆方向についても、まったく同じロジックが当てはまります。Serverは通常、Agentに配送したい特定の種類の最新の1つのメッセージだけを保持し、Clientへの接続が利用可能になった時点で送信すればよいのです。
スロットリング
WebSocketトランスポート
Serverが過負荷状態にあり、AgentToServerメッセージを処理できない場合、Serverは、error_responseに、typeフィールドをUNAVAILABLEに設定した値を入れたServerToAgentメッセージで応答するべき(SHOULD)です。Clientは切断し、待ち、その後再接続して動作を再開するべき(SHOULD)です。retry_infoフィールドには、再接続までにClientが待つべき時間を指定するretry_after_nanosecondsフィールドを任意で設定してもよい(MAY)ものとします。
message RetryInfo {
uint64 retry_after_nanoseconds = 1;
}
retry_infoが設定されていない場合、Clientは再試行の間隔を段階的に増やす指数バックオフ戦略を実装するべき(SHOULD)です。
プレーンHTTPトランスポート
プレーンHTTPトランスポートが使われる場合、およびWebSocketが使われていてServerが過負荷でHTTP接続をWebSocketにアップグレードできない場合のいずれにおいても、ServerはHTTP 503 Service UnavailableまたはHTTP 429 Too Many Requestsレスポンスを返してもよく(MAY)、Clientが再接続を試みるべきタイミングを示すために任意でRetry-Afterヘッダーを設定してもよい(MAY)ものとします。Clientは、HTTP仕様の対応する要件を尊重するべき(SHOULD)です。
注: Retry-Afterヘッダーは、Clientがサーバーへ再接続を試みる場合にのみ使われるべき(SHOULD)です。Agentが再接続中は、Clientは通常のハートビートメッセージを送信しようとするべきではありません。
推奨される最小の再試行間隔は30秒です。
セキュリティ
リモート設定とダウンロード可能なパッケージは、重大なセキュリティリスクです。悪意のあるServer側の設定や悪意のあるパッケージを送信することで、Serverは望ましくない作業をAgentに強制する可能性があります。この節では、Agentのセキュリティリスクを低減する推奨事項を定義します。
この節のガイドラインは実装上任意ですが、機密性の高いアプリケーションでは強く推奨されます。
一般的な推奨事項
Agentがゼロトラストのセキュリティモデルを採用し、Serverから受信するリモート設定やその他のオファーを自動的に信頼しないことを推奨します。Serverから受信したデータは、悪意のある攻撃者によって引き起こされる可能性のある被害を制限・防止するために、Agentによって検証・サニタイズされるべきです。以下を推奨します。
- Agentは、機密性の高いファイルへのアクセスや高権限操作の実行から自身を守るために、可能な限り最小の権限で動作すべきです。Agentはroot権限で動作するべきではありません。そうでなければ、侵害されたAgentが悪意のある攻撃者によるマシンの完全な制御につながる可能性があります。
- Agentがローカルデータを収集できる場合、収集を特定のディレクトリの集合に限定するべきです。この制限はローカルで指定されるべきであり、リモート設定によって上書き可能であってはなりません。この規則に従わない場合、リモート設定機能が悪用されてAgentのマシン上の機密情報にアクセスされる可能性があります。
- Agentが、稼働しているマシン上に存在する外部コードを実行できる能力を持ち、この機能をAgentの設定で指定できる場合、Agentはこの機能を、限定されたディレクトリの集合内にある特定のスクリプトのみに限定するべきです。この制限はローカルで指定されるべきであり、リモート設定によって上書き可能であってはなりません。この規則に従わない場合、リモート設定機能が悪用されてAgentのマシン上で任意のコードが実行される可能性があります。
設定の制限
Agentは、リモート設定によって強制される可能性のある動作を制限することが推奨されます。
特に、(テレメトリー収集Agentでよくあるように)設定によってAgentが稼働しているマシンからのデータ収集を指示できる場合、Agentがどのディレクトリやファイルを収集してよいかについてAgent側の制限を持つことを推奨します。リモート設定を受信した際、Agentは、その設定を制限の一覧と照合して検証しなければならず、制限に違反する場合は設定の全体または一部の適用を拒否するか、禁止されたディレクトリやファイルからデータを収集しないよう設定をサニタイズしなければなりません。
同様に、設定によってAgentが稼働しているマシン上でプロセスやスクリプトを実行するよう指示する手段が提供される場合、どのディレクトリのどの実行ファイルをAgentが実行してよいかについてAgent側の制限を持つことを推奨します。
これらの制限は、「拒否リスト」ではなく「許可リスト」の形式で指定されることが推奨されます。制限はハードコードされていてもよく、ローカルの設定ファイルでエンドユーザーが定義可能でもよいものとします。ServerからAgentへリモート設定を送信することでこれらの制限を上書きできてはなりません。
オプトイン方式のリモート設定
リモート設定機能は、デフォルトではAgentで有効化されないことが推奨されます。この機能はユーザーによってオプトインされるべきです。
コード署名
パッケージの一部である実行可能コードは、侵害されたServerが悪意のあるコードをAgentに配送することを防ぐために署名されるべきです。以下を推奨します。
- ダウンロード可能な実行可能コード(例えば実行可能パッケージ)はコード署名される必要があります。実際のコード署名と検証のメカニズムはAgent固有であり、OpAMP仕様書の関心の外にあります。
- Agentは、ダウンロードしたファイル内の実行可能コードについて、コード署名が有効であることを検証すべきです。
- ダウンロード可能なコードは、ファイル内容に含まれる署名で署名されることもあれば、DownloadableFileメッセージのsignatureフィールドに記録された分離署名を持つこともあります。分離署名は、例えばGPG signingで使われることがあります。
- コード署名にCertificate Authorityが使われる場合、侵害されたServerが悪意のあるコードに署名できないよう、Certificate Authorityとその秘密鍵はOpAMP Serverと同じ場所に配置しないことが推奨されます。
- Agentは、ダウンロードした実行可能コード(パッケージや、外部プロセスとして実行する任意のコード)が機密性の高いファイルへアクセスしたり高権限操作を実行したりしないよう、可能な限り最小の権限で実行すべきです。Agentは、ダウンロードしたコードをroot権限で実行するべきではありません。
相互運用性
部分的な実装の相互運用性
OpAMPは、Agentとサーバーに対して多数のケーパビリティを定義しています。これらのケーパビリティの大半は任意です。Agentまたはサーバーは、相手が特定のケーパビリティをサポートしていない場合に備えておくべきです。
AgentとServerはどちらも、最初のメッセージ交換で自身がサポートするケーパビリティを示します。ClientはAgentToServerメッセージ内でcapabilitiesビットフィールドを設定し、ServerはServerToAgentメッセージ内でcapabilitiesビットフィールドを設定します。
capabilitiesフィールド内で設定された各ビットは、特定のケーパビリティがサポートされていることを示します。Agentのケーパビリティの一覧はこちらにあります。Serverのケーパビリティの一覧はこちらにあります。
Serverは、特定のAgentのケーパビリティを把握した後、そのAgentがサポートしないケーパビリティの使用を停止しなければなりません(MUST)。
同様に、Agentは、Serverのケーパビリティを把握した後、Serverがサポートしないケーパビリティの使用を停止しなければなりません(MUST)。
相手が特定のケーパビリティをサポートしないことを検出した際にAgentとServerの振る舞いのどこがどう変わる必要があるかについては、この文書の関連する箇所で説明されています。
将来のケーパビリティの相互運用性
OpAMPが、この仕様書の現バージョンの実装と、この仕様書に記述されていない追加ケーパビリティを持つ将来の拡張版OpAMPの実装との間の相互運用性を可能にする方法は2つあります。
無視可能なケーパビリティ拡張
相手側で黙って無視できるような形で機能を拡張する新しいケーパビリティについては、任意のProtobufメッセージに新しいフィールドを追加できます。この新しいケーパビリティを実装する送信側は新しいフィールドを設定します。新しいケーパビリティを認識しない、この仕様書の古いバージョンを実装している受信側は、単純に新しいフィールドを無視します。Protobufエンコーディングによって、残りのフィールドは受信側によって正しくデシリアライズされることが保証されます。
無視不可能なケーパビリティ拡張
相手側で黙って無視できない形で機能を拡張する新しいケーパビリティについては、異なるアプローチが使われます。
AgentToServerおよびServerToAgentメッセージのcapabilitiesフィールドには、多数の予約ビットが含まれています。これらのビットは、将来OpAMPに追加される新しいケーパビリティのサポートを示すために使われるべき(SHOULD)です。
ClientとServerは、メッセージを送信する際にこれらの予約ビットを0に設定しなければなりません(MUST)。これにより、OpAMPの新しいバージョンを実装している受信側は、送信側が新しいケーパビリティをサポートしていないことを把握し、それに応じて自身の振る舞いを調整できます。
AgentToServerとServerToAgentのメッセージは、ClientとServerが最初に交換するメッセージであり、これによって双方が相手のケーパビリティを把握し、適切に振る舞いを調整できます。将来のケーパビリティに対して振る舞いが正確にどのように調整されるかは、その新しいケーパビリティの将来の仕様書で定義されなければなりません(MUST)。
Protobufスキーマの安定性
この仕様書は、OpAMP 1.0におけるProtobuf定義について、以下の安定性の保証を提供します。
- フィールドの型、番号、名前は変更されません。
- メッセージとenumの名前は変更されません。
- enumの選択肢に割り当てられた番号は変更されません。
- enumの選択肢の名前は変更されません。
- メッセージとenumの位置(トップレベルの字句スコープで宣言されているか、他のメッセージにネストされているか)は変更されません。
- パッケージ名とディレクトリ構造は変更されません。
- 既存のフィールドの
optionalとrepeatedの修飾子は変更されません。 - 既存のシンボルは削除されません。
上記の保証は、[Beta]とラベル付けされたメッセージとフィールドには適用されないことに注意してください。Betaのメッセージとフィールドは、maturity matrixで定義されているように、より弱い保証の対象になります。
将来のバージョンのOpAMP仕様書は、この仕様書のバージョンで定義されたProtobufスキーマを修正することで拡張されることがあります。以下のProtobufスキーマの変更は、この仕様書の他の箇所で定義されている相互運用性の要件に準拠する限り許可されます。
- 既存のメッセージへの新しいフィールドの追加。
- 新しいメッセージまたはenumの追加。
- 既存のenumへの新しい選択肢の追加。
- 既存のoneofフィールドへの新しい選択肢の追加。
将来の可能性
非常に大量(数百万以上)のAgentを管理する際にServerへの接続数を減らすための中継用プロキシ(Concentrating Proxy)の仕様を定義する。
参考文献
エージェント管理
- SplunkのDeployment Server
- vRealizeのLog Insight Agentsの集中管理設定
- Google CloudのGuest Agentは、HTTPのlong pollingを使用
設定管理
- Uber Flipr
- FacebookのHolistic Configuration Management(push方式)
セキュリティと証明書管理
クラウドプロバイダーのサポート
その他
- Websocket Load Balancing(原文の参考文献リンクは署名付きの一時URLで失効しているため、opamp-specリポジトリの参考文献節を参照してください)