Include list of principal into x509 certificate. This allows the

creating a remote user with valid logins (applied from traits) and
roles.
This commit is contained in:
Russell Jones 2018-08-23 00:19:24 +00:00 committed by Russell Jones
parent 410c33b7d9
commit d0b638802c
6 changed files with 49 additions and 16 deletions

View file

@ -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)

View file

@ -412,6 +412,7 @@ func (s *AuthServer) generateUserCert(req certRequest) (*certs, error) {
identity := tlsca.Identity{
Username: req.user.GetName(),
Groups: req.roles.RoleNames(),
Principals: allowedLogins,
Usage: req.usage,
}
certRequest := tlsca.CertificateRequest{

View file

@ -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)) {

View file

@ -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
}

View file

@ -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.

View file

@ -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,6 +93,7 @@ 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
}
@ -100,6 +103,7 @@ func FromSubject(subject pkix.Name) (*Identity, error) {
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 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: true, // no intermediate certs allowed
// BasicConstraintsValid is true to not allow any intermediate certs.
BasicConstraintsValid: true,
IsCA: false,
DNSNames: req.DNSNames,
}