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) }