Simplify and clarify configuration

- changed "secure port" to "tls port"
- removed the --create flag for "wwctl configure tls"; made it the default behavior
- fixed a TLS creation bug in "wwctl configure --all"
- added logging to "wwctl configure tls" and "wwctl configure --all" (for the tls case)

Signed-off-by: Jonathon Anderson <janderson@ciq.com>
This commit is contained in:
Jonathon Anderson
2026-03-04 08:18:07 -07:00
parent 6ce3d33f50
commit a886b4958b
13 changed files with 65 additions and 55 deletions

View File

@@ -61,7 +61,7 @@ if [ "${WWTLS}" = "true" ] && [ -f "$cert_file" ]; then
# TLS enabled: build HTTPS URI using wwid from kernel cmdline # TLS enabled: build HTTPS URI using wwid from kernel cmdline
# (mirrors wwclient URL construction in internal/app/wwclient/root.go) # (mirrors wwclient URL construction in internal/app/wwclient/root.go)
wwid=$(getarg wwid) wwid=$(getarg wwid)
runtime_uri="https://${WWIPADDR}:${WWSECUREPORT}/provision/${wwid}" runtime_uri="https://${WWIPADDR}:${WWTLSPORT}/provision/${wwid}"
get_stage "runtime" "${runtime_uri}" "${cert_file}" || warn "warewulf: unable to load runtime overlay over HTTPS (ignored)" get_stage "runtime" "${runtime_uri}" "${cert_file}" || warn "warewulf: unable to load runtime overlay over HTTPS (ignored)"
else else
# No TLS: fetch runtime over HTTP # No TLS: fetch runtime over HTTP

View File

@@ -7,6 +7,7 @@ nodeprofiles:
system overlay: system overlay:
- wwinit - wwinit
- wwclient - wwclient
- hosts
- fstab - fstab
- hostname - hostname
- ssh.host_keys - ssh.host_keys

View File

@@ -261,7 +261,7 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) {
port := conf.Warewulf.Port port := conf.Warewulf.Port
scheme := "http" scheme := "http"
if conf.Warewulf.EnableTLS() { if conf.Warewulf.EnableTLS() {
port = conf.Warewulf.SecurePort port = conf.Warewulf.TlsPort
scheme = "https" scheme = "https"
} }

View File

@@ -1,14 +1,11 @@
package configure package configure
import ( import (
"fmt"
"os" "os"
"path"
"github.com/spf13/cobra" "github.com/spf13/cobra"
warewulfconf "github.com/warewulf/warewulf/internal/pkg/config" warewulfconf "github.com/warewulf/warewulf/internal/pkg/config"
"github.com/warewulf/warewulf/internal/pkg/configure" "github.com/warewulf/warewulf/internal/pkg/configure"
"github.com/warewulf/warewulf/internal/pkg/util"
"github.com/warewulf/warewulf/internal/pkg/wwlog" "github.com/warewulf/warewulf/internal/pkg/wwlog"
) )
@@ -23,17 +20,8 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
} }
if allFunctions { if allFunctions {
keystore := path.Join(conf.Paths.Sysconfdir, "warewulf", "tls") if _, err = configure.TLS(false); err != nil {
keyFile := path.Join(keystore, "warewulf.key") return err
certFile := path.Join(keystore, "warewulf.crt")
if !util.IsFile(keyFile) || !util.IsFile(certFile) {
err = configure.GenTLSKeys()
if err != nil {
return err
}
} else {
fmt.Printf("Keys already exist in %s\n", keystore)
} }
err = configure.WAREWULFD() err = configure.WAREWULFD()

View File

@@ -19,10 +19,6 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
conf := config.Get() conf := config.Get()
keystore := path.Join(conf.Paths.Sysconfdir, "warewulf", "tls") keystore := path.Join(conf.Paths.Sysconfdir, "warewulf", "tls")
if err := os.MkdirAll(keystore, 0755); err != nil {
return fmt.Errorf("could not create keystore directory: %w", err)
}
keyFile := path.Join(keystore, "warewulf.key") keyFile := path.Join(keystore, "warewulf.key")
certFile := path.Join(keystore, "warewulf.crt") certFile := path.Join(keystore, "warewulf.crt")
@@ -75,21 +71,21 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
return nil return nil
} }
if util.IsFile(keyFile) && util.IsFile(certFile) && !force { if !conf.Warewulf.EnableTLS() {
if create { fmt.Fprintf(cmd.OutOrStdout(), "TLS is not enabled in warewulf.conf\n")
fmt.Fprintf(cmd.OutOrStdout(), "Keys already exist in %s\n", keystore) return nil
}
created, err := configure.TLS(force)
if err != nil {
return err
}
if created {
if err := configure.WAREWULFD(); err != nil {
return fmt.Errorf("failed to restart warewulfd: %w", err)
} }
} else { } else {
if create { fmt.Fprintf(cmd.OutOrStdout(), "Keys already exist in %s\n", keystore)
if err := configure.GenTLSKeys(); err != nil {
return err
}
if err := configure.WAREWULFD(); err != nil {
return fmt.Errorf("failed to restart warewulfd: %w", err)
}
} else {
return fmt.Errorf("keys not found in: %s", keystore)
}
} }
w := tabwriter.NewWriter(cmd.OutOrStdout(), 0, 0, 2, ' ', 0) w := tabwriter.NewWriter(cmd.OutOrStdout(), 0, 0, 2, ' ', 0)

