mirror of https://github.com/k3s-io/k3s
Add ECDSA support
parent
987aef1f64
commit
6333d8fd86
|
@ -71,7 +71,7 @@ func (s *APIServer) AddFlags(fs *pflag.FlagSet) {
|
|||
"Amount of time to retain events. Default is 1h.")
|
||||
|
||||
fs.StringVar(&s.ServiceAccountKeyFile, "service-account-key-file", s.ServiceAccountKeyFile, ""+
|
||||
"File containing PEM-encoded x509 RSA private or public key, used to verify "+
|
||||
"File containing PEM-encoded x509 RSA or ECDSA private or public key, used to verify "+
|
||||
"ServiceAccount tokens. If unspecified, --tls-private-key-file is used.")
|
||||
|
||||
fs.BoolVar(&s.ServiceAccountLookup, "service-account-lookup", s.ServiceAccountLookup,
|
||||
|
|
|
@ -158,7 +158,7 @@ func (s *CMServer) AddFlags(fs *pflag.FlagSet) {
|
|||
"Amount of time which we allow starting Node to be unresponsive before marking it unhealthy.")
|
||||
fs.DurationVar(&s.NodeMonitorPeriod.Duration, "node-monitor-period", s.NodeMonitorPeriod.Duration,
|
||||
"The period for syncing NodeStatus in NodeController.")
|
||||
fs.StringVar(&s.ServiceAccountKeyFile, "service-account-private-key-file", s.ServiceAccountKeyFile, "Filename containing a PEM-encoded private RSA key used to sign service account tokens.")
|
||||
fs.StringVar(&s.ServiceAccountKeyFile, "service-account-private-key-file", s.ServiceAccountKeyFile, "Filename containing a PEM-encoded private RSA or ECDSA key used to sign service account tokens.")
|
||||
fs.StringVar(&s.ClusterSigningCertFile, "cluster-signing-cert-file", s.ClusterSigningCertFile, "Filename containing a PEM-encoded X509 CA certificate used to issue cluster-scoped certificates")
|
||||
fs.StringVar(&s.ClusterSigningKeyFile, "cluster-signing-key-file", s.ClusterSigningKeyFile, "Filename containing a PEM-encoded RSA or ECDSA private key used to sign cluster-scoped certificates")
|
||||
fs.StringVar(&s.ApproveAllKubeletCSRsForGroup, "insecure-experimental-approve-all-kubelet-csrs-for-group", s.ApproveAllKubeletCSRsForGroup, "The group for which the controller-manager will auto approve all CSRs for kubelet client certificates.")
|
||||
|
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
|||
package authenticator
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"time"
|
||||
|
||||
"k8s.io/kubernetes/pkg/auth/authenticator"
|
||||
|
@ -183,7 +182,7 @@ func newServiceAccountAuthenticator(keyfile string, lookup bool, serviceAccountG
|
|||
return nil, err
|
||||
}
|
||||
|
||||
tokenAuthenticator := serviceaccount.JWTTokenAuthenticator([]*rsa.PublicKey{publicKey}, lookup, serviceAccountGetter)
|
||||
tokenAuthenticator := serviceaccount.JWTTokenAuthenticator([]interface{}{publicKey}, lookup, serviceAccountGetter)
|
||||
return bearertoken.New(tokenAuthenticator), nil
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@ package serviceaccount
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -54,43 +56,95 @@ type TokenGenerator interface {
|
|||
GenerateToken(serviceAccount api.ServiceAccount, secret api.Secret) (string, error)
|
||||
}
|
||||
|
||||
// ReadPrivateKey is a helper function for reading an rsa.PrivateKey from a PEM-encoded file
|
||||
func ReadPrivateKey(file string) (*rsa.PrivateKey, error) {
|
||||
// ReadPrivateKey is a helper function for reading a private key from a PEM-encoded file
|
||||
func ReadPrivateKey(file string) (interface{}, error) {
|
||||
data, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return jwt.ParseRSAPrivateKeyFromPEM(data)
|
||||
key, err := ReadPrivateKeyFromPEM(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading private key file %s: %v", file, err)
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// ReadPublicKey is a helper function for reading an rsa.PublicKey from a PEM-encoded file
|
||||
// Reads public keys from both public and private key files
|
||||
func ReadPublicKey(file string) (*rsa.PublicKey, error) {
|
||||
// ReadPrivateKeyFromPEM is a helper function for reading a private key from a PEM-encoded file
|
||||
func ReadPrivateKeyFromPEM(data []byte) (interface{}, error) {
|
||||
if key, err := jwt.ParseRSAPrivateKeyFromPEM(data); err == nil {
|
||||
return key, nil
|
||||
}
|
||||
if key, err := jwt.ParseECPrivateKeyFromPEM(data); err == nil {
|
||||
return key, nil
|
||||
}
|
||||
return nil, fmt.Errorf("data does not contain a valid RSA or ECDSA private key")
|
||||
}
|
||||
|
||||
// ReadPublicKey is a helper function for reading an rsa.PublicKey or ecdsa.PublicKey from a PEM-encoded file.
|
||||
// Reads public keys from both public and private key files.
|
||||
func ReadPublicKey(file string) (interface{}, error) {
|
||||
data, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key, err := ReadPublicKeyFromPEM(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading public key file %s: %v", file, err)
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// ReadPublicKeyFromPEM is a helper function for reading an rsa.PublicKey or ecdsa.PublicKey from a PEM-encoded byte array.
|
||||
// Reads public keys from both public and private key files.
|
||||
func ReadPublicKeyFromPEM(data []byte) (interface{}, error) {
|
||||
if privateKey, err := jwt.ParseRSAPrivateKeyFromPEM(data); err == nil {
|
||||
return &privateKey.PublicKey, nil
|
||||
}
|
||||
if publicKey, err := jwt.ParseRSAPublicKeyFromPEM(data); err == nil {
|
||||
return publicKey, nil
|
||||
}
|
||||
|
||||
return jwt.ParseRSAPublicKeyFromPEM(data)
|
||||
if privateKey, err := jwt.ParseECPrivateKeyFromPEM(data); err == nil {
|
||||
return &privateKey.PublicKey, nil
|
||||
}
|
||||
if publicKey, err := jwt.ParseECPublicKeyFromPEM(data); err == nil {
|
||||
return publicKey, nil
|
||||
}
|
||||
return nil, fmt.Errorf("data does not contain a valid RSA or ECDSA key")
|
||||
}
|
||||
|
||||
// JWTTokenGenerator returns a TokenGenerator that generates signed JWT tokens, using the given privateKey.
|
||||
// privateKey is a PEM-encoded byte array of a private RSA key.
|
||||
// JWTTokenAuthenticator()
|
||||
func JWTTokenGenerator(key *rsa.PrivateKey) TokenGenerator {
|
||||
return &jwtTokenGenerator{key}
|
||||
func JWTTokenGenerator(privateKey interface{}) TokenGenerator {
|
||||
return &jwtTokenGenerator{privateKey}
|
||||
}
|
||||
|
||||
type jwtTokenGenerator struct {
|
||||
key *rsa.PrivateKey
|
||||
privateKey interface{}
|
||||
}
|
||||
|
||||
func (j *jwtTokenGenerator) GenerateToken(serviceAccount api.ServiceAccount, secret api.Secret) (string, error) {
|
||||
token := jwt.New(jwt.SigningMethodRS256)
|
||||
var method jwt.SigningMethod
|
||||
switch privateKey := j.privateKey.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
method = jwt.SigningMethodRS256
|
||||
case *ecdsa.PrivateKey:
|
||||
switch privateKey.Curve {
|
||||
case elliptic.P256():
|
||||
method = jwt.SigningMethodES256
|
||||
case elliptic.P384():
|
||||
method = jwt.SigningMethodES384
|
||||
case elliptic.P521():
|
||||
method = jwt.SigningMethodES512
|
||||
default:
|
||||
return "", fmt.Errorf("unknown private key curve, must be 256, 384, or 521")
|
||||
}
|
||||
default:
|
||||
return "", fmt.Errorf("unknown private key type %T, must be *rsa.PrivateKey or *ecdsa.PrivateKey", j.privateKey)
|
||||
}
|
||||
|
||||
token := jwt.New(method)
|
||||
|
||||
claims, _ := token.Claims.(jwt.MapClaims)
|
||||
|
||||
|
@ -107,32 +161,44 @@ func (j *jwtTokenGenerator) GenerateToken(serviceAccount api.ServiceAccount, sec
|
|||
claims[SecretNameClaim] = secret.Name
|
||||
|
||||
// Sign and get the complete encoded token as a string
|
||||
return token.SignedString(j.key)
|
||||
return token.SignedString(j.privateKey)
|
||||
}
|
||||
|
||||
// JWTTokenAuthenticator authenticates tokens as JWT tokens produced by JWTTokenGenerator
|
||||
// Token signatures are verified using each of the given public keys until one works (allowing key rotation)
|
||||
// If lookup is true, the service account and secret referenced as claims inside the token are retrieved and verified with the provided ServiceAccountTokenGetter
|
||||
func JWTTokenAuthenticator(keys []*rsa.PublicKey, lookup bool, getter ServiceAccountTokenGetter) authenticator.Token {
|
||||
func JWTTokenAuthenticator(keys []interface{}, lookup bool, getter ServiceAccountTokenGetter) authenticator.Token {
|
||||
return &jwtTokenAuthenticator{keys, lookup, getter}
|
||||
}
|
||||
|
||||
type jwtTokenAuthenticator struct {
|
||||
keys []*rsa.PublicKey
|
||||
keys []interface{}
|
||||
lookup bool
|
||||
getter ServiceAccountTokenGetter
|
||||
}
|
||||
|
||||
var errMismatchedSigningMethod = errors.New("invalid signing method")
|
||||
|
||||
func (j *jwtTokenAuthenticator) AuthenticateToken(token string) (user.Info, bool, error) {
|
||||
var validationError error
|
||||
|
||||
for i, key := range j.keys {
|
||||
// Attempt to verify with each key until we find one that works
|
||||
parsedToken, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
|
||||
switch token.Method.(type) {
|
||||
case *jwt.SigningMethodRSA:
|
||||
if _, ok := key.(*rsa.PublicKey); ok {
|
||||
return key, nil
|
||||
}
|
||||
return nil, errMismatchedSigningMethod
|
||||
case *jwt.SigningMethodECDSA:
|
||||
if _, ok := key.(*ecdsa.PublicKey); ok {
|
||||
return key, nil
|
||||
}
|
||||
return nil, errMismatchedSigningMethod
|
||||
default:
|
||||
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
return key, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
|
@ -150,6 +216,15 @@ func (j *jwtTokenAuthenticator) AuthenticateToken(token string) (user.Info, bool
|
|||
validationError = err
|
||||
continue
|
||||
}
|
||||
|
||||
// This key doesn't apply to the given signature type
|
||||
// Perhaps one of the other keys will verify the signature
|
||||
// If not, we want to return this error
|
||||
if err.Inner == errMismatchedSigningMethod {
|
||||
glog.V(4).Infof("Mismatched key type (key %d): %v", i, err)
|
||||
validationError = err
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Other errors should just return as errors
|
||||
|
|
|
@ -17,14 +17,11 @@ limitations under the License.
|
|||
package serviceaccount_test
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
||||
|
@ -42,7 +39,7 @@ gPZm7ZsipmfbZK2Tkhnpsa4QxDg7zHJPMsB5kxRXW0cQipXcC3baDyN9KBApNXa0
|
|||
PwIDAQAB
|
||||
-----END PUBLIC KEY-----`
|
||||
|
||||
const publicKey = `-----BEGIN PUBLIC KEY-----
|
||||
const rsaPublicKey = `-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA249XwEo9k4tM8fMxV7zx
|
||||
OhcrP+WvXn917koM5Qr2ZXs4vo26e4ytdlrV0bQ9SlcLpQVSYjIxNfhTZdDt+ecI
|
||||
zshKuv1gKIxbbLQMOuK1eA/4HALyEkFgmS/tleLJrhc65tKPMGD+pKQ/xhmzRuCG
|
||||
|
@ -53,7 +50,7 @@ WwIDAQAB
|
|||
-----END PUBLIC KEY-----
|
||||
`
|
||||
|
||||
const privateKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||
const rsaPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEA249XwEo9k4tM8fMxV7zxOhcrP+WvXn917koM5Qr2ZXs4vo26
|
||||
e4ytdlrV0bQ9SlcLpQVSYjIxNfhTZdDt+ecIzshKuv1gKIxbbLQMOuK1eA/4HALy
|
||||
EkFgmS/tleLJrhc65tKPMGD+pKQ/xhmzRuCG51RoiMgbQxaCyYxGfNLpLAZK9L0T
|
||||
|
@ -82,16 +79,28 @@ X024wzbiw1q07jFCyfQmODzURAx1VNT7QVUMdz/N8vy47/H40AZJ
|
|||
-----END RSA PRIVATE KEY-----
|
||||
`
|
||||
|
||||
func getPrivateKey(data string) *rsa.PrivateKey {
|
||||
key, _ := jwt.ParseRSAPrivateKeyFromPEM([]byte(data))
|
||||
// openssl ecparam -name prime256v1 -genkey -noout -out ecdsa256.pem
|
||||
const ecdsaPrivateKey = `-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIEZmTmUhuanLjPA2CLquXivuwBDHTt5XYwgIr/kA1LtRoAoGCCqGSM49
|
||||
AwEHoUQDQgAEH6cuzP8XuD5wal6wf9M6xDljTOPLX2i8uIp/C/ASqiIGUeeKQtX0
|
||||
/IR3qCXyThP/dbCiHrF3v1cuhBOHY8CLVg==
|
||||
-----END EC PRIVATE KEY-----`
|
||||
|
||||
// openssl ec -in ecdsa256.pem -pubout -out ecdsa256pub.pem
|
||||
const ecdsaPublicKey = `-----BEGIN PUBLIC KEY-----
|
||||
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEH6cuzP8XuD5wal6wf9M6xDljTOPL
|
||||
X2i8uIp/C/ASqiIGUeeKQtX0/IR3qCXyThP/dbCiHrF3v1cuhBOHY8CLVg==
|
||||
-----END PUBLIC KEY-----`
|
||||
|
||||
func getPrivateKey(data string) interface{} {
|
||||
key, _ := serviceaccount.ReadPrivateKeyFromPEM([]byte(data))
|
||||
return key
|
||||
}
|
||||
|
||||
func getPublicKey(data string) *rsa.PublicKey {
|
||||
key, _ := jwt.ParseRSAPublicKeyFromPEM([]byte(data))
|
||||
func getPublicKey(data string) interface{} {
|
||||
key, _ := serviceaccount.ReadPublicKeyFromPEM([]byte(data))
|
||||
return key
|
||||
}
|
||||
|
||||
func TestReadPrivateKey(t *testing.T) {
|
||||
f, err := ioutil.TempFile("", "")
|
||||
if err != nil {
|
||||
|
@ -99,12 +108,18 @@ func TestReadPrivateKey(t *testing.T) {
|
|||
}
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
if err := ioutil.WriteFile(f.Name(), []byte(privateKey), os.FileMode(0600)); err != nil {
|
||||
if err := ioutil.WriteFile(f.Name(), []byte(rsaPrivateKey), os.FileMode(0600)); err != nil {
|
||||
t.Fatalf("error writing private key to tmpfile: %v", err)
|
||||
}
|
||||
|
||||
if _, err := serviceaccount.ReadPrivateKey(f.Name()); err != nil {
|
||||
t.Fatalf("error reading private key: %v", err)
|
||||
t.Fatalf("error reading private RSA key: %v", err)
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(f.Name(), []byte(ecdsaPrivateKey), os.FileMode(0600)); err != nil {
|
||||
t.Fatalf("error writing private key to tmpfile: %v", err)
|
||||
}
|
||||
if _, err := serviceaccount.ReadPrivateKey(f.Name()); err != nil {
|
||||
t.Fatalf("error reading private ECDSA key: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,12 +130,18 @@ func TestReadPublicKey(t *testing.T) {
|
|||
}
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
if err := ioutil.WriteFile(f.Name(), []byte(publicKey), os.FileMode(0600)); err != nil {
|
||||
if err := ioutil.WriteFile(f.Name(), []byte(rsaPublicKey), os.FileMode(0600)); err != nil {
|
||||
t.Fatalf("error writing public key to tmpfile: %v", err)
|
||||
}
|
||||
|
||||
if _, err := serviceaccount.ReadPublicKey(f.Name()); err != nil {
|
||||
t.Fatalf("error reading public key: %v", err)
|
||||
t.Fatalf("error reading RSA public key: %v", err)
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(f.Name(), []byte(ecdsaPublicKey), os.FileMode(0600)); err != nil {
|
||||
t.Fatalf("error writing public key to tmpfile: %v", err)
|
||||
}
|
||||
if _, err := serviceaccount.ReadPublicKey(f.Name()); err != nil {
|
||||
t.Fatalf("error reading ECDSA public key: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,31 +157,49 @@ func TestTokenGenerateAndValidate(t *testing.T) {
|
|||
Namespace: "test",
|
||||
},
|
||||
}
|
||||
secret := &api.Secret{
|
||||
rsaSecret := &api.Secret{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "my-secret",
|
||||
Name: "my-rsa-secret",
|
||||
Namespace: "test",
|
||||
},
|
||||
}
|
||||
ecdsaSecret := &api.Secret{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "my-ecdsa-secret",
|
||||
Namespace: "test",
|
||||
},
|
||||
}
|
||||
|
||||
// Generate the token
|
||||
generator := serviceaccount.JWTTokenGenerator(getPrivateKey(privateKey))
|
||||
token, err := generator.GenerateToken(*serviceAccount, *secret)
|
||||
// Generate the RSA token
|
||||
rsaGenerator := serviceaccount.JWTTokenGenerator(getPrivateKey(rsaPrivateKey))
|
||||
rsaToken, err := rsaGenerator.GenerateToken(*serviceAccount, *rsaSecret)
|
||||
if err != nil {
|
||||
t.Fatalf("error generating token: %v", err)
|
||||
}
|
||||
if len(token) == 0 {
|
||||
if len(rsaToken) == 0 {
|
||||
t.Fatalf("no token generated")
|
||||
}
|
||||
rsaSecret.Data = map[string][]byte{
|
||||
"token": []byte(rsaToken),
|
||||
}
|
||||
|
||||
// "Save" the token
|
||||
secret.Data = map[string][]byte{
|
||||
"token": []byte(token),
|
||||
// Generate the ECDSA token
|
||||
ecdsaGenerator := serviceaccount.JWTTokenGenerator(getPrivateKey(ecdsaPrivateKey))
|
||||
ecdsaToken, err := ecdsaGenerator.GenerateToken(*serviceAccount, *ecdsaSecret)
|
||||
if err != nil {
|
||||
t.Fatalf("error generating token: %v", err)
|
||||
}
|
||||
if len(ecdsaToken) == 0 {
|
||||
t.Fatalf("no token generated")
|
||||
}
|
||||
ecdsaSecret.Data = map[string][]byte{
|
||||
"token": []byte(ecdsaToken),
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
Client clientset.Interface
|
||||
Keys []*rsa.PublicKey
|
||||
Keys []interface{}
|
||||
Token string
|
||||
|
||||
ExpectedErr bool
|
||||
ExpectedOK bool
|
||||
|
@ -169,29 +208,60 @@ func TestTokenGenerateAndValidate(t *testing.T) {
|
|||
ExpectedGroups []string
|
||||
}{
|
||||
"no keys": {
|
||||
Token: rsaToken,
|
||||
Client: nil,
|
||||
Keys: []*rsa.PublicKey{},
|
||||
Keys: []interface{}{},
|
||||
ExpectedErr: false,
|
||||
ExpectedOK: false,
|
||||
},
|
||||
"invalid keys": {
|
||||
"invalid keys (rsa)": {
|
||||
Token: rsaToken,
|
||||
Client: nil,
|
||||
Keys: []*rsa.PublicKey{getPublicKey(otherPublicKey)},
|
||||
Keys: []interface{}{getPublicKey(otherPublicKey), getPublicKey(ecdsaPublicKey)},
|
||||
ExpectedErr: true,
|
||||
ExpectedOK: false,
|
||||
},
|
||||
"valid key": {
|
||||
"invalid keys (ecdsa)": {
|
||||
Token: ecdsaToken,
|
||||
Client: nil,
|
||||
Keys: []interface{}{getPublicKey(otherPublicKey), getPublicKey(rsaPublicKey)},
|
||||
ExpectedErr: true,
|
||||
ExpectedOK: false,
|
||||
},
|
||||
"valid key (rsa)": {
|
||||
Token: rsaToken,
|
||||
Client: nil,
|
||||
Keys: []*rsa.PublicKey{getPublicKey(publicKey)},
|
||||
Keys: []interface{}{getPublicKey(rsaPublicKey)},
|
||||
ExpectedErr: false,
|
||||
ExpectedOK: true,
|
||||
ExpectedUserName: expectedUserName,
|
||||
ExpectedUserUID: expectedUserUID,
|
||||
ExpectedGroups: []string{"system:serviceaccounts", "system:serviceaccounts:test"},
|
||||
},
|
||||
"rotated keys": {
|
||||
"valid key (ecdsa)": {
|
||||
Token: ecdsaToken,
|
||||
Client: nil,
|
||||
Keys: []*rsa.PublicKey{getPublicKey(otherPublicKey), getPublicKey(publicKey)},
|
||||
Keys: []interface{}{getPublicKey(ecdsaPublicKey)},
|
||||
ExpectedErr: false,
|
||||
ExpectedOK: true,
|
||||
ExpectedUserName: expectedUserName,
|
||||
ExpectedUserUID: expectedUserUID,
|
||||
ExpectedGroups: []string{"system:serviceaccounts", "system:serviceaccounts:test"},
|
||||
},
|
||||
"rotated keys (rsa)": {
|
||||
Token: rsaToken,
|
||||
Client: nil,
|
||||
Keys: []interface{}{getPublicKey(otherPublicKey), getPublicKey(ecdsaPublicKey), getPublicKey(rsaPublicKey)},
|
||||
ExpectedErr: false,
|
||||
ExpectedOK: true,
|
||||
ExpectedUserName: expectedUserName,
|
||||
ExpectedUserUID: expectedUserUID,
|
||||
ExpectedGroups: []string{"system:serviceaccounts", "system:serviceaccounts:test"},
|
||||
},
|
||||
"rotated keys (ecdsa)": {
|
||||
Token: ecdsaToken,
|
||||
Client: nil,
|
||||
Keys: []interface{}{getPublicKey(otherPublicKey), getPublicKey(rsaPublicKey), getPublicKey(ecdsaPublicKey)},
|
||||
ExpectedErr: false,
|
||||
ExpectedOK: true,
|
||||
ExpectedUserName: expectedUserName,
|
||||
|
@ -199,8 +269,9 @@ func TestTokenGenerateAndValidate(t *testing.T) {
|
|||
ExpectedGroups: []string{"system:serviceaccounts", "system:serviceaccounts:test"},
|
||||
},
|
||||
"valid lookup": {
|
||||
Client: fake.NewSimpleClientset(serviceAccount, secret),
|
||||
Keys: []*rsa.PublicKey{getPublicKey(publicKey)},
|
||||
Token: rsaToken,
|
||||
Client: fake.NewSimpleClientset(serviceAccount, rsaSecret, ecdsaSecret),
|
||||
Keys: []interface{}{getPublicKey(rsaPublicKey)},
|
||||
ExpectedErr: false,
|
||||
ExpectedOK: true,
|
||||
ExpectedUserName: expectedUserName,
|
||||
|
@ -208,14 +279,16 @@ func TestTokenGenerateAndValidate(t *testing.T) {
|
|||
ExpectedGroups: []string{"system:serviceaccounts", "system:serviceaccounts:test"},
|
||||
},
|
||||
"invalid secret lookup": {
|
||||
Token: rsaToken,
|
||||
Client: fake.NewSimpleClientset(serviceAccount),
|
||||
Keys: []*rsa.PublicKey{getPublicKey(publicKey)},
|
||||
Keys: []interface{}{getPublicKey(rsaPublicKey)},
|
||||
ExpectedErr: true,
|
||||
ExpectedOK: false,
|
||||
},
|
||||
"invalid serviceaccount lookup": {
|
||||
Client: fake.NewSimpleClientset(secret),
|
||||
Keys: []*rsa.PublicKey{getPublicKey(publicKey)},
|
||||
Token: rsaToken,
|
||||
Client: fake.NewSimpleClientset(rsaSecret, ecdsaSecret),
|
||||
Keys: []interface{}{getPublicKey(rsaPublicKey)},
|
||||
ExpectedErr: true,
|
||||
ExpectedOK: false,
|
||||
},
|
||||
|
@ -231,7 +304,7 @@ func TestTokenGenerateAndValidate(t *testing.T) {
|
|||
continue
|
||||
}
|
||||
|
||||
user, ok, err := authenticator.AuthenticateToken(token)
|
||||
user, ok, err := authenticator.AuthenticateToken(tc.Token)
|
||||
if (err != nil) != tc.ExpectedErr {
|
||||
t.Errorf("%s: Expected error=%v, got %v", k, tc.ExpectedErr, err)
|
||||
continue
|
||||
|
|
|
@ -361,7 +361,7 @@ func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclie
|
|||
})
|
||||
serviceAccountKey, _ := rsa.GenerateKey(rand.Reader, 2048)
|
||||
serviceAccountTokenGetter := serviceaccountcontroller.NewGetterFromClient(rootClientset)
|
||||
serviceAccountTokenAuth := serviceaccount.JWTTokenAuthenticator([]*rsa.PublicKey{&serviceAccountKey.PublicKey}, true, serviceAccountTokenGetter)
|
||||
serviceAccountTokenAuth := serviceaccount.JWTTokenAuthenticator([]interface{}{&serviceAccountKey.PublicKey}, true, serviceAccountTokenGetter)
|
||||
authenticator := union.New(
|
||||
bearertoken.New(rootTokenAuth),
|
||||
bearertoken.New(serviceAccountTokenAuth),
|
||||
|
|
Loading…
Reference in New Issue