diff --git a/api/gen/proto/go/teleport/workloadidentity/v1/resource.pb.go b/api/gen/proto/go/teleport/workloadidentity/v1/resource.pb.go index 0e1cf64b474e5..7e634f1c46691 100644 --- a/api/gen/proto/go/teleport/workloadidentity/v1/resource.pb.go +++ b/api/gen/proto/go/teleport/workloadidentity/v1/resource.pb.go @@ -24,6 +24,7 @@ import ( v1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + structpb "google.golang.org/protobuf/types/known/structpb" reflect "reflect" sync "sync" ) @@ -675,6 +676,53 @@ func (x *WorkloadIdentitySPIFFEX509) GetSubjectTemplate() *X509DistinguishedName return nil } +// Configuration specific to the issuance of JWT-SVIDs. +type WorkloadIdentitySPIFFEJWT struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Additional claims that will be added to the JWT. + ExtraClaims *structpb.Struct `protobuf:"bytes,1,opt,name=extra_claims,json=extraClaims,proto3" json:"extra_claims,omitempty"` +} + +func (x *WorkloadIdentitySPIFFEJWT) Reset() { + *x = WorkloadIdentitySPIFFEJWT{} + mi := &file_teleport_workloadidentity_v1_resource_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WorkloadIdentitySPIFFEJWT) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WorkloadIdentitySPIFFEJWT) ProtoMessage() {} + +func (x *WorkloadIdentitySPIFFEJWT) ProtoReflect() protoreflect.Message { + mi := &file_teleport_workloadidentity_v1_resource_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WorkloadIdentitySPIFFEJWT.ProtoReflect.Descriptor instead. +func (*WorkloadIdentitySPIFFEJWT) Descriptor() ([]byte, []int) { + return file_teleport_workloadidentity_v1_resource_proto_rawDescGZIP(), []int{10} +} + +func (x *WorkloadIdentitySPIFFEJWT) GetExtraClaims() *structpb.Struct { + if x != nil { + return x.ExtraClaims + } + return nil +} + // Configuration pertaining to the issuance of SPIFFE-compatible workload // identity credentials. type WorkloadIdentitySPIFFE struct { @@ -694,11 +742,13 @@ type WorkloadIdentitySPIFFE struct { Hint string `protobuf:"bytes,2,opt,name=hint,proto3" json:"hint,omitempty"` // Configuration specific to X509-SVIDs. X509 *WorkloadIdentitySPIFFEX509 `protobuf:"bytes,3,opt,name=x509,proto3" json:"x509,omitempty"` + // Configuration specific to JWT-SVIDs. + Jwt *WorkloadIdentitySPIFFEJWT `protobuf:"bytes,4,opt,name=jwt,proto3" json:"jwt,omitempty"` } func (x *WorkloadIdentitySPIFFE) Reset() { *x = WorkloadIdentitySPIFFE{} - mi := &file_teleport_workloadidentity_v1_resource_proto_msgTypes[10] + mi := &file_teleport_workloadidentity_v1_resource_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -710,7 +760,7 @@ func (x *WorkloadIdentitySPIFFE) String() string { func (*WorkloadIdentitySPIFFE) ProtoMessage() {} func (x *WorkloadIdentitySPIFFE) ProtoReflect() protoreflect.Message { - mi := &file_teleport_workloadidentity_v1_resource_proto_msgTypes[10] + mi := &file_teleport_workloadidentity_v1_resource_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -723,7 +773,7 @@ func (x *WorkloadIdentitySPIFFE) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkloadIdentitySPIFFE.ProtoReflect.Descriptor instead. func (*WorkloadIdentitySPIFFE) Descriptor() ([]byte, []int) { - return file_teleport_workloadidentity_v1_resource_proto_rawDescGZIP(), []int{10} + return file_teleport_workloadidentity_v1_resource_proto_rawDescGZIP(), []int{11} } func (x *WorkloadIdentitySPIFFE) GetId() string { @@ -747,6 +797,13 @@ func (x *WorkloadIdentitySPIFFE) GetX509() *WorkloadIdentitySPIFFEX509 { return nil } +func (x *WorkloadIdentitySPIFFE) GetJwt() *WorkloadIdentitySPIFFEJWT { + if x != nil { + return x.Jwt + } + return nil +} + // The spec for the WorkloadIdentity resource. type WorkloadIdentitySpec struct { state protoimpl.MessageState @@ -762,7 +819,7 @@ type WorkloadIdentitySpec struct { func (x *WorkloadIdentitySpec) Reset() { *x = WorkloadIdentitySpec{} - mi := &file_teleport_workloadidentity_v1_resource_proto_msgTypes[11] + mi := &file_teleport_workloadidentity_v1_resource_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -774,7 +831,7 @@ func (x *WorkloadIdentitySpec) String() string { func (*WorkloadIdentitySpec) ProtoMessage() {} func (x *WorkloadIdentitySpec) ProtoReflect() protoreflect.Message { - mi := &file_teleport_workloadidentity_v1_resource_proto_msgTypes[11] + mi := &file_teleport_workloadidentity_v1_resource_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -787,7 +844,7 @@ func (x *WorkloadIdentitySpec) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkloadIdentitySpec.ProtoReflect.Descriptor instead. func (*WorkloadIdentitySpec) Descriptor() ([]byte, []int) { - return file_teleport_workloadidentity_v1_resource_proto_rawDescGZIP(), []int{11} + return file_teleport_workloadidentity_v1_resource_proto_rawDescGZIP(), []int{12} } func (x *WorkloadIdentitySpec) GetRules() *WorkloadIdentityRules { @@ -811,125 +868,137 @@ var file_teleport_workloadidentity_v1_resource_proto_rawDesc = []byte{ 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x1a, 0x21, 0x74, 0x65, 0x6c, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x2f, - 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xdd, - 0x01, 0x0a, 0x10, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x75, 0x62, 0x5f, 0x6b, - 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x4b, 0x69, - 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x08, - 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x46, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, - 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, 0x33, - 0x0a, 0x1b, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x71, 0x12, 0x14, 0x0a, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x22, 0x36, 0x0a, 0x1e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x4e, 0x6f, 0x74, 0x45, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x35, 0x0a, 0x1b, 0x57, - 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, - 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x73, 0x22, 0x38, 0x0a, 0x1e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4e, - 0x6f, 0x74, 0x49, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x9b, 0x03, 0x0a, - 0x19, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x4b, 0x0a, 0x02, 0x65, 0x71, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, - 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x71, 0x48, - 0x00, 0x52, 0x02, 0x65, 0x71, 0x12, 0x55, 0x0a, 0x06, 0x6e, 0x6f, 0x74, 0x5f, 0x65, 0x71, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, + 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xdd, 0x01, 0x0a, + 0x10, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x75, 0x62, 0x5f, 0x6b, 0x69, 0x6e, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x4b, 0x69, 0x6e, 0x64, + 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x76, + 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x12, 0x46, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x77, 0x6f, + 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x76, + 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, 0x33, 0x0a, 0x1b, + 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x22, 0x36, 0x0a, 0x1e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, - 0x74, 0x45, 0x71, 0x48, 0x00, 0x52, 0x05, 0x6e, 0x6f, 0x74, 0x45, 0x71, 0x12, 0x4b, 0x0a, 0x02, - 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, - 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x6e, 0x48, 0x00, 0x52, 0x02, 0x69, 0x6e, 0x12, 0x55, 0x0a, 0x06, 0x6e, 0x6f, 0x74, - 0x5f, 0x69, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, - 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x49, 0x6e, 0x48, 0x00, 0x52, 0x05, 0x6e, 0x6f, 0x74, 0x49, 0x6e, - 0x42, 0x0a, 0x0a, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x4a, 0x04, 0x08, 0x02, - 0x10, 0x03, 0x52, 0x06, 0x65, 0x71, 0x75, 0x61, 0x6c, 0x73, 0x22, 0x8f, 0x01, 0x0a, 0x14, 0x57, - 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, - 0x75, 0x6c, 0x65, 0x12, 0x57, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x74, 0x45, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x35, 0x0a, 0x1b, 0x57, 0x6f, 0x72, + 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, + 0x22, 0x38, 0x0a, 0x1e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, + 0x49, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x9b, 0x03, 0x0a, 0x19, 0x57, + 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, + 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x74, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x4b, 0x0a, 0x02, 0x65, 0x71, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x77, 0x6f, + 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x76, + 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x71, 0x48, 0x00, 0x52, + 0x02, 0x65, 0x71, 0x12, 0x55, 0x0a, 0x06, 0x6e, 0x6f, 0x74, 0x5f, 0x65, 0x71, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x77, + 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, + 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x45, + 0x71, 0x48, 0x00, 0x52, 0x05, 0x6e, 0x6f, 0x74, 0x45, 0x71, 0x12, 0x4b, 0x0a, 0x02, 0x69, 0x6e, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x6e, 0x48, 0x00, 0x52, 0x02, 0x69, 0x6e, 0x12, 0x55, 0x0a, 0x06, 0x6e, 0x6f, 0x74, 0x5f, 0x69, + 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x0a, 0x0a, - 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x61, 0x0a, 0x15, - 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x48, 0x0a, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, - 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x22, - 0x95, 0x01, 0x0a, 0x1d, 0x58, 0x35, 0x30, 0x39, 0x44, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x75, - 0x69, 0x73, 0x68, 0x65, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, - 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2f, 0x0a, 0x13, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x12, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x61, 0x6c, 0x55, 0x6e, 0x69, 0x74, 0x22, 0x9f, 0x01, 0x0a, 0x1a, 0x57, 0x6f, 0x72, 0x6b, - 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x50, 0x49, 0x46, - 0x46, 0x45, 0x58, 0x35, 0x30, 0x39, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x6e, 0x73, 0x5f, 0x73, 0x61, - 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x64, 0x6e, 0x73, 0x53, 0x61, 0x6e, - 0x73, 0x12, 0x66, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x65, 0x6d, - 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x69, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x58, 0x35, 0x30, 0x39, 0x44, - 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, 0x65, 0x64, 0x4e, 0x61, 0x6d, 0x65, - 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x22, 0x8a, 0x01, 0x0a, 0x16, 0x57, 0x6f, - 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x50, - 0x49, 0x46, 0x46, 0x45, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x68, 0x69, 0x6e, 0x74, 0x12, 0x4c, 0x0a, 0x04, 0x78, 0x35, 0x30, 0x39, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x58, 0x35, 0x30, 0x39, - 0x52, 0x04, 0x78, 0x35, 0x30, 0x39, 0x22, 0xaf, 0x01, 0x0a, 0x14, 0x57, 0x6f, 0x72, 0x6b, 0x6c, - 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x70, 0x65, 0x63, 0x12, - 0x49, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, - 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, + 0x4e, 0x6f, 0x74, 0x49, 0x6e, 0x48, 0x00, 0x52, 0x05, 0x6e, 0x6f, 0x74, 0x49, 0x6e, 0x42, 0x0a, + 0x0a, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, + 0x52, 0x06, 0x65, 0x71, 0x75, 0x61, 0x6c, 0x73, 0x22, 0x8f, 0x01, 0x0a, 0x14, 0x57, 0x6f, 0x72, + 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x75, 0x6c, + 0x65, 0x12, 0x57, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, + 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x61, 0x0a, 0x15, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x75, - 0x6c, 0x65, 0x73, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x4c, 0x0a, 0x06, 0x73, 0x70, - 0x69, 0x66, 0x66, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x74, 0x65, 0x6c, + 0x6c, 0x65, 0x73, 0x12, 0x48, 0x0a, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x77, 0x6f, + 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x76, + 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x22, 0x95, 0x01, + 0x0a, 0x1d, 0x58, 0x35, 0x30, 0x39, 0x44, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x75, 0x69, 0x73, + 0x68, 0x65, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, + 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x22, 0x0a, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2f, 0x0a, 0x13, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x12, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, + 0x6c, 0x55, 0x6e, 0x69, 0x74, 0x22, 0x9f, 0x01, 0x0a, 0x1a, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, + 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, + 0x58, 0x35, 0x30, 0x39, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x6e, 0x73, 0x5f, 0x73, 0x61, 0x6e, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x64, 0x6e, 0x73, 0x53, 0x61, 0x6e, 0x73, 0x12, + 0x66, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x58, 0x35, 0x30, 0x39, 0x44, 0x69, 0x73, + 0x74, 0x69, 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, 0x65, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x54, 0x65, + 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x22, 0x57, 0x0a, 0x19, 0x57, 0x6f, 0x72, 0x6b, 0x6c, + 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x50, 0x49, 0x46, 0x46, + 0x45, 0x4a, 0x57, 0x54, 0x12, 0x3a, 0x0a, 0x0c, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x63, 0x6c, + 0x61, 0x69, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, + 0x75, 0x63, 0x74, 0x52, 0x0b, 0x65, 0x78, 0x74, 0x72, 0x61, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x73, + 0x22, 0xd5, 0x01, 0x0a, 0x16, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x68, + 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x69, 0x6e, 0x74, 0x12, + 0x4c, 0x0a, 0x04, 0x78, 0x35, 0x30, 0x39, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, + 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, + 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x50, 0x49, + 0x46, 0x46, 0x45, 0x58, 0x35, 0x30, 0x39, 0x52, 0x04, 0x78, 0x35, 0x30, 0x39, 0x12, 0x49, 0x0a, + 0x03, 0x6a, 0x77, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, - 0x52, 0x06, 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x42, 0x64, 0x5a, 0x62, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x76, 0x31, 0x3b, 0x77, 0x6f, 0x72, 0x6b, - 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x76, 0x31, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x4a, 0x57, 0x54, 0x52, 0x03, 0x6a, 0x77, 0x74, 0x22, 0xaf, 0x01, 0x0a, 0x14, 0x57, 0x6f, 0x72, + 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x70, 0x65, + 0x63, 0x12, 0x49, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x6b, + 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, + 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x52, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x4c, 0x0a, 0x06, + 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, + 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x50, 0x49, 0x46, + 0x46, 0x45, 0x52, 0x06, 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x42, 0x64, 0x5a, 0x62, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, + 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, + 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x76, 0x31, 0x3b, 0x77, 0x6f, + 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x76, 0x31, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -944,7 +1013,7 @@ func file_teleport_workloadidentity_v1_resource_proto_rawDescGZIP() []byte { return file_teleport_workloadidentity_v1_resource_proto_rawDescData } -var file_teleport_workloadidentity_v1_resource_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_teleport_workloadidentity_v1_resource_proto_msgTypes = make([]protoimpl.MessageInfo, 13) var file_teleport_workloadidentity_v1_resource_proto_goTypes = []any{ (*WorkloadIdentity)(nil), // 0: teleport.workloadidentity.v1.WorkloadIdentity (*WorkloadIdentityConditionEq)(nil), // 1: teleport.workloadidentity.v1.WorkloadIdentityConditionEq @@ -956,13 +1025,15 @@ var file_teleport_workloadidentity_v1_resource_proto_goTypes = []any{ (*WorkloadIdentityRules)(nil), // 7: teleport.workloadidentity.v1.WorkloadIdentityRules (*X509DistinguishedNameTemplate)(nil), // 8: teleport.workloadidentity.v1.X509DistinguishedNameTemplate (*WorkloadIdentitySPIFFEX509)(nil), // 9: teleport.workloadidentity.v1.WorkloadIdentitySPIFFEX509 - (*WorkloadIdentitySPIFFE)(nil), // 10: teleport.workloadidentity.v1.WorkloadIdentitySPIFFE - (*WorkloadIdentitySpec)(nil), // 11: teleport.workloadidentity.v1.WorkloadIdentitySpec - (*v1.Metadata)(nil), // 12: teleport.header.v1.Metadata + (*WorkloadIdentitySPIFFEJWT)(nil), // 10: teleport.workloadidentity.v1.WorkloadIdentitySPIFFEJWT + (*WorkloadIdentitySPIFFE)(nil), // 11: teleport.workloadidentity.v1.WorkloadIdentitySPIFFE + (*WorkloadIdentitySpec)(nil), // 12: teleport.workloadidentity.v1.WorkloadIdentitySpec + (*v1.Metadata)(nil), // 13: teleport.header.v1.Metadata + (*structpb.Struct)(nil), // 14: google.protobuf.Struct } var file_teleport_workloadidentity_v1_resource_proto_depIdxs = []int32{ - 12, // 0: teleport.workloadidentity.v1.WorkloadIdentity.metadata:type_name -> teleport.header.v1.Metadata - 11, // 1: teleport.workloadidentity.v1.WorkloadIdentity.spec:type_name -> teleport.workloadidentity.v1.WorkloadIdentitySpec + 13, // 0: teleport.workloadidentity.v1.WorkloadIdentity.metadata:type_name -> teleport.header.v1.Metadata + 12, // 1: teleport.workloadidentity.v1.WorkloadIdentity.spec:type_name -> teleport.workloadidentity.v1.WorkloadIdentitySpec 1, // 2: teleport.workloadidentity.v1.WorkloadIdentityCondition.eq:type_name -> teleport.workloadidentity.v1.WorkloadIdentityConditionEq 2, // 3: teleport.workloadidentity.v1.WorkloadIdentityCondition.not_eq:type_name -> teleport.workloadidentity.v1.WorkloadIdentityConditionNotEq 3, // 4: teleport.workloadidentity.v1.WorkloadIdentityCondition.in:type_name -> teleport.workloadidentity.v1.WorkloadIdentityConditionIn @@ -970,14 +1041,16 @@ var file_teleport_workloadidentity_v1_resource_proto_depIdxs = []int32{ 5, // 6: teleport.workloadidentity.v1.WorkloadIdentityRule.conditions:type_name -> teleport.workloadidentity.v1.WorkloadIdentityCondition 6, // 7: teleport.workloadidentity.v1.WorkloadIdentityRules.allow:type_name -> teleport.workloadidentity.v1.WorkloadIdentityRule 8, // 8: teleport.workloadidentity.v1.WorkloadIdentitySPIFFEX509.subject_template:type_name -> teleport.workloadidentity.v1.X509DistinguishedNameTemplate - 9, // 9: teleport.workloadidentity.v1.WorkloadIdentitySPIFFE.x509:type_name -> teleport.workloadidentity.v1.WorkloadIdentitySPIFFEX509 - 7, // 10: teleport.workloadidentity.v1.WorkloadIdentitySpec.rules:type_name -> teleport.workloadidentity.v1.WorkloadIdentityRules - 10, // 11: teleport.workloadidentity.v1.WorkloadIdentitySpec.spiffe:type_name -> teleport.workloadidentity.v1.WorkloadIdentitySPIFFE - 12, // [12:12] is the sub-list for method output_type - 12, // [12:12] is the sub-list for method input_type - 12, // [12:12] is the sub-list for extension type_name - 12, // [12:12] is the sub-list for extension extendee - 0, // [0:12] is the sub-list for field type_name + 14, // 9: teleport.workloadidentity.v1.WorkloadIdentitySPIFFEJWT.extra_claims:type_name -> google.protobuf.Struct + 9, // 10: teleport.workloadidentity.v1.WorkloadIdentitySPIFFE.x509:type_name -> teleport.workloadidentity.v1.WorkloadIdentitySPIFFEX509 + 10, // 11: teleport.workloadidentity.v1.WorkloadIdentitySPIFFE.jwt:type_name -> teleport.workloadidentity.v1.WorkloadIdentitySPIFFEJWT + 7, // 12: teleport.workloadidentity.v1.WorkloadIdentitySpec.rules:type_name -> teleport.workloadidentity.v1.WorkloadIdentityRules + 11, // 13: teleport.workloadidentity.v1.WorkloadIdentitySpec.spiffe:type_name -> teleport.workloadidentity.v1.WorkloadIdentitySPIFFE + 14, // [14:14] is the sub-list for method output_type + 14, // [14:14] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name } func init() { file_teleport_workloadidentity_v1_resource_proto_init() } @@ -997,7 +1070,7 @@ func file_teleport_workloadidentity_v1_resource_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_teleport_workloadidentity_v1_resource_proto_rawDesc, NumEnums: 0, - NumMessages: 12, + NumMessages: 13, NumExtensions: 0, NumServices: 0, }, diff --git a/api/proto/teleport/workloadidentity/v1/resource.proto b/api/proto/teleport/workloadidentity/v1/resource.proto index abf314a5cd4fb..3068b26bc6aee 100644 --- a/api/proto/teleport/workloadidentity/v1/resource.proto +++ b/api/proto/teleport/workloadidentity/v1/resource.proto @@ -16,6 +16,7 @@ syntax = "proto3"; package teleport.workloadidentity.v1; +import "google/protobuf/struct.proto"; import "teleport/header/v1/metadata.proto"; option go_package = "github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1;workloadidentityv1"; @@ -134,6 +135,12 @@ message WorkloadIdentitySPIFFEX509 { X509DistinguishedNameTemplate subject_template = 2; } +// Configuration specific to the issuance of JWT-SVIDs. +message WorkloadIdentitySPIFFEJWT { + // Additional claims that will be added to the JWT. + google.protobuf.Struct extra_claims = 1; +} + // Configuration pertaining to the issuance of SPIFFE-compatible workload // identity credentials. message WorkloadIdentitySPIFFE { @@ -149,6 +156,8 @@ message WorkloadIdentitySPIFFE { string hint = 2; // Configuration specific to X509-SVIDs. WorkloadIdentitySPIFFEX509 x509 = 3; + // Configuration specific to JWT-SVIDs. + WorkloadIdentitySPIFFEJWT jwt = 4; } // The spec for the WorkloadIdentity resource. diff --git a/integrations/terraform/protoc-gen-terraform-workloadidentity.yaml b/integrations/terraform/protoc-gen-terraform-workloadidentity.yaml index 016f3209037ba..0796fb645e2e7 100644 --- a/integrations/terraform/protoc-gen-terraform-workloadidentity.yaml +++ b/integrations/terraform/protoc-gen-terraform-workloadidentity.yaml @@ -36,6 +36,14 @@ exclude_fields: # Metadata (we id resources by name on our side) - "WorkloadIdentity.metadata.id" + # The extra_claims field is a `google.protobuf.Struct` which isn't currently + # supported by protoc-gen-terraform. We omit the entire jwt message because + # there are no other fields so the generated code contains an unused variable + # declaration otherwise. + # + # https://github.com/gravitational/protoc-gen-terraform/issues/52 + - "WorkloadIdentity.spec.spiffe.jwt" + # These fields will be marked as Computed: true computed_fields: # Metadata diff --git a/integrations/terraform/tfschema/workloadidentity/v1/resource_terraform.go b/integrations/terraform/tfschema/workloadidentity/v1/resource_terraform.go index 885c773fbdf62..5b324f6b12c5b 100644 --- a/integrations/terraform/tfschema/workloadidentity/v1/resource_terraform.go +++ b/integrations/terraform/tfschema/workloadidentity/v1/resource_terraform.go @@ -33,6 +33,7 @@ import ( github_com_hashicorp_terraform_plugin_framework_tfsdk "github.com/hashicorp/terraform-plugin-framework/tfsdk" github_com_hashicorp_terraform_plugin_framework_types "github.com/hashicorp/terraform-plugin-framework/types" github_com_hashicorp_terraform_plugin_go_tftypes "github.com/hashicorp/terraform-plugin-go/tftypes" + _ "google.golang.org/protobuf/types/known/structpb" ) // Reference imports to suppress errors if they are not otherwise used. diff --git a/lib/auth/machineid/workloadidentityv1/decision.go b/lib/auth/machineid/workloadidentityv1/decision.go index 28da3b47ed9ca..c307e362c1d7a 100644 --- a/lib/auth/machineid/workloadidentityv1/decision.go +++ b/lib/auth/machineid/workloadidentityv1/decision.go @@ -18,12 +18,14 @@ package workloadidentityv1 import ( "context" + "fmt" "slices" "strings" "github.com/gravitational/trace" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/types/known/structpb" workloadidentityv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1" "github.com/gravitational/teleport/lib/auth/machineid/workloadidentityv1/expression" @@ -118,6 +120,18 @@ func decide( dst.OrganizationalUnit = templated } + if ec := wi.GetSpec().GetSpiffe().GetJwt().GetExtraClaims(); ec != nil { + templated, err := templateExtraClaims(ec, attrs) + if err != nil { + d.reason = trace.Wrap( + err, + "templating spec.spiffe.jwt.extra_claims", + ) + return d + } + d.templatedWorkloadIdentity.Spec.Spiffe.Jwt.ExtraClaims = templated + } + // Yay - made it to the end! d.shouldIssue = true return d @@ -219,3 +233,67 @@ ruleLoop: // TODO: Eventually, we'll need to work support for deny rules into here. return trace.AccessDenied("no matching rule found") } + +func templateExtraClaims(templates *structpb.Struct, attrs *workloadidentityv1pb.Attrs) (*structpb.Struct, error) { + // render is called recursively on list elements and struct fields. + var render func(string, *structpb.Value, int) (*structpb.Value, error) + + const maxDepth = 10 + render = func(fieldName string, fieldValue *structpb.Value, depth int) (*structpb.Value, error) { + if depth >= maxDepth { + return nil, trace.BadParameter("extra_claims cannot contain more than %d levels of nesting", maxDepth) + } + + switch value := fieldValue.GetKind().(type) { + // Numbers, booleans, and nulls can be emitted as-is. + case *structpb.Value_NumberValue, *structpb.Value_BoolValue, *structpb.Value_NullValue: + return fieldValue, nil + + // We treat string values as templates. + case *structpb.Value_StringValue: + renderedString, err := expression.RenderTemplate(value.StringValue, attrs) + if err != nil { + return nil, trace.Wrap(err, "templating claim: %s", fieldName) + } + return structpb.NewStringValue(renderedString), nil + + // For struct values, we call render on each of their fields. + case *structpb.Value_StructValue: + result := &structpb.Struct{Fields: make(map[string]*structpb.Value)} + for structKey, structValue := range value.StructValue.GetFields() { + keyWithPrefix := structKey + if fieldName != "" { + keyWithPrefix = fmt.Sprintf("%s.%s", fieldName, structKey) + } + v, err := render(keyWithPrefix, structValue, depth+1) + if err != nil { + return nil, err + } + result.Fields[structKey] = v + } + return structpb.NewStructValue(result), nil + + // For list values, we call render on each of their elements. + case *structpb.Value_ListValue: + result := new(structpb.ListValue) + for idx, val := range value.ListValue.GetValues() { + v, err := render(fmt.Sprintf("%s[%d]", fieldName, idx), val, depth+1) + if err != nil { + return nil, err + } + result.Values = append(result.Values, v) + } + return structpb.NewListValue(result), nil + + // At the time of writing, there are no other possible value types. + default: + return nil, trace.Errorf("unsupported field type: %T", value) + } + } + + result, err := render("", structpb.NewStructValue(templates), 0) + if err != nil { + return nil, err + } + return result.GetStructValue(), nil +} diff --git a/lib/auth/machineid/workloadidentityv1/decision_test.go b/lib/auth/machineid/workloadidentityv1/decision_test.go index e4ebc2cb4d116..3ae9bdb5cd859 100644 --- a/lib/auth/machineid/workloadidentityv1/decision_test.go +++ b/lib/auth/machineid/workloadidentityv1/decision_test.go @@ -18,9 +18,13 @@ package workloadidentityv1 import ( "context" + "encoding/json" "testing" + "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/require" + "google.golang.org/protobuf/testing/protocmp" + "google.golang.org/protobuf/types/known/structpb" headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" workloadidentityv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1" @@ -401,3 +405,117 @@ func Test_evaluateRules(t *testing.T) { }) } } + +func TestTemplateExtraClaims_Success(t *testing.T) { + const inputJSON = ` + { + "simple-string": "hello world", + "simple-number": 1234, + "simple-bool": true, + "null": null, + "object": { + "message": "hello, {{user.name}}", + "workload": { + "podman": { + "pod_name": "{{workload.podman.pod.name}}", + "labels": ["{{workload.podman.pod.labels[\"a\"]}}", "{{workload.podman.pod.labels[\"b\"]}}", "c"] + } + } + } + } + ` + + const expectedOutputJSON = ` + { + "simple-string": "hello world", + "simple-number": 1234, + "simple-bool": true, + "null": null, + "object": { + "message": "hello, Bobby", + "workload": { + "podman": { + "pod_name": "webserver", + "labels": ["a", "b", "c"] + } + } + } + } + ` + + var input, expectedOutput *structpb.Struct + err := json.Unmarshal([]byte(inputJSON), &input) + require.NoError(t, err) + + err = json.Unmarshal([]byte(expectedOutputJSON), &expectedOutput) + require.NoError(t, err) + + output, err := templateExtraClaims(input, &workloadidentityv1pb.Attrs{ + User: &workloadidentityv1pb.UserAttrs{ + Name: "Bobby", + }, + Workload: &workloadidentityv1pb.WorkloadAttrs{ + Podman: &workloadidentityv1pb.WorkloadAttrsPodman{ + Pod: &workloadidentityv1pb.WorkloadAttrsPodmanPod{ + Name: "webserver", + Labels: map[string]string{"a": "a", "b": "b"}, + }, + }, + }, + }) + require.NoError(t, err) + require.Empty(t, cmp.Diff(expectedOutput, output, protocmp.Transform())) +} + +func TestTemplateExtraClaims_Failure(t *testing.T) { + const claimsJSON = ` + { + "foo": { + "bar": { + "baz": ["a", {"b":"{{blah}}"}, "c"] + } + } + } + ` + + var rawClaims *structpb.Struct + err := json.Unmarshal([]byte(claimsJSON), &rawClaims) + require.NoError(t, err) + + _, err = templateExtraClaims(rawClaims, &workloadidentityv1pb.Attrs{}) + require.ErrorContains(t, err, "templating claim: foo.bar.baz[1].b") + require.ErrorContains(t, err, `unknown identifier: "blah"`) +} + +func TestTemplateExtraClaims_TooDeeplyNested(t *testing.T) { + const claimsJSON = ` + { + "1": { + "2": { + "3": { + "4": { + "5": { + "6": { + "7": { + "8": { + "9": { + "10": "very deep" + } + } + } + } + } + } + } + } + } + } + ` + + var rawClaims *structpb.Struct + err := json.Unmarshal([]byte(claimsJSON), &rawClaims) + require.NoError(t, err) + + _, err = templateExtraClaims(rawClaims, &workloadidentityv1pb.Attrs{}) + require.ErrorContains(t, err, "cannot contain more than 10 levels of nesting") +} diff --git a/lib/auth/machineid/workloadidentityv1/issuer_service.go b/lib/auth/machineid/workloadidentityv1/issuer_service.go index cb64207395bef..e101f23c13099 100644 --- a/lib/auth/machineid/workloadidentityv1/issuer_service.go +++ b/lib/auth/machineid/workloadidentityv1/issuer_service.go @@ -627,6 +627,8 @@ func (s *IssuanceService) issueJWTSVID( SetIssuedAt: now, SetExpiry: notAfter, + + PrivateClaims: wid.GetSpec().GetSpiffe().GetJwt().GetExtraClaims().AsMap(), }) if err != nil { return nil, trace.Wrap(err, "signing jwt") diff --git a/lib/auth/machineid/workloadidentityv1/workloadidentityv1_test.go b/lib/auth/machineid/workloadidentityv1/workloadidentityv1_test.go index f0e2d98473a9c..354ebcb35783b 100644 --- a/lib/auth/machineid/workloadidentityv1/workloadidentityv1_test.go +++ b/lib/auth/machineid/workloadidentityv1/workloadidentityv1_test.go @@ -41,6 +41,7 @@ import ( "google.golang.org/protobuf/proto" "google.golang.org/protobuf/testing/protocmp" "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/timestamppb" apiproto "github.com/gravitational/teleport/api/client/proto" @@ -466,6 +467,31 @@ func TestIssueWorkloadIdentity(t *testing.T) { }) require.NoError(t, err) + extraClaimTemplates, err := structpb.NewStruct(map[string]any{ + "user_name": "{{user.name}}", + "k8s": map[string]any{ + "names": []any{"{{workload.kubernetes.pod_name}}"}, + }, + }) + require.NoError(t, err) + + extraClaims, err := tp.srv.Auth().CreateWorkloadIdentity(ctx, &workloadidentityv1pb.WorkloadIdentity{ + Kind: types.KindWorkloadIdentity, + Version: types.V1, + Metadata: &headerv1.Metadata{ + Name: "extra-claims", + }, + Spec: &workloadidentityv1pb.WorkloadIdentitySpec{ + Spiffe: &workloadidentityv1pb.WorkloadIdentitySPIFFE{ + Id: "/foo", + Jwt: &workloadidentityv1pb.WorkloadIdentitySPIFFEJWT{ + ExtraClaims: extraClaimTemplates, + }, + }, + }, + }) + require.NoError(t, err) + workloadAttrs := func(f func(attrs *workloadidentityv1pb.WorkloadAttrs)) *workloadidentityv1pb.WorkloadAttrs { attrs := &workloadidentityv1pb.WorkloadAttrs{ Kubernetes: &workloadidentityv1pb.WorkloadAttrsKubernetes{ @@ -577,6 +603,35 @@ func TestIssueWorkloadIdentity(t *testing.T) { )) }, }, + { + name: "jwt svid - extra claims", + client: wilcardAccessClient, + req: &workloadidentityv1pb.IssueWorkloadIdentityRequest{ + Name: extraClaims.GetMetadata().GetName(), + Credential: &workloadidentityv1pb.IssueWorkloadIdentityRequest_JwtSvidParams{ + JwtSvidParams: &workloadidentityv1pb.JWTSVIDParams{ + Audiences: []string{"example.com"}, + }, + }, + WorkloadAttrs: workloadAttrs(nil), + }, + requireErr: require.NoError, + assert: func(t *testing.T, res *workloadidentityv1pb.IssueWorkloadIdentityResponse) { + parsed, err := jwt.ParseSigned(res.GetCredential().GetJwtSvid().GetJwt()) + require.NoError(t, err) + + var claims struct { + UserName string `json:"user_name"` + K8s struct { + Names []string `json:"names"` + } `json:"k8s"` + } + err = parsed.Claims(tp.spiffeJWTSigner.Public(), &claims) + require.NoError(t, err) + require.Equal(t, "dog", claims.UserName) + require.Equal(t, []string{"test"}, claims.K8s.Names) + }, + }, { name: "x509 svid", client: wilcardAccessClient, diff --git a/lib/jwt/jwt.go b/lib/jwt/jwt.go index 5afe58f20d96a..8bf50ba3b8f5e 100644 --- a/lib/jwt/jwt.go +++ b/lib/jwt/jwt.go @@ -285,6 +285,9 @@ type SignParamsJWTSVID struct { SetExpiry time.Time // SetIssuedAt overrides the issued at time of the token. SetIssuedAt time.Time + + // PrivateClaims are any additional claims that should be added to the JWT. + PrivateClaims map[string]any } // SignJWTSVID signs a JWT SVID token. @@ -343,7 +346,34 @@ func (k *Key) SignJWTSVID(p SignParamsJWTSVID) (string, error) { // We will omit the inclusion of the type header until we can validate the // ramifications of including it. - return k.sign(claims, opts) + // > 3. JWT Claims: + // + // > Registered claims not described in this document, in addition to + // > private claims, MAY be used as implementers see fit. + var rawClaims any = claims + if len(p.PrivateClaims) != 0 { + // This is slightly awkward. We take a round-trip through json.Marshal + // and json.Unmarshal to get a version of the claims we can add to. + marshaled, err := json.Marshal(rawClaims) + if err != nil { + return "", trace.Wrap(err, "marshaling claims") + } + var unmarshaled map[string]any + if err := json.Unmarshal(marshaled, &unmarshaled); err != nil { + return "", trace.Wrap(err, "unmarshaling claims") + } + + // Only inject claims that don't conflict with an existing primary claim + // such as sub or aud. + for k, v := range p.PrivateClaims { + if _, ok := unmarshaled[k]; !ok { + unmarshaled[k] = v + } + } + rawClaims = unmarshaled + } + + return k.sign(rawClaims, opts) } // SignEntraOIDC signs a JWT for the Entra ID Integration.