func TestReadPublicKeys(t *testing.T) { f, err := ioutil.TempFile("", "") if err != nil { t.Fatalf("error creating tmpfile: %v", err) } defer os.Remove(f.Name()) if err := ioutil.WriteFile(f.Name(), []byte(rsaPublicKey), os.FileMode(0600)); err != nil { t.Fatalf("error writing public key to tmpfile: %v", err) } if keys, err := serviceaccount.ReadPublicKeys(f.Name()); err != nil { t.Fatalf("error reading RSA public key: %v", err) } else if len(keys) != 1 { t.Fatalf("expected 1 key, got %d", len(keys)) } if err := ioutil.WriteFile(f.Name(), []byte(ecdsaPublicKey), os.FileMode(0600)); err != nil { t.Fatalf("error writing public key to tmpfile: %v", err) } if keys, err := serviceaccount.ReadPublicKeys(f.Name()); err != nil { t.Fatalf("error reading ECDSA public key: %v", err) } else if len(keys) != 1 { t.Fatalf("expected 1 key, got %d", len(keys)) } if err := ioutil.WriteFile(f.Name(), []byte(rsaPublicKey+"\n"+ecdsaPublicKey), os.FileMode(0600)); err != nil { t.Fatalf("error writing public key to tmpfile: %v", err) } if keys, err := serviceaccount.ReadPublicKeys(f.Name()); err != nil { t.Fatalf("error reading combined RSA/ECDSA public key file: %v", err) } else if len(keys) != 2 { t.Fatalf("expected 2 keys, got %d", len(keys)) } }
// newServiceAccountAuthenticator returns an authenticator.Request or an error func newServiceAccountAuthenticator(keyfiles []string, lookup bool, serviceAccountGetter serviceaccount.ServiceAccountTokenGetter) (authenticator.Request, error) { allPublicKeys := []interface{}{} for _, keyfile := range keyfiles { publicKeys, err := serviceaccount.ReadPublicKeys(keyfile) if err != nil { return nil, err } allPublicKeys = append(allPublicKeys, publicKeys...) } tokenAuthenticator := serviceaccount.JWTTokenAuthenticator(allPublicKeys, lookup, serviceAccountGetter) return bearertoken.New(tokenAuthenticator), nil }
// IsValidServiceAccountKeyFile returns true if a valid public RSA key can be read from the given file func IsValidServiceAccountKeyFile(file string) bool { _, err := serviceaccount.ReadPublicKeys(file) return err == nil }
func newAuthenticator(config configapi.MasterConfig, restOptionsGetter restoptions.Getter, tokenGetter serviceaccount.ServiceAccountTokenGetter, apiClientCAs *x509.CertPool, groupMapper identitymapper.UserToGroupMapper) (authenticator.Request, error) { authenticators := []authenticator.Request{} tokenAuthenticators := []authenticator.Request{} // ServiceAccount token if len(config.ServiceAccountConfig.PublicKeyFiles) > 0 { publicKeys := []interface{}{} for _, keyFile := range config.ServiceAccountConfig.PublicKeyFiles { readPublicKeys, err := serviceaccount.ReadPublicKeys(keyFile) if err != nil { return nil, fmt.Errorf("Error reading service account key file %s: %v", keyFile, err) } publicKeys = append(publicKeys, readPublicKeys...) } serviceAccountTokenAuthenticator := serviceaccount.JWTTokenAuthenticator(publicKeys, true, tokenGetter) tokenAuthenticators = append(tokenAuthenticators, bearertoken.New(serviceAccountTokenAuthenticator, true)) } // OAuth token if config.OAuthConfig != nil { oauthTokenAuthenticator, err := getEtcdTokenAuthenticator(restOptionsGetter, groupMapper) if err != nil { return nil, fmt.Errorf("Error building OAuth token authenticator: %v", err) } oauthTokenRequestAuthenticators := []authenticator.Request{ bearertoken.New(oauthTokenAuthenticator, true), // Allow token as access_token param for WebSockets paramtoken.New("access_token", oauthTokenAuthenticator, true), } tokenAuthenticators = append(tokenAuthenticators, // if you have a bearer token, you're a human (usually) // if you change this, have a look at the impersonationFilter where we attach groups to the impersonated user group.NewGroupAdder(unionrequest.NewUnionAuthentication(oauthTokenRequestAuthenticators...), []string{bootstrappolicy.AuthenticatedOAuthGroup})) } if len(tokenAuthenticators) > 0 { authenticators = append(authenticators, unionrequest.NewUnionAuthentication(tokenAuthenticators...)) } if configapi.UseTLS(config.ServingInfo.ServingInfo) { // build cert authenticator // TODO: add "system:" prefix in authenticator, limit cert to username // TODO: add "system:" prefix to groups in authenticator, limit cert to group name opts := x509request.DefaultVerifyOptions() opts.Roots = apiClientCAs certauth := x509request.New(opts, x509request.SubjectToUserConversion) authenticators = append(authenticators, certauth) } ret := &unionrequest.Authenticator{ FailOnError: true, Handlers: []authenticator.Request{ // if you change this, have a look at the impersonationFilter where we attach groups to the impersonated user group.NewGroupAdder(&unionrequest.Authenticator{FailOnError: true, Handlers: authenticators}, []string{bootstrappolicy.AuthenticatedGroup}), anonymous.NewAuthenticator(), }, } return ret, nil }