mirror of https://github.com/grafana/grafana
Auth: Add SigningKeys Service (#64343)
* Add key service Co-authored-by: Misi <mgyongyosi@users.noreply.github.com> * Wire the service * Rename Service * Implement GetJWKS * Slipt interface and implementation Co-authored-by: Misi <mgyongyosi@users.noreply.github.com> * Change implementation, add tests * Align to the expected package hierarchy * Update CODEOWNERS * Align names and fix wire.go * Update pkg/services/signingkeys/signingkeysimpl/service.go Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com> * Update pkg/services/signingkeys/signingkeysimpl/service_test.go Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com> * Update pkg/services/signingkeys/signingkeysimpl/service_test.go Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com> * Update pkg/services/signingkeys/signingkeysimpl/service_test.go Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com> * Add AddPrivateKey method to SigningKeysService * Align tests to the guidelines * Add test for GetJWKS() method * Add comments to the interface * Add FakeSigningKeysService --------- Co-authored-by: Misi <mgyongyosi@users.noreply.github.com> Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>pull/66655/head
parent
3c2a69c82c
commit
4027254b87
@ -0,0 +1,9 @@ |
||||
package signingkeys |
||||
|
||||
import "github.com/grafana/grafana/pkg/util/errutil" |
||||
|
||||
var ( |
||||
ErrSigningKeyNotFound = errutil.NewBase(errutil.StatusNotFound, "signingkeys.keyNotFound") |
||||
ErrSigningKeyAlreadyExists = errutil.NewBase(errutil.StatusBadRequest, "signingkeys.keyAlreadyExists") |
||||
ErrKeyGenerationFailed = errutil.NewBase(errutil.StatusInternal, "signingkeys.keyGenerationFailed") |
||||
) |
@ -0,0 +1,32 @@ |
||||
// Package signingkeys implements the SigningKeys service which is responsible for managing
|
||||
// the signing keys used to sign and verify JWT tokens.
|
||||
//
|
||||
// The service is under active development and is not yet ready for production use.
|
||||
//
|
||||
// Currently, it only supports RSA keys and the keys are stored in memory.
|
||||
|
||||
package signingkeys |
||||
|
||||
import ( |
||||
"crypto" |
||||
|
||||
"github.com/go-jose/go-jose/v3" |
||||
) |
||||
|
||||
// Service provides functionality for managing signing keys used to sign and verify JWT tokens.
|
||||
//
|
||||
// The service is under active development and is not yet ready for production use.
|
||||
type Service interface { |
||||
// GetJWKS returns the JSON Web Key Set (JWKS) with all the keys that can be used to verify tokens (public keys)
|
||||
GetJWKS() jose.JSONWebKeySet |
||||
// GetJWK returns the JSON Web Key (JWK) with the specified key ID which can be used to verify tokens (public key)
|
||||
GetJWK(keyID string) (jose.JSONWebKey, error) |
||||
// GetPublicKey returns the public key with the specified key ID
|
||||
GetPublicKey(keyID string) (crypto.PublicKey, error) |
||||
// GetPrivateKey returns the private key with the specified key ID
|
||||
GetPrivateKey(keyID string) (crypto.PrivateKey, error) |
||||
// GetServerPrivateKey returns the private key used to sign tokens
|
||||
GetServerPrivateKey() (crypto.PrivateKey, error) |
||||
// AddPrivateKey adds a private key to the service
|
||||
AddPrivateKey(keyID string, privateKey crypto.PrivateKey) error |
||||
} |
@ -0,0 +1,113 @@ |
||||
package signingkeysimpl |
||||
|
||||
import ( |
||||
"crypto" |
||||
"crypto/rand" |
||||
"crypto/rsa" |
||||
|
||||
"github.com/go-jose/go-jose/v3" |
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log" |
||||
"github.com/grafana/grafana/pkg/services/featuremgmt" |
||||
"github.com/grafana/grafana/pkg/services/signingkeys" |
||||
) |
||||
|
||||
const ( |
||||
serverPrivateKeyID = "default" |
||||
) |
||||
|
||||
var _ signingkeys.Service = new(Service) |
||||
|
||||
func ProvideEmbeddedSigningKeysService(features *featuremgmt.FeatureManager) (*Service, error) { |
||||
s := &Service{ |
||||
log: log.New("auth.key_service"), |
||||
keys: map[string]crypto.Signer{}, |
||||
} |
||||
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 4096) |
||||
if err != nil { |
||||
s.log.Error("Error generating private key", "err", err) |
||||
return nil, signingkeys.ErrKeyGenerationFailed.Errorf("Error generating private key: %v", err) |
||||
} |
||||
|
||||
if err := s.AddPrivateKey(serverPrivateKeyID, privateKey); err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s, nil |
||||
} |
||||
|
||||
// Service provides functionality for managing signing keys used to sign and verify JWT tokens for
|
||||
// the OSS version of Grafana.
|
||||
//
|
||||
// The service is under active development and is not yet ready for production use.
|
||||
type Service struct { |
||||
log log.Logger |
||||
keys map[string]crypto.Signer |
||||
} |
||||
|
||||
// GetJWKS returns the JSON Web Key Set (JWKS) with all the keys that can be used to verify tokens (public keys)
|
||||
func (s *Service) GetJWKS() jose.JSONWebKeySet { |
||||
result := jose.JSONWebKeySet{} |
||||
|
||||
for keyID := range s.keys { |
||||
// Skip error check because keyID must be a valid key ID
|
||||
jwk, _ := s.GetJWK(keyID) |
||||
result.Keys = append(result.Keys, jwk) |
||||
} |
||||
|
||||
return result |
||||
} |
||||
|
||||
// GetJWK returns the JSON Web Key (JWK) with the specified key ID which can be used to verify tokens (public key)
|
||||
func (s *Service) GetJWK(keyID string) (jose.JSONWebKey, error) { |
||||
privateKey, ok := s.keys[keyID] |
||||
if !ok { |
||||
s.log.Error("The specified key was not found", "keyID", keyID) |
||||
return jose.JSONWebKey{}, signingkeys.ErrSigningKeyNotFound.Errorf("The specified key was not found: %s", keyID) |
||||
} |
||||
|
||||
result := jose.JSONWebKey{ |
||||
Key: privateKey.Public(), |
||||
Use: "sig", |
||||
} |
||||
|
||||
return result, nil |
||||
} |
||||
|
||||
// GetPublicKey returns the public key with the specified key ID
|
||||
func (s *Service) GetPublicKey(keyID string) (crypto.PublicKey, error) { |
||||
privateKey, ok := s.keys[keyID] |
||||
if !ok { |
||||
s.log.Error("The specified key was not found", "keyID", keyID) |
||||
return nil, signingkeys.ErrSigningKeyNotFound.Errorf("The specified key was not found: %s", keyID) |
||||
} |
||||
|
||||
return privateKey.Public(), nil |
||||
} |
||||
|
||||
// GetPrivateKey returns the private key with the specified key ID
|
||||
func (s *Service) GetPrivateKey(keyID string) (crypto.PrivateKey, error) { |
||||
privateKey, ok := s.keys[keyID] |
||||
if !ok { |
||||
s.log.Error("The specified key was not found", "keyID", keyID) |
||||
return nil, signingkeys.ErrSigningKeyNotFound.Errorf("The specified key was not found: %s", keyID) |
||||
} |
||||
|
||||
return privateKey, nil |
||||
} |
||||
|
||||
// AddPrivateKey adds a private key to the service
|
||||
func (s *Service) AddPrivateKey(keyID string, privateKey crypto.PrivateKey) error { |
||||
if _, ok := s.keys[keyID]; ok { |
||||
s.log.Error("The specified key ID is already in use", "keyID", keyID) |
||||
return signingkeys.ErrSigningKeyAlreadyExists.Errorf("The specified key ID is already in use: %s", keyID) |
||||
} |
||||
s.keys[keyID] = privateKey.(crypto.Signer) |
||||
return nil |
||||
} |
||||
|
||||
// GetServerPrivateKey returns the private key used to sign tokens
|
||||
func (s *Service) GetServerPrivateKey() (crypto.PrivateKey, error) { |
||||
return s.GetPrivateKey(serverPrivateKeyID) |
||||
} |
@ -0,0 +1,283 @@ |
||||
package signingkeysimpl |
||||
|
||||
import ( |
||||
"crypto" |
||||
"crypto/rsa" |
||||
"crypto/x509" |
||||
"encoding/json" |
||||
"encoding/pem" |
||||
"io" |
||||
"testing" |
||||
|
||||
"github.com/go-jose/go-jose/v3" |
||||
"github.com/grafana/grafana/pkg/infra/log" |
||||
"github.com/stretchr/testify/require" |
||||
) |
||||
|
||||
const ( |
||||
privateKeyPem = `-----BEGIN RSA PRIVATE KEY----- |
||||
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 |
||||
-----END RSA PRIVATE KEY-----` |
||||
) |
||||
|
||||
func getPrivateKey(t *testing.T) *rsa.PrivateKey { |
||||
pemBlock, _ := pem.Decode([]byte(privateKeyPem)) |
||||
privateKey, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes) |
||||
require.NoError(t, err) |
||||
return privateKey |
||||
} |
||||
|
||||
func setupTestService(t *testing.T) *Service { |
||||
svc := &Service{ |
||||
log: log.NewNopLogger(), |
||||
keys: map[string]crypto.Signer{serverPrivateKeyID: getPrivateKey(t)}, |
||||
} |
||||
return svc |
||||
} |
||||
|
||||
func TestEmbeddedKeyService_GetJWK(t *testing.T) { |
||||
tests := []struct { |
||||
name string |
||||
keyID string |
||||
want jose.JSONWebKey |
||||
wantErr bool |
||||
}{ |
||||
{name: "creates a JSON Web Key successfully", |
||||
keyID: "default", |
||||
want: jose.JSONWebKey{ |
||||
Key: getPrivateKey(t).Public(), |
||||
Use: "sig", |
||||
}, |
||||
wantErr: false, |
||||
}, |
||||
{name: "returns error when the specified key was not found", |
||||
keyID: "not-existing-key-id", |
||||
want: jose.JSONWebKey{}, |
||||
wantErr: true, |
||||
}, |
||||
} |
||||
svc := setupTestService(t) |
||||
for _, tt := range tests { |
||||
t.Run(tt.name, func(t *testing.T) { |
||||
got, err := svc.GetJWK(tt.keyID) |
||||
if tt.wantErr { |
||||
require.Error(t, err) |
||||
return |
||||
} |
||||
require.NoError(t, err) |
||||
require.Equal(t, got, tt.want) |
||||
}) |
||||
} |
||||
} |
||||
|
||||
func TestEmbeddedKeyService_GetJWK_OnlyPublicKeyShared(t *testing.T) { |
||||
svc := setupTestService(t) |
||||
jwk, err := svc.GetJWK("default") |
||||
|
||||
require.NoError(t, err) |
||||
|
||||
jwkJson, err := jwk.MarshalJSON() |
||||
require.NoError(t, err) |
||||
|
||||
kvs := make(map[string]interface{}) |
||||
err = json.Unmarshal(jwkJson, &kvs) |
||||
require.NoError(t, err) |
||||
|
||||
// check that the private key is not shared
|
||||
require.NotContains(t, kvs, "d") |
||||
require.NotContains(t, kvs, "p") |
||||
require.NotContains(t, kvs, "q") |
||||
} |
||||
|
||||
func TestEmbeddedKeyService_GetJWKS(t *testing.T) { |
||||
svc := &Service{ |
||||
log: log.NewNopLogger(), |
||||
keys: map[string]crypto.Signer{ |
||||
serverPrivateKeyID: getPrivateKey(t), |
||||
"other": getPrivateKey(t), |
||||
}, |
||||
} |
||||
jwk := svc.GetJWKS() |
||||
|
||||
require.Equal(t, 2, len(jwk.Keys)) |
||||
} |
||||
|
||||
func TestEmbeddedKeyService_GetJWKS_OnlyPublicKeyShared(t *testing.T) { |
||||
svc := setupTestService(t) |
||||
jwks := svc.GetJWKS() |
||||
|
||||
jwksJson, err := json.Marshal(jwks) |
||||
require.NoError(t, err) |
||||
|
||||
type keys struct { |
||||
Keys []map[string]interface{} `json:"keys"` |
||||
} |
||||
|
||||
var kvs keys |
||||
err = json.Unmarshal(jwksJson, &kvs) |
||||
require.NoError(t, err) |
||||
|
||||
for _, kv := range kvs.Keys { |
||||
// check that the private key is not shared
|
||||
require.NotContains(t, kv, "d") |
||||
require.NotContains(t, kv, "p") |
||||
require.NotContains(t, kv, "q") |
||||
} |
||||
} |
||||
|
||||
func TestEmbeddedKeyService_GetPublicKey(t *testing.T) { |
||||
tests := []struct { |
||||
name string |
||||
keyID string |
||||
want crypto.PublicKey |
||||
wantErr bool |
||||
}{ |
||||
{ |
||||
name: "returns the public key successfully", |
||||
keyID: "default", |
||||
want: getPrivateKey(t).Public(), |
||||
wantErr: false, |
||||
}, |
||||
{ |
||||
name: "returns error when the specified key was not found", |
||||
keyID: "not-existent-key-id", |
||||
want: nil, |
||||
wantErr: true, |
||||
}, |
||||
} |
||||
svc := setupTestService(t) |
||||
for _, tt := range tests { |
||||
t.Run(tt.name, func(t *testing.T) { |
||||
got, err := svc.GetPublicKey(tt.keyID) |
||||
if tt.wantErr { |
||||
require.Error(t, err) |
||||
return |
||||
} |
||||
require.NoError(t, err) |
||||
require.Equal(t, got, tt.want) |
||||
}) |
||||
} |
||||
} |
||||
|
||||
func TestEmbeddedKeyService_GetPrivateKey(t *testing.T) { |
||||
tests := []struct { |
||||
name string |
||||
keyID string |
||||
want crypto.PrivateKey |
||||
wantErr bool |
||||
}{ |
||||
{ |
||||
name: "returns the private key successfully", |
||||
keyID: "default", |
||||
want: getPrivateKey(t), |
||||
wantErr: false, |
||||
}, |
||||
{ |
||||
name: "returns error when the specified key was not found", |
||||
keyID: "not-existent-key-id", |
||||
want: nil, |
||||
wantErr: true, |
||||
}, |
||||
} |
||||
svc := setupTestService(t) |
||||
for _, tt := range tests { |
||||
t.Run(tt.name, func(t *testing.T) { |
||||
got, err := svc.GetPrivateKey(tt.keyID) |
||||
if tt.wantErr { |
||||
require.Error(t, err) |
||||
return |
||||
} |
||||
require.NoError(t, err) |
||||
require.Equal(t, got, tt.want) |
||||
}) |
||||
} |
||||
} |
||||
|
||||
func TestEmbeddedKeyService_AddPrivateKey(t *testing.T) { |
||||
tests := []struct { |
||||
name string |
||||
keyID string |
||||
wantErr bool |
||||
}{ |
||||
{ |
||||
name: "adds the private key successfully", |
||||
keyID: "new-key-id", |
||||
wantErr: false, |
||||
}, |
||||
{ |
||||
name: "returns error when the specified key is already in the store", |
||||
keyID: serverPrivateKeyID, |
||||
wantErr: true, |
||||
}, |
||||
} |
||||
svc := setupTestService(t) |
||||
for _, tt := range tests { |
||||
t.Run(tt.name, func(t *testing.T) { |
||||
err := svc.AddPrivateKey(tt.keyID, &dummyPrivateKey{}) |
||||
if tt.wantErr { |
||||
require.Error(t, err) |
||||
return |
||||
} |
||||
require.NoError(t, err) |
||||
}) |
||||
} |
||||
} |
||||
|
||||
type dummyPrivateKey struct { |
||||
} |
||||
|
||||
func (d dummyPrivateKey) Public() crypto.PublicKey { |
||||
return "" |
||||
} |
||||
|
||||
func (d dummyPrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { |
||||
return nil, nil |
||||
} |
@ -0,0 +1,48 @@ |
||||
package signingkeystest |
||||
|
||||
import ( |
||||
"crypto" |
||||
|
||||
"github.com/go-jose/go-jose/v3" |
||||
) |
||||
|
||||
type FakeSigningKeysService struct { |
||||
ExpectedJSONWebKeySet jose.JSONWebKeySet |
||||
ExpectedJSONWebKey jose.JSONWebKey |
||||
ExpectedKeys map[string]crypto.Signer |
||||
ExpectedServerPrivateKey crypto.PrivateKey |
||||
ExpectedError error |
||||
} |
||||
|
||||
func (s *FakeSigningKeysService) GetJWKS() jose.JSONWebKeySet { |
||||
return s.ExpectedJSONWebKeySet |
||||
} |
||||
|
||||
// GetJWK returns the JSON Web Key (JWK) with the specified key ID which can be used to verify tokens (public key)
|
||||
func (s *FakeSigningKeysService) GetJWK(keyID string) (jose.JSONWebKey, error) { |
||||
return s.ExpectedJSONWebKey, s.ExpectedError |
||||
} |
||||
|
||||
// GetPublicKey returns the public key with the specified key ID
|
||||
func (s *FakeSigningKeysService) GetPublicKey(keyID string) (crypto.PublicKey, error) { |
||||
return s.ExpectedKeys[keyID].Public(), s.ExpectedError |
||||
} |
||||
|
||||
// GetPrivateKey returns the private key with the specified key ID
|
||||
func (s *FakeSigningKeysService) GetPrivateKey(keyID string) (crypto.PrivateKey, error) { |
||||
return s.ExpectedKeys[keyID], s.ExpectedError |
||||
} |
||||
|
||||
// GetServerPrivateKey returns the private key used to sign tokens
|
||||
func (s *FakeSigningKeysService) GetServerPrivateKey() (crypto.PrivateKey, error) { |
||||
return s.ExpectedServerPrivateKey, s.ExpectedError |
||||
} |
||||
|
||||
// AddPrivateKey adds a private key to the service
|
||||
func (s *FakeSigningKeysService) AddPrivateKey(keyID string, privateKey crypto.PrivateKey) error { |
||||
if s.ExpectedError != nil { |
||||
return s.ExpectedError |
||||
} |
||||
s.ExpectedKeys[keyID] = privateKey.(crypto.Signer) |
||||
return nil |
||||
} |
Loading…
Reference in new issue