diff --git a/internal/daemon/controller/handlers/targets/credentials.go b/internal/daemon/controller/handlers/targets/credentials.go index f680971502..ad8f1184c5 100644 --- a/internal/daemon/controller/handlers/targets/credentials.go +++ b/internal/daemon/controller/handlers/targets/credentials.go @@ -33,7 +33,16 @@ func dynamicToWorkerCredential(ctx context.Context, cred credential.Dynamic) (se }, }, } - + case credential.SshCertificate: + workerCred = &serverpb.Credential{ + Credential: &serverpb.Credential_SshCertificate{ + SshCertificate: &serverpb.SshCertificate{ + Username: c.Username(), + PrivateKey: string(c.PrivateKey()), + Certificate: string(c.Certificate()), + }, + }, + } case credential.SshPrivateKey: workerCred = &serverpb.Credential{ Credential: &serverpb.Credential_SshPrivateKey{ diff --git a/internal/gen/controller/servers/services/credential.pb.go b/internal/gen/controller/servers/services/credential.pb.go index 6edb422ab5..2d310c0a46 100644 --- a/internal/gen/controller/servers/services/credential.pb.go +++ b/internal/gen/controller/servers/services/credential.pb.go @@ -29,6 +29,7 @@ type Credential struct { // // *Credential_UsernamePassword // *Credential_SshPrivateKey + // *Credential_SshCertificate Credential isCredential_Credential `protobuf_oneof:"credential"` } @@ -85,6 +86,13 @@ func (x *Credential) GetSshPrivateKey() *SshPrivateKey { return nil } +func (x *Credential) GetSshCertificate() *SshCertificate { + if x, ok := x.GetCredential().(*Credential_SshCertificate); ok { + return x.SshCertificate + } + return nil +} + type isCredential_Credential interface { isCredential_Credential() } @@ -97,10 +105,16 @@ type Credential_SshPrivateKey struct { SshPrivateKey *SshPrivateKey `protobuf:"bytes,3,opt,name=ssh_private_key,json=sshPrivateKey,proto3,oneof"` } +type Credential_SshCertificate struct { + SshCertificate *SshCertificate `protobuf:"bytes,4,opt,name=ssh_certificate,json=sshCertificate,proto3,oneof"` +} + func (*Credential_UsernamePassword) isCredential_Credential() {} func (*Credential_SshPrivateKey) isCredential_Credential() {} +func (*Credential_SshCertificate) isCredential_Credential() {} + // UsernamePassword is a credential containing a username and a password. type UsernamePassword struct { state protoimpl.MessageState @@ -227,6 +241,74 @@ func (x *SshPrivateKey) GetPrivateKeyPassphrase() string { return "" } +// SshCertificate is a credential containing a username, private key, and +// client certificate. +type SshCertificate struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The username of the credential + Username string `protobuf:"bytes,10,opt,name=username,proto3" json:"username,omitempty"` // @gotags: `class:"public"` + // The private key of the credential + PrivateKey string `protobuf:"bytes,20,opt,name=private_key,json=privateKey,proto3" json:"private_key,omitempty"` // @gotags: `class:"secret"` + // The client certificate signed by a CA to establish trust of the private key. + Certificate string `protobuf:"bytes,30,opt,name=certificate,proto3" json:"certificate,omitempty"` // @gotags: `class:"public"` +} + +func (x *SshCertificate) Reset() { + *x = SshCertificate{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_servers_services_v1_credential_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SshCertificate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SshCertificate) ProtoMessage() {} + +func (x *SshCertificate) ProtoReflect() protoreflect.Message { + mi := &file_controller_servers_services_v1_credential_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SshCertificate.ProtoReflect.Descriptor instead. +func (*SshCertificate) Descriptor() ([]byte, []int) { + return file_controller_servers_services_v1_credential_proto_rawDescGZIP(), []int{3} +} + +func (x *SshCertificate) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *SshCertificate) GetPrivateKey() string { + if x != nil { + return x.PrivateKey + } + return "" +} + +func (x *SshCertificate) GetCertificate() string { + if x != nil { + return x.Certificate + } + return "" +} + var File_controller_servers_services_v1_credential_proto protoreflect.FileDescriptor var file_controller_servers_services_v1_credential_proto_rawDesc = []byte{ @@ -235,7 +317,7 @@ var file_controller_servers_services_v1_credential_proto_rawDesc = []byte{ 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, - 0x31, 0x22, 0xe9, 0x01, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x31, 0x22, 0xc4, 0x02, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x5f, 0x0a, 0x11, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, @@ -247,28 +329,41 @@ var file_controller_servers_services_v1_credential_proto_rawDesc = []byte{ 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x73, 0x68, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x48, 0x00, 0x52, 0x0d, 0x73, 0x73, 0x68, - 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x52, 0x0d, - 0x75, 0x73, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x4a, 0x0a, - 0x10, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, - 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, - 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x82, 0x01, 0x0a, 0x0d, 0x53, 0x73, - 0x68, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x75, + 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x59, 0x0a, 0x0f, 0x73, 0x73, + 0x68, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x73, 0x68, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x73, 0x73, 0x68, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x5f, + 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x4a, 0x0a, 0x10, 0x55, 0x73, 0x65, 0x72, + 0x6e, 0x61, 0x6d, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1a, 0x0a, 0x08, + 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, + 0x77, 0x6f, 0x72, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, + 0x77, 0x6f, 0x72, 0x64, 0x22, 0x82, 0x01, 0x0a, 0x0d, 0x53, 0x73, 0x68, 0x50, 0x72, 0x69, 0x76, + 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, + 0x79, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, + 0x4b, 0x65, 0x79, 0x12, 0x34, 0x0a, 0x16, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, + 0x65, 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x18, 0x1e, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x14, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x50, + 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x22, 0x6f, 0x0a, 0x0e, 0x53, 0x73, 0x68, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, - 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x34, 0x0a, 0x16, 0x70, 0x72, 0x69, 0x76, - 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, - 0x73, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, - 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x42, 0x51, - 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, - 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2f, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x42, 0x51, 0x5a, 0x4f, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, + 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2f, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -283,20 +378,22 @@ func file_controller_servers_services_v1_credential_proto_rawDescGZIP() []byte { return file_controller_servers_services_v1_credential_proto_rawDescData } -var file_controller_servers_services_v1_credential_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_controller_servers_services_v1_credential_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_controller_servers_services_v1_credential_proto_goTypes = []interface{}{ (*Credential)(nil), // 0: controller.servers.services.v1.Credential (*UsernamePassword)(nil), // 1: controller.servers.services.v1.UsernamePassword (*SshPrivateKey)(nil), // 2: controller.servers.services.v1.SshPrivateKey + (*SshCertificate)(nil), // 3: controller.servers.services.v1.SshCertificate } var file_controller_servers_services_v1_credential_proto_depIdxs = []int32{ 1, // 0: controller.servers.services.v1.Credential.username_password:type_name -> controller.servers.services.v1.UsernamePassword 2, // 1: controller.servers.services.v1.Credential.ssh_private_key:type_name -> controller.servers.services.v1.SshPrivateKey - 2, // [2:2] is the sub-list for method output_type - 2, // [2:2] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 3, // 2: controller.servers.services.v1.Credential.ssh_certificate:type_name -> controller.servers.services.v1.SshCertificate + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name } func init() { file_controller_servers_services_v1_credential_proto_init() } @@ -341,10 +438,23 @@ func file_controller_servers_services_v1_credential_proto_init() { return nil } } + file_controller_servers_services_v1_credential_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SshCertificate); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_controller_servers_services_v1_credential_proto_msgTypes[0].OneofWrappers = []interface{}{ (*Credential_UsernamePassword)(nil), (*Credential_SshPrivateKey)(nil), + (*Credential_SshCertificate)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -352,7 +462,7 @@ func file_controller_servers_services_v1_credential_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_controller_servers_services_v1_credential_proto_rawDesc, NumEnums: 0, - NumMessages: 3, + NumMessages: 4, NumExtensions: 0, NumServices: 0, }, diff --git a/internal/proto/controller/servers/services/v1/credential.proto b/internal/proto/controller/servers/services/v1/credential.proto index 8943defffc..7ca4a43584 100644 --- a/internal/proto/controller/servers/services/v1/credential.proto +++ b/internal/proto/controller/servers/services/v1/credential.proto @@ -11,6 +11,7 @@ message Credential { oneof credential { UsernamePassword username_password = 2; SshPrivateKey ssh_private_key = 3; + SshCertificate ssh_certificate = 4; } } @@ -35,3 +36,16 @@ message SshPrivateKey { // The optional passphrase of the private_key string private_key_passphrase = 30; // @gotags: `class:"secret"` } + +// SshCertificate is a credential containing a username, private key, and +// client certificate. +message SshCertificate { + // The username of the credential + string username = 10; // @gotags: `class:"public"` + + // The private key of the credential + string private_key = 20; // @gotags: `class:"secret"` + + // The client certificate signed by a CA to establish trust of the private key. + string certificate = 30; // @gotags: `class:"public"` +}