-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21580 from enj/enj/f/bootstrap_oauth_user
Add bootstrap kube:admin OAuth user
- Loading branch information
Showing
20 changed files
with
395 additions
and
84 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
pkg/apiserver/authentication/oauth/bootstrapauthenticator.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package oauth | ||
|
||
import ( | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/types" | ||
kauthenticator "k8s.io/apiserver/pkg/authentication/authenticator" | ||
kuser "k8s.io/apiserver/pkg/authentication/user" | ||
"k8s.io/client-go/kubernetes/typed/core/v1" | ||
|
||
userapi "github.com/openshift/api/user/v1" | ||
oauthclient "github.com/openshift/client-go/oauth/clientset/versioned/typed/oauth/v1" | ||
"github.com/openshift/origin/pkg/oauthserver/authenticator/password/bootstrap" | ||
) | ||
|
||
type bootstrapAuthenticator struct { | ||
tokens oauthclient.OAuthAccessTokenInterface | ||
secrets v1.SecretInterface | ||
validator OAuthTokenValidator | ||
} | ||
|
||
func NewBootstrapAuthenticator(tokens oauthclient.OAuthAccessTokenInterface, secrets v1.SecretsGetter, validators ...OAuthTokenValidator) kauthenticator.Token { | ||
return &bootstrapAuthenticator{ | ||
tokens: tokens, | ||
secrets: secrets.Secrets(metav1.NamespaceSystem), | ||
validator: OAuthTokenValidators(validators), | ||
} | ||
} | ||
|
||
func (a *bootstrapAuthenticator) AuthenticateToken(name string) (kuser.Info, bool, error) { | ||
token, err := a.tokens.Get(name, metav1.GetOptions{}) | ||
if err != nil { | ||
return nil, false, errLookup // mask the error so we do not leak token data in logs | ||
} | ||
|
||
if token.UserName != bootstrap.BootstrapUser { | ||
return nil, false, nil | ||
} | ||
|
||
_, uid, ok, err := bootstrap.HashAndUID(a.secrets) | ||
if err != nil || !ok { | ||
return nil, ok, err | ||
} | ||
|
||
// this allows us to reuse existing validators | ||
// since the uid is based on the secret, if the secret changes, all | ||
// tokens issued for the bootstrap user before that change stop working | ||
fakeUser := &userapi.User{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
UID: types.UID(uid), | ||
}, | ||
} | ||
|
||
if err := a.validator.Validate(token, fakeUser); err != nil { | ||
return nil, false, err | ||
} | ||
|
||
// we explicitly do not set UID as we do not want to leak any derivative of the password | ||
return &kuser.DefaultInfo{ | ||
Name: bootstrap.BootstrapUser, | ||
Groups: []string{kuser.SystemPrivilegedGroup}, // authorized to do everything | ||
}, true, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package config | ||
|
||
import "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
|
||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object | ||
|
||
// BootstrapIdentityProvider serves as a marker for an "IDP" that is backed by osin | ||
// this allows us to reuse most of the logic from existing identity providers | ||
type BootstrapIdentityProvider struct { | ||
v1.TypeMeta | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
84 changes: 84 additions & 0 deletions
84
pkg/oauthserver/authenticator/password/bootstrap/bootstrap.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package bootstrap | ||
|
||
import ( | ||
"crypto/sha512" | ||
"encoding/base64" | ||
|
||
"golang.org/x/crypto/bcrypt" | ||
|
||
"k8s.io/apimachinery/pkg/api/errors" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/util/sets" | ||
"k8s.io/apiserver/pkg/authentication/authenticator" | ||
"k8s.io/apiserver/pkg/authentication/user" | ||
"k8s.io/client-go/kubernetes/typed/core/v1" | ||
) | ||
|
||
const ( | ||
// BootstrapUser is the magic bootstrap OAuth user that can perform any action | ||
BootstrapUser = "kube:admin" | ||
// support basic auth which does not allow : in username | ||
bootstrapUserBasicAuth = "kubeadmin" | ||
) | ||
|
||
func New(secrets v1.SecretsGetter) authenticator.Password { | ||
return &bootstrapPassword{ | ||
secrets: secrets.Secrets(metav1.NamespaceSystem), | ||
names: sets.NewString(BootstrapUser, bootstrapUserBasicAuth), | ||
} | ||
} | ||
|
||
type bootstrapPassword struct { | ||
secrets v1.SecretInterface | ||
names sets.String | ||
} | ||
|
||
func (b *bootstrapPassword) AuthenticatePassword(username, password string) (user.Info, bool, error) { | ||
if !b.names.Has(username) { | ||
return nil, false, nil | ||
} | ||
|
||
hashedPassword, uid, ok, err := HashAndUID(b.secrets) | ||
if err != nil || !ok { | ||
return nil, ok, err | ||
} | ||
|
||
if err := bcrypt.CompareHashAndPassword(hashedPassword, []byte(password)); err != nil { | ||
if err == bcrypt.ErrMismatchedHashAndPassword { | ||
return nil, false, nil | ||
} | ||
return nil, false, err | ||
} | ||
|
||
// do not set other fields, see identitymapper.userToInfo func | ||
return &user.DefaultInfo{ | ||
Name: BootstrapUser, | ||
UID: uid, // uid ties this authentication to the current state of the secret | ||
}, true, nil | ||
} | ||
|
||
func HashAndUID(secrets v1.SecretInterface) ([]byte, string, bool, error) { | ||
secret, err := secrets.Get(bootstrapUserBasicAuth, metav1.GetOptions{}) | ||
if errors.IsNotFound(err) { | ||
return nil, "", false, nil | ||
} | ||
if err != nil { | ||
return nil, "", false, err | ||
} | ||
|
||
hashedPassword := secret.Data[bootstrapUserBasicAuth] | ||
|
||
// make sure the value is a valid bcrypt hash | ||
if _, err := bcrypt.Cost(hashedPassword); err != nil { | ||
return nil, "", false, err | ||
} | ||
|
||
exactSecret := string(secret.UID) + secret.ResourceVersion | ||
both := append([]byte(exactSecret), hashedPassword...) | ||
|
||
// use a hash to avoid leaking any derivative of the password | ||
// this makes it easy for us to tell if the secret changed | ||
uidBytes := sha512.Sum512(both) | ||
|
||
return hashedPassword, base64.RawURLEncoding.EncodeToString(uidBytes[:]), true, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.