From fa9de9a0f123269cc257b849cec03b4ab316c133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20M=C3=B6hlmann?= Date: Tue, 24 Jun 2025 12:41:41 +0300 Subject: [PATCH] feat: generate webkeys setup step (#10105) # Which Problems Are Solved We are preparing to roll-out and stabilize webkeys in the next version of Zitadel. Before removing legacy signing-key code, we must ensure all existing instances have their webkeys generated. # How the Problems Are Solved Add a setup step which generate 2 webkeys for each existing instance that didn't have webkeys yet. # Additional Changes Return an error from the config type-switch, when the type is unknown. # Additional Context - Part 1/2 of https://github.com/zitadel/zitadel/issues/10029 - Should be back-ported to v3 --- cmd/setup/59.go | 54 ++++++++++++++++++++++++++++++++++++++ cmd/setup/config.go | 1 + cmd/setup/setup.go | 2 ++ internal/crypto/web_key.go | 3 +++ 4 files changed, 60 insertions(+) create mode 100644 cmd/setup/59.go diff --git a/cmd/setup/59.go b/cmd/setup/59.go new file mode 100644 index 0000000000..530937d1a5 --- /dev/null +++ b/cmd/setup/59.go @@ -0,0 +1,54 @@ +package setup + +import ( + "context" + "fmt" + + "github.com/zitadel/logging" + + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/command" + "github.com/zitadel/zitadel/internal/crypto" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/repository/instance" +) + +type SetupWebkeys struct { + eventstore *eventstore.Eventstore + commands *command.Commands +} + +func (mig *SetupWebkeys) Execute(ctx context.Context, _ eventstore.Event) error { + instances, err := mig.eventstore.InstanceIDs( + ctx, + eventstore.NewSearchQueryBuilder(eventstore.ColumnsInstanceIDs). + OrderDesc(). + AddQuery(). + AggregateTypes(instance.AggregateType). + EventTypes(instance.InstanceAddedEventType). + Builder().ExcludeAggregateIDs(). + AggregateTypes(instance.AggregateType). + EventTypes(instance.InstanceRemovedEventType). + Builder(), + ) + if err != nil { + return fmt.Errorf("%s get instance IDs: %w", mig, err) + } + conf := &crypto.WebKeyRSAConfig{ + Bits: crypto.RSABits2048, + Hasher: crypto.RSAHasherSHA256, + } + + for _, instance := range instances { + ctx := authz.WithInstanceID(ctx, instance) + logging.Info("prepare initial webkeys for instance", "instance_id", instance, "migration", mig) + if err := mig.commands.GenerateInitialWebKeys(ctx, conf); err != nil { + return fmt.Errorf("%s generate initial webkeys: %w", mig, err) + } + } + return nil +} + +func (mig *SetupWebkeys) String() string { + return "59_setup_webkeys" +} diff --git a/cmd/setup/config.go b/cmd/setup/config.go index 0c3f726902..7385cc7652 100644 --- a/cmd/setup/config.go +++ b/cmd/setup/config.go @@ -155,6 +155,7 @@ type Steps struct { s56IDPTemplate6SAMLFederatedLogout *IDPTemplate6SAMLFederatedLogout s57CreateResourceCounts *CreateResourceCounts s58ReplaceLoginNames3View *ReplaceLoginNames3View + s59SetupWebkeys *SetupWebkeys } func MustNewSteps(v *viper.Viper) *Steps { diff --git a/cmd/setup/setup.go b/cmd/setup/setup.go index 8ee8d7fc68..dd23c320c7 100644 --- a/cmd/setup/setup.go +++ b/cmd/setup/setup.go @@ -272,6 +272,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string) } commands, _, _, _ := startCommandsQueries(ctx, eventstoreClient, eventstoreV4, dbClient, masterKey, config) + steps.s59SetupWebkeys = &SetupWebkeys{eventstore: eventstoreClient, commands: commands} repeatableSteps := []migration.RepeatableMigration{ &externalConfigChange{ @@ -321,6 +322,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string) steps.s42Apps7OIDCConfigsLoginVersion, steps.s43CreateFieldsDomainIndex, steps.s48Apps7SAMLConfigsLoginVersion, + steps.s59SetupWebkeys, // this step needs commands. } { setupErr = executeMigration(ctx, eventstoreClient, step, "migration failed") if setupErr != nil { diff --git a/internal/crypto/web_key.go b/internal/crypto/web_key.go index c769cb1213..286305259b 100644 --- a/internal/crypto/web_key.go +++ b/internal/crypto/web_key.go @@ -7,6 +7,7 @@ import ( "crypto/rand" "crypto/rsa" "encoding/json" + "fmt" "github.com/go-jose/go-jose/v4" "github.com/muhlemmer/gu" @@ -219,6 +220,8 @@ func generateWebKey(keyID string, genConfig WebKeyConfig) (private, public *jose key, err = ecdsa.GenerateKey(conf.GetCurve(), rand.Reader) case *WebKeyED25519Config: _, key, err = ed25519.GenerateKey(rand.Reader) + default: + return nil, nil, fmt.Errorf("unknown webkey config type %T", genConfig) } if err != nil { return nil, nil, err