diff --git a/api/gen/proto/go/teleport/decision/v1alpha1/ssh_identity.pb.go b/api/gen/proto/go/teleport/decision/v1alpha1/ssh_identity.pb.go index afd8582b4e39d..8e47b7ca4109f 100644 --- a/api/gen/proto/go/teleport/decision/v1alpha1/ssh_identity.pb.go +++ b/api/gen/proto/go/teleport/decision/v1alpha1/ssh_identity.pb.go @@ -21,8 +21,10 @@ package decisionpb import ( + v1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/trait/v1" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" unsafe "unsafe" @@ -35,11 +37,199 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// CertExtensionMode specifies the type of extension to use in the cert. This type +// must be kept up to date with types.CertExtensionMode. +type CertExtensionMode int32 + +const ( + // CERT_EXTENSION_MODE_UNSPECIFIED is the default value and should not be used. + CertExtensionMode_CERT_EXTENSION_MODE_UNSPECIFIED CertExtensionMode = 0 + // EXTENSION represents a cert extension that may or may not be + // honored by the server. + CertExtensionMode_CERT_EXTENSION_MODE_EXTENSION CertExtensionMode = 1 +) + +// Enum value maps for CertExtensionMode. +var ( + CertExtensionMode_name = map[int32]string{ + 0: "CERT_EXTENSION_MODE_UNSPECIFIED", + 1: "CERT_EXTENSION_MODE_EXTENSION", + } + CertExtensionMode_value = map[string]int32{ + "CERT_EXTENSION_MODE_UNSPECIFIED": 0, + "CERT_EXTENSION_MODE_EXTENSION": 1, + } +) + +func (x CertExtensionMode) Enum() *CertExtensionMode { + p := new(CertExtensionMode) + *p = x + return p +} + +func (x CertExtensionMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CertExtensionMode) Descriptor() protoreflect.EnumDescriptor { + return file_teleport_decision_v1alpha1_ssh_identity_proto_enumTypes[0].Descriptor() +} + +func (CertExtensionMode) Type() protoreflect.EnumType { + return &file_teleport_decision_v1alpha1_ssh_identity_proto_enumTypes[0] +} + +func (x CertExtensionMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CertExtensionMode.Descriptor instead. +func (CertExtensionMode) EnumDescriptor() ([]byte, []int) { + return file_teleport_decision_v1alpha1_ssh_identity_proto_rawDescGZIP(), []int{0} +} + +// CertExtensionType represents the certificate type the extension is for. +// Currently only ssh is supported. This type must be kept up to date with +// types.CertExtensionType. +type CertExtensionType int32 + +const ( + // CERT_EXTENSION_TYPE_UNSPECIFIED is the default value and should not be used. + CertExtensionType_CERT_EXTENSION_TYPE_UNSPECIFIED CertExtensionType = 0 + // SSH is used when extending an ssh certificate + CertExtensionType_CERT_EXTENSION_TYPE_SSH CertExtensionType = 1 +) + +// Enum value maps for CertExtensionType. +var ( + CertExtensionType_name = map[int32]string{ + 0: "CERT_EXTENSION_TYPE_UNSPECIFIED", + 1: "CERT_EXTENSION_TYPE_SSH", + } + CertExtensionType_value = map[string]int32{ + "CERT_EXTENSION_TYPE_UNSPECIFIED": 0, + "CERT_EXTENSION_TYPE_SSH": 1, + } +) + +func (x CertExtensionType) Enum() *CertExtensionType { + p := new(CertExtensionType) + *p = x + return p +} + +func (x CertExtensionType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CertExtensionType) Descriptor() protoreflect.EnumDescriptor { + return file_teleport_decision_v1alpha1_ssh_identity_proto_enumTypes[1].Descriptor() +} + +func (CertExtensionType) Type() protoreflect.EnumType { + return &file_teleport_decision_v1alpha1_ssh_identity_proto_enumTypes[1] +} + +func (x CertExtensionType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CertExtensionType.Descriptor instead. +func (CertExtensionType) EnumDescriptor() ([]byte, []int) { + return file_teleport_decision_v1alpha1_ssh_identity_proto_rawDescGZIP(), []int{1} +} + // SSHIdentity is the identity used for SSH connections. type SSHIdentity struct { - state protoimpl.MessageState `protogen:"open.v1"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + // ValidAfter is the unix timestamp that marks the start time for when the certificate should + // be considered valid. + ValidAfter uint64 `protobuf:"varint,1,opt,name=valid_after,json=validAfter,proto3" json:"valid_after,omitempty"` + // ValidBefore is the unix timestamp that marks the end time for when the certificate should + // be considered valid. + ValidBefore uint64 `protobuf:"varint,2,opt,name=valid_before,json=validBefore,proto3" json:"valid_before,omitempty"` + // CertType indicates what type of cert this is (user or host). + CertType uint32 `protobuf:"varint,3,opt,name=cert_type,json=certType,proto3" json:"cert_type,omitempty"` + // Principals is the list of SSH principals associated with the certificate (this means the + // list of allowed unix logins in the case of user certs). + Principals []string `protobuf:"bytes,4,rep,name=principals,proto3" json:"principals,omitempty"` + // ClusterName is the name of the cluster within which a node lives + ClusterName string `protobuf:"bytes,5,opt,name=cluster_name,json=clusterName,proto3" json:"cluster_name,omitempty"` + // SystemRole identifies the system role of a Teleport instance + SystemRole string `protobuf:"bytes,6,opt,name=system_role,json=systemRole,proto3" json:"system_role,omitempty"` + // Username is teleport username + Username string `protobuf:"bytes,7,opt,name=username,proto3" json:"username,omitempty"` + // Impersonator is set when a user requests certificate for another user + Impersonator string `protobuf:"bytes,8,opt,name=impersonator,proto3" json:"impersonator,omitempty"` + // PermitX11Forwarding permits X11 forwarding for this cert + PermitX11Forwarding bool `protobuf:"varint,9,opt,name=permit_x11_forwarding,json=permitX11Forwarding,proto3" json:"permit_x11_forwarding,omitempty"` + // PermitAgentForwarding permits agent forwarding for this cert + PermitAgentForwarding bool `protobuf:"varint,10,opt,name=permit_agent_forwarding,json=permitAgentForwarding,proto3" json:"permit_agent_forwarding,omitempty"` + // PermitPortForwarding permits port forwarding. + PermitPortForwarding bool `protobuf:"varint,11,opt,name=permit_port_forwarding,json=permitPortForwarding,proto3" json:"permit_port_forwarding,omitempty"` + // Roles is a list of roles assigned to this user + Roles []string `protobuf:"bytes,12,rep,name=roles,proto3" json:"roles,omitempty"` + // RouteToCluster specifies the target cluster + // if present in the certificate, will be used + // to route the requests to + RouteToCluster string `protobuf:"bytes,13,opt,name=route_to_cluster,json=routeToCluster,proto3" json:"route_to_cluster,omitempty"` + // Traits hold claim data used to populate a role at runtime. + Traits []*v1.Trait `protobuf:"bytes,14,rep,name=traits,proto3" json:"traits,omitempty"` + // ActiveRequests tracks privilege escalation requests applied during + // certificate construction. + ActiveRequests []string `protobuf:"bytes,15,rep,name=active_requests,json=activeRequests,proto3" json:"active_requests,omitempty"` + // MFAVerified is the UUID of an MFA device when this Identity was + // confirmed immediately after an MFA check. + MfaVerified string `protobuf:"bytes,16,opt,name=mfa_verified,json=mfaVerified,proto3" json:"mfa_verified,omitempty"` + // PreviousIdentityExpires is the expiry time of the identity/cert that this + // identity/cert was derived from. It is used to determine a session's hard + // deadline in cases where both require_session_mfa and disconnect_expired_cert + // are enabled. See https://github.com/gravitational/teleport/issues/18544. + PreviousIdentityExpires *timestamppb.Timestamp `protobuf:"bytes,17,opt,name=previous_identity_expires,json=previousIdentityExpires,proto3" json:"previous_identity_expires,omitempty"` + // LoginIP is an observed IP of the client on the moment of certificate creation. + LoginIp string `protobuf:"bytes,18,opt,name=login_ip,json=loginIp,proto3" json:"login_ip,omitempty"` + // PinnedIP is an IP from which client must communicate with Teleport. + PinnedIp string `protobuf:"bytes,19,opt,name=pinned_ip,json=pinnedIp,proto3" json:"pinned_ip,omitempty"` + // DisallowReissue flags that any attempt to request new certificates while + // authenticated with this cert should be denied. + DisallowReissue bool `protobuf:"varint,20,opt,name=disallow_reissue,json=disallowReissue,proto3" json:"disallow_reissue,omitempty"` + // CertificateExtensions are user configured ssh key extensions (note: this field also + // ends up aggregating all *unknown* extensions during cert parsing, meaning that this + // can sometimes contain fields that were inserted by a newer version of teleport). + CertificateExtensions []*CertExtension `protobuf:"bytes,21,rep,name=certificate_extensions,json=certificateExtensions,proto3" json:"certificate_extensions,omitempty"` + // Renewable indicates this certificate is renewable. + Renewable bool `protobuf:"varint,22,opt,name=renewable,proto3" json:"renewable,omitempty"` + // Generation counts the number of times a certificate has been renewed, with a generation of 1 + // meaning the cert has never been renewed. A generation of zero means the cert's generation is + // not being tracked. + Generation uint64 `protobuf:"varint,23,opt,name=generation,proto3" json:"generation,omitempty"` + // BotName is set to the name of the bot, if the user is a Machine ID bot user. + // Empty for human users. + BotName string `protobuf:"bytes,24,opt,name=bot_name,json=botName,proto3" json:"bot_name,omitempty"` + // BotInstanceID is the unique identifier for the bot instance, if this is a + // Machine ID bot. It is empty for human users. + BotInstanceId string `protobuf:"bytes,25,opt,name=bot_instance_id,json=botInstanceId,proto3" json:"bot_instance_id,omitempty"` + // AllowedResourceIDs lists the resources the user should be able to access. + AllowedResourceIds []*ResourceId `protobuf:"bytes,26,rep,name=allowed_resource_ids,json=allowedResourceIds,proto3" json:"allowed_resource_ids,omitempty"` + // ConnectionDiagnosticID references the ConnectionDiagnostic that we should use to append traces when testing a Connection. + ConnectionDiagnosticId string `protobuf:"bytes,27,opt,name=connection_diagnostic_id,json=connectionDiagnosticId,proto3" json:"connection_diagnostic_id,omitempty"` + // PrivateKeyPolicy is the private key policy supported by this certificate. + PrivateKeyPolicy string `protobuf:"bytes,28,opt,name=private_key_policy,json=privateKeyPolicy,proto3" json:"private_key_policy,omitempty"` + // DeviceID is the trusted device identifier. + DeviceId string `protobuf:"bytes,29,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"` + // DeviceAssetTag is the device inventory identifier. + DeviceAssetTag string `protobuf:"bytes,30,opt,name=device_asset_tag,json=deviceAssetTag,proto3" json:"device_asset_tag,omitempty"` + // DeviceCredentialID is the identifier for the credential used by the device + // to authenticate itself. + DeviceCredentialId string `protobuf:"bytes,31,opt,name=device_credential_id,json=deviceCredentialId,proto3" json:"device_credential_id,omitempty"` + // GitHubUserID indicates the GitHub user ID identified by the GitHub + // connector. + GithubUserId string `protobuf:"bytes,32,opt,name=github_user_id,json=githubUserId,proto3" json:"github_user_id,omitempty"` + // GitHubUsername indicates the GitHub username identified by the GitHub + // connector. + GithubUsername string `protobuf:"bytes,33,opt,name=github_username,json=githubUsername,proto3" json:"github_username,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SSHIdentity) Reset() { @@ -72,6 +262,315 @@ func (*SSHIdentity) Descriptor() ([]byte, []int) { return file_teleport_decision_v1alpha1_ssh_identity_proto_rawDescGZIP(), []int{0} } +func (x *SSHIdentity) GetValidAfter() uint64 { + if x != nil { + return x.ValidAfter + } + return 0 +} + +func (x *SSHIdentity) GetValidBefore() uint64 { + if x != nil { + return x.ValidBefore + } + return 0 +} + +func (x *SSHIdentity) GetCertType() uint32 { + if x != nil { + return x.CertType + } + return 0 +} + +func (x *SSHIdentity) GetPrincipals() []string { + if x != nil { + return x.Principals + } + return nil +} + +func (x *SSHIdentity) GetClusterName() string { + if x != nil { + return x.ClusterName + } + return "" +} + +func (x *SSHIdentity) GetSystemRole() string { + if x != nil { + return x.SystemRole + } + return "" +} + +func (x *SSHIdentity) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *SSHIdentity) GetImpersonator() string { + if x != nil { + return x.Impersonator + } + return "" +} + +func (x *SSHIdentity) GetPermitX11Forwarding() bool { + if x != nil { + return x.PermitX11Forwarding + } + return false +} + +func (x *SSHIdentity) GetPermitAgentForwarding() bool { + if x != nil { + return x.PermitAgentForwarding + } + return false +} + +func (x *SSHIdentity) GetPermitPortForwarding() bool { + if x != nil { + return x.PermitPortForwarding + } + return false +} + +func (x *SSHIdentity) GetRoles() []string { + if x != nil { + return x.Roles + } + return nil +} + +func (x *SSHIdentity) GetRouteToCluster() string { + if x != nil { + return x.RouteToCluster + } + return "" +} + +func (x *SSHIdentity) GetTraits() []*v1.Trait { + if x != nil { + return x.Traits + } + return nil +} + +func (x *SSHIdentity) GetActiveRequests() []string { + if x != nil { + return x.ActiveRequests + } + return nil +} + +func (x *SSHIdentity) GetMfaVerified() string { + if x != nil { + return x.MfaVerified + } + return "" +} + +func (x *SSHIdentity) GetPreviousIdentityExpires() *timestamppb.Timestamp { + if x != nil { + return x.PreviousIdentityExpires + } + return nil +} + +func (x *SSHIdentity) GetLoginIp() string { + if x != nil { + return x.LoginIp + } + return "" +} + +func (x *SSHIdentity) GetPinnedIp() string { + if x != nil { + return x.PinnedIp + } + return "" +} + +func (x *SSHIdentity) GetDisallowReissue() bool { + if x != nil { + return x.DisallowReissue + } + return false +} + +func (x *SSHIdentity) GetCertificateExtensions() []*CertExtension { + if x != nil { + return x.CertificateExtensions + } + return nil +} + +func (x *SSHIdentity) GetRenewable() bool { + if x != nil { + return x.Renewable + } + return false +} + +func (x *SSHIdentity) GetGeneration() uint64 { + if x != nil { + return x.Generation + } + return 0 +} + +func (x *SSHIdentity) GetBotName() string { + if x != nil { + return x.BotName + } + return "" +} + +func (x *SSHIdentity) GetBotInstanceId() string { + if x != nil { + return x.BotInstanceId + } + return "" +} + +func (x *SSHIdentity) GetAllowedResourceIds() []*ResourceId { + if x != nil { + return x.AllowedResourceIds + } + return nil +} + +func (x *SSHIdentity) GetConnectionDiagnosticId() string { + if x != nil { + return x.ConnectionDiagnosticId + } + return "" +} + +func (x *SSHIdentity) GetPrivateKeyPolicy() string { + if x != nil { + return x.PrivateKeyPolicy + } + return "" +} + +func (x *SSHIdentity) GetDeviceId() string { + if x != nil { + return x.DeviceId + } + return "" +} + +func (x *SSHIdentity) GetDeviceAssetTag() string { + if x != nil { + return x.DeviceAssetTag + } + return "" +} + +func (x *SSHIdentity) GetDeviceCredentialId() string { + if x != nil { + return x.DeviceCredentialId + } + return "" +} + +func (x *SSHIdentity) GetGithubUserId() string { + if x != nil { + return x.GithubUserId + } + return "" +} + +func (x *SSHIdentity) GetGithubUsername() string { + if x != nil { + return x.GithubUsername + } + return "" +} + +// CertExtension represents a key/value for a certificate extension. This type must +// be kept up to date with types.CertExtension. +type CertExtension struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Type represents the certificate type being extended, only ssh + // is supported at this time. + // 0 is "ssh". + Type CertExtensionType `protobuf:"varint,1,opt,name=type,proto3,enum=teleport.decision.v1alpha1.CertExtensionType" json:"type,omitempty"` + // Mode is the type of extension to be used -- currently + // critical-option is not supported. + // 0 is "extension". + Mode CertExtensionMode `protobuf:"varint,2,opt,name=mode,proto3,enum=teleport.decision.v1alpha1.CertExtensionMode" json:"mode,omitempty"` + // Name specifies the key to be used in the cert extension. + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + // Value specifies the value to be used in the cert extension. + Value string `protobuf:"bytes,4,opt,name=value,proto3" json:"value,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CertExtension) Reset() { + *x = CertExtension{} + mi := &file_teleport_decision_v1alpha1_ssh_identity_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CertExtension) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CertExtension) ProtoMessage() {} + +func (x *CertExtension) ProtoReflect() protoreflect.Message { + mi := &file_teleport_decision_v1alpha1_ssh_identity_proto_msgTypes[1] + 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 CertExtension.ProtoReflect.Descriptor instead. +func (*CertExtension) Descriptor() ([]byte, []int) { + return file_teleport_decision_v1alpha1_ssh_identity_proto_rawDescGZIP(), []int{1} +} + +func (x *CertExtension) GetType() CertExtensionType { + if x != nil { + return x.Type + } + return CertExtensionType_CERT_EXTENSION_TYPE_UNSPECIFIED +} + +func (x *CertExtension) GetMode() CertExtensionMode { + if x != nil { + return x.Mode + } + return CertExtensionMode_CERT_EXTENSION_MODE_UNSPECIFIED +} + +func (x *CertExtension) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CertExtension) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + var File_teleport_decision_v1alpha1_ssh_identity_proto protoreflect.FileDescriptor var file_teleport_decision_v1alpha1_ssh_identity_proto_rawDesc = string([]byte{ @@ -79,14 +578,134 @@ var file_teleport_decision_v1alpha1_ssh_identity_proto_rawDesc = string([]byte{ 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x73, 0x73, 0x68, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1a, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x22, 0x0d, 0x0a, 0x0b, 0x53, - 0x53, 0x48, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x42, 0x5a, 0x5a, 0x58, 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, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3b, 0x64, 0x65, 0x63, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2d, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2f, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x74, 0x6c, 0x73, 0x5f, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1d, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x74, 0x72, 0x61, 0x69, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x74, + 0x72, 0x61, 0x69, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9a, 0x0b, 0x0a, 0x0b, 0x53, + 0x53, 0x48, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x76, + 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x12, 0x1b, + 0x0a, 0x09, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x08, 0x63, 0x65, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, + 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0a, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, + 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, + 0x0a, 0x0b, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x6f, 0x6c, 0x65, 0x12, + 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x69, + 0x6d, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x69, 0x6d, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x12, + 0x32, 0x0a, 0x15, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x5f, 0x78, 0x31, 0x31, 0x5f, 0x66, 0x6f, + 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, + 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x58, 0x31, 0x31, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, + 0x69, 0x6e, 0x67, 0x12, 0x36, 0x0a, 0x17, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x5f, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x5f, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x41, 0x67, 0x65, 0x6e, + 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x16, 0x70, + 0x65, 0x72, 0x6d, 0x69, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x66, 0x6f, 0x72, 0x77, 0x61, + 0x72, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x70, 0x65, 0x72, + 0x6d, 0x69, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, + 0x67, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x6f, 0x75, 0x74, 0x65, + 0x5f, 0x74, 0x6f, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x54, 0x6f, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, + 0x72, 0x12, 0x30, 0x0a, 0x06, 0x74, 0x72, 0x61, 0x69, 0x74, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, 0x61, + 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, 0x69, 0x74, 0x52, 0x06, 0x74, 0x72, 0x61, + 0x69, 0x74, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x21, 0x0a, 0x0c, + 0x6d, 0x66, 0x61, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x10, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x66, 0x61, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, + 0x56, 0x0a, 0x19, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x18, 0x11, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x17, + 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x69, 0x6e, + 0x5f, 0x69, 0x70, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x69, 0x6e, + 0x49, 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x70, 0x18, + 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x49, 0x70, 0x12, + 0x29, 0x0a, 0x10, 0x64, 0x69, 0x73, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x65, 0x69, 0x73, + 0x73, 0x75, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x6c, + 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x69, 0x73, 0x73, 0x75, 0x65, 0x12, 0x60, 0x0a, 0x16, 0x63, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x15, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x45, 0x78, 0x74, 0x65, + 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x15, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1c, 0x0a, 0x09, + 0x72, 0x65, 0x6e, 0x65, 0x77, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x09, 0x72, 0x65, 0x6e, 0x65, 0x77, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x67, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x17, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, + 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x6f, + 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x18, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x6f, + 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x62, 0x6f, 0x74, 0x5f, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x19, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x62, 0x6f, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x58, 0x0a, + 0x14, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x1a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x49, 0x64, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x73, 0x12, 0x38, 0x0a, 0x18, 0x63, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, + 0x5f, 0x69, 0x64, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x63, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x49, + 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, + 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, + 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, + 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x1d, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x10, + 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x67, + 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x73, + 0x73, 0x65, 0x74, 0x54, 0x61, 0x67, 0x12, 0x30, 0x0a, 0x14, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x1f, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x20, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x27, + 0x0a, 0x0f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x21, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x55, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xbf, 0x01, 0x0a, 0x0d, 0x43, 0x65, 0x72, 0x74, + 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x41, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, + 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x41, 0x0a, 0x04, + 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x45, 0x78, 0x74, 0x65, + 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x5b, 0x0a, 0x11, 0x43, 0x65, 0x72, + 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x23, + 0x0a, 0x1f, 0x43, 0x45, 0x52, 0x54, 0x5f, 0x45, 0x58, 0x54, 0x45, 0x4e, 0x53, 0x49, 0x4f, 0x4e, + 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x21, 0x0a, 0x1d, 0x43, 0x45, 0x52, 0x54, 0x5f, 0x45, 0x58, 0x54, 0x45, + 0x4e, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x45, 0x58, 0x54, 0x45, 0x4e, + 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x2a, 0x55, 0x0a, 0x11, 0x43, 0x65, 0x72, 0x74, 0x45, 0x78, + 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x1f, 0x43, + 0x45, 0x52, 0x54, 0x5f, 0x45, 0x58, 0x54, 0x45, 0x4e, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x45, 0x52, 0x54, 0x5f, 0x45, 0x58, 0x54, 0x45, 0x4e, 0x53, 0x49, + 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x53, 0x48, 0x10, 0x01, 0x42, 0x5a, 0x5a, + 0x58, 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, 0x64, 0x65, 0x63, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3b, 0x64, + 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, }) var ( @@ -101,16 +720,29 @@ func file_teleport_decision_v1alpha1_ssh_identity_proto_rawDescGZIP() []byte { return file_teleport_decision_v1alpha1_ssh_identity_proto_rawDescData } -var file_teleport_decision_v1alpha1_ssh_identity_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_teleport_decision_v1alpha1_ssh_identity_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_teleport_decision_v1alpha1_ssh_identity_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_teleport_decision_v1alpha1_ssh_identity_proto_goTypes = []any{ - (*SSHIdentity)(nil), // 0: teleport.decision.v1alpha1.SSHIdentity + (CertExtensionMode)(0), // 0: teleport.decision.v1alpha1.CertExtensionMode + (CertExtensionType)(0), // 1: teleport.decision.v1alpha1.CertExtensionType + (*SSHIdentity)(nil), // 2: teleport.decision.v1alpha1.SSHIdentity + (*CertExtension)(nil), // 3: teleport.decision.v1alpha1.CertExtension + (*v1.Trait)(nil), // 4: teleport.trait.v1.Trait + (*timestamppb.Timestamp)(nil), // 5: google.protobuf.Timestamp + (*ResourceId)(nil), // 6: teleport.decision.v1alpha1.ResourceId } var file_teleport_decision_v1alpha1_ssh_identity_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 4, // 0: teleport.decision.v1alpha1.SSHIdentity.traits:type_name -> teleport.trait.v1.Trait + 5, // 1: teleport.decision.v1alpha1.SSHIdentity.previous_identity_expires:type_name -> google.protobuf.Timestamp + 3, // 2: teleport.decision.v1alpha1.SSHIdentity.certificate_extensions:type_name -> teleport.decision.v1alpha1.CertExtension + 6, // 3: teleport.decision.v1alpha1.SSHIdentity.allowed_resource_ids:type_name -> teleport.decision.v1alpha1.ResourceId + 1, // 4: teleport.decision.v1alpha1.CertExtension.type:type_name -> teleport.decision.v1alpha1.CertExtensionType + 0, // 5: teleport.decision.v1alpha1.CertExtension.mode:type_name -> teleport.decision.v1alpha1.CertExtensionMode + 6, // [6:6] is the sub-list for method output_type + 6, // [6:6] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { file_teleport_decision_v1alpha1_ssh_identity_proto_init() } @@ -118,18 +750,20 @@ func file_teleport_decision_v1alpha1_ssh_identity_proto_init() { if File_teleport_decision_v1alpha1_ssh_identity_proto != nil { return } + file_teleport_decision_v1alpha1_tls_identity_proto_init() type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_teleport_decision_v1alpha1_ssh_identity_proto_rawDesc), len(file_teleport_decision_v1alpha1_ssh_identity_proto_rawDesc)), - NumEnums: 0, - NumMessages: 1, + NumEnums: 2, + NumMessages: 2, NumExtensions: 0, NumServices: 0, }, GoTypes: file_teleport_decision_v1alpha1_ssh_identity_proto_goTypes, DependencyIndexes: file_teleport_decision_v1alpha1_ssh_identity_proto_depIdxs, + EnumInfos: file_teleport_decision_v1alpha1_ssh_identity_proto_enumTypes, MessageInfos: file_teleport_decision_v1alpha1_ssh_identity_proto_msgTypes, }.Build() File_teleport_decision_v1alpha1_ssh_identity_proto = out.File diff --git a/api/proto/teleport/decision/v1alpha1/ssh_identity.proto b/api/proto/teleport/decision/v1alpha1/ssh_identity.proto index 01f4ea2af2d58..c63fa2f73850c 100644 --- a/api/proto/teleport/decision/v1alpha1/ssh_identity.proto +++ b/api/proto/teleport/decision/v1alpha1/ssh_identity.proto @@ -16,9 +16,174 @@ syntax = "proto3"; package teleport.decision.v1alpha1; +import "google/protobuf/timestamp.proto"; +import "teleport/decision/v1alpha1/tls_identity.proto"; +import "teleport/trait/v1/trait.proto"; + option go_package = "github.com/gravitational/teleport/api/gen/proto/go/teleport/decision/v1alpha1;decisionpb"; // SSHIdentity is the identity used for SSH connections. message SSHIdentity { - // TBD + // --- common identity fields --- + + // ValidAfter is the unix timestamp that marks the start time for when the certificate should + // be considered valid. + uint64 valid_after = 1; + + // ValidBefore is the unix timestamp that marks the end time for when the certificate should + // be considered valid. + uint64 valid_before = 2; + + // CertType indicates what type of cert this is (user or host). + uint32 cert_type = 3; + + // Principals is the list of SSH principals associated with the certificate (this means the + // list of allowed unix logins in the case of user certs). + repeated string principals = 4; + + // --- host identity fields --- + + // ClusterName is the name of the cluster within which a node lives + string cluster_name = 5; + // SystemRole identifies the system role of a Teleport instance + string system_role = 6; + + // -- user identity fields --- + + // Username is teleport username + string username = 7; + + // Impersonator is set when a user requests certificate for another user + string impersonator = 8; + + // PermitX11Forwarding permits X11 forwarding for this cert + bool permit_x11_forwarding = 9; + + // PermitAgentForwarding permits agent forwarding for this cert + bool permit_agent_forwarding = 10; + + // PermitPortForwarding permits port forwarding. + bool permit_port_forwarding = 11; + + // Roles is a list of roles assigned to this user + repeated string roles = 12; + + // RouteToCluster specifies the target cluster + // if present in the certificate, will be used + // to route the requests to + string route_to_cluster = 13; + + // Traits hold claim data used to populate a role at runtime. + repeated teleport.trait.v1.Trait traits = 14; + + // ActiveRequests tracks privilege escalation requests applied during + // certificate construction. + repeated string active_requests = 15; + + // MFAVerified is the UUID of an MFA device when this Identity was + // confirmed immediately after an MFA check. + string mfa_verified = 16; + + // PreviousIdentityExpires is the expiry time of the identity/cert that this + // identity/cert was derived from. It is used to determine a session's hard + // deadline in cases where both require_session_mfa and disconnect_expired_cert + // are enabled. See https://github.com/gravitational/teleport/issues/18544. + google.protobuf.Timestamp previous_identity_expires = 17; + + // LoginIP is an observed IP of the client on the moment of certificate creation. + string login_ip = 18; + + // PinnedIP is an IP from which client must communicate with Teleport. + string pinned_ip = 19; + + // DisallowReissue flags that any attempt to request new certificates while + // authenticated with this cert should be denied. + bool disallow_reissue = 20; + + // CertificateExtensions are user configured ssh key extensions (note: this field also + // ends up aggregating all *unknown* extensions during cert parsing, meaning that this + // can sometimes contain fields that were inserted by a newer version of teleport). + repeated CertExtension certificate_extensions = 21; + + // Renewable indicates this certificate is renewable. + bool renewable = 22; + + // Generation counts the number of times a certificate has been renewed, with a generation of 1 + // meaning the cert has never been renewed. A generation of zero means the cert's generation is + // not being tracked. + uint64 generation = 23; + + // BotName is set to the name of the bot, if the user is a Machine ID bot user. + // Empty for human users. + string bot_name = 24; + + // BotInstanceID is the unique identifier for the bot instance, if this is a + // Machine ID bot. It is empty for human users. + string bot_instance_id = 25; + + // AllowedResourceIDs lists the resources the user should be able to access. + repeated ResourceId allowed_resource_ids = 26; + + // ConnectionDiagnosticID references the ConnectionDiagnostic that we should use to append traces when testing a Connection. + string connection_diagnostic_id = 27; + + // PrivateKeyPolicy is the private key policy supported by this certificate. + string private_key_policy = 28; + + // DeviceID is the trusted device identifier. + string device_id = 29; + + // DeviceAssetTag is the device inventory identifier. + string device_asset_tag = 30; + + // DeviceCredentialID is the identifier for the credential used by the device + // to authenticate itself. + string device_credential_id = 31; + + // GitHubUserID indicates the GitHub user ID identified by the GitHub + // connector. + string github_user_id = 32; + + // GitHubUsername indicates the GitHub username identified by the GitHub + // connector. + string github_username = 33; +} + +// CertExtensionMode specifies the type of extension to use in the cert. This type +// must be kept up to date with types.CertExtensionMode. +enum CertExtensionMode { + // CERT_EXTENSION_MODE_UNSPECIFIED is the default value and should not be used. + CERT_EXTENSION_MODE_UNSPECIFIED = 0; + + // EXTENSION represents a cert extension that may or may not be + // honored by the server. + CERT_EXTENSION_MODE_EXTENSION = 1; +} + +// CertExtensionType represents the certificate type the extension is for. +// Currently only ssh is supported. This type must be kept up to date with +// types.CertExtensionType. +enum CertExtensionType { + // CERT_EXTENSION_TYPE_UNSPECIFIED is the default value and should not be used. + CERT_EXTENSION_TYPE_UNSPECIFIED = 0; + + // SSH is used when extending an ssh certificate + CERT_EXTENSION_TYPE_SSH = 1; +} + +// CertExtension represents a key/value for a certificate extension. This type must +// be kept up to date with types.CertExtension. +message CertExtension { + // Type represents the certificate type being extended, only ssh + // is supported at this time. + // 0 is "ssh". + CertExtensionType type = 1; + // Mode is the type of extension to be used -- currently + // critical-option is not supported. + // 0 is "extension". + CertExtensionMode mode = 2; + // Name specifies the key to be used in the cert extension. + string name = 3; + // Value specifies the value to be used in the cert extension. + string value = 4; } diff --git a/lib/decision/ssh_identity.go b/lib/decision/ssh_identity.go new file mode 100644 index 0000000000000..0bf120d5307a2 --- /dev/null +++ b/lib/decision/ssh_identity.go @@ -0,0 +1,143 @@ +// Teleport +// Copyright (C) 2025 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package decision + +import ( + decisionpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/decision/v1alpha1" + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/api/utils/keys" + "github.com/gravitational/teleport/lib/sshca" +) + +// SSHIdentityToSSHCA transforms a [decisionpb.SSHIdentity] into its +// equivalent [sshca.Identity]. +// Note that certain types, like slices, are not deep-copied. +func SSHIdentityToSSHCA(id *decisionpb.SSHIdentity) *sshca.Identity { + if id == nil { + return nil + } + + return &sshca.Identity{ + ValidAfter: id.ValidAfter, + ValidBefore: id.ValidBefore, + CertType: id.CertType, + ClusterName: id.ClusterName, + SystemRole: types.SystemRole(id.SystemRole), + Username: id.Username, + Impersonator: id.Impersonator, + Principals: id.Principals, + PermitX11Forwarding: id.PermitX11Forwarding, + PermitAgentForwarding: id.PermitAgentForwarding, + PermitPortForwarding: id.PermitPortForwarding, + Roles: id.Roles, + RouteToCluster: id.RouteToCluster, + Traits: traitToWrappers(id.Traits), + ActiveRequests: id.ActiveRequests, + MFAVerified: id.MfaVerified, + PreviousIdentityExpires: timestampToGoTime(id.PreviousIdentityExpires), + LoginIP: id.LoginIp, + PinnedIP: id.PinnedIp, + DisallowReissue: id.DisallowReissue, + CertificateExtensions: certExtensionsFromProto(id.CertificateExtensions), + Renewable: id.Renewable, + Generation: id.Generation, + BotName: id.BotName, + BotInstanceID: id.BotInstanceId, + AllowedResourceIDs: resourceIDsToTypes(id.AllowedResourceIds), + ConnectionDiagnosticID: id.ConnectionDiagnosticId, + PrivateKeyPolicy: keys.PrivateKeyPolicy(id.PrivateKeyPolicy), + DeviceID: id.DeviceId, + DeviceAssetTag: id.DeviceAssetTag, + DeviceCredentialID: id.DeviceCredentialId, + GitHubUserID: id.GithubUserId, + GitHubUsername: id.GithubUsername, + } +} + +func SSHIdentityFromSSHCA(id *sshca.Identity) *decisionpb.SSHIdentity { + if id == nil { + return nil + } + + return &decisionpb.SSHIdentity{ + ValidAfter: id.ValidAfter, + ValidBefore: id.ValidBefore, + CertType: id.CertType, + ClusterName: id.ClusterName, + SystemRole: string(id.SystemRole), + Username: id.Username, + Impersonator: id.Impersonator, + Principals: id.Principals, + PermitX11Forwarding: id.PermitX11Forwarding, + PermitAgentForwarding: id.PermitAgentForwarding, + PermitPortForwarding: id.PermitPortForwarding, + Roles: id.Roles, + RouteToCluster: id.RouteToCluster, + Traits: traitFromWrappers(id.Traits), + ActiveRequests: id.ActiveRequests, + MfaVerified: id.MFAVerified, + PreviousIdentityExpires: timestampFromGoTime(id.PreviousIdentityExpires), + LoginIp: id.LoginIP, + PinnedIp: id.PinnedIP, + DisallowReissue: id.DisallowReissue, + CertificateExtensions: certExtensionsToProto(id.CertificateExtensions), + Renewable: id.Renewable, + Generation: id.Generation, + BotName: id.BotName, + BotInstanceId: id.BotInstanceID, + AllowedResourceIds: resourceIDsFromTypes(id.AllowedResourceIDs), + ConnectionDiagnosticId: id.ConnectionDiagnosticID, + PrivateKeyPolicy: string(id.PrivateKeyPolicy), + DeviceId: id.DeviceID, + DeviceAssetTag: id.DeviceAssetTag, + DeviceCredentialId: id.DeviceCredentialID, + GithubUserId: id.GitHubUserID, + GithubUsername: id.GitHubUsername, + } +} + +func certExtensionsFromProto(extensions []*decisionpb.CertExtension) []*types.CertExtension { + if len(extensions) == 0 { + return nil + } + out := make([]*types.CertExtension, 0, len(extensions)) + for _, extension := range extensions { + out = append(out, &types.CertExtension{ + Mode: types.CertExtensionMode(int32(extension.Mode) - 1), // enum is equivalent but off by 1 + Type: types.CertExtensionType(int32(extension.Type) - 1), // enum is equivalent but off by 1 + Name: extension.Name, + Value: extension.Value, + }) + } + return out +} + +func certExtensionsToProto(extensions []*types.CertExtension) []*decisionpb.CertExtension { + if len(extensions) == 0 { + return nil + } + out := make([]*decisionpb.CertExtension, 0, len(extensions)) + for _, extension := range extensions { + out = append(out, &decisionpb.CertExtension{ + Mode: decisionpb.CertExtensionMode(int32(extension.Mode) + 1), // enum is equivalent but off by 1 + Type: decisionpb.CertExtensionType(int32(extension.Type) + 1), // enum is equivalent but off by 1 + Name: extension.Name, + Value: extension.Value, + }) + } + return out +} diff --git a/lib/decision/ssh_identity_test.go b/lib/decision/ssh_identity_test.go new file mode 100644 index 0000000000000..9bd1412143010 --- /dev/null +++ b/lib/decision/ssh_identity_test.go @@ -0,0 +1,101 @@ +// Teleport +// Copyright (C) 2025 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package decision + +import ( + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/google/uuid" + "github.com/stretchr/testify/require" + "golang.org/x/crypto/ssh" + + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/api/types/wrappers" + "github.com/gravitational/teleport/api/utils/keys" + "github.com/gravitational/teleport/lib/sshca" + "github.com/gravitational/teleport/lib/utils/testutils" +) + +func TestSSHIdentityConversion(t *testing.T) { + ident := &sshca.Identity{ + ValidAfter: 1, + ValidBefore: 2, + CertType: ssh.UserCert, + ClusterName: "some-cluster", + SystemRole: types.RoleNode, + Username: "user", + Impersonator: "impersonator", + Principals: []string{"login1", "login2"}, + PermitX11Forwarding: true, + PermitAgentForwarding: true, + PermitPortForwarding: true, + Roles: []string{"role1", "role2"}, + RouteToCluster: "cluster", + Traits: wrappers.Traits{"trait1": []string{"value1"}, "trait2": []string{"value2"}}, + ActiveRequests: []string{uuid.NewString()}, + MFAVerified: "mfa", + PreviousIdentityExpires: time.Unix(12345, 0), + LoginIP: "127.0.0.1", + PinnedIP: "127.0.0.1", + DisallowReissue: true, + CertificateExtensions: []*types.CertExtension{&types.CertExtension{ + Name: "extname", + Value: "extvalue", + Type: types.CertExtensionType_SSH, + Mode: types.CertExtensionMode_EXTENSION, + }}, + Renewable: true, + Generation: 3, + BotName: "bot", + BotInstanceID: "instance", + AllowedResourceIDs: []types.ResourceID{{ + ClusterName: "cluster", + Kind: types.KindKubePod, // must use a kube resource kind for parsing of sub-resource to work correctly + Name: "name", + SubResourceName: "sub/sub", + }}, + ConnectionDiagnosticID: "diag", + PrivateKeyPolicy: keys.PrivateKeyPolicy("policy"), + DeviceID: "device", + DeviceAssetTag: "asset", + DeviceCredentialID: "cred", + GitHubUserID: "github", + GitHubUsername: "ghuser", + } + + ignores := []string{ + "CertExtension.Type", // only currently defined enum variant is a zero value + "CertExtension.Mode", // only currently defined enum variant is a zero value + // TODO(fspmarshall): figure out a mechanism for making ignore of grpc fields more convenient + "CertExtension.XXX_NoUnkeyedLiteral", + "CertExtension.XXX_unrecognized", + "CertExtension.XXX_sizecache", + "ResourceID.XXX_NoUnkeyedLiteral", + "ResourceID.XXX_unrecognized", + "ResourceID.XXX_sizecache", + } + + require.True(t, testutils.ExhaustiveNonEmpty(ident, ignores...), "empty=%+v", testutils.FindAllEmpty(ident, ignores...)) + + proto := SSHIdentityFromSSHCA(ident) + + ident2 := SSHIdentityToSSHCA(proto) + + require.Empty(t, cmp.Diff(ident, ident2)) +}