Skip to content

Commit

Permalink
auth, etcdserver: authenticate clients based on certificate CommonName
Browse files Browse the repository at this point in the history
This commit lets v3 auth mechanism authenticate clients based on
CommonName of certificate like v2 auth.
  • Loading branch information
mitake committed Jan 31, 2017
1 parent 7d6280f commit 0191509
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 4 deletions.
27 changes: 27 additions & 0 deletions auth/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ import (
"github.com/coreos/pkg/capnslog"
"golang.org/x/crypto/bcrypt"
"golang.org/x/net/context"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/peer"
)

var (
Expand Down Expand Up @@ -159,6 +161,9 @@ type AuthStore interface {

// AuthInfoFromCtx gets AuthInfo from gRPC's context
AuthInfoFromCtx(ctx context.Context) (*AuthInfo, error)

// AuthInfoFromTLS gets AuthInfo from TLS info of gRPC's context
AuthInfoFromTLS(ctx context.Context) *AuthInfo
}

type authStore struct {
Expand Down Expand Up @@ -950,6 +955,28 @@ func (as *authStore) isValidSimpleToken(token string, ctx context.Context) bool
return false
}

func (as *authStore) AuthInfoFromTLS(ctx context.Context) *AuthInfo {
peer, ok := peer.FromContext(ctx)
if !ok || peer == nil || peer.AuthInfo == nil {
return nil
}

tlsInfo := peer.AuthInfo.(credentials.TLSInfo)
for _, chains := range tlsInfo.State.VerifiedChains {
for _, chain := range chains {
cn := chain.Subject.CommonName
plog.Debugf("found common name %s", cn)

return &AuthInfo{
Username: cn,
Revision: as.Revision(),
}
}
}

return nil
}

func (as *authStore) AuthInfoFromCtx(ctx context.Context) (*AuthInfo, error) {
md, ok := metadata.FromContext(ctx)
if !ok {
Expand Down
3 changes: 2 additions & 1 deletion etcdserver/api/v3rpc/maintenance.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type RaftStatusGetter interface {
}

type AuthGetter interface {
AuthInfoFromCtx(ctx context.Context) (*auth.AuthInfo, error)
AuthStore() auth.AuthStore
}

Expand Down Expand Up @@ -152,7 +153,7 @@ type authMaintenanceServer struct {
}

func (ams *authMaintenanceServer) isAuthenticated(ctx context.Context) error {
authInfo, err := ams.ag.AuthStore().AuthInfoFromCtx(ctx)
authInfo, err := ams.ag.AuthInfoFromCtx(ctx)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion etcdserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1022,7 +1022,7 @@ func (s *EtcdServer) checkMembershipOperationPermission(ctx context.Context) err
// in the state machine layer
// However, both of membership change and role management requires the root privilege.
// So careful operation by admins can prevent the problem.
authInfo, err := s.AuthStore().AuthInfoFromCtx(ctx)
authInfo, err := s.AuthInfoFromCtx(ctx)
if err != nil {
return err
}
Expand Down
15 changes: 13 additions & 2 deletions etcdserver/v3_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ func (s *EtcdServer) RoleDelete(ctx context.Context, r *pb.AuthRoleDeleteRequest
// doSerialize handles the auth logic, with permissions checked by "chk", for a serialized request "get". Returns a non-nil error on authentication failure.
func (s *EtcdServer) doSerialize(ctx context.Context, chk func(*auth.AuthInfo) error, get func()) error {
for {
ai, err := s.AuthStore().AuthInfoFromCtx(ctx)
ai, err := s.AuthInfoFromCtx(ctx)
if err != nil {
return err
}
Expand Down Expand Up @@ -652,7 +652,7 @@ func (s *EtcdServer) processInternalRaftRequestOnce(ctx context.Context, r pb.In
ID: s.reqIDGen.Next(),
}

authInfo, err := s.AuthStore().AuthInfoFromCtx(ctx)
authInfo, err := s.AuthInfoFromCtx(ctx)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -802,3 +802,14 @@ func (s *EtcdServer) linearizableReadNotify(ctx context.Context) error {
return ErrStopped
}
}

func (s *EtcdServer) AuthInfoFromCtx(ctx context.Context) (*auth.AuthInfo, error) {
if s.Cfg.ClientCertAuthEnabled {
authInfo := s.AuthStore().AuthInfoFromTLS(ctx)
if authInfo != nil {
return authInfo, nil
}
}

return s.AuthStore().AuthInfoFromCtx(ctx)
}

0 comments on commit 0191509

Please sign in to comment.