View File

@@ -14,6 +14,9 @@ func Test_Keys(t *testing.T) {
env := testenv.New(t) env := testenv.New(t)
defer env.RemoveAll() defer env.RemoveAll()
// Enable TLS in the test config
env.WriteFile("etc/warewulf/warewulf.conf", "warewulf:\n tls: true\n")
// Define a keystore path within the test environment // Define a keystore path within the test environment
keystoreRelPath := "etc/warewulf/tls" keystoreRelPath := "etc/warewulf/tls"
keystorePath := env.GetPath(keystoreRelPath) keystorePath := env.GetPath(keystoreRelPath)
@@ -24,11 +27,10 @@ func Test_Keys(t *testing.T) {
t.Run("keys create", func(t *testing.T) { t.Run("keys create", func(t *testing.T) {
baseCmd := GetCommand() baseCmd := GetCommand()
// Reset flags // Reset flags
create = true
importPath = "" importPath = ""
exportPath = "" exportPath = ""
baseCmd.SetArgs([]string{"--create"}) baseCmd.SetArgs([]string{})
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
baseCmd.SetOut(buf) baseCmd.SetOut(buf)
baseCmd.SetErr(buf) baseCmd.SetErr(buf)
@@ -43,11 +45,10 @@ func Test_Keys(t *testing.T) {
t.Run("keys exist check", func(t *testing.T) { t.Run("keys exist check", func(t *testing.T) {
baseCmd := GetCommand() baseCmd := GetCommand()
// Reset flags // Reset flags
create = true // Even with create, it should say they exist
importPath = "" importPath = ""
exportPath = "" exportPath = ""
baseCmd.SetArgs([]string{"--create"}) baseCmd.SetArgs([]string{})
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
baseCmd.SetOut(buf) baseCmd.SetOut(buf)
baseCmd.SetErr(buf) baseCmd.SetErr(buf)
@@ -61,7 +62,6 @@ func Test_Keys(t *testing.T) {
t.Run("keys display", func(t *testing.T) { t.Run("keys display", func(t *testing.T) {
baseCmd := GetCommand() baseCmd := GetCommand()
// Reset flags // Reset flags
create = false
importPath = "" importPath = ""
exportPath = "" exportPath = ""
@@ -88,7 +88,6 @@ func Test_Keys(t *testing.T) {
baseCmd := GetCommand() baseCmd := GetCommand()
// Reset flags // Reset flags
create = false
importPath = "" importPath = ""
exportPath = exportFullPath exportPath = exportFullPath

View File

@@ -18,14 +18,12 @@ var (
} }
importPath string importPath string
exportPath string exportPath string
create bool
force bool force bool
) )
func init() { func init() {
baseCmd.PersistentFlags().StringVar(&importPath, "import", "", "Import keys from directory") baseCmd.PersistentFlags().StringVar(&importPath, "import", "", "Import keys from directory")
baseCmd.PersistentFlags().StringVar(&exportPath, "export", "", "Export keys to directory") baseCmd.PersistentFlags().StringVar(&exportPath, "export", "", "Export keys to directory")
baseCmd.PersistentFlags().BoolVar(&create, "create", false, "Create keys if they do not exist")
baseCmd.PersistentFlags().BoolVarP(&force, "force", "f", false, "Enforce creation of keys even if they exist") baseCmd.PersistentFlags().BoolVarP(&force, "force", "f", false, "Enforce creation of keys even if they exist")
} }

View File

@@ -42,7 +42,7 @@ func (conf TFTPConf) Enabled() bool {
// BaseConf. // BaseConf.
type WarewulfConf struct { type WarewulfConf struct {
Port int `yaml:"port,omitempty" default:"9873"` Port int `yaml:"port,omitempty" default:"9873"`
SecurePort int `yaml:"secure port,omitempty" default:"9874"` TlsPort int `yaml:"tls port,omitempty" default:"9874"`
SecureP *bool `yaml:"secure,omitempty" default:"true"` SecureP *bool `yaml:"secure,omitempty" default:"true"`
EnableTLSP *bool `yaml:"tls,omitempty" default:"false"` EnableTLSP *bool `yaml:"tls,omitempty" default:"false"`
UpdateInterval int `yaml:"update interval,omitempty" default:"60"` UpdateInterval int `yaml:"update interval,omitempty" default:"60"`

View File

@@ -22,7 +22,7 @@ warewulf:
host overlay: true host overlay: true
port: 9873 port: 9873
secure: true secure: true
secure port: 9874 tls port: 9874
update interval: 60 update interval: 60
nfs: nfs:
enabled: true enabled: true
@@ -70,7 +70,7 @@ warewulf:
host overlay: true host overlay: true
port: 9873 port: 9873
secure: true secure: true
secure port: 9874 tls port: 9874
update interval: 60 update interval: 60
nfs: nfs:
enabled: true enabled: true
@@ -120,7 +120,7 @@ warewulf:
host overlay: true host overlay: true
port: 9873 port: 9873
secure: true secure: true
secure port: 9874 tls port: 9874
update interval: 60 update interval: 60
nfs: nfs:
enabled: true enabled: true
@@ -167,7 +167,7 @@ warewulf:
host overlay: true host overlay: true
port: 9873 port: 9873
secure: true secure: true
secure port: 9874 tls port: 9874
update interval: 60 update interval: 60
nfs: nfs:
enabled: true enabled: true
@@ -243,7 +243,7 @@ warewulf:
host overlay: true host overlay: true
port: 9873 port: 9873
secure: false secure: false
secure port: 9874 tls port: 9874
update interval: 60 update interval: 60
nfs: nfs:
enabled: true enabled: true

View File

@@ -14,16 +14,44 @@ import (
"time" "time"
warewulfconf "github.com/warewulf/warewulf/internal/pkg/config" warewulfconf "github.com/warewulf/warewulf/internal/pkg/config"
"github.com/warewulf/warewulf/internal/pkg/util"
"github.com/warewulf/warewulf/internal/pkg/wwlog" "github.com/warewulf/warewulf/internal/pkg/wwlog"
) )
/* // TLS ensures TLS keys exist if TLS is enabled.
GenTLSKeys checks for existence of x509 keys and creates them if they don't exist. // If force is true, regenerates even if keys already exist.
*/ // Returns true if new keys were generated.
func TLS(force bool) (bool, error) {
conf := warewulfconf.Get()
if !conf.Warewulf.EnableTLS() {
return false, nil
}
keystore := path.Join(conf.Paths.Sysconfdir, "warewulf", "tls")
keyFile := path.Join(keystore, "warewulf.key")
certFile := path.Join(keystore, "warewulf.crt")
if !force && util.IsFile(keyFile) && util.IsFile(certFile) {
wwlog.Info("TLS keys already exist in %s", keystore)
return false, nil
}
if err := GenTLSKeys(); err != nil {
return false, err
}
wwlog.Info("TLS keys generated in %s", keystore)
return true, nil
}
// GenTLSKeys generates new TLS keys and certificate unconditionally.
func GenTLSKeys() error { func GenTLSKeys() error {
conf := warewulfconf.Get() conf := warewulfconf.Get()
keystore := path.Join(conf.Paths.Sysconfdir, "warewulf", "tls") keystore := path.Join(conf.Paths.Sysconfdir, "warewulf", "tls")
if err := os.MkdirAll(keystore, 0755); err != nil {
return fmt.Errorf("could not create keystore directory: %w", err)
}
keyFile := path.Join(keystore, "warewulf.key") keyFile := path.Join(keystore, "warewulf.key")
certFile := path.Join(keystore, "warewulf.crt") certFile := path.Join(keystore, "warewulf.crt")
wwlog.Verbose("Generating new x509 keys in %s", keystore) wwlog.Verbose("Generating new x509 keys in %s", keystore)

View File

@@ -94,12 +94,12 @@ func RunServer() error {
crt := path.Join(conf.Paths.Sysconfdir, "warewulf", "tls", "warewulf.crt") crt := path.Join(conf.Paths.Sysconfdir, "warewulf", "tls", "warewulf.crt")
if !util.IsFile(key) || !util.IsFile(crt) { if !util.IsFile(key) || !util.IsFile(crt) {
return fmt.Errorf("TLS enabled but keys not found in %s, run 'wwctl configure tls --create' to generate keys", path.Join(conf.Paths.Sysconfdir, "warewulf", "tls")) return fmt.Errorf("TLS enabled but keys not found in %s, run 'wwctl configure tls' to generate keys", path.Join(conf.Paths.Sysconfdir, "warewulf", "tls"))
} }
httpsHandler := configureRootHandler(apiHandler) httpsHandler := configureRootHandler(apiHandler)
go func() { go func() {
wwlog.Info("Starting HTTPS service on port %d", conf.Warewulf.SecurePort) wwlog.Info("Starting HTTPS service on port %d", conf.Warewulf.TlsPort)
if err := http.ListenAndServeTLS(":"+strconv.Itoa(conf.Warewulf.SecurePort), crt, key, httpsHandler); err != nil { if err := http.ListenAndServeTLS(":"+strconv.Itoa(conf.Warewulf.TlsPort), crt, key, httpsHandler); err != nil {
errChan <- fmt.Errorf("could not start HTTPS service: %w", err) errChan <- fmt.Errorf("could not start HTTPS service: %w", err)
} }
}() }()

View File

@@ -103,7 +103,7 @@ WWIPMI_USER="user"
WWIPMI_PASSWORD="password" WWIPMI_PASSWORD="password"
WWIPMI_WRITE="true" WWIPMI_WRITE="true"
WWTLS=false WWTLS=false
WWSECUREPORT=9874 WWTLSPORT=9874
WWIPADDR=192.168.0.1 WWIPADDR=192.168.0.1
` `

View File

@@ -12,5 +12,5 @@ WWIPMI_WRITE="{{$.Ipmi.Write.Bool}}"
WWIPMI_VLAN="{{$.Ipmi.Tags.vlan}}" WWIPMI_VLAN="{{$.Ipmi.Tags.vlan}}"
{{- end }} {{- end }}
WWTLS={{$.Warewulf.EnableTLS}} WWTLS={{$.Warewulf.EnableTLS}}
WWSECUREPORT={{$.Warewulf.SecurePort}} WWTLSPORT={{$.Warewulf.TlsPort}}
WWIPADDR={{$.Ipaddr}} WWIPADDR={{$.Ipaddr}}