feat: encryption keys in database (#3265)

* enable overwrite of adminUser fields in defaults.yaml

* create schema and table

* cli: create keys

* cli: create keys

* read encryptionkey from db

* merge v2

* file names

* cleanup defaults.yaml

* remove custom errors

* load encryptionKeys on start

* cleanup

* fix merge

* update system defaults

* fix error message
This commit is contained in:
Livio Amstutz
2022-03-14 07:55:09 +01:00
committed by GitHub
parent 7899a0b851
commit 5463244376
57 changed files with 1618 additions and 471 deletions

View File

@@ -19,6 +19,7 @@ import (
"github.com/caos/zitadel/internal/command"
"github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/crypto"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/handler/crdb"
"github.com/caos/zitadel/internal/i18n"
@@ -44,7 +45,6 @@ type Config struct {
DefaultRefreshTokenExpiration time.Duration
UserAgentCookieConfig *middleware.UserAgentCookieConfig
Cache *middleware.CacheConfig
KeyConfig *crypto.KeyConfig
CustomEndpoints *EndpointConfig
}
@@ -83,18 +83,15 @@ type OPStorage struct {
assetAPIPrefix string
}
func NewProvider(ctx context.Context, config Config, issuer, defaultLogoutRedirectURI string, command *command.Commands, query *query.Queries, repo repository.Repository, keyConfig systemdefaults.KeyConfig, es *eventstore.Eventstore, projections *sql.DB, keyChan <-chan interface{}, userAgentCookie func(http.Handler) http.Handler) (op.OpenIDProvider, error) {
opConfig, err := createOPConfig(config, issuer, defaultLogoutRedirectURI)
func NewProvider(ctx context.Context, config Config, issuer, defaultLogoutRedirectURI string, command *command.Commands, query *query.Queries, repo repository.Repository, keyConfig systemdefaults.KeyConfig, encryptionAlg crypto.EncryptionAlgorithm, cryptoKey []byte, es *eventstore.Eventstore, projections *sql.DB, keyChan <-chan interface{}, userAgentCookie func(http.Handler) http.Handler) (op.OpenIDProvider, error) {
opConfig, err := createOPConfig(config, issuer, defaultLogoutRedirectURI, cryptoKey)
if err != nil {
return nil, fmt.Errorf("cannot create op config: %w", err)
}
storage, err := newStorage(config, command, query, repo, keyConfig, config.KeyConfig, es, projections, keyChan)
if err != nil {
return nil, fmt.Errorf("cannot create storage: %w", err)
return nil, caos_errs.ThrowInternal(err, "OIDC-EGrqd", "cannot create op config: %w")
}
storage := newStorage(config, command, query, repo, keyConfig, encryptionAlg, es, projections, keyChan)
options, err := createOptions(config, userAgentCookie)
if err != nil {
return nil, fmt.Errorf("cannot create options: %w", err)
return nil, caos_errs.ThrowInternal(err, "OIDC-D3gq1", "cannot create options: %w")
}
provider, err := op.NewOpenIDProvider(
ctx,
@@ -103,7 +100,7 @@ func NewProvider(ctx context.Context, config Config, issuer, defaultLogoutRedire
options...,
)
if err != nil {
return nil, fmt.Errorf("cannot create provider: %w", err)
return nil, caos_errs.ThrowInternal(err, "OIDC-DAtg3", "cannot create provider: %w")
}
return provider, nil
}
@@ -112,7 +109,7 @@ func Issuer(domain string, port uint16, externalSecure bool) string {
return http_utils.BuildHTTP(domain, port, externalSecure) + HandlerPrefix
}
func createOPConfig(config Config, issuer, defaultLogoutRedirectURI string) (*op.Config, error) {
func createOPConfig(config Config, issuer, defaultLogoutRedirectURI string, cryptoKey []byte) (*op.Config, error) {
supportedLanguages, err := getSupportedLanguages()
if err != nil {
return nil, err
@@ -127,25 +124,13 @@ func createOPConfig(config Config, issuer, defaultLogoutRedirectURI string) (*op
RequestObjectSupported: config.RequestObjectSupported,
SupportedUILocales: supportedLanguages,
}
if err := cryptoKey(opConfig, config.KeyConfig); err != nil {
return nil, err
if cryptoLength := len(cryptoKey); cryptoLength != 32 {
return nil, caos_errs.ThrowInternalf(nil, "OIDC-D43gf", "crypto key must be 32 bytes, but is %d", cryptoLength)
}
copy(opConfig.CryptoKey[:], cryptoKey)
return opConfig, nil
}
func cryptoKey(config *op.Config, keyConfig *crypto.KeyConfig) error {
tokenKey, err := crypto.LoadKey(keyConfig, keyConfig.EncryptionKeyID)
if err != nil {
return fmt.Errorf("cannot load OP crypto key: %w", err)
}
cryptoKey := []byte(tokenKey)
if len(cryptoKey) != 32 {
return fmt.Errorf("OP crypto key must be exactly 32 bytes")
}
copy(config.CryptoKey[:], cryptoKey)
return nil
}
func createOptions(config Config, userAgentCookie func(http.Handler) http.Handler) ([]op.Option, error) {
metricTypes := []metrics.MetricType{metrics.MetricTypeRequestCount, metrics.MetricTypeStatusCode, metrics.MetricTypeTotalCount}
interceptor := op.WithHttpInterceptors(
@@ -191,11 +176,7 @@ func customEndpoints(endpointConfig *EndpointConfig) []op.Option {
return options
}
func newStorage(config Config, command *command.Commands, query *query.Queries, repo repository.Repository, keyConfig systemdefaults.KeyConfig, c *crypto.KeyConfig, es *eventstore.Eventstore, projections *sql.DB, keyChan <-chan interface{}) (*OPStorage, error) {
encAlg, err := crypto.NewAESCrypto(c)
if err != nil {
return nil, err
}
func newStorage(config Config, command *command.Commands, query *query.Queries, repo repository.Repository, keyConfig systemdefaults.KeyConfig, encAlg crypto.EncryptionAlgorithm, es *eventstore.Eventstore, projections *sql.DB, keyChan <-chan interface{}) *OPStorage {
return &OPStorage{
repo: repo,
command: command,
@@ -213,7 +194,7 @@ func newStorage(config Config, command *command.Commands, query *query.Queries,
locker: crdb.NewLocker(projections, locksTable, signingKey),
keyChan: keyChan,
assetAPIPrefix: assets.HandlerPrefix,
}, nil
}
}
func (o *OPStorage) Health(ctx context.Context) error {