mirror of
https://github.com/gravitational/teleport
synced 2024-10-19 00:33:50 +00:00
Adjust clientIP/pinnedIP fields according to IP pinning RFD (#21866)
* Adjust clientIP/pinnedIP fields according to IP pinning RFD * Improve wording. Co-authored-by: Noah Stride <noah.stride@goteleport.com> --------- Co-authored-by: Noah Stride <noah.stride@goteleport.com>
This commit is contained in:
parent
03184ee32c
commit
13fad744d6
|
@ -431,9 +431,9 @@ const (
|
|||
// deadline in cases where both require_session_mfa and disconnect_expired_cert
|
||||
// are enabled. See https://github.com/gravitational/teleport/issues/18544.
|
||||
CertExtensionPreviousIdentityExpires = "prev-identity-expires"
|
||||
// CertExtensionClientIP is used to embed the IP of the client that created
|
||||
// CertExtensionLoginIP is used to embed the IP of the client that created
|
||||
// the certificate.
|
||||
CertExtensionClientIP = "client-ip"
|
||||
CertExtensionLoginIP = "login-ip"
|
||||
// CertExtensionImpersonator is set when one user has requested certificates
|
||||
// for another user
|
||||
CertExtensionImpersonator = "impersonator"
|
||||
|
|
|
@ -1120,10 +1120,10 @@ type certRequest struct {
|
|||
// deadline in cases where both require_session_mfa and disconnect_expired_cert
|
||||
// are enabled. See https://github.com/gravitational/teleport/issues/18544.
|
||||
previousIdentityExpires time.Time
|
||||
// clientIP is an IP of the client requesting the certificate.
|
||||
clientIP string
|
||||
// sourceIP is an IP this certificate should be pinned to
|
||||
sourceIP string
|
||||
// loginIP is an IP of the client requesting the certificate.
|
||||
loginIP string
|
||||
// pinIP flags that client's login IP should be pinned in the certificate
|
||||
pinIP bool
|
||||
// disallowReissue flags that a cert should not be allowed to issue future
|
||||
// certificates.
|
||||
disallowReissue bool
|
||||
|
@ -1177,8 +1177,8 @@ func certRequestPreviousIdentityExpires(previousIdentityExpires time.Time) certR
|
|||
return func(r *certRequest) { r.previousIdentityExpires = previousIdentityExpires }
|
||||
}
|
||||
|
||||
func certRequestClientIP(ip string) certRequestOption {
|
||||
return func(r *certRequest) { r.clientIP = ip }
|
||||
func certRequestLoginIP(ip string) certRequestOption {
|
||||
return func(r *certRequest) { r.loginIP = ip }
|
||||
}
|
||||
|
||||
func certRequestDeviceExtensions(ext tlsca.DeviceExtensions) certRequestOption {
|
||||
|
@ -1188,7 +1188,7 @@ func certRequestDeviceExtensions(ext tlsca.DeviceExtensions) certRequestOption {
|
|||
}
|
||||
|
||||
// GenerateUserTestCerts is used to generate user certificate, used internally for tests
|
||||
func (a *Server) GenerateUserTestCerts(key []byte, username string, ttl time.Duration, compatibility, routeToCluster, sourceIP string) ([]byte, []byte, error) {
|
||||
func (a *Server) GenerateUserTestCerts(key []byte, username string, ttl time.Duration, compatibility, routeToCluster, pinnedIP string) ([]byte, []byte, error) {
|
||||
user, err := a.GetUser(username, false)
|
||||
if err != nil {
|
||||
return nil, nil, trace.Wrap(err)
|
||||
|
@ -1210,7 +1210,8 @@ func (a *Server) GenerateUserTestCerts(key []byte, username string, ttl time.Dur
|
|||
routeToCluster: routeToCluster,
|
||||
checker: checker,
|
||||
traits: user.GetTraits(),
|
||||
sourceIP: sourceIP,
|
||||
loginIP: pinnedIP,
|
||||
pinIP: pinnedIP != "",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, trace.Wrap(err)
|
||||
|
@ -1749,16 +1750,14 @@ func (a *Server) generateUserCert(req certRequest) (*proto.Certs, error) {
|
|||
}
|
||||
|
||||
pinnedIP := ""
|
||||
if req.checker.PinSourceIP() {
|
||||
if req.clientIP == "" && req.sourceIP == "" {
|
||||
// TODO(anton): make sure all upstream callers provide clientIP and make this into hard error instead of warning.
|
||||
if req.checker.PinSourceIP() || req.pinIP {
|
||||
if req.loginIP == "" {
|
||||
// TODO(anton): make sure all upstream callers provide clientIP and make this into hard error
|
||||
// instead of warning, after merging #21080
|
||||
log.Warnf("IP pinning is enabled for user %q but there is no client ip information", req.user.GetName())
|
||||
}
|
||||
|
||||
pinnedIP = req.clientIP
|
||||
if req.sourceIP != "" {
|
||||
pinnedIP = req.sourceIP
|
||||
}
|
||||
pinnedIP = req.loginIP
|
||||
}
|
||||
|
||||
params := services.UserCertParams{
|
||||
|
@ -1778,13 +1777,13 @@ func (a *Server) generateUserCert(req certRequest) (*proto.Certs, error) {
|
|||
ActiveRequests: req.activeRequests,
|
||||
MFAVerified: req.mfaVerified,
|
||||
PreviousIdentityExpires: req.previousIdentityExpires,
|
||||
ClientIP: req.clientIP,
|
||||
LoginIP: req.loginIP,
|
||||
PinnedIP: pinnedIP,
|
||||
DisallowReissue: req.disallowReissue,
|
||||
Renewable: req.renewable,
|
||||
Generation: req.generation,
|
||||
CertificateExtensions: req.checker.CertificateExtensions(),
|
||||
AllowedResourceIDs: requestedResourcesStr,
|
||||
SourceIP: pinnedIP,
|
||||
ConnectionDiagnosticID: req.connectionDiagnosticID,
|
||||
PrivateKeyPolicy: attestedKeyPolicy,
|
||||
DeviceID: req.deviceExtensions.DeviceID,
|
||||
|
@ -1871,7 +1870,8 @@ func (a *Server) generateUserCert(req certRequest) (*proto.Certs, error) {
|
|||
DatabaseUsers: dbUsers,
|
||||
MFAVerified: req.mfaVerified,
|
||||
PreviousIdentityExpires: req.previousIdentityExpires,
|
||||
ClientIP: req.clientIP,
|
||||
LoginIP: req.loginIP,
|
||||
PinnedIP: pinnedIP,
|
||||
AWSRoleARNs: roleARNs,
|
||||
AzureIdentities: azureIdentities,
|
||||
GCPServiceAccounts: gcpAccounts,
|
||||
|
|
|
@ -1750,9 +1750,18 @@ func TestGenerateUserCertIPPinning(t *testing.T) {
|
|||
err = s.a.UpsertRole(ctx, pinnedRole)
|
||||
require.NoError(t, err)
|
||||
|
||||
findTLSClientIP := func(names []pkix.AttributeTypeAndValue) any {
|
||||
findTLSLoginIP := func(names []pkix.AttributeTypeAndValue) any {
|
||||
for _, name := range names {
|
||||
if name.Type.Equal(tlsca.ClientIPASN1ExtensionOID) {
|
||||
if name.Type.Equal(tlsca.LoginIPASN1ExtensionOID) {
|
||||
return name.Value
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
findTLSPinnedIP := func(names []pkix.AttributeTypeAndValue) any {
|
||||
for _, name := range names {
|
||||
if name.Type.Equal(tlsca.PinnedIPASN1ExtensionOID) {
|
||||
return name.Value
|
||||
}
|
||||
}
|
||||
|
@ -1762,13 +1771,13 @@ func TestGenerateUserCertIPPinning(t *testing.T) {
|
|||
testCases := []struct {
|
||||
desc string
|
||||
user string
|
||||
clientIP string
|
||||
loginIP string
|
||||
wantPinned bool
|
||||
}{
|
||||
{desc: "no client ip, not pinned", user: unpinnedUser, clientIP: "", wantPinned: false},
|
||||
{desc: "client ip, not pinned", user: unpinnedUser, clientIP: "1.2.3.4", wantPinned: false},
|
||||
{desc: "client ip, pinned", user: pinnedUser, clientIP: "1.2.3.4", wantPinned: true},
|
||||
{desc: "no client ip, pinned", user: pinnedUser, clientIP: "", wantPinned: true},
|
||||
{desc: "no client ip, not pinned", user: unpinnedUser, loginIP: "", wantPinned: false},
|
||||
{desc: "client ip, not pinned", user: unpinnedUser, loginIP: "1.2.3.4", wantPinned: false},
|
||||
{desc: "client ip, pinned", user: pinnedUser, loginIP: "1.2.3.4", wantPinned: true},
|
||||
{desc: "no client ip, pinned", user: pinnedUser, loginIP: "", wantPinned: true},
|
||||
}
|
||||
|
||||
baseAuthRequest := AuthenticateSSHRequest{
|
||||
|
@ -1784,13 +1793,13 @@ func TestGenerateUserCertIPPinning(t *testing.T) {
|
|||
t.Run(tt.desc, func(t *testing.T) {
|
||||
authRequest := baseAuthRequest
|
||||
authRequest.AuthenticateUserRequest.Username = tt.user
|
||||
if tt.clientIP != "" {
|
||||
if tt.loginIP != "" {
|
||||
authRequest.ClientMetadata = &ForwardedClientMetadata{
|
||||
RemoteAddr: tt.clientIP,
|
||||
RemoteAddr: tt.loginIP,
|
||||
}
|
||||
}
|
||||
resp, err := s.a.AuthenticateSSHUser(ctx, authRequest)
|
||||
if tt.wantPinned && tt.clientIP == "" {
|
||||
if tt.wantPinned && tt.loginIP == "" {
|
||||
require.ErrorContains(t, err, "source IP pinning is enabled but client IP is unknown")
|
||||
return
|
||||
}
|
||||
|
@ -1803,26 +1812,32 @@ func TestGenerateUserCertIPPinning(t *testing.T) {
|
|||
tlsCert, err := tlsca.ParseCertificatePEM(resp.TLSCert)
|
||||
require.NoError(t, err)
|
||||
|
||||
tlsClientIP := findTLSClientIP(tlsCert.Subject.Names)
|
||||
sshClientIP, sshClientIPOK := sshCert.Extensions[teleport.CertExtensionClientIP]
|
||||
tlsLoginIP := findTLSLoginIP(tlsCert.Subject.Names)
|
||||
tlsPinnedIP := findTLSPinnedIP(tlsCert.Subject.Names)
|
||||
sshLoginIP, sshLoginIPOK := sshCert.Extensions[teleport.CertExtensionLoginIP]
|
||||
sshCriticalAddress, sshCriticalAddressOK := sshCert.CriticalOptions["source-address"]
|
||||
|
||||
if tt.clientIP != "" {
|
||||
require.NotNil(t, tlsClientIP, "client IP not found on TLS cert")
|
||||
require.Equal(t, tlsClientIP, tt.clientIP, "TLS ClientIP mismatch")
|
||||
if tt.loginIP != "" {
|
||||
require.NotNil(t, tlsLoginIP, "client IP not found on TLS cert")
|
||||
require.Equal(t, tlsLoginIP, tt.loginIP, "TLS LoginIP mismatch")
|
||||
|
||||
require.True(t, sshClientIPOK, "SSH ClientIP extension not present")
|
||||
require.Equal(t, tt.clientIP, sshClientIP, "SSH ClientIP mismatch")
|
||||
require.True(t, sshLoginIPOK, "SSH LoginIP extension not present")
|
||||
require.Equal(t, tt.loginIP, sshLoginIP, "SSH LoginIP mismatch")
|
||||
} else {
|
||||
require.Nil(t, tlsClientIP, "client IP unexpectedly found on TLS cert")
|
||||
require.Nil(t, tlsLoginIP, "client IP unexpectedly found on TLS cert")
|
||||
|
||||
require.False(t, sshClientIPOK, "client IP unexpectedly found on SSH cert")
|
||||
require.False(t, sshLoginIPOK, "client IP unexpectedly found on SSH cert")
|
||||
}
|
||||
|
||||
if tt.wantPinned {
|
||||
require.NotNil(t, tlsPinnedIP, "pinned IP not found on TLS cert")
|
||||
require.Equal(t, tt.loginIP, tlsPinnedIP, "pinned IP on TLS cert mismatch")
|
||||
|
||||
require.True(t, sshCriticalAddressOK, "source address not found on SSH cert")
|
||||
require.Equal(t, tt.clientIP+"/32", sshCriticalAddress, "SSH source address mismatch")
|
||||
require.Equal(t, tt.loginIP+"/32", sshCriticalAddress, "SSH source address mismatch")
|
||||
} else {
|
||||
require.Nil(t, tlsPinnedIP, "pinned IP unexpectedly found on TLS cert")
|
||||
|
||||
require.False(t, sshCriticalAddressOK, "source address unexpectedly found on SSH cert")
|
||||
}
|
||||
})
|
||||
|
|
|
@ -2716,8 +2716,8 @@ func (a *ServerWithRoles) generateUserCerts(ctx context.Context, req proto.UserC
|
|||
checker: checker,
|
||||
// Copy IP from current identity to the generated certificate, if present,
|
||||
// to avoid generateUserCerts() being used to drop IP pinning in the new certificates.
|
||||
clientIP: a.context.Identity.GetIdentity().ClientIP,
|
||||
traits: accessInfo.Traits,
|
||||
loginIP: a.context.Identity.GetIdentity().LoginIP,
|
||||
traits: accessInfo.Traits,
|
||||
activeRequests: services.RequestIDs{
|
||||
AccessRequests: req.AccessRequests,
|
||||
},
|
||||
|
|
|
@ -2582,7 +2582,7 @@ func userSingleUseCertsGenerate(ctx context.Context, actx *grpcContext, req prot
|
|||
ctx, req,
|
||||
certRequestMFAVerified(mfaDev.Id),
|
||||
certRequestPreviousIdentityExpires(actx.Identity.GetIdentity().Expires),
|
||||
certRequestClientIP(clientIP),
|
||||
certRequestLoginIP(clientIP),
|
||||
certRequestDeviceExtensions(actx.Identity.GetIdentity().DeviceExtensions),
|
||||
)
|
||||
if err != nil {
|
||||
|
|
|
@ -1265,7 +1265,7 @@ func TestGenerateUserSingleUseCert(t *testing.T) {
|
|||
|
||||
require.Equal(t, webDevID, cert.Extensions[teleport.CertExtensionMFAVerified])
|
||||
require.Equal(t, userCertExpires.Format(time.RFC3339), cert.Extensions[teleport.CertExtensionPreviousIdentityExpires])
|
||||
require.True(t, net.ParseIP(cert.Extensions[teleport.CertExtensionClientIP]).IsLoopback())
|
||||
require.True(t, net.ParseIP(cert.Extensions[teleport.CertExtensionLoginIP]).IsLoopback())
|
||||
require.Equal(t, uint64(clock.Now().Add(teleport.UserSingleUseCertTTL).Unix()), cert.ValidBefore)
|
||||
},
|
||||
},
|
||||
|
@ -1294,7 +1294,7 @@ func TestGenerateUserSingleUseCert(t *testing.T) {
|
|||
|
||||
require.Equal(t, webDevID, cert.Extensions[teleport.CertExtensionMFAVerified])
|
||||
require.Equal(t, userCertExpires.Format(time.RFC3339), cert.Extensions[teleport.CertExtensionPreviousIdentityExpires])
|
||||
require.True(t, net.ParseIP(cert.Extensions[teleport.CertExtensionClientIP]).IsLoopback())
|
||||
require.True(t, net.ParseIP(cert.Extensions[teleport.CertExtensionLoginIP]).IsLoopback())
|
||||
require.Equal(t, uint64(clock.Now().Add(teleport.UserSingleUseCertTTL).Unix()), cert.ValidBefore)
|
||||
},
|
||||
},
|
||||
|
@ -1326,7 +1326,7 @@ func TestGenerateUserSingleUseCert(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.Equal(t, webDevID, identity.MFAVerified)
|
||||
require.Equal(t, userCertExpires, identity.PreviousIdentityExpires)
|
||||
require.True(t, net.ParseIP(identity.ClientIP).IsLoopback())
|
||||
require.True(t, net.ParseIP(identity.LoginIP).IsLoopback())
|
||||
require.Equal(t, []string{teleport.UsageKubeOnly}, identity.Usage)
|
||||
require.Equal(t, "kube-a", identity.KubernetesCluster)
|
||||
},
|
||||
|
@ -1361,7 +1361,7 @@ func TestGenerateUserSingleUseCert(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.Equal(t, webDevID, identity.MFAVerified)
|
||||
require.Equal(t, userCertExpires, identity.PreviousIdentityExpires)
|
||||
require.True(t, net.ParseIP(identity.ClientIP).IsLoopback())
|
||||
require.True(t, net.ParseIP(identity.LoginIP).IsLoopback())
|
||||
require.Equal(t, []string{teleport.UsageDatabaseOnly}, identity.Usage)
|
||||
require.Equal(t, identity.RouteToDatabase.ServiceName, "db-a")
|
||||
},
|
||||
|
@ -1398,7 +1398,7 @@ func TestGenerateUserSingleUseCert(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.Equal(t, webDevID, identity.MFAVerified)
|
||||
require.Equal(t, userCertExpires, identity.PreviousIdentityExpires)
|
||||
require.True(t, net.ParseIP(identity.ClientIP).IsLoopback())
|
||||
require.True(t, net.ParseIP(identity.LoginIP).IsLoopback())
|
||||
require.Equal(t, []string{teleport.UsageDatabaseOnly}, identity.Usage)
|
||||
require.Equal(t, identity.RouteToDatabase.ServiceName, "db-a")
|
||||
},
|
||||
|
|
|
@ -195,8 +195,8 @@ func (k *Keygen) GenerateUserCertWithoutValidation(c services.UserCertParams) ([
|
|||
if !c.PreviousIdentityExpires.IsZero() {
|
||||
cert.Permissions.Extensions[teleport.CertExtensionPreviousIdentityExpires] = c.PreviousIdentityExpires.Format(time.RFC3339)
|
||||
}
|
||||
if c.ClientIP != "" {
|
||||
cert.Permissions.Extensions[teleport.CertExtensionClientIP] = c.ClientIP
|
||||
if c.LoginIP != "" {
|
||||
cert.Permissions.Extensions[teleport.CertExtensionLoginIP] = c.LoginIP
|
||||
}
|
||||
if c.Impersonator != "" {
|
||||
cert.Permissions.Extensions[teleport.CertExtensionImpersonator] = c.Impersonator
|
||||
|
@ -229,7 +229,7 @@ func (k *Keygen) GenerateUserCertWithoutValidation(c services.UserCertParams) ([
|
|||
cert.Permissions.Extensions[teleport.CertExtensionDeviceCredentialID] = credID
|
||||
}
|
||||
|
||||
if c.SourceIP != "" {
|
||||
if c.PinnedIP != "" {
|
||||
if modules.GetModules().BuildType() != modules.BuildEnterprise {
|
||||
return nil, trace.AccessDenied("source IP pinning is only supported in Teleport Enterprise")
|
||||
}
|
||||
|
@ -237,10 +237,10 @@ func (k *Keygen) GenerateUserCertWithoutValidation(c services.UserCertParams) ([
|
|||
cert.CriticalOptions = make(map[string]string)
|
||||
}
|
||||
//IPv4, all bits matter
|
||||
ip := c.SourceIP + "/32"
|
||||
if strings.Contains(c.SourceIP, ":") {
|
||||
ip := c.PinnedIP + "/32"
|
||||
if strings.Contains(c.PinnedIP, ":") {
|
||||
//IPv6
|
||||
ip = c.SourceIP + "/128"
|
||||
ip = c.PinnedIP + "/128"
|
||||
}
|
||||
cert.CriticalOptions[sourceAddress] = ip
|
||||
}
|
||||
|
|
|
@ -516,7 +516,7 @@ func (s *Server) AuthenticateSSHUser(ctx context.Context, req AuthenticateSSHReq
|
|||
traits: user.GetTraits(),
|
||||
routeToCluster: req.RouteToCluster,
|
||||
kubernetesCluster: req.KubernetesCluster,
|
||||
clientIP: clientIP,
|
||||
loginIP: clientIP,
|
||||
attestationStatement: req.AttestationStatement,
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -347,7 +347,7 @@ func (a *authorizer) authorizeRemoteUser(ctx context.Context, u RemoteUser) (*Co
|
|||
RouteToApp: u.Identity.RouteToApp,
|
||||
RouteToDatabase: u.Identity.RouteToDatabase,
|
||||
MFAVerified: u.Identity.MFAVerified,
|
||||
ClientIP: u.Identity.ClientIP,
|
||||
LoginIP: u.Identity.LoginIP,
|
||||
PrivateKeyPolicy: u.Identity.PrivateKeyPolicy,
|
||||
}
|
||||
|
||||
|
|
|
@ -344,10 +344,10 @@ type UserCertParams struct {
|
|||
// deadline in cases where both require_session_mfa and disconnect_expired_cert
|
||||
// are enabled. See https://github.com/gravitational/teleport/issues/18544.
|
||||
PreviousIdentityExpires time.Time
|
||||
// ClientIP is an IP of the client to embed in the certificate.
|
||||
ClientIP string
|
||||
// SourceIP is an IP that certificate should be pinned to.
|
||||
SourceIP string
|
||||
// LoginIP is an observed IP of the client on the moment of certificate creation.
|
||||
LoginIP string
|
||||
// PinnedIP is an IP from which client must communicate with Teleport.
|
||||
PinnedIP string
|
||||
// DisallowReissue flags that any attempt to request new certificates while
|
||||
// authenticated with this cert should be denied.
|
||||
DisallowReissue bool
|
||||
|
|
|
@ -99,7 +99,7 @@ func (a *audit) OnSessionStart(ctx context.Context, serverID string, identity *t
|
|||
},
|
||||
UserMetadata: identity.GetUserMetadata(),
|
||||
ConnectionMetadata: apievents.ConnectionMetadata{
|
||||
RemoteAddr: identity.ClientIP,
|
||||
RemoteAddr: identity.LoginIP,
|
||||
},
|
||||
AppMetadata: apievents.AppMetadata{
|
||||
AppURI: app.GetURI(),
|
||||
|
@ -128,7 +128,7 @@ func (a *audit) OnSessionEnd(ctx context.Context, serverID string, identity *tls
|
|||
},
|
||||
UserMetadata: identity.GetUserMetadata(),
|
||||
ConnectionMetadata: apievents.ConnectionMetadata{
|
||||
RemoteAddr: identity.ClientIP,
|
||||
RemoteAddr: identity.LoginIP,
|
||||
},
|
||||
AppMetadata: apievents.AppMetadata{
|
||||
AppURI: app.GetURI(),
|
||||
|
|
|
@ -608,7 +608,7 @@ func (s *ProxyServer) Authorize(ctx context.Context, tlsConn utils.TLSConn, para
|
|||
identity.RouteToDatabase.Database = params.Database
|
||||
}
|
||||
if params.ClientIP != "" {
|
||||
identity.ClientIP = params.ClientIP
|
||||
identity.LoginIP = params.ClientIP
|
||||
}
|
||||
cluster, servers, err := s.getDatabaseServers(ctx, identity)
|
||||
if err != nil {
|
||||
|
|
|
@ -912,8 +912,8 @@ func (s *Server) handleConnection(ctx context.Context, clientConn net.Conn) erro
|
|||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
// TODO(jakule): ClientIP should be required starting from 10.0.
|
||||
clientIP := sessionCtx.Identity.ClientIP
|
||||
// TODO(jakule): LoginIP should be required starting from 10.0.
|
||||
clientIP := sessionCtx.Identity.LoginIP
|
||||
if clientIP != "" {
|
||||
s.log.Debugf("Real client IP %s", clientIP)
|
||||
|
||||
|
@ -924,7 +924,7 @@ func (s *Server) handleConnection(ctx context.Context, clientConn net.Conn) erro
|
|||
}
|
||||
defer release()
|
||||
} else {
|
||||
s.log.Debug("ClientIP is not set (Proxy Service has to be updated). Rate limiting is disabled.")
|
||||
s.log.Debug("LoginIP is not set (Proxy Service has to be updated). Rate limiting is disabled.")
|
||||
}
|
||||
|
||||
err = engine.HandleConnection(ctx, sessionCtx)
|
||||
|
|
|
@ -46,7 +46,7 @@ func (s *WindowsService) onSessionStart(ctx context.Context, emitter events.Emit
|
|||
WithMFA: id.MFAVerified,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: id.ClientIP,
|
||||
LocalAddr: id.LoginIP,
|
||||
RemoteAddr: desktop.GetAddr(),
|
||||
Protocol: libevents.EventProtocolTDP,
|
||||
},
|
||||
|
@ -116,7 +116,7 @@ func (s *WindowsService) onClipboardSend(ctx context.Context, emitter events.Emi
|
|||
WithMFA: id.MFAVerified,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: id.ClientIP,
|
||||
LocalAddr: id.LoginIP,
|
||||
RemoteAddr: desktopAddr,
|
||||
Protocol: libevents.EventProtocolTDP,
|
||||
},
|
||||
|
@ -140,7 +140,7 @@ func (s *WindowsService) onClipboardReceive(ctx context.Context, emitter events.
|
|||
WithMFA: id.MFAVerified,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: id.ClientIP,
|
||||
LocalAddr: id.LoginIP,
|
||||
RemoteAddr: desktopAddr,
|
||||
Protocol: libevents.EventProtocolTDP,
|
||||
},
|
||||
|
@ -182,7 +182,7 @@ func (s *WindowsService) onSharedDirectoryAnnounce(
|
|||
WithMFA: id.MFAVerified,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: id.ClientIP,
|
||||
LocalAddr: id.LoginIP,
|
||||
RemoteAddr: desktopAddr,
|
||||
Protocol: libevents.EventProtocolTDP,
|
||||
},
|
||||
|
@ -235,7 +235,7 @@ func (s *WindowsService) onSharedDirectoryAcknowledge(
|
|||
WithMFA: id.MFAVerified,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: id.ClientIP,
|
||||
LocalAddr: id.LoginIP,
|
||||
RemoteAddr: desktopAddr,
|
||||
Protocol: libevents.EventProtocolTDP,
|
||||
},
|
||||
|
@ -294,7 +294,7 @@ func (s *WindowsService) onSharedDirectoryReadRequest(
|
|||
WithMFA: id.MFAVerified,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: id.ClientIP,
|
||||
LocalAddr: id.LoginIP,
|
||||
RemoteAddr: desktopAddr,
|
||||
Protocol: libevents.EventProtocolTDP,
|
||||
},
|
||||
|
@ -366,7 +366,7 @@ func (s *WindowsService) onSharedDirectoryReadResponse(
|
|||
WithMFA: id.MFAVerified,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: id.ClientIP,
|
||||
LocalAddr: id.LoginIP,
|
||||
RemoteAddr: desktopAddr,
|
||||
Protocol: libevents.EventProtocolTDP,
|
||||
},
|
||||
|
@ -428,7 +428,7 @@ func (s *WindowsService) onSharedDirectoryWriteRequest(
|
|||
WithMFA: id.MFAVerified,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: id.ClientIP,
|
||||
LocalAddr: id.LoginIP,
|
||||
RemoteAddr: desktopAddr,
|
||||
Protocol: libevents.EventProtocolTDP,
|
||||
},
|
||||
|
@ -500,7 +500,7 @@ func (s *WindowsService) onSharedDirectoryWriteResponse(
|
|||
WithMFA: id.MFAVerified,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: id.ClientIP,
|
||||
LocalAddr: id.LoginIP,
|
||||
RemoteAddr: desktopAddr,
|
||||
Protocol: libevents.EventProtocolTDP,
|
||||
},
|
||||
|
|
|
@ -60,7 +60,7 @@ func setup() (*WindowsService, *tlsca.Identity, *eventstest.MockEmitter) {
|
|||
Username: "foo",
|
||||
Impersonator: "bar",
|
||||
MFAVerified: "mfa-id",
|
||||
ClientIP: "127.0.0.1",
|
||||
LoginIP: "127.0.0.1",
|
||||
}
|
||||
|
||||
return s, id, emitter
|
||||
|
@ -97,7 +97,7 @@ func TestSessionStartEvent(t *testing.T) {
|
|||
WithMFA: id.MFAVerified,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: id.ClientIP,
|
||||
LocalAddr: id.LoginIP,
|
||||
RemoteAddr: desktop.GetAddr(),
|
||||
Protocol: libevents.EventProtocolTDP,
|
||||
},
|
||||
|
@ -310,7 +310,7 @@ func TestDesktopSharedDirectoryStartEvent(t *testing.T) {
|
|||
WithMFA: id.MFAVerified,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: id.ClientIP,
|
||||
LocalAddr: id.LoginIP,
|
||||
RemoteAddr: desktopAddr,
|
||||
Protocol: libevents.EventProtocolTDP,
|
||||
},
|
||||
|
@ -488,7 +488,7 @@ func TestDesktopSharedDirectoryReadEvent(t *testing.T) {
|
|||
WithMFA: id.MFAVerified,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: id.ClientIP,
|
||||
LocalAddr: id.LoginIP,
|
||||
RemoteAddr: desktopAddr,
|
||||
Protocol: libevents.EventProtocolTDP,
|
||||
},
|
||||
|
@ -661,7 +661,7 @@ func TestDesktopSharedDirectoryWriteEvent(t *testing.T) {
|
|||
WithMFA: id.MFAVerified,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: id.ClientIP,
|
||||
LocalAddr: id.LoginIP,
|
||||
RemoteAddr: desktopAddr,
|
||||
Protocol: libevents.EventProtocolTDP,
|
||||
},
|
||||
|
@ -737,7 +737,7 @@ func TestDesktopSharedDirectoryStartEventAuditCacheMax(t *testing.T) {
|
|||
WithMFA: id.MFAVerified,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: id.ClientIP,
|
||||
LocalAddr: id.LoginIP,
|
||||
RemoteAddr: desktopAddr,
|
||||
Protocol: libevents.EventProtocolTDP,
|
||||
},
|
||||
|
@ -825,7 +825,7 @@ func TestDesktopSharedDirectoryReadEventAuditCacheMax(t *testing.T) {
|
|||
WithMFA: id.MFAVerified,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: id.ClientIP,
|
||||
LocalAddr: id.LoginIP,
|
||||
RemoteAddr: desktopAddr,
|
||||
Protocol: libevents.EventProtocolTDP,
|
||||
},
|
||||
|
@ -916,7 +916,7 @@ func TestDesktopSharedDirectoryWriteEventAuditCacheMax(t *testing.T) {
|
|||
WithMFA: id.MFAVerified,
|
||||
},
|
||||
ConnectionMetadata: events.ConnectionMetadata{
|
||||
LocalAddr: id.ClientIP,
|
||||
LocalAddr: id.LoginIP,
|
||||
RemoteAddr: desktopAddr,
|
||||
Protocol: libevents.EventProtocolTDP,
|
||||
},
|
||||
|
|
|
@ -158,8 +158,10 @@ type Identity struct {
|
|||
// deadline in cases where both require_session_mfa and disconnect_expired_cert
|
||||
// are enabled. See https://github.com/gravitational/teleport/issues/18544.
|
||||
PreviousIdentityExpires time.Time
|
||||
// ClientIP is an observed IP of the client that this Identity represents.
|
||||
ClientIP string
|
||||
// LoginIP is an observed IP of the client that this Identity represents.
|
||||
LoginIP string
|
||||
// PinnedIP is an IP the certificate is pinned to.
|
||||
PinnedIP string
|
||||
// AWSRoleARNs is a list of allowed AWS role ARNs user can assume.
|
||||
AWSRoleARNs []string
|
||||
// AzureIdentities is a list of allowed Azure identities user can assume.
|
||||
|
@ -310,7 +312,7 @@ func (id *Identity) GetEventIdentity() events.Identity {
|
|||
DatabaseUsers: id.DatabaseUsers,
|
||||
MFADeviceUUID: id.MFAVerified,
|
||||
PreviousIdentityExpires: id.PreviousIdentityExpires,
|
||||
ClientIP: id.ClientIP,
|
||||
ClientIP: id.LoginIP,
|
||||
AWSRoleARNs: id.AWSRoleARNs,
|
||||
AzureIdentities: id.AzureIdentities,
|
||||
GCPServiceAccounts: id.GCPServiceAccounts,
|
||||
|
@ -370,9 +372,9 @@ var (
|
|||
// the MFAVerified flag into certificates.
|
||||
MFAVerifiedASN1ExtensionOID = asn1.ObjectIdentifier{1, 3, 9999, 1, 8}
|
||||
|
||||
// ClientIPASN1ExtensionOID is an extension ID used when encoding/decoding
|
||||
// the client IP into certificates.
|
||||
ClientIPASN1ExtensionOID = asn1.ObjectIdentifier{1, 3, 9999, 1, 9}
|
||||
// LoginIPASN1ExtensionOID is an extension ID used when encoding/decoding
|
||||
// the client's login IP into certificates.
|
||||
LoginIPASN1ExtensionOID = asn1.ObjectIdentifier{1, 3, 9999, 1, 9}
|
||||
|
||||
// AppNameASN1ExtensionOID is an extension ID used when encoding/decoding
|
||||
// application name into a certificate.
|
||||
|
@ -474,6 +476,10 @@ var (
|
|||
// LicenseOID is an extension OID signaling the license type of Teleport build.
|
||||
// It should take values "oss" or "ent" (the values returned by modules.GetModules().BuildType())
|
||||
LicenseOID = asn1.ObjectIdentifier{1, 3, 9999, 2, 14}
|
||||
|
||||
// PinnedIPASN1ExtensionOID is an extension ID used when encoding/decoding
|
||||
// the IP the certificate is pinned to.
|
||||
PinnedIPASN1ExtensionOID = asn1.ObjectIdentifier{1, 3, 9999, 2, 15}
|
||||
)
|
||||
|
||||
// Device Trust OIDs.
|
||||
|
@ -645,11 +651,18 @@ func (id *Identity) Subject() (pkix.Name, error) {
|
|||
Value: id.PreviousIdentityExpires.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
if id.ClientIP != "" {
|
||||
if id.LoginIP != "" {
|
||||
subject.ExtraNames = append(subject.ExtraNames,
|
||||
pkix.AttributeTypeAndValue{
|
||||
Type: ClientIPASN1ExtensionOID,
|
||||
Value: id.ClientIP,
|
||||
Type: LoginIPASN1ExtensionOID,
|
||||
Value: id.LoginIP,
|
||||
})
|
||||
}
|
||||
if id.PinnedIP != "" {
|
||||
subject.ExtraNames = append(subject.ExtraNames,
|
||||
pkix.AttributeTypeAndValue{
|
||||
Type: PinnedIPASN1ExtensionOID,
|
||||
Value: id.PinnedIP,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -903,10 +916,10 @@ func FromSubject(subject pkix.Name, expires time.Time) (*Identity, error) {
|
|||
}
|
||||
id.PreviousIdentityExpires = asTime
|
||||
}
|
||||
case attr.Type.Equal(ClientIPASN1ExtensionOID):
|
||||
case attr.Type.Equal(LoginIPASN1ExtensionOID):
|
||||
val, ok := attr.Value.(string)
|
||||
if ok {
|
||||
id.ClientIP = val
|
||||
id.LoginIP = val
|
||||
}
|
||||
case attr.Type.Equal(DatabaseServiceNameASN1ExtensionOID):
|
||||
val, ok := attr.Value.(string)
|
||||
|
@ -995,6 +1008,10 @@ func FromSubject(subject pkix.Name, expires time.Time) (*Identity, error) {
|
|||
if val, ok := attr.Value.(string); ok {
|
||||
id.DeviceExtensions.CredentialID = val
|
||||
}
|
||||
case attr.Type.Equal(PinnedIPASN1ExtensionOID):
|
||||
if val, ok := attr.Value.(string); ok {
|
||||
id.PinnedIP = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue