diff --git a/cli/cmd/init_install_config.go b/cli/cmd/init_install_config.go index b6fe9cbec..83afad602 100644 --- a/cli/cmd/init_install_config.go +++ b/cli/cmd/init_install_config.go @@ -82,6 +82,9 @@ type InitInstallConfigOpts struct { ACMEEABMacKey string ACMEDNS01Provider string + ACMECustomDomainsEABKeyID string + ACMECustomDomainsEABMacKey string + CodesphereDomain string CodespherePublicIP string CodesphereWorkspaceHostingBaseDomain string @@ -198,6 +201,8 @@ func AddInitInstallConfigCmd(init *cobra.Command, opts *util.GlobalOptions) { c.cmd.Flags().StringVar(&c.Opts.ACMEServer, "acme-server", "https://acme-v02.api.letsencrypt.org/directory", "ACME server URL") c.cmd.Flags().StringVar(&c.Opts.ACMEEABKeyID, "acme-eab-key-id", "", "External Account Binding key ID (required by some ACME providers)") c.cmd.Flags().StringVar(&c.Opts.ACMEEABMacKey, "acme-eab-mac-key", "", "External Account Binding MAC key (required by some ACME providers)") + c.cmd.Flags().StringVar(&c.Opts.ACMECustomDomainsEABKeyID, "acme-custom-domains-eab-key-id", "", "External Account Binding key ID for custom-domain certificates (must differ from --acme-eab-key-id)") + c.cmd.Flags().StringVar(&c.Opts.ACMECustomDomainsEABMacKey, "acme-custom-domains-eab-mac-key", "", "External Account Binding MAC key for custom-domain certificates") c.cmd.Flags().StringVar(&c.Opts.ACMEDNS01Provider, "acme-dns01-provider", "", "DNS provider for DNS-01 solver (e.g., cloudflare)") c.cmd.Flags().StringVar(&c.Opts.CodesphereDomain, "domain", "", "Main Codesphere domain") @@ -512,6 +517,12 @@ func (c *InitInstallConfigCmd) updateConfigFromOpts(config *files.RootConfig, va if c.Opts.ACMEEABMacKey != "" { vault.SetSecret(files.SecretEntry{Name: files.SecretAcmeEabMacKey, Fields: &files.SecretFields{Password: c.Opts.ACMEEABMacKey}}) } + if c.Opts.ACMECustomDomainsEABKeyID != "" { + certIssuer.Acme.CustomDomainsEABKeyID = c.Opts.ACMECustomDomainsEABKeyID + } + if c.Opts.ACMECustomDomainsEABMacKey != "" { + vault.SetSecret(files.SecretEntry{Name: files.SecretAcmeCustomDomainsEabMacKey, Fields: &files.SecretFields{Password: c.Opts.ACMECustomDomainsEABMacKey}}) + } // Configure DNS-01 solver if c.Opts.ACMEDNS01Provider != "" { diff --git a/cli/cmd/k0s/install_k0s.go b/cli/cmd/k0s/install_k0s.go index f67257fcd..e1d48067a 100644 --- a/cli/cmd/k0s/install_k0s.go +++ b/cli/cmd/k0s/install_k0s.go @@ -80,7 +80,7 @@ func AddInstallCmd(install *cobra.Command, opts *util.GlobalOptions) { FileWriter: intutil.NewFilesystemWriter(), } k0s.cmd.Flags().StringVarP(&k0s.Opts.Version, "version", "v", installer.DefaultK0sVersion, "Version of k0s to install") - k0s.cmd.Flags().StringVar(&k0s.Opts.K0sctlVersion, "k0sctl-version", "", "Version of k0sctl to use") + k0s.cmd.Flags().StringVar(&k0s.Opts.K0sctlVersion, "k0sctl-version", installer.DefaultK0sctlVersion, "Version of k0sctl to use") k0s.cmd.Flags().StringVarP(&k0s.Opts.Package, "package", "p", "", "Package file (e.g. codesphere-v1.2.3-installer-lite.tar.gz) to load k0s from") k0s.cmd.Flags().StringVar(&k0s.Opts.InstallConfig, "install-config", "", "Path to Codesphere install-config file (required)") k0s.cmd.Flags().StringVar(&k0s.Opts.SSHKeyPath, "ssh-key-path", "", "SSH private key path for remote installation") diff --git a/cli/cmd/update_install_config.go b/cli/cmd/update_install_config.go index 3260e1deb..ae5a2097b 100644 --- a/cli/cmd/update_install_config.go +++ b/cli/cmd/update_install_config.go @@ -67,6 +67,9 @@ type UpdateInstallConfigOpts struct { ACMEEABMacKey string ACMEDNS01Provider string + ACMECustomDomainsEABKeyID string + ACMECustomDomainsEABMacKey string + CodesphereDomain string CodespherePublicIP string CodesphereWorkspaceHostingBaseDomain string @@ -151,6 +154,8 @@ func AddUpdateInstallConfigCmd(update *cobra.Command, opts *util.GlobalOptions) c.cmd.Flags().StringVar(&c.Opts.ACMEServer, "acme-server", "", "ACME server URL") c.cmd.Flags().StringVar(&c.Opts.ACMEEABKeyID, "acme-eab-key-id", "", "External Account Binding key ID (required by some ACME providers)") c.cmd.Flags().StringVar(&c.Opts.ACMEEABMacKey, "acme-eab-mac-key", "", "External Account Binding MAC key (required by some ACME providers)") + c.cmd.Flags().StringVar(&c.Opts.ACMECustomDomainsEABKeyID, "acme-custom-domains-eab-key-id", "", "External Account Binding key ID for custom-domain certificates (must differ from --acme-eab-key-id)") + c.cmd.Flags().StringVar(&c.Opts.ACMECustomDomainsEABMacKey, "acme-custom-domains-eab-mac-key", "", "External Account Binding MAC key for custom-domain certificates") c.cmd.Flags().StringVar(&c.Opts.ACMEDNS01Provider, "acme-dns01-provider", "", "DNS provider for DNS-01 solver") // Codesphere update flags @@ -383,6 +388,24 @@ func (c *UpdateInstallConfigCmd) applyACMEUpdates(config *files.RootConfig, vaul } } + if c.Opts.ACMECustomDomainsEABKeyID != "" && certIssuer.Acme.CustomDomainsEABKeyID != c.Opts.ACMECustomDomainsEABKeyID { + log.Printf("Updating ACME custom-domains EAB key ID: %s -> %s\n", certIssuer.Acme.CustomDomainsEABKeyID, c.Opts.ACMECustomDomainsEABKeyID) + certIssuer.Acme.CustomDomainsEABKeyID = c.Opts.ACMECustomDomainsEABKeyID + acmeChanged = true + } + + if c.Opts.ACMECustomDomainsEABMacKey != "" { + currentKey := "" + if s := vault.GetSecret(files.SecretAcmeCustomDomainsEabMacKey); s != nil && s.Fields != nil { + currentKey = s.Fields.Password + } + if currentKey != c.Opts.ACMECustomDomainsEABMacKey { + log.Printf("Updating ACME custom-domains EAB MAC key\n") + vault.SetSecret(files.SecretEntry{Name: files.SecretAcmeCustomDomainsEabMacKey, Fields: &files.SecretFields{Password: c.Opts.ACMECustomDomainsEABMacKey}}) + acmeChanged = true + } + } + // Update DNS-01 solver configuration if c.Opts.ACMEDNS01Provider != "" { if certIssuer.Acme.Solver.DNS01 == nil { diff --git a/docs/oms_init_install-config.md b/docs/oms_init_install-config.md index 342c45beb..7367a2c78 100644 --- a/docs/oms_init_install-config.md +++ b/docs/oms_init_install-config.md @@ -50,6 +50,8 @@ $ oms init install-config --validate -c config.yaml --vault prod.vault.yaml ### Options ``` + --acme-custom-domains-eab-key-id string External Account Binding key ID for custom-domain certificates (must differ from --acme-eab-key-id) + --acme-custom-domains-eab-mac-key string External Account Binding MAC key for custom-domain certificates --acme-dns01-provider string DNS provider for DNS-01 solver (e.g., cloudflare) --acme-eab-key-id string External Account Binding key ID (required by some ACME providers) --acme-eab-mac-key string External Account Binding MAC key (required by some ACME providers) diff --git a/docs/oms_install_k0s.md b/docs/oms_install_k0s.md index 73d8f8057..06e37b88b 100644 --- a/docs/oms_install_k0s.md +++ b/docs/oms_install_k0s.md @@ -48,7 +48,7 @@ $ oms install k0s --no-download -f, --force Force new download and installation -h, --help help for k0s --install-config string Path to Codesphere install-config file (required) - --k0sctl-version string Version of k0sctl to use + --k0sctl-version string Version of k0sctl to use (default "v0.31.1") --no-download Skip downloading k0s binary -p, --package string Package file (e.g. codesphere-v1.2.3-installer-lite.tar.gz) to load k0s from --ssh-key-path string SSH private key path for remote installation diff --git a/docs/oms_update_install-config.md b/docs/oms_update_install-config.md index 94a51de06..96b44bc3c 100644 --- a/docs/oms_update_install-config.md +++ b/docs/oms_update_install-config.md @@ -41,6 +41,8 @@ $ oms update install-config --k8s-api-server 10.0.0.10 --config config.yaml --va ### Options ``` + --acme-custom-domains-eab-key-id string External Account Binding key ID for custom-domain certificates (must differ from --acme-eab-key-id) + --acme-custom-domains-eab-mac-key string External Account Binding MAC key for custom-domain certificates --acme-dns01-provider string DNS provider for DNS-01 solver --acme-eab-key-id string External Account Binding key ID (required by some ACME providers) --acme-eab-mac-key string External Account Binding MAC key (required by some ACME providers) diff --git a/internal/bootstrap/gcp/gce.go b/internal/bootstrap/gcp/gce.go index e71f7927d..b2ca09e65 100644 --- a/internal/bootstrap/gcp/gce.go +++ b/internal/bootstrap/gcp/gce.go @@ -159,6 +159,7 @@ func (b *GCPBootstrapper) EnsureComputeInstances() error { b.Env.Jumpbox = &node.Node{ NodeClient: b.NodeClient, FileIO: b.fw, + KeyPath: util.ExpandPath(b.Env.SSHPrivateKeyPath), } dcByID := map[int]*datacenter.DataCenter{} @@ -555,6 +556,7 @@ func (b *GCPBootstrapper) GetNodeByName(name string) (*node.Node, error) { existingNode := &node.Node{ NodeClient: b.NodeClient, FileIO: b.fw, + KeyPath: util.ExpandPath(b.Env.SSHPrivateKeyPath), } internalIP, externalIP := ExtractInstanceIPs(existingInstance) diff --git a/internal/bootstrap/gcp/install_config.go b/internal/bootstrap/gcp/install_config.go index 19c73ddc8..70cd36bdb 100644 --- a/internal/bootstrap/gcp/install_config.go +++ b/internal/bootstrap/gcp/install_config.go @@ -240,9 +240,19 @@ func (b *GCPBootstrapper) UpdateInstallConfig() error { if err != nil { return fmt.Errorf("failed to obtain Google Public CA EAB credentials: %w", err) } + + customDomainsKeyID, customDomainsB64MacKey, err := b.GCPClient.CreatePublicCAExternalAccountKey(b.Env.ProjectID) + if err != nil { + return fmt.Errorf("failed to obtain Google Public CA EAB credentials for custom domains: %w", err) + } + if customDomainsKeyID == keyID { + return fmt.Errorf("google Public CA returned the same EAB key ID for the default and custom-domains ACME accounts") + } acmeConfig.Server = "https://dv.acme-v02.api.pki.goog/directory" acmeConfig.EABKeyID = keyID + acmeConfig.CustomDomainsEABKeyID = customDomainsKeyID b.icg.GetVault().SetSecret(files.SecretEntry{Name: files.SecretAcmeEabMacKey, Fields: &files.SecretFields{Password: b64MacKey}}) + b.icg.GetVault().SetSecret(files.SecretEntry{Name: files.SecretAcmeCustomDomainsEabMacKey, Fields: &files.SecretFields{Password: customDomainsB64MacKey}}) } b.Env.InstallConfig.Codesphere.CertIssuer = &files.CertIssuerConfig{ Type: "acme", diff --git a/internal/bootstrap/gcp/install_config_test.go b/internal/bootstrap/gcp/install_config_test.go index 9655fc1c4..919758caf 100644 --- a/internal/bootstrap/gcp/install_config_test.go +++ b/internal/bootstrap/gcp/install_config_test.go @@ -762,7 +762,8 @@ var _ = Describe("Installconfig & Secrets", func() { csEnv.GoogleACMEIssuer = true }) It("requests EAB credentials from Public CA and uses them in the ACME config", func() { - gc.EXPECT().CreatePublicCAExternalAccountKey(mock.Anything).Return("fake-eab-key-id", "fake-eab-mac-key", nil) + gc.EXPECT().CreatePublicCAExternalAccountKey(mock.Anything).Return("fake-eab-key-id", "fake-eab-mac-key", nil).Once() + gc.EXPECT().CreatePublicCAExternalAccountKey(mock.Anything).Return("fake-cd-eab-key-id", "fake-cd-eab-mac-key", nil).Once() icg.EXPECT().GenerateSecrets().Return(nil) icg.EXPECT().WriteInstallConfig("fake-config-file", true).Return(nil) icg.EXPECT().WriteVault("fake-secret", true).Return(nil) @@ -775,6 +776,8 @@ var _ = Describe("Installconfig & Secrets", func() { Expect(bs.Env.InstallConfig.Codesphere.CertIssuer.Acme.Server).To(Equal("https://dv.acme-v02.api.pki.goog/directory")) Expect(bs.Env.InstallConfig.Codesphere.CertIssuer.Acme.EABKeyID).To(Equal("fake-eab-key-id")) Expect(vault.GetSecret(files.SecretAcmeEabMacKey).Fields.Password).To(Equal("fake-eab-mac-key")) + Expect(bs.Env.InstallConfig.Codesphere.CertIssuer.Acme.CustomDomainsEABKeyID).To(Equal("fake-cd-eab-key-id")) + Expect(vault.GetSecret(files.SecretAcmeCustomDomainsEabMacKey).Fields.Password).To(Equal("fake-cd-eab-mac-key")) issuers := bs.Env.InstallConfig.Cluster.Certificates.Override["issuers"].(map[string]interface{}) httpIssuer := issuers["letsEncryptHttp"].(map[string]interface{}) @@ -787,6 +790,22 @@ var _ = Describe("Installconfig & Secrets", func() { Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("failed to obtain Google Public CA EAB credentials")) }) + It("returns an error when the second public API call for custom domains fails", func() { + gc.EXPECT().CreatePublicCAExternalAccountKey(mock.Anything).Return("fake-eab-key-id", "fake-eab-mac-key", nil).Once() + gc.EXPECT().CreatePublicCAExternalAccountKey(mock.Anything).Return("", "", fmt.Errorf("api boom")).Once() + + err := bs.UpdateInstallConfig() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to obtain Google Public CA EAB credentials for custom domains")) + }) + It("returns an error when both EAB key IDs are the same", func() { + gc.EXPECT().CreatePublicCAExternalAccountKey(mock.Anything).Return("same-eab-key-id", "fake-eab-mac-key", nil).Once() + gc.EXPECT().CreatePublicCAExternalAccountKey(mock.Anything).Return("same-eab-key-id", "fake-cd-eab-mac-key", nil).Once() + + err := bs.UpdateInstallConfig() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("google Public CA returned the same EAB key ID for the default and custom-domains ACME accounts")) + }) }) Context("When ACME staging is enabled", func() { diff --git a/internal/installer/config_generator_collector.go b/internal/installer/config_generator_collector.go index 370ed5697..50bec736d 100644 --- a/internal/installer/config_generator_collector.go +++ b/internal/installer/config_generator_collector.go @@ -280,6 +280,28 @@ func (g *InstallConfig) collectACMEConfig(prompter prompt.Prompter) { } } + // External Account Binding (EAB) for custom domains + log.Println("\n--- Custom Domains External Account Binding (Optional) ---") + hasCustomDomainsEAB := prompter.Bool("Configure a separate External Account Binding for custom-domain certificates", certIssuer.Acme.CustomDomainsEABKeyID != "") + + certIssuer.Acme.CustomDomainsEABKeyID = "" + if hasCustomDomainsEAB { + certIssuer.Acme.CustomDomainsEABKeyID = g.collectString(prompter, "Custom Domains EAB Key ID", certIssuer.Acme.CustomDomainsEABKeyID) + existingCustomDomainsEabKey := "" + if g.Vault != nil { + if s := g.Vault.GetSecret(files.SecretAcmeCustomDomainsEabMacKey); s != nil && s.Fields != nil { + existingCustomDomainsEabKey = s.Fields.Password + } + } + newCustomDomainsEabKey := g.collectString(prompter, "Custom Domains EAB MAC Key", existingCustomDomainsEabKey) + if newCustomDomainsEabKey != "" { + if g.Vault == nil { + g.Vault = &files.InstallVault{} + } + g.Vault.SetSecret(files.SecretEntry{Name: files.SecretAcmeCustomDomainsEabMacKey, Fields: &files.SecretFields{Password: newCustomDomainsEabKey}}) + } + } + // DNS-01 Challenge Configuration log.Println("\n--- DNS-01 Challenge Configuration (Optional) ---") if certIssuer.Acme.Solver.DNS01 == nil { diff --git a/internal/installer/config_manager.go b/internal/installer/config_manager.go index cb3c184b3..3bd39ccdb 100644 --- a/internal/installer/config_manager.go +++ b/internal/installer/config_manager.go @@ -239,6 +239,13 @@ func (g *InstallConfig) ValidateInstallConfig() []string { } } + if ci := g.Config.Codesphere.CertIssuer; ci != nil && ci.Acme != nil { + acme := ci.Acme + if acme.EABKeyID != "" && acme.CustomDomainsEABKeyID != "" && acme.EABKeyID == acme.CustomDomainsEABKeyID { + errors = append(errors, "ACME EAB key ID and custom-domains EAB key ID must be different") + } + } + errors = append(errors, validateOpenFga(g.Config.Codesphere.OpenFga)...) return errors diff --git a/internal/installer/config_manager_test.go b/internal/installer/config_manager_test.go index 42733f855..8ed60729b 100644 --- a/internal/installer/config_manager_test.go +++ b/internal/installer/config_manager_test.go @@ -310,6 +310,35 @@ var _ = Describe("ConfigManager", func() { }) }) + Context("ACME validation", func() { + BeforeEach(func() { + configManager.Config.Codesphere.CertIssuer = &files.CertIssuerConfig{ + Type: files.CertIssuerTypeACME, + Acme: &files.ACMEConfig{ + Enabled: true, + EABKeyID: "eab-key-id", + }, + } + }) + + It("should not error when only the primary EAB key ID is set", func() { + errors := configManager.ValidateInstallConfig() + Expect(errors).ToNot(ContainElement(ContainSubstring("EAB key ID"))) + }) + + It("should not error when the EAB key IDs differ", func() { + configManager.Config.Codesphere.CertIssuer.Acme.CustomDomainsEABKeyID = "custom-domains-eab-key-id" + errors := configManager.ValidateInstallConfig() + Expect(errors).ToNot(ContainElement(ContainSubstring("EAB key ID"))) + }) + + It("should error when the EAB key IDs are the same", func() { + configManager.Config.Codesphere.CertIssuer.Acme.CustomDomainsEABKeyID = "eab-key-id" + errors := configManager.ValidateInstallConfig() + Expect(errors).To(ContainElement(ContainSubstring("ACME EAB key ID and custom-domains EAB key ID must be different"))) + }) + }) + Context("openfga backups validation", func() { It("should require destinationPath and endpointURL when enabled", func() { configManager.Config.Codesphere.OpenfgaBackups = &files.OpenfgaBackupsConfig{ diff --git a/internal/installer/files/config_yaml.go b/internal/installer/files/config_yaml.go index b0f3050f4..efb7c76f7 100644 --- a/internal/installer/files/config_yaml.go +++ b/internal/installer/files/config_yaml.go @@ -254,7 +254,8 @@ type ACMEConfig struct { PrivateKeySecretName string `yaml:"-"` Solver ACMESolver `yaml:"-"` - EABKeyID string `yaml:"eabKeyId,omitempty"` + EABKeyID string `yaml:"eabKeyId,omitempty"` + CustomDomainsEABKeyID string `yaml:"customDomainsEabKeyId,omitempty"` } type ACMESolver struct { diff --git a/internal/installer/files/secret_names.go b/internal/installer/files/secret_names.go index c4791f43d..bdcf57489 100644 --- a/internal/installer/files/secret_names.go +++ b/internal/installer/files/secret_names.go @@ -38,7 +38,8 @@ const ( SecretRegistryPassword = "registryPassword" // ACME - SecretAcmeEabMacKey = "acmeEabMacKey" + SecretAcmeEabMacKey = "acmeEabMacKey" + SecretAcmeCustomDomainsEabMacKey = "acmeCustomDomainsEabMacKey" // OpenBao SecretOpenBaoPassword = "openBaoPassword" diff --git a/internal/installer/k0sctl.go b/internal/installer/k0sctl.go index 7ff1e677e..9dffddf3c 100644 --- a/internal/installer/k0sctl.go +++ b/internal/installer/k0sctl.go @@ -17,6 +17,9 @@ import ( "github.com/codesphere-cloud/oms/internal/util" ) +// DefaultK0sctlVersion is the currently verified k0sctl version. +const DefaultK0sctlVersion = "v0.31.1" + //mockery:generate: true type K0sctlManager interface { GetLatestVersion() (string, error) diff --git a/internal/installer/node/node.go b/internal/installer/node/node.go index 74ec1f45f..040882f13 100644 --- a/internal/installer/node/node.go +++ b/internal/installer/node/node.go @@ -26,7 +26,7 @@ type Node struct { // If connecting via the Jumpbox Jumpbox *Node `json:"-"` // Config - keyPath string `json:"-"` + KeyPath string `json:"-"` Name string `json:"name"` ExternalIP string `json:"external_ip"` InternalIP string `json:"internal_ip"` @@ -123,7 +123,7 @@ func (n *Node) CreateSubNode(name string, externalIP string, internalIP string) // Inherited from jumpbox FileIO: n.FileIO, Jumpbox: n, - keyPath: util.ExpandPath(n.keyPath), + KeyPath: util.ExpandPath(n.KeyPath), sshQuiet: n.sshQuiet, NodeClient: n.NodeClient, @@ -594,7 +594,7 @@ func (n *Node) getAuthMethods() ([]ssh.AuthMethod, error) { } // 2. Add Private Key (File) if needed - if n.keyPath != "" { + if n.KeyPath != "" { shouldLoad := true // Use cached signer if available @@ -605,7 +605,7 @@ func (n *Node) getAuthMethods() ([]ssh.AuthMethod, error) { // Check if key is already in agent (requires .pub file) if shouldLoad && len(signers) > 0 { - if pubBytes, err := n.FileIO.ReadFile(n.keyPath + ".pub"); err == nil { + if pubBytes, err := n.FileIO.ReadFile(n.KeyPath + ".pub"); err == nil { if targetPub, _, _, _, err := ssh.ParseAuthorizedKey(pubBytes); err == nil { targetMarshaled := string(targetPub.Marshal()) for _, s := range signers { @@ -638,9 +638,9 @@ func (n *Node) getAuthMethods() ([]ssh.AuthMethod, error) { // loadPrivateKey reads and parses the private key, prompting for passphrase if needed. func (n *Node) loadPrivateKey() (ssh.Signer, error) { - key, err := n.FileIO.ReadFile(n.keyPath) + key, err := n.FileIO.ReadFile(n.KeyPath) if err != nil { - return nil, fmt.Errorf("failed to read private key file %s: %v", n.keyPath, err) + return nil, fmt.Errorf("failed to read private key file %s: %v", n.KeyPath, err) } signer, err := ssh.ParsePrivateKey(key) @@ -653,7 +653,7 @@ func (n *Node) loadPrivateKey() (ssh.Signer, error) { } // Key is encrypted, prompt for passphrase - log.Printf("Enter passphrase for key '%s': ", n.keyPath) + log.Printf("Enter passphrase for key '%s': ", n.KeyPath) passphrase, err := term.ReadPassword(int(syscall.Stdin)) log.Println() if err != nil { diff --git a/internal/installer/secrets/datacenter.go b/internal/installer/secrets/datacenter.go index 94abf1663..5e76835e6 100644 --- a/internal/installer/secrets/datacenter.go +++ b/internal/installer/secrets/datacenter.go @@ -26,6 +26,9 @@ var DataCenterScopedSecretNames = []string{ files.SecretKubeConfig, // ACME external account binding — paired with codesphere.certIssuer.acme.eabKeyId. files.SecretAcmeEabMacKey, + // ACME external account binding for custom domains — paired with + // codesphere.certIssuer.acme.customDomainsEabKeyId. + files.SecretAcmeCustomDomainsEabMacKey, // Only present in recovered vaults; keyed to a single cluster's nix cache. files.SecretPrivNixSigningKey, files.SecretPubNixSigningKey, @@ -100,8 +103,10 @@ func clearDataCenterScopedConfig(config *files.RootConfig) { config.Cluster.Certificates.CA.CertPem = "" // Paired with cephSshPrivateKey, written by EnsureCephSSHKeys. config.Ceph.CephAdmSSHKey.PublicKey = "" - // Paired with acmeEabMacKey, obtained per data center from the ACME CA. + // Paired with acmeEabMacKey / acmeCustomDomainsEabMacKey, obtained per data center from + // the ACME CA. if config.Codesphere.CertIssuer != nil && config.Codesphere.CertIssuer.Acme != nil { config.Codesphere.CertIssuer.Acme.EABKeyID = "" + config.Codesphere.CertIssuer.Acme.CustomDomainsEABKeyID = "" } }