From 0aae3983dd5219025a740411e231e223a7df8321 Mon Sep 17 00:00:00 2001 From: Or Ozeri Date: Wed, 10 Jul 2024 15:28:00 +0300 Subject: [PATCH] controlplane/authz: Use a faster JWT algorithm This commit switched the JWT algorithm from RS256 to HS256. Signed-off-by: Or Ozeri --- pkg/controlplane/api/authz.go | 2 +- pkg/controlplane/authz/manager.go | 37 ++++++++++++----------------- pkg/controlplane/control/manager.go | 35 +++++---------------------- 3 files changed, 22 insertions(+), 52 deletions(-) diff --git a/pkg/controlplane/api/authz.go b/pkg/controlplane/api/authz.go index fb793fafc..f48c49295 100644 --- a/pkg/controlplane/api/authz.go +++ b/pkg/controlplane/api/authz.go @@ -39,7 +39,7 @@ const ( AccessTokenHeader = "x-access-token" // JWTSignatureAlgorithm defines the signing algorithm for JWT tokens. - JWTSignatureAlgorithm = jwa.RS256 + JWTSignatureAlgorithm = jwa.HS256 // ExportNameJWTClaim holds the name of the requested exported service. ExportNameJWTClaim = "export_name" // ExportNamespaceJWTClaim holds the namespace of the requested exported service. diff --git a/pkg/controlplane/authz/manager.go b/pkg/controlplane/authz/manager.go index b65173235..ffcb88530 100644 --- a/pkg/controlplane/authz/manager.go +++ b/pkg/controlplane/authz/manager.go @@ -108,9 +108,8 @@ type Manager struct { ipToPod map[string]types.NamespacedName podList map[types.NamespacedName]podInfo - jwksLock sync.RWMutex - jwkSignKey jwk.Key - jwkVerifyKey jwk.Key + jwksLock sync.RWMutex + jwkKey jwk.Key logger *logrus.Entry } @@ -182,25 +181,19 @@ func (m *Manager) addSecret(secret *v1.Secret) error { return nil } - privateKey, err := control.ParseJWKSSecret(secret) + key, err := control.ParseJWKSSecret(secret) if err != nil { return fmt.Errorf("cannot parse JWKS secret: %w", err) } - jwkSignKey, err := jwk.New(privateKey) + jwkKey, err := jwk.New(key) if err != nil { - return fmt.Errorf("unable to create JWK signing key: %w", err) - } - - jwkVerifyKey, err := jwk.New(privateKey.PublicKey) - if err != nil { - return fmt.Errorf("unable to create JWK verifing key: %w", err) + return fmt.Errorf("unable to create JWK key: %w", err) } m.jwksLock.Lock() defer m.jwksLock.Unlock() - m.jwkSignKey = jwkSignKey - m.jwkVerifyKey = jwkVerifyKey + m.jwkKey = jwkKey return nil } @@ -322,15 +315,15 @@ func (m *Manager) parseAuthorizationHeader(token string) (string, error) { m.logger.Debug("Parsing access token.") m.jwksLock.RLock() - jwkVerifyKey := m.jwkVerifyKey + jwkkey := m.jwkKey m.jwksLock.RUnlock() - if jwkVerifyKey == nil { - return "", fmt.Errorf("jwk verify key undefined") + if jwkkey == nil { + return "", fmt.Errorf("jwk key undefined") } parsedToken, err := jwt.ParseString( - token, jwt.WithVerify(cpapi.JWTSignatureAlgorithm, jwkVerifyKey), jwt.WithValidate(true)) + token, jwt.WithVerify(cpapi.JWTSignatureAlgorithm, jwkkey), jwt.WithValidate(true)) if err != nil { return "", err } @@ -407,15 +400,15 @@ func (m *Manager) authorizeIngress( } m.jwksLock.RLock() - jwkSignKey := m.jwkSignKey + jwkKey := m.jwkKey m.jwksLock.RUnlock() - if jwkSignKey == nil { - return nil, fmt.Errorf("jwk sign key undefined") + if jwkKey == nil { + return nil, fmt.Errorf("jwk key undefined") } // sign access token - signed, err := jwt.Sign(token, cpapi.JWTSignatureAlgorithm, jwkSignKey) + signed, err := jwt.Sign(token, cpapi.JWTSignatureAlgorithm, jwkKey) if err != nil { return nil, fmt.Errorf("unable to sign access token: %w", err) } @@ -458,7 +451,7 @@ func (m *Manager) SetPeerCertificates(peerTLS *tls.ParsedCertData, _ *tls.RawCer func (m *Manager) IsReady() bool { m.jwksLock.RLock() defer m.jwksLock.RUnlock() - return m.jwkSignKey != nil + return m.jwkKey != nil } // NewManager returns a new authorization manager. diff --git a/pkg/controlplane/control/manager.go b/pkg/controlplane/control/manager.go index 079a41cb7..887c4a175 100644 --- a/pkg/controlplane/control/manager.go +++ b/pkg/controlplane/control/manager.go @@ -14,16 +14,12 @@ package control import ( - "bytes" "context" //nolint:gosec // G505: use of weak cryptographic primitive is fine for service name "crypto/md5" "crypto/rand" - "crypto/rsa" - "crypto/x509" "encoding/base64" - "encoding/pem" "errors" "fmt" "reflect" @@ -879,22 +875,13 @@ func (m *Manager) CreateJWKSSecret(ctx context.Context) error { } func generateJWKSecret() ([]byte, error) { - rsaKey, err := rsa.GenerateKey(rand.Reader, 2048) + keyBytes := make([]byte, 32) + _, err := rand.Read(keyBytes) if err != nil { return nil, fmt.Errorf("unable to generate JWK key: %w", err) } - // PEM encode private key - keyPEM := new(bytes.Buffer) - err = pem.Encode(keyPEM, &pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(rsaKey), - }) - if err != nil { - return nil, fmt.Errorf("cannot encode JWK key: %w", err) - } - - return []byte(base64.StdEncoding.EncodeToString(keyPEM.Bytes())), nil + return []byte(base64.StdEncoding.EncodeToString(keyBytes)), nil } func checkServiceLabels(service *v1.Service, importName types.NamespacedName) bool { @@ -1033,28 +1020,18 @@ func endpointSliceChanged(endpointSlice1, endpointSlice2 *discv1.EndpointSlice) return false } -func ParseJWKSSecret(secret *v1.Secret) (*rsa.PrivateKey, error) { +func ParseJWKSSecret(secret *v1.Secret) ([]byte, error) { keyBase64, ok := secret.Data[JWKSecretKeyName] if !ok { return nil, fmt.Errorf("secret missing %s key", JWKSecretKeyName) } - keyPEM, err := base64.StdEncoding.DecodeString(string(keyBase64)) + keyBytes, err := base64.StdEncoding.DecodeString(string(keyBase64)) if err != nil { return nil, fmt.Errorf("cannot base64 decode key") } - keyBlock, _ := pem.Decode(keyPEM) - if keyBlock == nil { - return nil, fmt.Errorf("key is not in PEM format") - } - - privateKey, err := x509.ParsePKCS1PrivateKey(keyBlock.Bytes) - if err != nil { - return nil, fmt.Errorf("error parsing private key: %w", err) - } - - return privateKey, nil + return keyBytes, nil } // NewManager returns a new control manager.