// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: BUSL-1.1 syntax = "proto3"; package hashicorp.consul.internal.peering; import "annotations/ratelimit/ratelimit.proto"; import "google/protobuf/timestamp.proto"; import "private/pbcommon/common.proto"; // PeeringService handles operations for establishing peering relationships // between disparate Consul clusters. service PeeringService { rpc GenerateToken(GenerateTokenRequest) returns (GenerateTokenResponse) { option (hashicorp.consul.internal.ratelimit.spec) = { operation_type: OPERATION_TYPE_WRITE, operation_category: OPERATION_CATEGORY_PEERING }; } rpc Establish(EstablishRequest) returns (EstablishResponse) { option (hashicorp.consul.internal.ratelimit.spec) = { operation_type: OPERATION_TYPE_WRITE, operation_category: OPERATION_CATEGORY_PEERING }; } rpc PeeringRead(PeeringReadRequest) returns (PeeringReadResponse) { option (hashicorp.consul.internal.ratelimit.spec) = { operation_type: OPERATION_TYPE_READ, operation_category: OPERATION_CATEGORY_PEERING }; } rpc PeeringList(PeeringListRequest) returns (PeeringListResponse) { option (hashicorp.consul.internal.ratelimit.spec) = { operation_type: OPERATION_TYPE_READ, operation_category: OPERATION_CATEGORY_PEERING }; } rpc PeeringDelete(PeeringDeleteRequest) returns (PeeringDeleteResponse) { option (hashicorp.consul.internal.ratelimit.spec) = { operation_type: OPERATION_TYPE_WRITE, operation_category: OPERATION_CATEGORY_PEERING }; } // TODO(peering): As of writing, this method is only used in tests to set up Peerings in the state store. // Consider removing if we can find another way to populate state store in peering_endpoint_test.go rpc PeeringWrite(PeeringWriteRequest) returns (PeeringWriteResponse) { option (hashicorp.consul.internal.ratelimit.spec) = { operation_type: OPERATION_TYPE_WRITE, operation_category: OPERATION_CATEGORY_PEERING }; } // TODO(peering): Rename this to PeeredServiceRoots? or something like that? rpc TrustBundleListByService(TrustBundleListByServiceRequest) returns (TrustBundleListByServiceResponse) { option (hashicorp.consul.internal.ratelimit.spec) = { operation_type: OPERATION_TYPE_READ, operation_category: OPERATION_CATEGORY_PEERING }; } rpc TrustBundleRead(TrustBundleReadRequest) returns (TrustBundleReadResponse) { option (hashicorp.consul.internal.ratelimit.spec) = { operation_type: OPERATION_TYPE_READ, operation_category: OPERATION_CATEGORY_PEERING }; } } // PeeringState enumerates all the states a peering can be in. enum PeeringState { // Undefined represents an unset value for PeeringState during // writes. UNDEFINED = 0; // Pending means the peering was created by generating a peering token. // Peerings stay in a pending state until the peer uses the token to dial // the local cluster. PENDING = 1; // Establishing means the peering is being established from a peering token. // This is the initial state for dialing peers. ESTABLISHING = 2; // Active means that the peering connection is active and healthy. ACTIVE = 3; // Failing means the peering connection has been interrupted but has not yet // been terminated. FAILING = 4; // Deleting means a peering was marked for deletion and is in the process // of being deleted. DELETING = 5; // Terminated means the peering relationship has been removed. TERMINATED = 6; } // SecretsWriteRequest encodes a request to write a peering secret as the result // of some operation. Different operations, such as generating a peering token, // lead to modifying the known secrets associated with a peering. message SecretsWriteRequest { // PeerID is the local UUID of the peering this request applies to. string PeerID = 1; oneof Request { GenerateTokenRequest generate_token = 2; ExchangeSecretRequest exchange_secret = 3; PromotePendingRequest promote_pending = 4; EstablishRequest establish = 5; } // GenerateTokenRequest encodes a request to persist a peering establishment // secret. It is triggered by generating a new peering token for a peer cluster. message GenerateTokenRequest { // establishment_secret is the proposed secret ID to store as the establishment // secret for this peering. string establishment_secret = 1; } // ExchangeSecretRequest encodes a request to persist a pending stream secret // secret. It is triggered by an acceptor peer generating a long-lived stream secret // in exchange for an establishment secret. message ExchangeSecretRequest { // establishment_secret is the secret to exchange for the given pending stream secret. string establishment_secret = 1; // pending_stream_secret is the proposed secret ID to store as the pending stream // secret for this peering. string pending_stream_secret = 2; } // PromotePendingRequest encodes a request to promote a pending stream secret // to be an active stream secret. It is triggered when the accepting stream handler // validates an Open request from a peer with a pending stream secret. message PromotePendingRequest { // active_stream_secret is the proposed secret ID to store as the active stream // secret for this peering. string active_stream_secret = 1; } // EstablishRequest encodes a request to persist an active stream secret. // It is triggered after a dialing peer exchanges their establishment secret // for a long-lived active stream secret. message EstablishRequest { // active_stream_secret is the proposed secret ID to store as the active stream // secret for this peering. string active_stream_secret = 1; } } // PeeringSecrets defines a secret used for authenticating/authorizing peer clusters. message PeeringSecrets { // PeerID is the local UUID of the peering this secret was generated for. string PeerID = 1; message Establishment { // SecretID is the one-time-use peering establishment secret. string SecretID = 1; } message Stream { // ActiveSecretID is the active UUID-v4 secret being used for authorization at // the peering stream. string ActiveSecretID = 1; // PendingSecretID is a UUID-v4 secret introduced during secret rotation. // When a peering is established or re-established, both the active secret and // pending secret are considered valid. However, once the dialing peer uses // the pending secret then it transitions to active and the previously active // secret is discarded. // // Pending secret IDs are only valid for long-lived stream secrets. // Only one establishment secret can exist for a peer at a time since they // are designed for one-time use. string PendingSecretID = 2; } Establishment establishment = 2; Stream stream = 3; } // Peering defines a peering relationship between two disparate Consul clusters // // mog annotation: // // target=github.com/hashicorp/consul/api.Peering // output=peering.gen.go // name=API message Peering { // ID is a datacenter-scoped UUID for the peering. // The ID is generated when a peering is first written to the state store. string ID = 1; // Name is the local alias for the peering relationship. string Name = 2; // Partition is the local partition connecting to the peer. string Partition = 3; // DeletedAt is the time when the Peering was marked for deletion // This is nullable so that we can omit if empty when encoding in JSON // mog: func-to=TimePtrFromProto func-from=TimePtrToProto google.protobuf.Timestamp DeletedAt = 4; // Meta is a mapping of some string value to any other string value map Meta = 5; // State is one of the valid PeeringState values to represent the status of // peering relationship. // // mog: func-to=PeeringStateToAPI func-from=PeeringStateFromAPI PeeringState State = 6; // PeerID is the ID that our peer assigned to this peering. // This ID is to be used when dialing the peer, so that it can know who dialed it. string PeerID = 7; // PeerCAPems contains all the CA certificates for the remote peer. repeated string PeerCAPems = 8; // PeerServerName is the name of the remote server as it relates to TLS. string PeerServerName = 9; // PeerServerAddresses contains all the connection addresses for the remote peer. repeated string PeerServerAddresses = 10; // StreamStatus contains information computed on read based on the state of the stream. // // mog: func-to=StreamStatusToAPI func-from=StreamStatusFromAPI StreamStatus StreamStatus = 13; // CreateIndex is the Raft index at which the Peering was created. // @gotags: bexpr:"-" uint64 CreateIndex = 11; // ModifyIndex is the latest Raft index at which the Peering. was modified. // @gotags: bexpr:"-" uint64 ModifyIndex = 12; // Remote contains metadata about the remote peer. RemoteInfo Remote = 17; // ManualServerAddresses provides a list of manually specified server addresses from the // user. If this is defined, then the automatic PeerServerAddresses are ignored. repeated string ManualServerAddresses = 18; } // RemoteInfo contains metadata about the remote peer. // mog annotation: // // target=github.com/hashicorp/consul/api.PeeringRemoteInfo // output=peering.gen.go // name=API message RemoteInfo { // Partition is the remote peer's partition. string Partition = 1; // Datacenter is the remote peer's datacenter. string Datacenter = 2; // Locality identifies where the peer is running. // mog: func-to=LocalityToAPI func-from=LocalityFromAPI common.Locality Locality = 3; } // StreamStatus represents information about an active peering stream. message StreamStatus { // ImportedServices is the list of services imported from this peering. repeated string ImportedServices = 1; // ExportedServices is the list of services exported to this peering. repeated string ExportedServices = 2; // LastHeartbeat represents when the last heartbeat message was received. google.protobuf.Timestamp LastHeartbeat = 3; // LastReceive represents when any message was last received, regardless of success or error. google.protobuf.Timestamp LastReceive = 4; // LastSend represents when any message was last sent, regardless of success or error. google.protobuf.Timestamp LastSend = 5; } // PeeringTrustBundle holds the trust information for validating requests from a peer. message PeeringTrustBundle { // TrustDomain is the domain for the bundle, example.com, foo.bar.gov for example. Note that this must not have a prefix such as "spiffe://". string TrustDomain = 1; // PeerName associates the trust bundle with a peer. string PeerName = 2; // Partition isolates the bundle from other trust bundles in separate local partitions. string Partition = 3; // RootPEMs holds ASN.1 DER encoded X.509 certificate data for the trust bundle. repeated string RootPEMs = 4; // ExportedPartition references the remote partition of the peer // which sent this trust bundle. Used for generating SpiffeIDs. string ExportedPartition = 5; // CreateIndex is the Raft index at which the trust domain was created. // @gotags: bexpr:"-" uint64 CreateIndex = 6; // ModifyIndex is the latest Raft index at which the trust bundle was modified. // @gotags: bexpr:"-" uint64 ModifyIndex = 7; } // PeeringServerAddresses contains the latest snapshot of all known // server addresses for a peer. message PeeringServerAddresses { repeated string Addresses = 1; } message PeeringReadRequest { string Name = 1; string Partition = 2; } message PeeringReadResponse { Peering Peering = 1; } message PeeringListRequest { string Partition = 1; } message PeeringListResponse { repeated Peering Peerings = 1; uint64 OBSOLETE_Index = 2; // Deprecated in favor of gRPC metadata } message PeeringWriteRequest { // Peering is the peering to write with the request. Peering Peering = 1; // SecretsWriteRequest contains the optional peering secrets to persist // with the peering. Peering secrets are not embedded in the peering // object to avoid leaking them. SecretsWriteRequest SecretsRequest = 2; map Meta = 3; } // TODO(peering): Consider returning Peering if we keep this endpoint around message PeeringWriteResponse {} message PeeringDeleteRequest { string Name = 1; string Partition = 2; } message PeeringDeleteResponse {} message TrustBundleListByServiceRequest { string ServiceName = 1; string Namespace = 2; string Partition = 3; string Kind = 4; } message TrustBundleListByServiceResponse { uint64 OBSOLETE_Index = 1; // Deprecated in favor of gRPC metadata repeated PeeringTrustBundle Bundles = 2; } message TrustBundleReadRequest { string Name = 1; string Partition = 2; } message TrustBundleReadResponse { uint64 OBSOLETE_Index = 1; // Deprecated in favor of gRPC metadata PeeringTrustBundle Bundle = 2; } // This is a purely internal type and does not require query metadata. message PeeringTerminateByIDRequest { string ID = 1; } message PeeringTerminateByIDResponse {} message PeeringTrustBundleWriteRequest { PeeringTrustBundle PeeringTrustBundle = 1; } message PeeringTrustBundleWriteResponse {} message PeeringTrustBundleDeleteRequest { string Name = 1; string Partition = 2; } message PeeringTrustBundleDeleteResponse {} // mog annotation: // // target=github.com/hashicorp/consul/api.PeeringGenerateTokenRequest // output=peering.gen.go // name=API message GenerateTokenRequest { // Name of the remote peer. string PeerName = 1; // Partition is the local partition being peered. string Partition = 2; // Meta is a mapping of some string value to any other string value map Meta = 5; // ServerExternalAddresses is a list of addresses to put into the generated token. This could be used to specify // load balancer(s) or external IPs to reach the servers from the dialing side, and will override any server // addresses obtained from the "consul" service. repeated string ServerExternalAddresses = 6; } // mog annotation: // // target=github.com/hashicorp/consul/api.PeeringGenerateTokenResponse // output=peering.gen.go // name=API message GenerateTokenResponse { // PeeringToken is an opaque string provided to the remote peer for it to complete // the peering initialization handshake. string PeeringToken = 1; } // mog annotation: // // target=github.com/hashicorp/consul/api.PeeringEstablishRequest // output=peering.gen.go // name=API message EstablishRequest { // Name of the remote peer. string PeerName = 1; // The peering token returned from the peer's GenerateToken endpoint. string PeeringToken = 2; // Partition is the local partition being peered. string Partition = 3; // Meta is a mapping of some string value to any other string value map Meta = 4; } // mog annotation: // // target=github.com/hashicorp/consul/api.PeeringEstablishResponse // output=peering.gen.go // name=API message EstablishResponse {}