diff --git a/integration/integration_test.go b/integration/integration_test.go index d2fcc83c52f..c7d29b7350d 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -1286,6 +1286,13 @@ func (s *IntSuite) TestMapRoles(c *check.C) { } } + // Make sure that GetNodes returns nodes in the remote site. This makes + // sure identity aware GetNodes works for remote clusters. Testing of the + // correct nodes that identity aware GetNodes is done in TestList. + nodes, err := aux.Process.GetAuthServer().GetNodes(defaults.Namespace, services.SkipValidation()) + c.Assert(err, check.IsNil) + c.Assert(nodes, check.HasLen, 2) + cmd := []string{"echo", "hello world"} tc, err := main.NewClient(ClientConfig{Login: username, Cluster: clusterAux, Host: "127.0.0.1", Port: sshPort}) c.Assert(err, check.IsNil) diff --git a/lib/auth/auth.go b/lib/auth/auth.go index 03e4edacfc1..18dcba6115d 100644 --- a/lib/auth/auth.go +++ b/lib/auth/auth.go @@ -410,9 +410,10 @@ func (s *AuthServer) generateUserCert(req certRequest) (*certs, error) { return nil, trace.Wrap(err) } identity := tlsca.Identity{ - Username: req.user.GetName(), - Groups: req.roles.RoleNames(), - Usage: req.usage, + Username: req.user.GetName(), + Groups: req.roles.RoleNames(), + Principals: allowedLogins, + Usage: req.usage, } certRequest := tlsca.CertificateRequest{ Clock: s.clock, diff --git a/lib/auth/auth_with_roles.go b/lib/auth/auth_with_roles.go index 92544c34180..c74c872a05d 100644 --- a/lib/auth/auth_with_roles.go +++ b/lib/auth/auth_with_roles.go @@ -334,10 +334,12 @@ func (a *AuthWithRoles) UpsertNode(s services.Server) error { // filterNodes filters nodes based off the role of the logged in user. func (a *AuthWithRoles) filterNodes(nodes []services.Server) ([]services.Server, error) { - // For certain built-in roles, continue to allow access and return the full - // set of nodes to not break existing clusters during migration. This is - // also used by the proxy to cache a list of all nodes for it's smart - // resolution. + // For certain built-in roles, continue to allow full access and return + // the full set of nodes to not break existing clusters during migration. + // + // In addition, allow proxy (and remote proxy) to access all nodes for it's + // smart resolution address resolution. Once the smart resolution logic is + // moved to the auth server, this logic can be removed. if a.hasBuiltinRole(string(teleport.RoleAdmin)) || a.hasBuiltinRole(string(teleport.RoleProxy)) || a.hasRemoteBuiltinRole(string(teleport.RoleRemoteProxy)) { diff --git a/lib/auth/middleware.go b/lib/auth/middleware.go index a5b42027a4c..f2101ba1a0b 100644 --- a/lib/auth/middleware.go +++ b/lib/auth/middleware.go @@ -227,6 +227,7 @@ func (a *AuthMiddleware) GetUser(r *http.Request) (interface{}, error) { return RemoteUser{ ClusterName: certClusterName, Username: identity.Username, + Principals: identity.Principals, RemoteRoles: identity.Groups, }, nil } diff --git a/lib/auth/permissions.go b/lib/auth/permissions.go index f50b300f670..cc845e263ab 100644 --- a/lib/auth/permissions.go +++ b/lib/auth/permissions.go @@ -149,6 +149,18 @@ func (a *authorizer) authorizeRemoteUser(u RemoteUser) (*AuthContext, error) { if err != nil { return nil, trace.Wrap(err) } + + // Set "logins" trait for the remote user. This allows Teleport to work by + // passing exact logins to the remote cluster. Note that claims (OIDC/SAML) + // are not passed, but rather the exact logins. + traits := map[string][]string{ + teleport.TraitLogins: u.Principals, + } + user.SetTraits(traits) + + // Set the list of roles this user has in the remote cluster. + user.SetRoles(roleNames) + return &AuthContext{ User: user, Checker: checker, @@ -503,6 +515,9 @@ type RemoteUser struct { // RemoteRoles is optional list of remote roles RemoteRoles []string `json:"remote_roles"` + + // Principals is a list of Unix logins. + Principals []string `json:"principals"` } // GetClusterConfigFunc returns a cached services.ClusterConfig. diff --git a/lib/tlsca/ca.go b/lib/tlsca/ca.go index 3b1a2c0dd43..7bc389a21f1 100644 --- a/lib/tlsca/ca.go +++ b/lib/tlsca/ca.go @@ -71,6 +71,8 @@ type Identity struct { Groups []string // Usage is a list of usage restrictions encoded in the identity Usage []string + // Principals is a list of Unix logins allowed. + Principals []string } // CheckAndSetDefaults checks and sets default values @@ -91,15 +93,17 @@ func (id *Identity) Subject() pkix.Name { } subject.Organization = append([]string{}, id.Groups...) subject.OrganizationalUnit = append([]string{}, id.Usage...) + subject.Locality = append([]string{}, id.Principals...) return subject } // FromSubject returns identity from subject name func FromSubject(subject pkix.Name) (*Identity, error) { i := &Identity{ - Username: subject.CommonName, - Groups: subject.Organization, - Usage: subject.OrganizationalUnit, + Username: subject.CommonName, + Groups: subject.Organization, + Usage: subject.OrganizationalUnit, + Principals: subject.Locality, } if err := i.CheckAndSetDefaults(); err != nil { return nil, trace.Wrap(err) @@ -156,17 +160,20 @@ func (ca *CertAuthority) GenerateCertificate(req CertificateRequest) ([]byte, er "common_name": req.Subject.CommonName, "org": req.Subject.Organization, "org_unit": req.Subject.OrganizationalUnit, + "locality": req.Subject.Locality, }).Infof("Generating TLS certificate %v.", req) template := &x509.Certificate{ SerialNumber: serialNumber, Subject: req.Subject, - // substitue one minute to prevent "Not yet valid" errors on time scewed clusters - NotBefore: req.Clock.Now().UTC().Add(-1 * time.Minute), - NotAfter: req.NotAfter, - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, - BasicConstraintsValid: true, // no intermediate certs allowed + // NotBefore is one minute in the past to prevent "Not yet valid" errors on + // time skewed clusters. + NotBefore: req.Clock.Now().UTC().Add(-1 * time.Minute), + NotAfter: req.NotAfter, + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, + // BasicConstraintsValid is true to not allow any intermediate certs. + BasicConstraintsValid: true, IsCA: false, DNSNames: req.DNSNames, }