From d0c199b62c17e6d0d54f4e6f45cad47364dc3d94 Mon Sep 17 00:00:00 2001 From: Bobby Rullo Date: Tue, 25 Aug 2015 16:44:38 -0700 Subject: [PATCH] cmd, server: base64 encode multiple secrets Two things here: * key secrets are now base64 encoded strings, so we get the full key space * we can pass >1 of them in so we can rotate them --- cmd/dex-overlord/main.go | 32 ++++++++++++++++++++++++++------ cmd/dex-worker/main.go | 7 +++++-- server/config.go | 6 +++--- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/cmd/dex-overlord/main.go b/cmd/dex-overlord/main.go index 419b6f2c..be56db47 100644 --- a/cmd/dex-overlord/main.go +++ b/cmd/dex-overlord/main.go @@ -28,7 +28,10 @@ func init() { func main() { fs := flag.NewFlagSet("dex-overlord", flag.ExitOnError) - secret := fs.String("key-secret", "", "symmetric key used to encrypt/decrypt signing key data in DB") + + keySecrets := pflag.NewBase64List(32) + fs.Var(keySecrets, "key-secrets", "A comma-separated list of base64 encoded 32 byte strings used as symmetric keys used to encrypt/decrypt signing key data in DB. The first key is considered the active key and used for encryption, while the others are used to decrypt.") + dbURL := fs.String("db-url", "", "DSN-formatted database connection string") dbMigrate := fs.Bool("db-migrate", true, "perform database migrations when starting up overlord. This includes the initial DB objects creation.") @@ -59,10 +62,6 @@ func main() { log.EnableTimestamps() } - if len(*secret) == 0 { - log.Fatalf("--key-secret unset") - } - adminURL, err := url.Parse(*adminListen) if err != nil { log.Fatalf("Unable to use --admin-listen flag: %v", err) @@ -96,11 +95,32 @@ func main() { userManager := user.NewManager(userRepo, pwiRepo, db.TransactionFactory(dbc), user.ManagerOptions{}) adminAPI := admin.NewAdminAPI(userManager, userRepo, pwiRepo, *localConnectorID) - kRepo, err := db.NewPrivateKeySetRepo(dbc, *secret) + kRepo, err := db.NewPrivateKeySetRepo(dbc, keySecrets.BytesSlice()...) if err != nil { log.Fatalf(err.Error()) } + var sleep time.Duration + for { + var done bool + _, err := kRepo.Get() + switch err { + case nil: + done = true + case key.ErrorNoKeys: + done = true + case db.ErrorCannotDecryptKeys: + log.Fatalf("Cannot decrypt keys using any of the given key secrets. The key secrets must be changed to include one that can decrypt the existing keys, or the existing keys must be deleted.") + } + + if done { + break + } + sleep = ptime.ExpBackoff(sleep, time.Minute) + log.Errorf("Unable to get keys from repository, retrying in %v: %v", sleep, err) + time.Sleep(sleep) + } + krot := key.NewPrivateKeyRotator(kRepo, *keyPeriod) s := server.NewAdminServer(adminAPI, krot) h := s.HTTPHandler() diff --git a/cmd/dex-worker/main.go b/cmd/dex-worker/main.go index 2a93b481..e9a50ea2 100644 --- a/cmd/dex-worker/main.go +++ b/cmd/dex-worker/main.go @@ -41,7 +41,10 @@ func main() { // ignored if --no-db is set dbURL := fs.String("db-url", "", "DSN-formatted database connection string") - keySecret := fs.String("key-secret", "", "symmetric key used to encrypt/decrypt signing key data in DB") + + keySecrets := pflag.NewBase64List(32) + fs.Var(keySecrets, "key-secrets", "A comma-separated list of base64 encoded 32 byte strings used as symmetric keys used to encrypt/decrypt signing key data in DB. The first key is considered the active key and used for encryption, while the others are used to decrypt.") + dbMaxIdleConns := fs.Int("db-max-idle-conns", 0, "maximum number of connections in the idle connection pool") dbMaxOpenConns := fs.Int("db-max-open-conns", 0, "maximum number of open connections to the database") @@ -109,7 +112,7 @@ func main() { MaxOpenConnections: *dbMaxOpenConns, } scfg.StateConfig = &server.MultiServerConfig{ - KeySecret: *keySecret, + KeySecrets: keySecrets.BytesSlice(), DatabaseConfig: dbCfg, } } diff --git a/server/config.go b/server/config.go index 17171d52..b44ad702 100644 --- a/server/config.go +++ b/server/config.go @@ -44,7 +44,7 @@ type SingleServerConfig struct { } type MultiServerConfig struct { - KeySecret string + KeySecrets [][]byte DatabaseConfig db.Config } @@ -141,7 +141,7 @@ func (cfg *SingleServerConfig) Configure(srv *Server) error { } func (cfg *MultiServerConfig) Configure(srv *Server) error { - if cfg.KeySecret == "" { + if len(cfg.KeySecrets) == 0 { return errors.New("missing key secret") } @@ -154,7 +154,7 @@ func (cfg *MultiServerConfig) Configure(srv *Server) error { return fmt.Errorf("unable to initialize database connection: %v", err) } - kRepo, err := db.NewPrivateKeySetRepo(dbc, cfg.KeySecret) + kRepo, err := db.NewPrivateKeySetRepo(dbc, cfg.KeySecrets...) if err != nil { return fmt.Errorf("unable to create PrivateKeySetRepo: %v", err) }