mirror of
https://github.com/gravitational/teleport.git
synced 2026-10-12 02:15:01 +00:00
Apply overrides to Windows certificates (#66411)
* Apply overrides to Windows certificates * Add lib/subca.CalculateOverrideResult.ToClientOverrideDetailsProto * Propagate CA override details to audit
This commit is contained in:
@@ -151,6 +151,7 @@ import (
|
||||
dbvnet "github.com/gravitational/teleport/lib/srv/db/vnet"
|
||||
"github.com/gravitational/teleport/lib/sshca"
|
||||
"github.com/gravitational/teleport/lib/sshutils"
|
||||
"github.com/gravitational/teleport/lib/subca"
|
||||
"github.com/gravitational/teleport/lib/tlsca"
|
||||
"github.com/gravitational/teleport/lib/tpm"
|
||||
usagereporter "github.com/gravitational/teleport/lib/usagereporter/teleport"
|
||||
@@ -788,6 +789,7 @@ func NewServer(cfg *InitConfig, opts ...ServerOption) (as *Server, err error) {
|
||||
insecureMode: cfg.InsecureMode,
|
||||
remoteClusterRefreshLimit: cmp.Or(cfg.RemoteClusterRefreshLimit, defaultRemoteClusterRefreshLimit),
|
||||
remoteClusterRefreshBuckets: cmp.Or(cfg.RemoteClusterRefreshBuckets, defaultRemoteClusterRefreshBuckets),
|
||||
subCAEnabled: subca.Enabled(),
|
||||
}
|
||||
as.inventory = inventory.NewController(as, services,
|
||||
inventory.WithAuthServerID(cfg.HostUUID),
|
||||
@@ -1558,6 +1560,10 @@ type Server struct {
|
||||
// RemoteClusterRefreshBuckets is the maximum number of refresh cycles that should guarantee the status update
|
||||
// of all remote clusters if their number exceeds RemoteClusterRefreshLimit × RemoteClusterRefreshBuckets.
|
||||
remoteClusterRefreshBuckets int
|
||||
|
||||
// subCAEnabled records the value of subca.Enabled()
|
||||
// Used by tests to enable the feature.
|
||||
subCAEnabled bool
|
||||
}
|
||||
|
||||
// SetSAMLService registers svc as the SAMLService that provides the SAML
|
||||
|
||||
+18
-1
@@ -37,6 +37,7 @@ import (
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
"github.com/gravitational/teleport/entitlements"
|
||||
"github.com/gravitational/teleport/lib/authz"
|
||||
"github.com/gravitational/teleport/lib/subca"
|
||||
"github.com/gravitational/teleport/lib/tlsca"
|
||||
"github.com/gravitational/teleport/lib/utils"
|
||||
"github.com/gravitational/teleport/lib/winpki"
|
||||
@@ -88,6 +89,21 @@ func (a *Server) GenerateWindowsDesktopCert(ctx context.Context, req *proto.Wind
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
// Calculate CA override.
|
||||
subCAResolver, err := subca.NewCAOverrideResolver(a.Cache, a.subCAEnabled)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
overrideResult, err := subCAResolver.CalculateOverride(ctx, types.CertAuthorityOverrideID{
|
||||
ClusterName: ca.GetClusterName(),
|
||||
CAType: string(ca.GetType()),
|
||||
}, subca.Certificate{PEM: caCert})
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err, "calculate CA override")
|
||||
}
|
||||
caCert = overrideResult.CACertificate.PEM
|
||||
|
||||
tlsCA, err := tlsca.FromCertAndSigner(caCert, signer)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
@@ -136,7 +152,8 @@ func (a *Server) GenerateWindowsDesktopCert(ctx context.Context, req *proto.Wind
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return &proto.WindowsDesktopCertResponse{
|
||||
Cert: cert,
|
||||
Cert: cert,
|
||||
CaOverride: overrideResult.ToClientOverrideDetailsProto(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -19,13 +19,22 @@
|
||||
package auth_test
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
|
||||
"github.com/gravitational/teleport/api/client/proto"
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
"github.com/gravitational/teleport/api/utils/tlsutils"
|
||||
"github.com/gravitational/teleport/lib/modules"
|
||||
"github.com/gravitational/teleport/lib/modules/modulestest"
|
||||
"github.com/gravitational/teleport/lib/subca/testenv"
|
||||
"github.com/gravitational/teleport/lib/winpki"
|
||||
)
|
||||
|
||||
// TestDesktopAccessDisabled makes sure desktop access can be disabled via modules.
|
||||
@@ -49,3 +58,76 @@ func TestDesktopAccessDisabled(t *testing.T) {
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "this Teleport cluster is not licensed for desktop access, please contact the cluster administrator")
|
||||
}
|
||||
|
||||
func TestDesktopAccessCAOverrides(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tlsServer := newTestTLSServer(t)
|
||||
authServer := tlsServer.Auth()
|
||||
authServer.SetSubCAEnabled(true)
|
||||
|
||||
cn, err := authServer.GetClusterName(t.Context())
|
||||
require.NoError(t, err)
|
||||
clusterName := cn.GetClusterName()
|
||||
|
||||
// Fetch the CA and self-signed certificate.
|
||||
const loadKeys = false
|
||||
ca, err := authServer.GetCertAuthority(t.Context(), types.CertAuthID{
|
||||
Type: types.WindowsCA,
|
||||
DomainName: clusterName,
|
||||
}, loadKeys)
|
||||
require.NoError(t, err)
|
||||
caCert, err := tlsutils.ParseCertificatePEM(ca.GetActiveKeys().TLS[0].Cert)
|
||||
require.NoError(t, err)
|
||||
|
||||
runTest := func(
|
||||
t *testing.T,
|
||||
wantParent *x509.Certificate,
|
||||
wantDetails *proto.CAOverrideCertificateDetails,
|
||||
) {
|
||||
genResp, err := winpki.GenerateWindowsDesktopCredentials(t.Context(), authServer, &winpki.GenerateCredentialsRequest{
|
||||
Username: "Administrator",
|
||||
Domain: "LLAMA",
|
||||
TTL: 1 * time.Hour,
|
||||
ClusterName: clusterName,
|
||||
})
|
||||
require.NoError(t, err, "GenerateWindowsDesktopCredentials errored")
|
||||
|
||||
genCert, err := x509.ParseCertificate(genResp.CertDER)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NoError(t,
|
||||
genCert.CheckSignatureFrom(wantParent),
|
||||
"Certificate signature verification failed (self-signed CA)",
|
||||
)
|
||||
if diff := cmp.Diff(wantDetails, genResp.CAOverrideDetails, protocmp.Transform()); diff != "" {
|
||||
t.Errorf("genResp.CAOverrideDetails mismatch (-want +got)\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("generate without override", func(t *testing.T) {
|
||||
runTest(t, caCert, nil)
|
||||
})
|
||||
|
||||
// Create an active override for caCert.
|
||||
externalCA, err := testenv.NewSelfSignedCA(nil)
|
||||
require.NoError(t, err)
|
||||
env := &testenv.Env{
|
||||
Clock: tlsServer.Clock(),
|
||||
ClusterName: clusterName,
|
||||
ExternalRoot: externalCA,
|
||||
}
|
||||
caOverride := env.NewOverrideForCA(t, ca, nil)
|
||||
override := caOverride.Spec.CertificateOverrides[0]
|
||||
override.Disabled = false // enable
|
||||
_, err = authServer.CreateCertAuthorityOverride(t.Context(), caOverride)
|
||||
require.NoError(t, err, "CreateCertAuthorityOverride errored")
|
||||
overrideCert, err := tlsutils.ParseCertificatePEM([]byte(override.Certificate))
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("generate with override", func(t *testing.T) {
|
||||
runTest(t, overrideCert, &proto.CAOverrideCertificateDetails{
|
||||
PublicKeyHash: override.PublicKey,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -207,6 +207,10 @@ func (a *Server) CreateGithubUser(ctx context.Context, p *CreateUserParams, dryR
|
||||
return a.createGithubUser(ctx, p, dryRun)
|
||||
}
|
||||
|
||||
func (a *Server) SetSubCAEnabled(b bool) {
|
||||
a.subCAEnabled = b
|
||||
}
|
||||
|
||||
func BuildAPIEndpoint(apiEndpointURLStr string) (string, error) {
|
||||
return buildAPIEndpoint(apiEndpointURLStr)
|
||||
}
|
||||
|
||||
@@ -52,6 +52,8 @@ type desktopSessionAuditor struct {
|
||||
|
||||
compactor auditCompactor
|
||||
auditCache sharedDirectoryAuditCache
|
||||
|
||||
caOverrideDetails *events.CAOverrideCertificateDetails
|
||||
}
|
||||
|
||||
func (d *desktopSessionAuditor) getSessionMetadata() events.SessionMetadata {
|
||||
@@ -115,6 +117,7 @@ func (d *desktopSessionAuditor) makeSessionStart(err error) *events.WindowsDeskt
|
||||
WindowsUser: d.windowsUser,
|
||||
DesktopLabels: d.desktop.GetAllLabels(),
|
||||
NLA: d.enableNLA && !d.desktop.NonAD(),
|
||||
CAOverride: d.caOverrideDetails,
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/jonboulle/clockwork"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
|
||||
tdpbv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/desktop/v1"
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
@@ -171,6 +172,23 @@ func TestSessionStartEvent(t *testing.T) {
|
||||
require.Empty(t, cmp.Diff(test.exp(), *startEvent))
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("audit emits CAOverride details", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, audit := setup(testDesktop)
|
||||
|
||||
const aPublicKeyHash = "6fbd7ba3f34c526f5d6d8ea2659f9fb5ca031712ee588ce35941d568742d44ed"
|
||||
audit.caOverrideDetails = &events.CAOverrideCertificateDetails{
|
||||
Active: true,
|
||||
PublicKeyHash: aPublicKeyHash,
|
||||
}
|
||||
|
||||
got := audit.makeSessionStart(nil)
|
||||
if diff := cmp.Diff(audit.caOverrideDetails, got.CAOverride, protocmp.Transform()); diff != "" {
|
||||
t.Errorf("CAOverrideDetails mismatch (-want +got)\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSessionEndEvent(t *testing.T) {
|
||||
|
||||
@@ -487,7 +487,7 @@ func (s *WindowsService) issueNewTLSConfigForLDAP() (*tls.Config, error) {
|
||||
if s.cfg.SID == "" {
|
||||
s.cfg.Logger.WarnContext(context.Background(), "LDAP configuration is missing service account SID")
|
||||
}
|
||||
certDER, keyDER, err := s.generateCredentials(s.closeCtx, generateCredentialsRequest{
|
||||
genResp, err := s.generateCredentials(s.closeCtx, generateCredentialsRequest{
|
||||
username: user,
|
||||
domain: s.cfg.Domain,
|
||||
ttl: windowsDesktopServiceCertTTL,
|
||||
@@ -498,12 +498,12 @@ func (s *WindowsService) issueNewTLSConfigForLDAP() (*tls.Config, error) {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
cert, err := x509.ParseCertificate(certDER)
|
||||
cert, err := x509.ParseCertificate(genResp.CertDER)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err, "parsing cert DER")
|
||||
}
|
||||
|
||||
key, err := x509.ParsePKCS1PrivateKey(keyDER)
|
||||
key, err := x509.ParsePKCS1PrivateKey(genResp.KeyDER)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err, "parsing key DER")
|
||||
}
|
||||
@@ -944,10 +944,20 @@ func (s *WindowsService) connectRDP(ctx context.Context, log *slog.Logger, tdpCo
|
||||
}
|
||||
|
||||
// Generate client certificates to be used for the RDP connection.
|
||||
certDER, keyDER, err := s.generateUserCert(ctx, windowsUser, windowsUserCertTTL, desktop, createUsers, groups)
|
||||
genResp, err := s.generateUserCert(ctx, windowsUser, windowsUserCertTTL, desktop, createUsers, groups)
|
||||
if err != nil {
|
||||
return trace.Wrap(err, "could not generate client certificates for RDP")
|
||||
}
|
||||
certDER := genResp.CertDER
|
||||
keyDER := genResp.KeyDER
|
||||
|
||||
// Include CA override data in audit.
|
||||
if genResp.CAOverrideDetails != nil {
|
||||
audit.caOverrideDetails = &events.CAOverrideCertificateDetails{
|
||||
Active: true,
|
||||
PublicKeyHash: genResp.CAOverrideDetails.PublicKeyHash,
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.trackSession(ctx, &identity, windowsUser, string(sessionID), desktop); err != nil {
|
||||
return trace.Wrap(err)
|
||||
@@ -1280,7 +1290,14 @@ type entry struct {
|
||||
|
||||
// generateUserCert generates a keypair for the given Windows username,
|
||||
// optionally querying LDAP for the user's Security Identifier.
|
||||
func (s *WindowsService) generateUserCert(ctx context.Context, username string, ttl time.Duration, desktop types.WindowsDesktop, createUsers bool, groups []string) (certDER, keyDER []byte, err error) {
|
||||
func (s *WindowsService) generateUserCert(
|
||||
ctx context.Context,
|
||||
username string,
|
||||
ttl time.Duration,
|
||||
desktop types.WindowsDesktop,
|
||||
createUsers bool,
|
||||
groups []string,
|
||||
) (*winpki.GenerateCredentialsResponse, error) {
|
||||
var activeDirectorySID string
|
||||
var distinguishedName string
|
||||
|
||||
@@ -1314,12 +1331,12 @@ func (s *WindowsService) generateUserCert(ctx context.Context, username string,
|
||||
}, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, trace.Wrap(err)
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
activeDirectorySID = entry.sid
|
||||
distinguishedName = entry.distinguishedName
|
||||
}
|
||||
return s.generateCredentials(ctx, generateCredentialsRequest{
|
||||
genResp, err := s.generateCredentials(ctx, generateCredentialsRequest{
|
||||
username: username,
|
||||
domain: desktop.GetDomain(),
|
||||
distinguishedName: distinguishedName,
|
||||
@@ -1329,6 +1346,7 @@ func (s *WindowsService) generateUserCert(ctx context.Context, username string,
|
||||
createUser: createUsers,
|
||||
groups: groups,
|
||||
})
|
||||
return genResp, trace.Wrap(err)
|
||||
}
|
||||
|
||||
// generateCredentialsRequest are the request parameters for generating a windows cert/key pair
|
||||
@@ -1359,8 +1377,11 @@ type generateCredentialsRequest struct {
|
||||
// the regular Teleport user certificate, to meet the requirements of Active
|
||||
// Directory. See:
|
||||
// https://docs.microsoft.com/en-us/windows/security/identity-protection/smart-cards/smart-card-certificate-requirements-and-enumeration
|
||||
func (s *WindowsService) generateCredentials(ctx context.Context, request generateCredentialsRequest) (certDER, keyDER []byte, err error) {
|
||||
return winpki.GenerateWindowsDesktopCredentials(ctx, s.cfg.AuthClient, &winpki.GenerateCredentialsRequest{
|
||||
func (s *WindowsService) generateCredentials(
|
||||
ctx context.Context,
|
||||
request generateCredentialsRequest,
|
||||
) (*winpki.GenerateCredentialsResponse, error) {
|
||||
resp, err := winpki.GenerateWindowsDesktopCredentials(ctx, s.cfg.AuthClient, &winpki.GenerateCredentialsRequest{
|
||||
Username: request.username,
|
||||
DistinguishedName: request.distinguishedName,
|
||||
Domain: request.domain,
|
||||
@@ -1373,6 +1394,7 @@ func (s *WindowsService) generateCredentials(ctx context.Context, request genera
|
||||
Groups: request.groups,
|
||||
OmitCDP: request.omitCDP,
|
||||
})
|
||||
return resp, trace.Wrap(err)
|
||||
}
|
||||
|
||||
// trackSession creates a session tracker for the given sessionID and
|
||||
|
||||
@@ -210,7 +210,7 @@ func TestGenerateCredentials(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
certb, keyb, err := winpki.GenerateWindowsDesktopCredentials(ctx, client, &winpki.GenerateCredentialsRequest{
|
||||
genResp, err := winpki.GenerateWindowsDesktopCredentials(ctx, client, &winpki.GenerateCredentialsRequest{
|
||||
AD: true,
|
||||
Username: user,
|
||||
Domain: domain,
|
||||
@@ -219,6 +219,8 @@ func TestGenerateCredentials(t *testing.T) {
|
||||
ActiveDirectorySID: test.activeDirectorySID,
|
||||
DisableWindowsCASupportForTesting: test.disableWindowsCASupport,
|
||||
})
|
||||
certb := genResp.CertDER
|
||||
keyb := genResp.KeyDER
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, certb)
|
||||
require.NotNil(t, keyb)
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
|
||||
"github.com/gravitational/teleport/api/client/proto"
|
||||
subcav1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/subca/v1"
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
"github.com/gravitational/teleport/api/utils/tlsutils"
|
||||
@@ -77,6 +78,19 @@ type CalculateOverrideResult struct {
|
||||
CAChain []Certificate
|
||||
}
|
||||
|
||||
// ToClientOverrideDetailsProto returns a [proto.CAOverrideCertificateDetails]
|
||||
// instance matching the CalculateOverrideResult.
|
||||
//
|
||||
// Returns nil if OverrideActive is false.
|
||||
func (res *CalculateOverrideResult) ToClientOverrideDetailsProto() *proto.CAOverrideCertificateDetails {
|
||||
if res == nil || !res.OverrideActive {
|
||||
return nil
|
||||
}
|
||||
return &proto.CAOverrideCertificateDetails{
|
||||
PublicKeyHash: res.PublicKeyHash,
|
||||
}
|
||||
}
|
||||
|
||||
// CalculateOverride calculates CA overrides for a self-signed CA certificate.
|
||||
//
|
||||
// Returns a result with the CA certificate and chain to be used, with either
|
||||
|
||||
@@ -23,7 +23,9 @@ import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
|
||||
"github.com/gravitational/teleport/api/client/proto"
|
||||
headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1"
|
||||
subcav1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/subca/v1"
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
@@ -33,6 +35,51 @@ import (
|
||||
"github.com/gravitational/teleport/lib/tlscatest"
|
||||
)
|
||||
|
||||
func TestCalculateOverrideResult_ToClientOverrideDetailsProto(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const aPublicKeyHash = "6fbd7ba3f34c526f5d6d8ea2659f9fb5ca031712ee588ce35941d568742d44ed"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
res *subca.CalculateOverrideResult
|
||||
want *proto.CAOverrideCertificateDetails
|
||||
}{
|
||||
{
|
||||
name: "nil returns nil",
|
||||
},
|
||||
{
|
||||
name: "not active returns nil",
|
||||
res: &subca.CalculateOverrideResult{
|
||||
OverrideActive: false,
|
||||
PublicKeyHash: aPublicKeyHash,
|
||||
CACertificate: subca.Certificate{PEM: []byte("llama456")},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "active returns proto",
|
||||
res: &subca.CalculateOverrideResult{
|
||||
OverrideActive: true,
|
||||
PublicKeyHash: aPublicKeyHash,
|
||||
CACertificate: subca.Certificate{PEM: []byte("llama456")},
|
||||
},
|
||||
want: &proto.CAOverrideCertificateDetails{
|
||||
PublicKeyHash: aPublicKeyHash,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := test.res.ToClientOverrideDetailsProto()
|
||||
if diff := cmp.Diff(test.want, got, protocmp.Transform()); diff != "" {
|
||||
t.Errorf("ToOverrideDetailsProto mismatch (-want +got)\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCAOverrideResolver_CalculateOverride(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
+21
-7
@@ -286,15 +286,27 @@ type GenerateCredentialsRequest struct {
|
||||
DisableWindowsCASupportForTesting bool
|
||||
}
|
||||
|
||||
// GenerateCredentialsResponse is the outcome of a successful
|
||||
// [GenerateWindowsDesktopCredentials] invocation.
|
||||
type GenerateCredentialsResponse struct {
|
||||
CertDER []byte
|
||||
KeyDER []byte
|
||||
CAOverrideDetails *proto.CAOverrideCertificateDetails
|
||||
}
|
||||
|
||||
// GenerateWindowsDesktopCredentials generates a private key / certificate pair for the given
|
||||
// Windows username. The certificate has certain special fields different from
|
||||
// the regular Teleport user certificate, to meet the requirements of Active
|
||||
// Directory. See:
|
||||
// https://docs.microsoft.com/en-us/windows/security/identity-protection/smart-cards/smart-card-certificate-requirements-and-enumeration
|
||||
func GenerateWindowsDesktopCredentials(ctx context.Context, auth AuthInterface, req *GenerateCredentialsRequest) (certDER, keyDER []byte, err error) {
|
||||
func GenerateWindowsDesktopCredentials(
|
||||
ctx context.Context,
|
||||
auth AuthInterface,
|
||||
req *GenerateCredentialsRequest,
|
||||
) (*GenerateCredentialsResponse, error) {
|
||||
certReq, err := getCertRequest(req)
|
||||
if err != nil {
|
||||
return nil, nil, trace.Wrap(err)
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
genResp, err := auth.GenerateWindowsDesktopCert(ctx, &proto.WindowsDesktopCertRequest{
|
||||
CSR: certReq.csrPEM,
|
||||
@@ -303,15 +315,17 @@ func GenerateWindowsDesktopCredentials(ctx context.Context, auth AuthInterface,
|
||||
SupportsWindowsCA: !req.DisableWindowsCASupportForTesting,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, trace.Wrap(err)
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
certBlock, _ := pem.Decode(genResp.Cert)
|
||||
if certBlock == nil {
|
||||
return nil, nil, trace.BadParameter("failed to decode certificate")
|
||||
return nil, trace.BadParameter("failed to decode certificate")
|
||||
}
|
||||
certDER = certBlock.Bytes
|
||||
keyDER = certReq.keyDER
|
||||
return certDER, keyDER, nil
|
||||
return &GenerateCredentialsResponse{
|
||||
CertDER: certBlock.Bytes,
|
||||
KeyDER: certReq.keyDER,
|
||||
CAOverrideDetails: genResp.CaOverride,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// generateDatabaseCredentials generates a private key / certificate pair for the given
|
||||
|
||||
@@ -430,7 +430,7 @@ func (a *AuthCommand) generateWindowsCert(ctx context.Context, clusterAPI certif
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
certDER, _, err := winpki.GenerateWindowsDesktopCredentials(ctx, clusterAPI, &winpki.GenerateCredentialsRequest{
|
||||
genResp, err := winpki.GenerateWindowsDesktopCredentials(ctx, clusterAPI, &winpki.GenerateCredentialsRequest{
|
||||
Username: a.windowsUser,
|
||||
Domain: a.windowsDomain,
|
||||
PKIDomain: a.windowsPKIDomain,
|
||||
@@ -445,7 +445,7 @@ func (a *AuthCommand) generateWindowsCert(ctx context.Context, clusterAPI certif
|
||||
|
||||
_, err = identityfile.Write(ctx, identityfile.WriteConfig{
|
||||
OutputPath: a.output,
|
||||
WindowsDesktopCerts: map[string][]byte{a.windowsUser: certDER},
|
||||
WindowsDesktopCerts: map[string][]byte{a.windowsUser: genResp.CertDER},
|
||||
Format: a.outputFormat,
|
||||
OverwriteDestination: a.signOverwrite,
|
||||
Writer: a.identityWriter,
|
||||
|
||||
Reference in New Issue
Block a user