mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
114 lines
3.3 KiB
Go
114 lines
3.3 KiB
Go
|
|
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)
|
||
|
|
}
|