GitHub Proxy part 3: gen github user cert and export CA (#49396)

* GitHub Proxy part 3: gen github user cert and export CA

* address pr comment

* minor refactor

* use cache

* fix build and cache
This commit is contained in:
STeve (Xin) Huang
2024-12-03 18:17:21 +00:00
committed by GitHub
parent b7a16e51c5
commit 903fee053f
21 changed files with 1371 additions and 152 deletions
+5
View File
@@ -5196,3 +5196,8 @@ func (c *Client) IdentityCenterClient() identitycenterv1.IdentityCenterServiceCl
func (c *Client) ProvisioningServiceClient() provisioningv1.ProvisioningServiceClient {
return provisioningv1.NewProvisioningServiceClient(c.conn)
}
// IntegrationsClient returns integrations client.
func (c *Client) IntegrationsClient() integrationpb.IntegrationServiceClient {
return c.integrationsClient()
}
@@ -24,6 +24,7 @@ import (
types "github.com/gravitational/teleport/api/types"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
durationpb "google.golang.org/protobuf/types/known/durationpb"
emptypb "google.golang.org/protobuf/types/known/emptypb"
reflect "reflect"
sync "sync"
@@ -494,6 +495,233 @@ func (x *GenerateAWSOIDCTokenResponse) GetToken() string {
return ""
}
// GenerateGitHubUserCertRequest is a request to sign a client certificate used by
// GitHub integration to authenticate with GitHub enterprise.
type GenerateGitHubUserCertRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Integration is the name of the integration;
Integration string `protobuf:"bytes,1,opt,name=integration,proto3" json:"integration,omitempty"`
// PublicKey is the public key to be signed.
PublicKey []byte `protobuf:"bytes,2,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
// UserId is the GitHub user id.
UserId string `protobuf:"bytes,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
// KeyId is the certificate ID, usually the Teleport username.
KeyId string `protobuf:"bytes,4,opt,name=key_id,json=keyId,proto3" json:"key_id,omitempty"`
// Ttl is the duration the certificate will be valid for.
Ttl *durationpb.Duration `protobuf:"bytes,5,opt,name=ttl,proto3" json:"ttl,omitempty"`
}
func (x *GenerateGitHubUserCertRequest) Reset() {
*x = GenerateGitHubUserCertRequest{}
mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GenerateGitHubUserCertRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GenerateGitHubUserCertRequest) ProtoMessage() {}
func (x *GenerateGitHubUserCertRequest) ProtoReflect() protoreflect.Message {
mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[9]
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 GenerateGitHubUserCertRequest.ProtoReflect.Descriptor instead.
func (*GenerateGitHubUserCertRequest) Descriptor() ([]byte, []int) {
return file_teleport_integration_v1_integration_service_proto_rawDescGZIP(), []int{9}
}
func (x *GenerateGitHubUserCertRequest) GetIntegration() string {
if x != nil {
return x.Integration
}
return ""
}
func (x *GenerateGitHubUserCertRequest) GetPublicKey() []byte {
if x != nil {
return x.PublicKey
}
return nil
}
func (x *GenerateGitHubUserCertRequest) GetUserId() string {
if x != nil {
return x.UserId
}
return ""
}
func (x *GenerateGitHubUserCertRequest) GetKeyId() string {
if x != nil {
return x.KeyId
}
return ""
}
func (x *GenerateGitHubUserCertRequest) GetTtl() *durationpb.Duration {
if x != nil {
return x.Ttl
}
return nil
}
// GenerateGitHubUserCertResponse contains a signed certificate.
type GenerateGitHubUserCertResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// AuthorizedKey is the signed certificate.
AuthorizedKey []byte `protobuf:"bytes,1,opt,name=authorized_key,json=authorizedKey,proto3" json:"authorized_key,omitempty"`
}
func (x *GenerateGitHubUserCertResponse) Reset() {
*x = GenerateGitHubUserCertResponse{}
mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GenerateGitHubUserCertResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GenerateGitHubUserCertResponse) ProtoMessage() {}
func (x *GenerateGitHubUserCertResponse) ProtoReflect() protoreflect.Message {
mi := &file_teleport_integration_v1_integration_service_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 GenerateGitHubUserCertResponse.ProtoReflect.Descriptor instead.
func (*GenerateGitHubUserCertResponse) Descriptor() ([]byte, []int) {
return file_teleport_integration_v1_integration_service_proto_rawDescGZIP(), []int{10}
}
func (x *GenerateGitHubUserCertResponse) GetAuthorizedKey() []byte {
if x != nil {
return x.AuthorizedKey
}
return nil
}
// ExportIntegrationCertAuthoritiesRequest is the request to export cert
// authorities for an integration.
type ExportIntegrationCertAuthoritiesRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Integration is the name of the integration;
Integration string `protobuf:"bytes,1,opt,name=integration,proto3" json:"integration,omitempty"`
}
func (x *ExportIntegrationCertAuthoritiesRequest) Reset() {
*x = ExportIntegrationCertAuthoritiesRequest{}
mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ExportIntegrationCertAuthoritiesRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ExportIntegrationCertAuthoritiesRequest) ProtoMessage() {}
func (x *ExportIntegrationCertAuthoritiesRequest) ProtoReflect() protoreflect.Message {
mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[11]
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 ExportIntegrationCertAuthoritiesRequest.ProtoReflect.Descriptor instead.
func (*ExportIntegrationCertAuthoritiesRequest) Descriptor() ([]byte, []int) {
return file_teleport_integration_v1_integration_service_proto_rawDescGZIP(), []int{11}
}
func (x *ExportIntegrationCertAuthoritiesRequest) GetIntegration() string {
if x != nil {
return x.Integration
}
return ""
}
// ExportIntegrationCertAuthoritiesResponse is the response to
// ExportIntegrationCertAuthorities.
type ExportIntegrationCertAuthoritiesResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// CertAuthorities are the CA key sets used to sign any new certificates.
CertAuthorities *types.CAKeySet `protobuf:"bytes,1,opt,name=cert_authorities,json=certAuthorities,proto3" json:"cert_authorities,omitempty"`
}
func (x *ExportIntegrationCertAuthoritiesResponse) Reset() {
*x = ExportIntegrationCertAuthoritiesResponse{}
mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ExportIntegrationCertAuthoritiesResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ExportIntegrationCertAuthoritiesResponse) ProtoMessage() {}
func (x *ExportIntegrationCertAuthoritiesResponse) ProtoReflect() protoreflect.Message {
mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[12]
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 ExportIntegrationCertAuthoritiesResponse.ProtoReflect.Descriptor instead.
func (*ExportIntegrationCertAuthoritiesResponse) Descriptor() ([]byte, []int) {
return file_teleport_integration_v1_integration_service_proto_rawDescGZIP(), []int{12}
}
func (x *ExportIntegrationCertAuthoritiesResponse) GetCertAuthorities() *types.CAKeySet {
if x != nil {
return x.CertAuthorities
}
return nil
}
var File_teleport_integration_v1_integration_service_proto protoreflect.FileDescriptor
var file_teleport_integration_v1_integration_service_proto_rawDesc = []byte{
@@ -501,7 +729,9 @@ var file_teleport_integration_v1_integration_service_proto_rawDesc = []byte{
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x12, 0x17, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,
0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x1a, 0x1b, 0x67, 0x6f,
0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x1a, 0x1e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d,
0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x74, 0x65, 0x6c, 0x65, 0x70,
0x6f, 0x72, 0x74, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73,
@@ -547,60 +777,107 @@ var file_teleport_integration_v1_integration_service_proto_rawDesc = []byte{
0x1c, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x57, 0x53, 0x4f, 0x49, 0x44, 0x43,
0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a,
0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f,
0x6b, 0x65, 0x6e, 0x32, 0xef, 0x05, 0x0a, 0x12, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x77, 0x0a, 0x10, 0x4c, 0x69,
0x73, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x30,
0x6b, 0x65, 0x6e, 0x22, 0xbd, 0x01, 0x0a, 0x1d, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65,
0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x55, 0x73, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65,
0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69,
0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62,
0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69,
0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12,
0x15, 0x0a, 0x06, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x6b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x05, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03,
0x74, 0x74, 0x6c, 0x22, 0x47, 0x0a, 0x1e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x47,
0x69, 0x74, 0x48, 0x75, 0x62, 0x55, 0x73, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
0x7a, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x61,
0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x22, 0x4b, 0x0a, 0x27,
0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e,
0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x66, 0x0a, 0x28, 0x45, 0x78, 0x70,
0x6f, 0x72, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x65,
0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x10, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x61, 0x75,
0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x0f, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x41, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x74,
0x52, 0x0f, 0x63, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65,
0x73, 0x32, 0xa5, 0x08, 0x0a, 0x12, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x77, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74,
0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x30, 0x2e, 0x74,
0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31,
0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x74,
0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65,
0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49,
0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e,
0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e,
0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x31, 0x12, 0x5c, 0x0a, 0x11, 0x43,
0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x12, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65,
0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74,
0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75,
0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0x56, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69,
0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65,
0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x65,
0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x31, 0x12, 0x5c, 0x0a, 0x11, 0x55, 0x70, 0x64,
0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x31, 0x12, 0x5c, 0x0a, 0x11, 0x43, 0x72, 0x65,
0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x31,
0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49,
0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x31, 0x12, 0x5e, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x31, 0x12, 0x5c, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74,
0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x31, 0x2e, 0x74,
0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x74,
0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74,
0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x66, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x41, 0x6c, 0x6c, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x12, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65,
0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x41, 0x6c, 0x6c, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12,
0x83, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x57, 0x53, 0x4f,
0x49, 0x44, 0x43, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70,
0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e,
0x76, 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x57, 0x53, 0x4f, 0x49,
0x44, 0x43, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35,
0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x56, 0x31, 0x12, 0x5e, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49,
0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x31, 0x2e, 0x74, 0x65, 0x6c,
0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x66, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41,
0x6c, 0x6c, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x35,
0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41,
0x6c, 0x6c, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x83, 0x01,
0x0a, 0x14, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x57, 0x53, 0x4f, 0x49, 0x44,
0x43, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72,
0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31,
0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x57, 0x53, 0x4f, 0x49, 0x44, 0x43,
0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x74,
0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41,
0x57, 0x53, 0x4f, 0x49, 0x44, 0x43, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x89, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65,
0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x55, 0x73, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x12, 0x36,
0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74,
0x65, 0x41, 0x57, 0x53, 0x4f, 0x49, 0x44, 0x43, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 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, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x2f, 0x76, 0x31, 0x3b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x76,
0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x65, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x55, 0x73, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72,
0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31,
0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x55,
0x73, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0xa7, 0x01, 0x0a, 0x20, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
0x74, 0x69, 0x65, 0x73, 0x12, 0x40, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e,
0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45,
0x78, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x41, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72,
0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31,
0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65,
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 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, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x3b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -615,43 +892,55 @@ func file_teleport_integration_v1_integration_service_proto_rawDescGZIP() []byte
return file_teleport_integration_v1_integration_service_proto_rawDescData
}
var file_teleport_integration_v1_integration_service_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_teleport_integration_v1_integration_service_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
var file_teleport_integration_v1_integration_service_proto_goTypes = []any{
(*ListIntegrationsRequest)(nil), // 0: teleport.integration.v1.ListIntegrationsRequest
(*ListIntegrationsResponse)(nil), // 1: teleport.integration.v1.ListIntegrationsResponse
(*GetIntegrationRequest)(nil), // 2: teleport.integration.v1.GetIntegrationRequest
(*CreateIntegrationRequest)(nil), // 3: teleport.integration.v1.CreateIntegrationRequest
(*UpdateIntegrationRequest)(nil), // 4: teleport.integration.v1.UpdateIntegrationRequest
(*DeleteIntegrationRequest)(nil), // 5: teleport.integration.v1.DeleteIntegrationRequest
(*DeleteAllIntegrationsRequest)(nil), // 6: teleport.integration.v1.DeleteAllIntegrationsRequest
(*GenerateAWSOIDCTokenRequest)(nil), // 7: teleport.integration.v1.GenerateAWSOIDCTokenRequest
(*GenerateAWSOIDCTokenResponse)(nil), // 8: teleport.integration.v1.GenerateAWSOIDCTokenResponse
(*types.IntegrationV1)(nil), // 9: types.IntegrationV1
(*emptypb.Empty)(nil), // 10: google.protobuf.Empty
(*ListIntegrationsRequest)(nil), // 0: teleport.integration.v1.ListIntegrationsRequest
(*ListIntegrationsResponse)(nil), // 1: teleport.integration.v1.ListIntegrationsResponse
(*GetIntegrationRequest)(nil), // 2: teleport.integration.v1.GetIntegrationRequest
(*CreateIntegrationRequest)(nil), // 3: teleport.integration.v1.CreateIntegrationRequest
(*UpdateIntegrationRequest)(nil), // 4: teleport.integration.v1.UpdateIntegrationRequest
(*DeleteIntegrationRequest)(nil), // 5: teleport.integration.v1.DeleteIntegrationRequest
(*DeleteAllIntegrationsRequest)(nil), // 6: teleport.integration.v1.DeleteAllIntegrationsRequest
(*GenerateAWSOIDCTokenRequest)(nil), // 7: teleport.integration.v1.GenerateAWSOIDCTokenRequest
(*GenerateAWSOIDCTokenResponse)(nil), // 8: teleport.integration.v1.GenerateAWSOIDCTokenResponse
(*GenerateGitHubUserCertRequest)(nil), // 9: teleport.integration.v1.GenerateGitHubUserCertRequest
(*GenerateGitHubUserCertResponse)(nil), // 10: teleport.integration.v1.GenerateGitHubUserCertResponse
(*ExportIntegrationCertAuthoritiesRequest)(nil), // 11: teleport.integration.v1.ExportIntegrationCertAuthoritiesRequest
(*ExportIntegrationCertAuthoritiesResponse)(nil), // 12: teleport.integration.v1.ExportIntegrationCertAuthoritiesResponse
(*types.IntegrationV1)(nil), // 13: types.IntegrationV1
(*durationpb.Duration)(nil), // 14: google.protobuf.Duration
(*types.CAKeySet)(nil), // 15: types.CAKeySet
(*emptypb.Empty)(nil), // 16: google.protobuf.Empty
}
var file_teleport_integration_v1_integration_service_proto_depIdxs = []int32{
9, // 0: teleport.integration.v1.ListIntegrationsResponse.integrations:type_name -> types.IntegrationV1
9, // 1: teleport.integration.v1.CreateIntegrationRequest.integration:type_name -> types.IntegrationV1
9, // 2: teleport.integration.v1.UpdateIntegrationRequest.integration:type_name -> types.IntegrationV1
0, // 3: teleport.integration.v1.IntegrationService.ListIntegrations:input_type -> teleport.integration.v1.ListIntegrationsRequest
2, // 4: teleport.integration.v1.IntegrationService.GetIntegration:input_type -> teleport.integration.v1.GetIntegrationRequest
3, // 5: teleport.integration.v1.IntegrationService.CreateIntegration:input_type -> teleport.integration.v1.CreateIntegrationRequest
4, // 6: teleport.integration.v1.IntegrationService.UpdateIntegration:input_type -> teleport.integration.v1.UpdateIntegrationRequest
5, // 7: teleport.integration.v1.IntegrationService.DeleteIntegration:input_type -> teleport.integration.v1.DeleteIntegrationRequest
6, // 8: teleport.integration.v1.IntegrationService.DeleteAllIntegrations:input_type -> teleport.integration.v1.DeleteAllIntegrationsRequest
7, // 9: teleport.integration.v1.IntegrationService.GenerateAWSOIDCToken:input_type -> teleport.integration.v1.GenerateAWSOIDCTokenRequest
1, // 10: teleport.integration.v1.IntegrationService.ListIntegrations:output_type -> teleport.integration.v1.ListIntegrationsResponse
9, // 11: teleport.integration.v1.IntegrationService.GetIntegration:output_type -> types.IntegrationV1
9, // 12: teleport.integration.v1.IntegrationService.CreateIntegration:output_type -> types.IntegrationV1
9, // 13: teleport.integration.v1.IntegrationService.UpdateIntegration:output_type -> types.IntegrationV1
10, // 14: teleport.integration.v1.IntegrationService.DeleteIntegration:output_type -> google.protobuf.Empty
10, // 15: teleport.integration.v1.IntegrationService.DeleteAllIntegrations:output_type -> google.protobuf.Empty
8, // 16: teleport.integration.v1.IntegrationService.GenerateAWSOIDCToken:output_type -> teleport.integration.v1.GenerateAWSOIDCTokenResponse
10, // [10:17] is the sub-list for method output_type
3, // [3:10] 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
13, // 0: teleport.integration.v1.ListIntegrationsResponse.integrations:type_name -> types.IntegrationV1
13, // 1: teleport.integration.v1.CreateIntegrationRequest.integration:type_name -> types.IntegrationV1
13, // 2: teleport.integration.v1.UpdateIntegrationRequest.integration:type_name -> types.IntegrationV1
14, // 3: teleport.integration.v1.GenerateGitHubUserCertRequest.ttl:type_name -> google.protobuf.Duration
15, // 4: teleport.integration.v1.ExportIntegrationCertAuthoritiesResponse.cert_authorities:type_name -> types.CAKeySet
0, // 5: teleport.integration.v1.IntegrationService.ListIntegrations:input_type -> teleport.integration.v1.ListIntegrationsRequest
2, // 6: teleport.integration.v1.IntegrationService.GetIntegration:input_type -> teleport.integration.v1.GetIntegrationRequest
3, // 7: teleport.integration.v1.IntegrationService.CreateIntegration:input_type -> teleport.integration.v1.CreateIntegrationRequest
4, // 8: teleport.integration.v1.IntegrationService.UpdateIntegration:input_type -> teleport.integration.v1.UpdateIntegrationRequest
5, // 9: teleport.integration.v1.IntegrationService.DeleteIntegration:input_type -> teleport.integration.v1.DeleteIntegrationRequest
6, // 10: teleport.integration.v1.IntegrationService.DeleteAllIntegrations:input_type -> teleport.integration.v1.DeleteAllIntegrationsRequest
7, // 11: teleport.integration.v1.IntegrationService.GenerateAWSOIDCToken:input_type -> teleport.integration.v1.GenerateAWSOIDCTokenRequest
9, // 12: teleport.integration.v1.IntegrationService.GenerateGitHubUserCert:input_type -> teleport.integration.v1.GenerateGitHubUserCertRequest
11, // 13: teleport.integration.v1.IntegrationService.ExportIntegrationCertAuthorities:input_type -> teleport.integration.v1.ExportIntegrationCertAuthoritiesRequest
1, // 14: teleport.integration.v1.IntegrationService.ListIntegrations:output_type -> teleport.integration.v1.ListIntegrationsResponse
13, // 15: teleport.integration.v1.IntegrationService.GetIntegration:output_type -> types.IntegrationV1
13, // 16: teleport.integration.v1.IntegrationService.CreateIntegration:output_type -> types.IntegrationV1
13, // 17: teleport.integration.v1.IntegrationService.UpdateIntegration:output_type -> types.IntegrationV1
16, // 18: teleport.integration.v1.IntegrationService.DeleteIntegration:output_type -> google.protobuf.Empty
16, // 19: teleport.integration.v1.IntegrationService.DeleteAllIntegrations:output_type -> google.protobuf.Empty
8, // 20: teleport.integration.v1.IntegrationService.GenerateAWSOIDCToken:output_type -> teleport.integration.v1.GenerateAWSOIDCTokenResponse
10, // 21: teleport.integration.v1.IntegrationService.GenerateGitHubUserCert:output_type -> teleport.integration.v1.GenerateGitHubUserCertResponse
12, // 22: teleport.integration.v1.IntegrationService.ExportIntegrationCertAuthorities:output_type -> teleport.integration.v1.ExportIntegrationCertAuthoritiesResponse
14, // [14:23] is the sub-list for method output_type
5, // [5:14] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_teleport_integration_v1_integration_service_proto_init() }
@@ -665,7 +954,7 @@ func file_teleport_integration_v1_integration_service_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_teleport_integration_v1_integration_service_proto_rawDesc,
NumEnums: 0,
NumMessages: 9,
NumMessages: 13,
NumExtensions: 0,
NumServices: 1,
},
@@ -35,13 +35,15 @@ import (
const _ = grpc.SupportPackageIsVersion9
const (
IntegrationService_ListIntegrations_FullMethodName = "/teleport.integration.v1.IntegrationService/ListIntegrations"
IntegrationService_GetIntegration_FullMethodName = "/teleport.integration.v1.IntegrationService/GetIntegration"
IntegrationService_CreateIntegration_FullMethodName = "/teleport.integration.v1.IntegrationService/CreateIntegration"
IntegrationService_UpdateIntegration_FullMethodName = "/teleport.integration.v1.IntegrationService/UpdateIntegration"
IntegrationService_DeleteIntegration_FullMethodName = "/teleport.integration.v1.IntegrationService/DeleteIntegration"
IntegrationService_DeleteAllIntegrations_FullMethodName = "/teleport.integration.v1.IntegrationService/DeleteAllIntegrations"
IntegrationService_GenerateAWSOIDCToken_FullMethodName = "/teleport.integration.v1.IntegrationService/GenerateAWSOIDCToken"
IntegrationService_ListIntegrations_FullMethodName = "/teleport.integration.v1.IntegrationService/ListIntegrations"
IntegrationService_GetIntegration_FullMethodName = "/teleport.integration.v1.IntegrationService/GetIntegration"
IntegrationService_CreateIntegration_FullMethodName = "/teleport.integration.v1.IntegrationService/CreateIntegration"
IntegrationService_UpdateIntegration_FullMethodName = "/teleport.integration.v1.IntegrationService/UpdateIntegration"
IntegrationService_DeleteIntegration_FullMethodName = "/teleport.integration.v1.IntegrationService/DeleteIntegration"
IntegrationService_DeleteAllIntegrations_FullMethodName = "/teleport.integration.v1.IntegrationService/DeleteAllIntegrations"
IntegrationService_GenerateAWSOIDCToken_FullMethodName = "/teleport.integration.v1.IntegrationService/GenerateAWSOIDCToken"
IntegrationService_GenerateGitHubUserCert_FullMethodName = "/teleport.integration.v1.IntegrationService/GenerateGitHubUserCert"
IntegrationService_ExportIntegrationCertAuthorities_FullMethodName = "/teleport.integration.v1.IntegrationService/ExportIntegrationCertAuthorities"
)
// IntegrationServiceClient is the client API for IntegrationService service.
@@ -65,6 +67,10 @@ type IntegrationServiceClient interface {
DeleteAllIntegrations(ctx context.Context, in *DeleteAllIntegrationsRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
// GenerateAWSOIDCToken generates a token to be used when executing an AWS OIDC Integration action.
GenerateAWSOIDCToken(ctx context.Context, in *GenerateAWSOIDCTokenRequest, opts ...grpc.CallOption) (*GenerateAWSOIDCTokenResponse, error)
// GenerateGitHubUserCert signs a SSH certificate for GitHub integration.
GenerateGitHubUserCert(ctx context.Context, in *GenerateGitHubUserCertRequest, opts ...grpc.CallOption) (*GenerateGitHubUserCertResponse, error)
// ExportIntegrationCertAuthorities exports cert authorities for an integration.
ExportIntegrationCertAuthorities(ctx context.Context, in *ExportIntegrationCertAuthoritiesRequest, opts ...grpc.CallOption) (*ExportIntegrationCertAuthoritiesResponse, error)
}
type integrationServiceClient struct {
@@ -145,6 +151,26 @@ func (c *integrationServiceClient) GenerateAWSOIDCToken(ctx context.Context, in
return out, nil
}
func (c *integrationServiceClient) GenerateGitHubUserCert(ctx context.Context, in *GenerateGitHubUserCertRequest, opts ...grpc.CallOption) (*GenerateGitHubUserCertResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GenerateGitHubUserCertResponse)
err := c.cc.Invoke(ctx, IntegrationService_GenerateGitHubUserCert_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *integrationServiceClient) ExportIntegrationCertAuthorities(ctx context.Context, in *ExportIntegrationCertAuthoritiesRequest, opts ...grpc.CallOption) (*ExportIntegrationCertAuthoritiesResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ExportIntegrationCertAuthoritiesResponse)
err := c.cc.Invoke(ctx, IntegrationService_ExportIntegrationCertAuthorities_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// IntegrationServiceServer is the server API for IntegrationService service.
// All implementations must embed UnimplementedIntegrationServiceServer
// for forward compatibility.
@@ -166,6 +192,10 @@ type IntegrationServiceServer interface {
DeleteAllIntegrations(context.Context, *DeleteAllIntegrationsRequest) (*emptypb.Empty, error)
// GenerateAWSOIDCToken generates a token to be used when executing an AWS OIDC Integration action.
GenerateAWSOIDCToken(context.Context, *GenerateAWSOIDCTokenRequest) (*GenerateAWSOIDCTokenResponse, error)
// GenerateGitHubUserCert signs a SSH certificate for GitHub integration.
GenerateGitHubUserCert(context.Context, *GenerateGitHubUserCertRequest) (*GenerateGitHubUserCertResponse, error)
// ExportIntegrationCertAuthorities exports cert authorities for an integration.
ExportIntegrationCertAuthorities(context.Context, *ExportIntegrationCertAuthoritiesRequest) (*ExportIntegrationCertAuthoritiesResponse, error)
mustEmbedUnimplementedIntegrationServiceServer()
}
@@ -197,6 +227,12 @@ func (UnimplementedIntegrationServiceServer) DeleteAllIntegrations(context.Conte
func (UnimplementedIntegrationServiceServer) GenerateAWSOIDCToken(context.Context, *GenerateAWSOIDCTokenRequest) (*GenerateAWSOIDCTokenResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GenerateAWSOIDCToken not implemented")
}
func (UnimplementedIntegrationServiceServer) GenerateGitHubUserCert(context.Context, *GenerateGitHubUserCertRequest) (*GenerateGitHubUserCertResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GenerateGitHubUserCert not implemented")
}
func (UnimplementedIntegrationServiceServer) ExportIntegrationCertAuthorities(context.Context, *ExportIntegrationCertAuthoritiesRequest) (*ExportIntegrationCertAuthoritiesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ExportIntegrationCertAuthorities not implemented")
}
func (UnimplementedIntegrationServiceServer) mustEmbedUnimplementedIntegrationServiceServer() {}
func (UnimplementedIntegrationServiceServer) testEmbeddedByValue() {}
@@ -344,6 +380,42 @@ func _IntegrationService_GenerateAWSOIDCToken_Handler(srv interface{}, ctx conte
return interceptor(ctx, in, info, handler)
}
func _IntegrationService_GenerateGitHubUserCert_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GenerateGitHubUserCertRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(IntegrationServiceServer).GenerateGitHubUserCert(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: IntegrationService_GenerateGitHubUserCert_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(IntegrationServiceServer).GenerateGitHubUserCert(ctx, req.(*GenerateGitHubUserCertRequest))
}
return interceptor(ctx, in, info, handler)
}
func _IntegrationService_ExportIntegrationCertAuthorities_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ExportIntegrationCertAuthoritiesRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(IntegrationServiceServer).ExportIntegrationCertAuthorities(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: IntegrationService_ExportIntegrationCertAuthorities_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(IntegrationServiceServer).ExportIntegrationCertAuthorities(ctx, req.(*ExportIntegrationCertAuthoritiesRequest))
}
return interceptor(ctx, in, info, handler)
}
// IntegrationService_ServiceDesc is the grpc.ServiceDesc for IntegrationService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@@ -379,6 +451,14 @@ var IntegrationService_ServiceDesc = grpc.ServiceDesc{
MethodName: "GenerateAWSOIDCToken",
Handler: _IntegrationService_GenerateAWSOIDCToken_Handler,
},
{
MethodName: "GenerateGitHubUserCert",
Handler: _IntegrationService_GenerateGitHubUserCert_Handler,
},
{
MethodName: "ExportIntegrationCertAuthorities",
Handler: _IntegrationService_ExportIntegrationCertAuthorities_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "teleport/integration/v1/integration_service.proto",
@@ -16,6 +16,7 @@ syntax = "proto3";
package teleport.integration.v1;
import "google/protobuf/duration.proto";
import "google/protobuf/empty.proto";
import "teleport/legacy/types/types.proto";
@@ -44,6 +45,12 @@ service IntegrationService {
// GenerateAWSOIDCToken generates a token to be used when executing an AWS OIDC Integration action.
rpc GenerateAWSOIDCToken(GenerateAWSOIDCTokenRequest) returns (GenerateAWSOIDCTokenResponse);
// GenerateGitHubUserCert signs a SSH certificate for GitHub integration.
rpc GenerateGitHubUserCert(GenerateGitHubUserCertRequest) returns (GenerateGitHubUserCertResponse);
// ExportIntegrationCertAuthorities exports cert authorities for an integration.
rpc ExportIntegrationCertAuthorities(ExportIntegrationCertAuthoritiesRequest) returns (ExportIntegrationCertAuthoritiesResponse);
}
// ListIntegrationsRequest is a request for a paginated list of Integrations.
@@ -111,3 +118,38 @@ message GenerateAWSOIDCTokenResponse {
// Token is the signed JWT ready to be used
string token = 1;
}
// GenerateGitHubUserCertRequest is a request to sign a client certificate used by
// GitHub integration to authenticate with GitHub enterprise.
message GenerateGitHubUserCertRequest {
// Integration is the name of the integration;
string integration = 1;
// PublicKey is the public key to be signed.
bytes public_key = 2;
// UserId is the GitHub user id.
string user_id = 3;
// KeyId is the certificate ID, usually the Teleport username.
string key_id = 4;
// Ttl is the duration the certificate will be valid for.
google.protobuf.Duration ttl = 5;
}
// GenerateGitHubUserCertResponse contains a signed certificate.
message GenerateGitHubUserCertResponse {
// AuthorizedKey is the signed certificate.
bytes authorized_key = 1;
}
// ExportIntegrationCertAuthoritiesRequest is the request to export cert
// authorities for an integration.
message ExportIntegrationCertAuthoritiesRequest {
// Integration is the name of the integration;
string integration = 1;
}
// ExportIntegrationCertAuthoritiesResponse is the response to
// ExportIntegrationCertAuthorities.
message ExportIntegrationCertAuthoritiesResponse {
// CertAuthorities are the CA key sets used to sign any new certificates.
types.CAKeySet cert_authorities = 1;
}
+3
View File
@@ -1242,6 +1242,9 @@ type Cache interface {
// ListAccountAssignments fetches a paginated list of IdentityCenter Account Assignments
ListAccountAssignments(context.Context, int, *pagination.PageRequestToken) ([]services.IdentityCenterAccountAssignment, pagination.NextPageToken, error)
// GetPluginStaticCredentialsByLabels will get a list of plugin static credentials resource by matching labels.
GetPluginStaticCredentialsByLabels(ctx context.Context, labels map[string]string) ([]types.PluginStaticCredentials, error)
}
type NodeWrapper struct {
+3
View File
@@ -1892,6 +1892,9 @@ type ClientI interface {
// ProvisioningServiceClient returns provisioning service client.
ProvisioningServiceClient() provisioningv1.ProvisioningServiceClient
// IntegrationsClient returns integrations client.
IntegrationsClient() integrationv1.IntegrationServiceClient
// GitServerClient returns git server client.
GitServerClient() gitserverv1.GitServerServiceClient
}
@@ -0,0 +1,107 @@
/*
* Teleport
* Copyright (C) 2024 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 <http://www.gnu.org/licenses/>.
*/
package credentials
import (
"context"
"maps"
"github.com/google/uuid"
"github.com/gravitational/trace"
"github.com/gravitational/teleport/api/types"
)
// Package credentials defines constants and provides helper functions for
// integration credentials.
const (
// LabelStaticCredentialsIntegration is the label used to store the
// UUID ref in the static credentials.
LabelStaticCredentialsIntegration = types.TeleportInternalLabelPrefix + types.KindIntegration
// LabelStaticCredentialsPurpose is the label used to store the purpose of
// the static credentials.
LabelStaticCredentialsPurpose = "purpose"
// PurposeGitHubSSHCA is the label value that indicates the static
// credentials contains the GitHub SSH CA.
PurposeGitHubSSHCA = "github-sshca"
// PurposeGitHubOAuth is the label value that indicates the static
// credentials contains the GitHub OAuth ID and secret.
PurposeGitHubOAuth = "github-oauth"
)
// NewRef creates a new PluginStaticCredentialsRef that is saved along with the
// integration resource in the backend. The actual credentials are saved as
// PlugStaticCredentials and can only be retrieved by the ref.
func NewRef() *types.PluginStaticCredentialsRef {
return NewRefWithUUID(uuid.NewString())
}
// NewRefWithUUID creates a PluginStaticCredentialsRef with provided UUID.
func NewRefWithUUID(uuid string) *types.PluginStaticCredentialsRef {
return &types.PluginStaticCredentialsRef{
Labels: map[string]string{
LabelStaticCredentialsIntegration: uuid,
},
}
}
// CopyRefLabels copies the labels from the Ref to the actual credentials so the
// credentials can be retrieved using the same labels.
func CopyRefLabels(cred types.PluginStaticCredentials, ref *types.PluginStaticCredentialsRef) {
labels := cred.GetStaticLabels()
if labels == nil {
labels = make(map[string]string)
}
maps.Copy(labels, ref.Labels)
cred.SetStaticLabels(labels)
}
// ByLabelsGetter defines an interface to retrieve credentials by labels.
type ByLabelsGetter interface {
// GetPluginStaticCredentialsByLabels will get a list of plugin static credentials resource by matching labels.
GetPluginStaticCredentialsByLabels(ctx context.Context, labels map[string]string) ([]types.PluginStaticCredentials, error)
}
// GetByPurpose retrieves a credentials based on the provided purpose.
func GetByPurpose(ctx context.Context, ref *types.PluginStaticCredentialsRef, purpose string, getter ByLabelsGetter) (types.PluginStaticCredentials, error) {
if ref == nil {
return nil, trace.BadParameter("missing credentials ref")
}
labels := ref.Labels
if len(labels) == 0 {
return nil, trace.BadParameter("missing labels from credentials ref")
}
labels[LabelStaticCredentialsPurpose] = purpose
creds, err := getter.GetPluginStaticCredentialsByLabels(ctx, labels)
if err != nil {
return nil, trace.Wrap(err)
}
switch len(creds) {
case 0:
return nil, trace.NotFound("%v credentials not found", purpose)
case 1:
return creds[0], nil
default:
return nil, trace.CompareFailed("expecting one plugin static credentials but got %v", len(creds))
}
}
@@ -0,0 +1,139 @@
/*
* Teleport
* Copyright (C) 2024 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 <http://www.gnu.org/licenses/>.
*/
package credentials
import (
"context"
"fmt"
"maps"
"testing"
"github.com/google/uuid"
"github.com/gravitational/trace"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/gravitational/teleport/api/types"
)
type mockByLabelsGetter struct {
mock.Mock
}
func (m *mockByLabelsGetter) GetPluginStaticCredentialsByLabels(_ context.Context, labels map[string]string) ([]types.PluginStaticCredentials, error) {
args := m.Called(labels)
creds, ok := args.Get(0).([]types.PluginStaticCredentials)
if ok {
return creds, args.Error(1)
}
return nil, args.Error(1)
}
func mustMakeCred(t *testing.T, labels map[string]string) types.PluginStaticCredentials {
t.Helper()
cred, err := types.NewPluginStaticCredentials(
types.Metadata{
Name: uuid.NewString(),
Labels: labels,
},
types.PluginStaticCredentialsSpecV1{
Credentials: &types.PluginStaticCredentialsSpecV1_APIToken{
APIToken: "token",
},
},
)
require.NoError(t, err)
return cred
}
func TestGetByPurpose(t *testing.T) {
ref := NewRef()
purpose := "test-found"
labels := map[string]string{LabelStaticCredentialsPurpose: purpose}
maps.Copy(labels, ref.Labels)
cred := mustMakeCred(t, labels)
tests := []struct {
name string
ref *types.PluginStaticCredentialsRef
setupMock func(m *mockByLabelsGetter)
wantError func(error) bool
wantCred types.PluginStaticCredentials
}{
{
name: "nil ref",
ref: nil,
wantError: trace.IsBadParameter,
},
{
name: "success",
ref: ref,
setupMock: func(m *mockByLabelsGetter) {
m.On("GetPluginStaticCredentialsByLabels", labels).
Return([]types.PluginStaticCredentials{cred}, nil)
},
wantCred: cred,
},
{
name: "no creds found",
ref: ref,
setupMock: func(m *mockByLabelsGetter) {
m.On("GetPluginStaticCredentialsByLabels", labels).
Return([]types.PluginStaticCredentials{}, nil)
},
wantError: trace.IsNotFound,
},
{
name: "too mandy creds found",
ref: ref,
setupMock: func(m *mockByLabelsGetter) {
m.On("GetPluginStaticCredentialsByLabels", labels).
Return([]types.PluginStaticCredentials{cred, mustMakeCred(t, labels)}, nil)
},
wantError: trace.IsCompareFailed,
},
{
name: "backend issue",
ref: ref,
setupMock: func(m *mockByLabelsGetter) {
m.On("GetPluginStaticCredentialsByLabels", labels).
Return(nil, trace.ConnectionProblem(fmt.Errorf("backend"), "problem"))
},
wantError: trace.IsConnectionProblem,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
m := &mockByLabelsGetter{}
if test.setupMock != nil {
test.setupMock(m)
}
cred, err := GetByPurpose(context.Background(), test.ref, purpose, m)
if test.wantError != nil {
require.True(t, test.wantError(err))
return
}
require.NoError(t, err)
require.Equal(t, test.wantCred, cred)
})
}
}
@@ -20,47 +20,42 @@ package integrationv1
import (
"context"
"maps"
"github.com/google/uuid"
"github.com/gravitational/trace"
integrationpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/integration/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/auth/integration/credentials"
"github.com/gravitational/teleport/lib/cryptosuites"
)
const (
// labelStaticCredentialsIntegration is the label used to store the
// UUID ref in the static credentials.
labelStaticCredentialsIntegration = types.TeleportInternalLabelPrefix + types.KindIntegration
// labelStaticCredentialsPurpose is the label used to store the purpose of
// the static credentials.
labelStaticCredentialsPurpose = "purpose"
// purposeGitHubSSHCA is the label value that indicates the static
// credentials contains the GitHub SSH CA.
purposeGitHubSSHCA = "github-sshca"
// purposeGitHubOAuth is the label value that indicates the static
// credentials contains the GitHub OAuth ID and secret.
purposeGitHubOAuth = "github-oauth"
)
func newStaticCredentialsRef(uuid string) *types.PluginStaticCredentialsRef {
return &types.PluginStaticCredentialsRef{
Labels: map[string]string{
labelStaticCredentialsIntegration: uuid,
},
// ExportIntegrationCertAuthorities exports cert authorities for an integration.
func (s *Service) ExportIntegrationCertAuthorities(ctx context.Context, in *integrationpb.ExportIntegrationCertAuthoritiesRequest) (*integrationpb.ExportIntegrationCertAuthoritiesResponse, error) {
authCtx, err := s.authorizer.Authorize(ctx)
if err != nil {
return nil, trace.Wrap(err)
}
}
func copyRefLabels(cred types.PluginStaticCredentials, ref *types.PluginStaticCredentialsRef) {
labels := cred.GetStaticLabels()
if labels == nil {
labels = make(map[string]string)
if err := authCtx.CheckAccessToKind(types.KindIntegration, types.VerbRead); err != nil {
return nil, trace.Wrap(err)
}
ig, err := s.cache.GetIntegration(ctx, in.Integration)
if err != nil {
return nil, trace.Wrap(err)
}
maps.Copy(labels, ref.Labels)
cred.SetStaticLabels(labels)
// Currently only public keys are exported.
switch ig.GetSubKind() {
case types.IntegrationSubKindGitHub:
caKeySet, err := s.getGitHubCertAuthorities(ctx, ig)
if err != nil {
return nil, trace.Wrap(err)
}
caKeySetWithoutSecerts := caKeySet.WithoutSecrets()
return &integrationpb.ExportIntegrationCertAuthoritiesResponse{CertAuthorities: &caKeySetWithoutSecerts}, nil
default:
return nil, trace.BadParameter("unsupported for integration subkind %v", ig.GetSubKind())
}
}
func buildGitHubOAuthCredentials(ig types.Integration) (*types.PluginStaticCredentialsV1, error) {
@@ -73,7 +68,7 @@ func buildGitHubOAuthCredentials(ig types.Integration) (*types.PluginStaticCrede
Metadata: types.Metadata{
Name: uuid.NewString(),
Labels: map[string]string{
labelStaticCredentialsPurpose: purposeGitHubOAuth,
credentials.LabelStaticCredentialsPurpose: credentials.PurposeGitHubOAuth,
},
},
},
@@ -98,7 +93,7 @@ func (s *Service) newGitHubSSHCA(ctx context.Context) (*types.PluginStaticCreden
Metadata: types.Metadata{
Name: uuid.NewString(),
Labels: map[string]string{
labelStaticCredentialsPurpose: purposeGitHubSSHCA,
credentials.LabelStaticCredentialsPurpose: credentials.PurposeGitHubSSHCA,
},
},
},
@@ -132,11 +127,11 @@ func (s *Service) createGitHubCredentials(ctx context.Context, ig types.Integrat
}
func (s *Service) createStaticCredentials(ctx context.Context, ig types.Integration, creds ...types.PluginStaticCredentials) error {
ref := newStaticCredentialsRef(uuid.NewString())
ref := credentials.NewRef()
for _, cred := range creds {
s.logger.DebugContext(ctx, "Creating static credentials", "integration", ig.GetName(), "labels", cred.GetStaticLabels())
copyRefLabels(cred, ref)
credentials.CopyRefLabels(cred, ref)
if err := s.backend.CreatePluginStaticCredentials(ctx, cred); err != nil {
return trace.Wrap(err)
}
@@ -185,7 +180,7 @@ func (s *Service) updateStaticCredentials(ctx context.Context, ig types.Integrat
s.logger.DebugContext(ctx, "Updating static credentials", "integration", ig.GetName(), "labels", cred.GetStaticLabels())
// Use same labels to find existing credentials.
copyRefLabels(cred, ref)
credentials.CopyRefLabels(cred, ref)
oldCreds, err := s.backend.GetPluginStaticCredentialsByLabels(ctx, cred.GetStaticLabels())
if err != nil {
return trace.Wrap(err)
@@ -226,3 +221,29 @@ func (s *Service) removeStaticCredentials(ctx context.Context, ig types.Integrat
}
return trace.NewAggregate(errors...)
}
func (s *Service) getStaticCredentialsWithPurpose(ctx context.Context, ig types.Integration, purpose string) (types.PluginStaticCredentials, error) {
if ig.GetCredentials() == nil {
return nil, trace.BadParameter("missing credentials")
}
return credentials.GetByPurpose(ctx, ig.GetCredentials().GetStaticCredentialsRef(), purpose, s.cache)
}
func (s *Service) getGitHubCertAuthorities(ctx context.Context, ig types.Integration) (*types.CAKeySet, error) {
if ig.GetSubKind() != types.IntegrationSubKindGitHub {
return nil, trace.BadParameter("integration is not a GitHub integration")
}
creds, err := s.getStaticCredentialsWithPurpose(ctx, ig, credentials.PurposeGitHubSSHCA)
if err != nil {
return nil, trace.Wrap(err)
}
cas := creds.GetSSHCertAuthorities()
if len(cas) == 0 {
return nil, trace.BadParameter("missing SSH cert authorities from plugin static credentials")
}
return &types.CAKeySet{
SSH: cas,
}, nil
}
@@ -0,0 +1,125 @@
/*
* Teleport
* Copyright (C) 2024 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 <http://www.gnu.org/licenses/>.
*/
package integrationv1
import (
"context"
"testing"
"github.com/gravitational/trace"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
integrationpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/integration/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/authz"
)
func TestExportIntegrationCertAuthorities(t *testing.T) {
t.Parallel()
ca := newCertAuthority(t, types.HostCA, "test-cluster")
ctx, localClient, resourceSvc := initSvc(t, ca, ca.GetClusterName(), "127.0.0.1")
githubIntegration, err := newGitHubIntegration("github-my-org", "id", "secret")
require.NoError(t, err)
oidcIntegration, err := types.NewIntegrationAWSOIDC(
types.Metadata{Name: "aws-oidc"},
&types.AWSOIDCIntegrationSpecV1{
RoleARN: "arn:aws:iam::123456789012:role/OpsTeam",
},
)
require.NoError(t, err)
adminCtx := authz.ContextWithUser(ctx, authz.BuiltinRole{
Role: types.RoleAdmin,
Username: string(types.RoleAdmin),
})
_, err = resourceSvc.CreateIntegration(adminCtx, &integrationpb.CreateIntegrationRequest{Integration: githubIntegration})
require.NoError(t, err)
_, err = resourceSvc.CreateIntegration(adminCtx, &integrationpb.CreateIntegrationRequest{Integration: oidcIntegration})
require.NoError(t, err)
tests := []struct {
name string
integration string
identity context.Context
check func(*testing.T, *integrationpb.ExportIntegrationCertAuthoritiesResponse, error)
}{
{
name: "success",
integration: githubIntegration.GetName(),
identity: adminCtx,
check: func(t *testing.T, resp *integrationpb.ExportIntegrationCertAuthoritiesResponse, err error) {
t.Helper()
require.NoError(t, err)
require.NotNil(t, resp)
require.NotNil(t, resp.CertAuthorities)
require.Len(t, resp.CertAuthorities.SSH, 1)
require.NotNil(t, resp.CertAuthorities.SSH[0])
assert.NotEmpty(t, resp.CertAuthorities.SSH[0].PublicKey)
assert.Empty(t, resp.CertAuthorities.SSH[0].PrivateKey)
},
},
{
name: "not found",
integration: "not-found",
identity: adminCtx,
check: func(t *testing.T, resp *integrationpb.ExportIntegrationCertAuthoritiesResponse, err error) {
t.Helper()
require.Nil(t, resp)
require.Error(t, err)
require.True(t, trace.IsNotFound(err))
},
},
{
name: "not allowed",
integration: githubIntegration.GetName(),
identity: authorizerForDummyUser(t, ctx, types.RoleSpecV6{}, localClient),
check: func(t *testing.T, resp *integrationpb.ExportIntegrationCertAuthoritiesResponse, err error) {
t.Helper()
require.Nil(t, resp)
require.Error(t, err)
require.True(t, trace.IsAccessDenied(err))
},
},
{
name: "not supported",
integration: oidcIntegration.GetName(),
identity: adminCtx,
check: func(t *testing.T, resp *integrationpb.ExportIntegrationCertAuthoritiesResponse, err error) {
t.Helper()
require.Nil(t, resp)
require.Error(t, err)
require.True(t, trace.IsBadParameter(err))
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
resp, err := resourceSvc.ExportIntegrationCertAuthorities(test.identity, &integrationpb.ExportIntegrationCertAuthoritiesRequest{
Integration: test.integration,
})
test.check(t, resp, err)
})
}
}
@@ -0,0 +1,103 @@
/*
* Teleport
* Copyright (C) 2024 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 <http://www.gnu.org/licenses/>.
*/
package integrationv1
import (
"context"
"crypto/rand"
"time"
"github.com/gravitational/trace"
"golang.org/x/crypto/ssh"
integrationpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/integration/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/authz"
)
// GenerateGitHubUserCert signs a SSH certificate for GitHub integration.
func (s *Service) GenerateGitHubUserCert(ctx context.Context, in *integrationpb.GenerateGitHubUserCertRequest) (*integrationpb.GenerateGitHubUserCertResponse, error) {
authCtx, err := s.authorizer.Authorize(ctx)
if err != nil {
return nil, trace.Wrap(err)
}
if !authz.HasBuiltinRole(*authCtx, string(types.RoleProxy)) {
return nil, trace.AccessDenied("GenerateGitHubUserCert is only available to proxy services")
}
cert, err := s.prepareGitHubCert(in)
if err != nil {
return nil, trace.Wrap(err)
}
caSigner, err := s.getGitHubSigner(ctx, in.Integration)
if err != nil {
return nil, trace.Wrap(err)
}
if err := cert.SignCert(rand.Reader, caSigner); err != nil {
return nil, trace.Wrap(err)
}
return &integrationpb.GenerateGitHubUserCertResponse{
AuthorizedKey: ssh.MarshalAuthorizedKey(cert),
}, nil
}
func (s *Service) prepareGitHubCert(in *integrationpb.GenerateGitHubUserCertRequest) (*ssh.Certificate, error) {
if in.UserId == "" {
return nil, trace.BadParameter("missing UserId for GenerateGitHubUserCert")
}
if in.KeyId == "" {
return nil, trace.BadParameter("missing KeyId for GenerateGitHubUserCert")
}
key, _, _, _, err := ssh.ParseAuthorizedKey(in.PublicKey)
if err != nil {
return nil, trace.Wrap(err)
}
// Sign with user ID set in [email protected] extension.
// https://docs.github.com/en/enterprise-cloud@latest/organizations/managing-git-access-to-your-organizations-repositories/about-ssh-certificate-authorities
now := s.clock.Now()
cert := &ssh.Certificate{
Key: key,
CertType: ssh.UserCert,
KeyId: in.KeyId,
ValidAfter: uint64(now.Add(-time.Minute).Unix()),
ValidBefore: uint64(now.Add(in.Ttl.AsDuration()).Unix()),
Permissions: ssh.Permissions{
Extensions: map[string]string{
"[email protected]": in.UserId,
},
},
}
return cert, nil
}
func (s *Service) getGitHubSigner(ctx context.Context, integration string) (ssh.Signer, error) {
ig, err := s.cache.GetIntegration(ctx, integration)
if err != nil {
return nil, trace.Wrap(err)
}
caKeySet, err := s.getGitHubCertAuthorities(ctx, ig)
if err != nil {
return nil, trace.Wrap(err)
}
caSigner, err := s.keyStoreManager.GetSSHSignerFromKeySet(ctx, *caKeySet)
if err != nil {
return nil, trace.Wrap(err)
}
return caSigner, nil
}
@@ -0,0 +1,82 @@
/*
* Teleport
* Copyright (C) 2024 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 <http://www.gnu.org/licenses/>.
*/
package integrationv1
import (
"testing"
"time"
"github.com/gravitational/trace"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/ssh"
"google.golang.org/protobuf/types/known/durationpb"
integrationpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/integration/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/authz"
"github.com/gravitational/teleport/lib/cryptosuites"
)
func TestGenerateGitHubUserCert(t *testing.T) {
t.Parallel()
ca := newCertAuthority(t, types.HostCA, "test-cluster")
ctx, _, resourceSvc := initSvc(t, ca, ca.GetClusterName(), "127.0.0.1.nip.io")
githubIntegration, err := newGitHubIntegration("github-my-org", "id", "secret")
require.NoError(t, err)
adminCtx := authz.ContextWithUser(ctx, authz.BuiltinRole{
Role: types.RoleAdmin,
Username: string(types.RoleAdmin),
})
_, err = resourceSvc.CreateIntegration(adminCtx, &integrationpb.CreateIntegrationRequest{Integration: githubIntegration})
require.NoError(t, err)
key, err := cryptosuites.GeneratePrivateKeyWithAlgorithm(cryptosuites.Ed25519)
require.NoError(t, err)
req := &integrationpb.GenerateGitHubUserCertRequest{
Integration: "github-my-org",
PublicKey: key.MarshalSSHPublicKey(),
UserId: "1122334455",
KeyId: "alice",
Ttl: durationpb.New(time.Minute),
}
// Admin users cannot generate certs.
_, err = resourceSvc.GenerateGitHubUserCert(adminCtx, req)
require.True(t, trace.IsAccessDenied(err))
// Call as Proxy.
proxyCtx := authz.ContextWithUser(ctx, authz.BuiltinRole{
Role: types.RoleProxy,
Username: string(types.RoleProxy),
})
resp, err := resourceSvc.GenerateGitHubUserCert(proxyCtx, req)
require.NoError(t, err)
authorizedKey, _, _, _, err := ssh.ParseAuthorizedKey(resp.AuthorizedKey)
require.NoError(t, err)
sshCert, ok := authorizedKey.(*ssh.Certificate)
require.True(t, ok)
assert.Equal(t, "alice", sshCert.KeyId)
assert.Equal(t, map[string]string{"[email protected]": "1122334455"}, sshCert.Permissions.Extensions)
}
@@ -53,6 +53,9 @@ type Cache interface {
// IntegrationsGetter defines methods to access Integration resources.
services.IntegrationsGetter
// GetPluginStaticCredentialsByLabels will get a list of plugin static credentials resource by matching labels.
GetPluginStaticCredentialsByLabels(ctx context.Context, labels map[string]string) ([]types.PluginStaticCredentials, error)
}
// KeyStoreManager defines methods to get signers using the server's keystore.
@@ -30,6 +30,7 @@ import (
integrationpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/integration/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/types/externalauditstorage"
"github.com/gravitational/teleport/lib/auth/integration/credentials"
"github.com/gravitational/teleport/lib/auth/keystore"
"github.com/gravitational/teleport/lib/auth/testauthority"
"github.com/gravitational/teleport/lib/authz"
@@ -63,32 +64,6 @@ func TestIntegrationCRUD(t *testing.T) {
return ig
}
newGitHubIntegration := func(name, id, secret string) (*types.IntegrationV1, error) {
ig, err := types.NewIntegrationGitHub(
types.Metadata{
Name: name,
},
&types.GitHubIntegrationSpecV1{
Organization: "my-org",
},
)
if err != nil {
return nil, trace.Wrap(err)
}
if secret != "" {
ig.SetCredentials(&types.PluginCredentialsV1{
Credentials: &types.PluginCredentialsV1_IdSecret{
IdSecret: &types.PluginIdSecretCredential{
Id: id,
Secret: secret,
},
},
})
}
return ig, nil
}
tt := []struct {
Name string
Role types.RoleSpecV6
@@ -446,7 +421,7 @@ func TestIntegrationCRUD(t *testing.T) {
refUUID := uuid.NewString()
ig.SetCredentials(&types.PluginCredentialsV1{
Credentials: &types.PluginCredentialsV1_StaticCredentialsRef{
StaticCredentialsRef: newStaticCredentialsRef(refUUID),
StaticCredentialsRef: credentials.NewRefWithUUID(refUUID),
},
})
@@ -459,8 +434,8 @@ func TestIntegrationCRUD(t *testing.T) {
Metadata: types.Metadata{
Name: igName,
Labels: map[string]string{
labelStaticCredentialsIntegration: refUUID,
labelStaticCredentialsPurpose: "test",
credentials.LabelStaticCredentialsIntegration: refUUID,
credentials.LabelStaticCredentialsPurpose: "test",
},
},
},
@@ -652,7 +627,8 @@ func initSvc(t *testing.T, ca types.CertAuthority, clusterName string, proxyPubl
PublicAddrs: []string{proxyPublicAddr},
}},
},
IntegrationsService: *cacheResourceService,
IntegrationsService: *cacheResourceService,
PluginStaticCredentialsService: localCredService,
}
resourceSvc, err := NewService(&ServiceConfig{
@@ -689,6 +665,7 @@ type mockCache struct {
returnErr error
local.IntegrationsService
*local.PluginStaticCredentialsService
}
func (m *mockCache) GetProxies() ([]types.Server, error) {
@@ -769,6 +746,32 @@ func newPlugin(t *testing.T, integrationName string) *types.PluginV1 {
}
}
func newGitHubIntegration(name, id, secret string) (*types.IntegrationV1, error) {
ig, err := types.NewIntegrationGitHub(
types.Metadata{
Name: name,
},
&types.GitHubIntegrationSpecV1{
Organization: "my-org",
},
)
if err != nil {
return nil, trace.Wrap(err)
}
if secret != "" {
ig.SetCredentials(&types.PluginCredentialsV1{
Credentials: &types.PluginCredentialsV1_IdSecret{
IdSecret: &types.PluginIdSecretCredential{
Id: id,
Secret: secret,
},
},
})
}
return ig, nil
}
func mustFindGitHubCredentials(t *testing.T, localClient Backend, igName, wantId, wantSecret string) {
t.Helper()
+1 -1
View File
@@ -58,7 +58,7 @@ var _ executor[types.PluginStaticCredentials, pluginStaticCredentialsGetter] = p
type pluginStaticCredentialsExecutor struct{}
func (pluginStaticCredentialsExecutor) getAll(ctx context.Context, cache *Cache, loadSecrets bool) ([]types.PluginStaticCredentials, error) {
return cache.pluginStaticCredentialsCache.GetAllPluginStaticCredentials(ctx)
return cache.PluginStaticCredentials.GetAllPluginStaticCredentials(ctx)
}
func (pluginStaticCredentialsExecutor) upsert(ctx context.Context, cache *Cache, resource types.PluginStaticCredentials) error {
+76
View File
@@ -22,12 +22,15 @@ import (
"context"
"encoding/pem"
"errors"
"fmt"
"log/slog"
"strings"
"time"
"github.com/gravitational/trace"
apidefaults "github.com/gravitational/teleport/api/defaults"
integrationpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/integration/v1"
"github.com/gravitational/teleport/api/mfa"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/auth/authclient"
@@ -49,6 +52,23 @@ type ExportAuthoritiesRequest struct {
AuthType string
ExportAuthorityFingerprint string
UseCompatVersion bool
Integration string
}
func (r *ExportAuthoritiesRequest) shouldExportIntegration(ctx context.Context) (bool, error) {
switch r.AuthType {
case "github":
if r.Integration == "" {
return false, trace.BadParameter("integration name must be provided for %q CAs", r.AuthType)
}
return true, nil
default:
if r.Integration != "" {
r.Integration = ""
slog.DebugContext(ctx, "Integration name is ignored for non-integration CAs")
}
return false, nil
}
}
// ExportAuthorities returns the list of authorities in OpenSSH compatible formats as a string.
@@ -76,12 +96,22 @@ type ExportAuthoritiesRequest struct {
// > @cert-authority *.cluster-a ssh-rsa AAA... type=host
// URL encoding is used to pass the CA type and allowed logins into the comment field.
func ExportAuthorities(ctx context.Context, client authclient.ClientI, req ExportAuthoritiesRequest) (string, error) {
if isIntegration, err := req.shouldExportIntegration(ctx); err != nil {
return "", trace.Wrap(err)
} else if isIntegration {
return exportAuthForIntegration(ctx, client, req)
}
return exportAuth(ctx, client, req, false /* exportSecrets */)
}
// ExportAuthoritiesSecrets exports the Authority Certificate secrets (private keys).
// See ExportAuthorities for more information.
func ExportAuthoritiesSecrets(ctx context.Context, client authclient.ClientI, req ExportAuthoritiesRequest) (string, error) {
if isIntegration, err := req.shouldExportIntegration(ctx); err != nil {
return "", trace.Wrap(err)
} else if isIntegration {
return "", trace.NotImplemented("export with secrets is not supported for %q CAs", req.AuthType)
}
return exportAuth(ctx, client, req, true /* exportSecrets */)
}
@@ -344,3 +374,49 @@ func hostCAFormat(ca types.CertAuthority, keyBytes []byte, client authclient.Cli
},
})
}
func exportAuthForIntegration(ctx context.Context, client authclient.ClientI, req ExportAuthoritiesRequest) (string, error) {
switch req.AuthType {
case "github":
keySet, err := fetchIntegrationCAKeySet(ctx, client, req.Integration)
if err != nil {
return "", trace.Wrap(err)
}
ret, err := exportGitHubCAs(keySet, req)
if err != nil {
return "", trace.Wrap(err)
}
return ret, nil
default:
return "", trace.BadParameter("unknown integration CA type %q", req.AuthType)
}
}
func fetchIntegrationCAKeySet(ctx context.Context, client authclient.ClientI, integration string) (*types.CAKeySet, error) {
resp, err := client.IntegrationsClient().ExportIntegrationCertAuthorities(ctx, &integrationpb.ExportIntegrationCertAuthoritiesRequest{
Integration: integration,
})
if err != nil {
return nil, trace.Wrap(err)
}
return resp.CertAuthorities, nil
}
func exportGitHubCAs(keySet *types.CAKeySet, req ExportAuthoritiesRequest) (string, error) {
ret := strings.Builder{}
for _, key := range keySet.SSH {
if req.ExportAuthorityFingerprint != "" {
if fingerprint, err := sshutils.AuthorizedKeyFingerprint(key.PublicKey); err != nil {
return "", trace.Wrap(err)
} else if !sshutils.EqualFingerprints(req.ExportAuthorityFingerprint, fingerprint) {
continue
}
}
// GitHub only needs the keys like "ssh-rsa xxx" so print them without
// cert-authority for easier copy-and-paste.
ret.WriteString(fmt.Sprintf("%s integration=%s\n", strings.TrimSpace(string(key.PublicKey)), req.Integration))
}
return ret.String(), nil
}
+51 -1
View File
@@ -26,18 +26,22 @@ import (
"testing"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
"github.com/gravitational/teleport/api/client/proto"
integrationpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/integration/v1"
"github.com/gravitational/teleport/api/mfa"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/utils/keys"
"github.com/gravitational/teleport/lib/auth"
"github.com/gravitational/teleport/lib/auth/authclient"
"github.com/gravitational/teleport/lib/fixtures"
)
type mockAuthClient struct {
authclient.ClientI
server *auth.Server
server *auth.Server
integrationsClient mockIntegrationsClient
}
func (m *mockAuthClient) GetDomainName(ctx context.Context) (string, error) {
@@ -57,6 +61,21 @@ func (m *mockAuthClient) PerformMFACeremony(ctx context.Context, challengeReques
return nil, &mfa.ErrMFANotRequired
}
func (m *mockAuthClient) IntegrationsClient() integrationpb.IntegrationServiceClient {
return &m.integrationsClient
}
type mockIntegrationsClient struct {
integrationpb.IntegrationServiceClient
caKeySet *types.CAKeySet
}
func (m *mockIntegrationsClient) ExportIntegrationCertAuthorities(ctx context.Context, in *integrationpb.ExportIntegrationCertAuthoritiesRequest, opts ...grpc.CallOption) (*integrationpb.ExportIntegrationCertAuthoritiesResponse, error) {
return &integrationpb.ExportIntegrationCertAuthoritiesResponse{
CertAuthorities: m.caKeySet,
}, nil
}
func TestExportAuthorities(t *testing.T) {
ctx := context.Background()
const localClusterName = "localcluster"
@@ -100,6 +119,10 @@ func TestExportAuthorities(t *testing.T) {
require.NotNil(t, privKey, "x509.ParsePKCS8PrivateKey returned a nil key")
}
validateGitHubCAFunc := func(t *testing.T, s string) {
require.Contains(t, s, fixtures.SSHCAPublicKey)
}
for _, exportSecrets := range []bool{false, true} {
for _, tt := range []struct {
name string
@@ -247,10 +270,33 @@ func TestExportAuthorities(t *testing.T) {
assertNoSecrets: validateTLSCertificateDERFunc,
assertSecrets: validateRSAPrivateKeyDERFunc,
},
{
name: "github missing integration",
req: ExportAuthoritiesRequest{
AuthType: "github",
},
errorCheck: require.Error,
},
{
name: "github",
req: ExportAuthoritiesRequest{
AuthType: "github",
Integration: "my-github",
},
errorCheck: require.NoError,
assertNoSecrets: validateGitHubCAFunc,
},
} {
t.Run(fmt.Sprintf("%s_exportSecrets_%v", tt.name, exportSecrets), func(t *testing.T) {
mockedClient := &mockAuthClient{
server: testAuth.AuthServer,
integrationsClient: mockIntegrationsClient{
caKeySet: &types.CAKeySet{
SSH: []*types.SSHKeyPair{{
PublicKey: []byte(fixtures.SSHCAPublicKey),
}},
},
},
}
var (
err error
@@ -264,6 +310,10 @@ func TestExportAuthorities(t *testing.T) {
checkFunc = tt.assertSecrets
}
if checkFunc == nil {
t.Skip("assert func not provided")
}
exported, err = exportFunc(ctx, mockedClient, tt.req)
tt.errorCheck(t, err)
@@ -44,6 +44,9 @@ type PluginStaticCredentials interface {
// DeletePluginStaticCredentials will delete a plugin static credentials resource.
DeletePluginStaticCredentials(ctx context.Context, name string) error
// GetAllPluginStaticCredentials will get all plugin static credentials.
GetAllPluginStaticCredentials(ctx context.Context) ([]types.PluginStaticCredentials, error)
}
// MarshalPluginStaticCredentials marshals PluginStaticCredentials resource to JSON.
+17
View File
@@ -19,6 +19,8 @@
package sshutils
import (
"strings"
"github.com/gravitational/trace"
"golang.org/x/crypto/ssh"
)
@@ -47,3 +49,18 @@ func PrivateKeyFingerprint(keyBytes []byte) (string, error) {
}
return Fingerprint(signer.PublicKey()), nil
}
// fingerprintPrefix is the fingerprint prefix added by ssh.FingerprintSHA256.
const fingerprintPrefix = "SHA256:"
func maybeAddPrefix(fingerprint string) string {
if !strings.HasPrefix(fingerprint, fingerprintPrefix) {
return fingerprintPrefix + fingerprint
}
return fingerprint
}
// EqualFingerprints checks if two finger prints are equal.
func EqualFingerprints(a, b string) bool {
return strings.EqualFold(maybeAddPrefix(a), maybeAddPrefix(b))
}
+64
View File
@@ -0,0 +1,64 @@
/*
* Teleport
* Copyright (C) 2024 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 <http://www.gnu.org/licenses/>.
*/
package sshutils
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestEqualFingerprints(t *testing.T) {
tests := []struct {
name string
a string
b string
check require.BoolAssertionFunc
}{
{
name: "equal",
a: "SHA256:fingerprint",
b: "SHA256:fingerprint",
check: require.True,
},
{
name: "not equal",
a: "SHA256:fingerprint",
b: "SHA256:fingerprint2",
check: require.False,
},
{
name: "equal without prefix",
a: "SHA256:fingerprint",
b: "fingerprint",
check: require.True,
},
{
name: "equal fold",
a: "FINGERPRINT",
b: "SHA256:fingerprint",
check: require.True,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
test.check(t, EqualFingerprints(test.a, test.b))
})
}
}
+4
View File
@@ -87,6 +87,7 @@ type AuthCommand struct {
caType string
streamTarfile bool
identityWriter identityfile.ConfigWriter
integration string
rotateGracePeriod time.Duration
rotateType string
@@ -116,6 +117,7 @@ func (a *AuthCommand) Initialize(app *kingpin.Application, config *servicecfg.Co
a.authExport.Flag("type",
fmt.Sprintf("export certificate type (%v)", strings.Join(allowedCertificateTypes, ", "))).
EnumVar(&a.authType, allowedCertificateTypes...)
a.authExport.Flag("integration", "Name of the integration. Only applies to \"github\" CAs.").StringVar(&a.integration)
a.authGenerate = auth.Command("gen", "Generate a new SSH keypair.").Hidden()
a.authGenerate.Flag("pub-key", "path to the public key").Required().StringVar(&a.genPubPath)
@@ -206,6 +208,7 @@ var allowedCertificateTypes = []string{
"db-client-der",
"openssh",
"saml-idp",
"github",
}
// allowedCRLCertificateTypes list of certificate authorities types that can
@@ -233,6 +236,7 @@ func (a *AuthCommand) ExportAuthorities(ctx context.Context, clt *authclient.Cli
AuthType: a.authType,
ExportAuthorityFingerprint: a.exportAuthorityFingerprint,
UseCompatVersion: a.compatVersion == "1.0",
Integration: a.integration,
},
)
if err != nil {