From d9c13c3f36d53276045f0c2ed1d576e6867c23e3 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Mon, 24 Jan 2022 00:32:02 +0000 Subject: [PATCH 1/7] Initial commit of asset key tag security check --- etc/ipxe/arm_image.ipxe | 27 +++++ etc/ipxe/big_image.ipxe | 26 ---- etc/ipxe/default.ipxe | 10 +- internal/app/wwctl/node/list/main.go | 2 + internal/app/wwctl/node/set/main.go | 5 + internal/app/wwctl/node/set/root.go | 2 + internal/app/wwctl/profile/list/main.go | 1 + internal/app/wwctl/profile/set/main.go | 5 + internal/app/wwctl/profile/set/root.go | 2 + internal/pkg/node/constructors.go | 6 +- internal/pkg/node/datastructure.go | 2 + internal/pkg/node/modifiers.go | 2 + internal/pkg/warewulfd/container.go | 15 ++- internal/pkg/warewulfd/daemon.go | 37 ++++++ internal/pkg/warewulfd/ipxe.go | 150 ++++++++++++------------ internal/pkg/warewulfd/kernel.go | 15 ++- internal/pkg/warewulfd/kmods.go | 16 ++- internal/pkg/warewulfd/parser.go | 50 ++++++++ internal/pkg/warewulfd/runtime.go | 76 +++++------- internal/pkg/warewulfd/system.go | 45 ++++--- internal/pkg/warewulfd/util.go | 38 ------ 21 files changed, 320 insertions(+), 212 deletions(-) create mode 100644 etc/ipxe/arm_image.ipxe delete mode 100644 etc/ipxe/big_image.ipxe create mode 100644 internal/pkg/warewulfd/parser.go diff --git a/etc/ipxe/arm_image.ipxe b/etc/ipxe/arm_image.ipxe new file mode 100644 index 00000000..ee5da3cc --- /dev/null +++ b/etc/ipxe/arm_image.ipxe @@ -0,0 +1,27 @@ +#!ipxe + +echo +echo ================================================================================ +echo Warewulf v4 now booting: {{.Fqdn}} +echo +echo Container: {{.ContainerName}} +echo Kernel: {{.KernelVersion}} +echo KernelArgs: {{.KernelArgs}} +echo + +set base http://{{.Ipaddr}}:{{.Port}} + +kernel --name kernel ${base}/kernel/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot +initrd --name container ${base}/container/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot +initrd --name kmods ${base}/kmods/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot +initrd --name system ${base}/overlay-system/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot +initrd --name runtime ${base}/overlay-runtime/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot + +boot kernel initrd=container initrd=kmods initrd=system initrd=runtime {{.KernelArgs}} || goto reboot + +:reboot +echo +echo There was an error, rebooting in 15s... +echo +sleep 15 +reboot diff --git a/etc/ipxe/big_image.ipxe b/etc/ipxe/big_image.ipxe deleted file mode 100644 index a3f9bda0..00000000 --- a/etc/ipxe/big_image.ipxe +++ /dev/null @@ -1,26 +0,0 @@ -#!ipxe - -echo -echo ================================================================================ -echo Warewulf v4 now booting: {{.Fqdn}} -echo -echo Container: {{.ContainerName}} -echo Kernel: {{.KernelVersion}} -echo KernelArgs: {{.KernelArgs}} -echo - -set base http://{{.Ipaddr}}:{{.Port}} - -kernel --name kernel ${base}/kernel/{{.Hwaddr}} || goto reboot -imgextract --name container ${base}/container/{{.Hwaddr}} || goto reboot -imgextract --name kmods ${base}/kmods/{{.Hwaddr}} || goto reboot -imgextract --name system ${base}/overlay-system/{{.Hwaddr}} || goto reboot - -boot kernel initrd=container initrd=kmods initrd=system {{.KernelArgs}} || goto reboot - -:reboot -echo -echo There was an error, rebooting in 15s... -echo -sleep 15 -reboot diff --git a/etc/ipxe/default.ipxe b/etc/ipxe/default.ipxe index 137f7da2..c5123134 100644 --- a/etc/ipxe/default.ipxe +++ b/etc/ipxe/default.ipxe @@ -11,11 +11,11 @@ echo set base http://{{.Ipaddr}}:{{.Port}} -kernel --name kernel ${base}/kernel/{{.Hwaddr}} || goto reboot -initrd --name container ${base}/container/{{.Hwaddr}} || goto reboot -initrd --name kmods ${base}/kmods/{{.Hwaddr}} || goto reboot -initrd --name system ${base}/overlay-system/{{.Hwaddr}} || goto reboot -initrd --name runtime ${base}/overlay-runtime/{{.Hwaddr}} || goto reboot +kernel --name kernel ${base}/kernel/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot +imgextract --name container ${base}/container/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot +imgextract --name kmods ${base}/kmods/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot +imgextract --name system ${base}/overlay-system/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot +imgextract --name runtime ${base}/overlay-runtime/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot boot kernel initrd=container initrd=kmods initrd=system initrd=runtime {{.KernelArgs}} || goto reboot diff --git a/internal/app/wwctl/node/list/main.go b/internal/app/wwctl/node/list/main.go index 6c7530e6..d2b0b68d 100644 --- a/internal/app/wwctl/node/list/main.go +++ b/internal/app/wwctl/node/list/main.go @@ -48,6 +48,8 @@ func CobraRunE(cmd *cobra.Command, args []string) error { fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "Ipxe", node.Ipxe.Source(), node.Ipxe.Print()) fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "Init", node.Init.Source(), node.Init.Print()) fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "Root", node.Root.Source(), node.Root.Print()) + fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "AssetKey", node.AssetKey.Source(), node.AssetKey.Print()) + fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "IpmiIpaddr", node.IpmiIpaddr.Source(), node.IpmiIpaddr.Print()) fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "IpmiNetmask", node.IpmiNetmask.Source(), node.IpmiNetmask.Print()) fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "IpmiPort", node.IpmiPort.Source(), node.IpmiPort.Print()) diff --git a/internal/app/wwctl/node/set/main.go b/internal/app/wwctl/node/set/main.go index 427bda68..5302245e 100644 --- a/internal/app/wwctl/node/set/main.go +++ b/internal/app/wwctl/node/set/main.go @@ -70,6 +70,11 @@ func CobraRunE(cmd *cobra.Command, args []string) error { n.Root.Set(SetRoot) } + if SetAssetKey != "" { + wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting asset key to: %s\n", n.Id.Get(), SetAssetKey) + n.AssetKey.Set(SetAssetKey) + } + if SetKernel != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting kernel to: %s\n", n.Id.Get(), SetKernel) n.KernelVersion.Set(SetKernel) diff --git a/internal/app/wwctl/node/set/root.go b/internal/app/wwctl/node/set/root.go index 6dbede5a..370ab2b6 100644 --- a/internal/app/wwctl/node/set/root.go +++ b/internal/app/wwctl/node/set/root.go @@ -71,6 +71,7 @@ var ( SetKey string SetValue string SetKeyDel bool + SetAssetKey string ) func init() { @@ -94,6 +95,7 @@ func init() { baseCmd.PersistentFlags().StringVar(&SetIpxe, "ipxe", "", "Set the node's iPXE template name") baseCmd.PersistentFlags().StringVarP(&SetInit, "init", "i", "", "Define the init process to boot the container") baseCmd.PersistentFlags().StringVar(&SetRoot, "root", "", "Define the rootfs") + baseCmd.PersistentFlags().StringVar(&SetAssetKey, "assetkey", "", "Set the node's Asset tag (key)") baseCmd.PersistentFlags().StringVarP(&SetInitOverlay, "wwinit", "O", "", "Set the node's initialization overlay") baseCmd.PersistentFlags().StringVarP(&SetRuntimeOverlay, "runtime", "R", "", "Set the node's runtime overlay") if err := baseCmd.RegisterFlagCompletionFunc("runtime", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { diff --git a/internal/app/wwctl/profile/list/main.go b/internal/app/wwctl/profile/list/main.go index 6831521f..bac61c3a 100644 --- a/internal/app/wwctl/profile/list/main.go +++ b/internal/app/wwctl/profile/list/main.go @@ -37,6 +37,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "KernelArgs", profile.KernelArgs.Print()) fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "Init", profile.Init.Print()) fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "Root", profile.Root.Print()) + fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "AssetKey", profile.AssetKey.Print()) fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "SystemOverlay", profile.SystemOverlay.Print()) fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "RuntimeOverlay", profile.RuntimeOverlay.Print()) diff --git a/internal/app/wwctl/profile/set/main.go b/internal/app/wwctl/profile/set/main.go index cb5a343e..e950ce02 100644 --- a/internal/app/wwctl/profile/set/main.go +++ b/internal/app/wwctl/profile/set/main.go @@ -70,6 +70,11 @@ func CobraRunE(cmd *cobra.Command, args []string) error { p.Root.Set(SetRoot) } + if SetAssetKey != "" { + wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting asset key to: %s\n", p.Id.Get(), SetAssetKey) + p.AssetKey.Set(SetAssetKey) + } + if SetKernel != "" { wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting Kernel to: %s\n", p.Id.Get(), SetKernel) p.KernelVersion.Set(SetKernel) diff --git a/internal/app/wwctl/profile/set/root.go b/internal/app/wwctl/profile/set/root.go index 39a9630f..d9286d4f 100644 --- a/internal/app/wwctl/profile/set/root.go +++ b/internal/app/wwctl/profile/set/root.go @@ -67,6 +67,7 @@ var ( SetKey string SetValue string SetKeyDel bool + SetAssetKey string ) func init() { @@ -90,6 +91,7 @@ func init() { baseCmd.PersistentFlags().StringVarP(&SetIpxe, "ipxe", "P", "", "Set the node's iPXE template name") baseCmd.PersistentFlags().StringVarP(&SetInit, "init", "i", "", "Define the init process to boot the container") baseCmd.PersistentFlags().StringVar(&SetRoot, "root", "", "Define the rootfs") + baseCmd.PersistentFlags().StringVar(&SetAssetKey, "assetkey", "", "Set the node's Asset tag (key)") baseCmd.PersistentFlags().StringVarP(&SetRuntimeOverlay, "runtime", "R", "", "Set the node's runtime overlay") if err := baseCmd.RegisterFlagCompletionFunc("runtime", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go index de4f6c0a..dc20ffcb 100644 --- a/internal/pkg/node/constructors.go +++ b/internal/pkg/node/constructors.go @@ -87,6 +87,7 @@ func (config *nodeYaml) FindAllNodes() ([]NodeInfo, error) { n.SystemOverlay.Set(node.SystemOverlay) n.RuntimeOverlay.Set(node.RuntimeOverlay) n.Root.Set(node.Root) + n.AssetKey.Set(node.AssetKey) n.Discoverable.SetB(node.Discoverable) @@ -142,11 +143,11 @@ func (config *nodeYaml) FindAllNodes() ([]NodeInfo, error) { n.IpmiInterface.SetAlt(config.NodeProfiles[p].IpmiInterface, p) n.SystemOverlay.SetAlt(config.NodeProfiles[p].SystemOverlay, p) n.RuntimeOverlay.SetAlt(config.NodeProfiles[p].RuntimeOverlay, p) + n.Root.SetAlt(config.NodeProfiles[p].Root, p) + n.AssetKey.SetAlt(config.NodeProfiles[p].AssetKey, p) n.Discoverable.SetAltB(config.NodeProfiles[p].Discoverable, p) - n.Root.SetAlt(config.NodeProfiles[p].Root, p) - for devname, netdev := range config.NodeProfiles[p].NetDevs { if _, ok := n.NetDevs[devname]; !ok { var netdev NetDevEntry @@ -216,6 +217,7 @@ func (config *nodeYaml) FindAllProfiles() ([]NodeInfo, error) { p.RuntimeOverlay.Set(profile.RuntimeOverlay) p.SystemOverlay.Set(profile.SystemOverlay) p.Root.Set(profile.Root) + p.AssetKey.Set(profile.AssetKey) p.Discoverable.SetB(profile.Discoverable) diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go index 1d85a5fa..8ca704ba 100644 --- a/internal/pkg/node/datastructure.go +++ b/internal/pkg/node/datastructure.go @@ -32,6 +32,7 @@ type NodeConf struct { SystemOverlay string `yaml:"system overlay,omitempty"` Init string `yaml:"init,omitempty"` Root string `yaml:"root,omitempty"` + AssetKey string `yaml:"asset key,omitempty"` Discoverable bool `yaml:"discoverable,omitempty"` Profiles []string `yaml:"profiles,omitempty"` NetDevs map[string]*NetDevs `yaml:"network devices,omitempty"` @@ -85,6 +86,7 @@ type NodeInfo struct { Root Entry Discoverable Entry Init Entry //TODO: Finish adding this... + AssetKey Entry Profiles []string GroupProfiles []string NetDevs map[string]*NetDevEntry diff --git a/internal/pkg/node/modifiers.go b/internal/pkg/node/modifiers.go index 767178eb..51ae915a 100644 --- a/internal/pkg/node/modifiers.go +++ b/internal/pkg/node/modifiers.go @@ -72,6 +72,7 @@ func (config *nodeYaml) NodeUpdate(node NodeInfo) error { config.Nodes[nodeID].RuntimeOverlay = node.RuntimeOverlay.GetReal() config.Nodes[nodeID].SystemOverlay = node.SystemOverlay.GetReal() config.Nodes[nodeID].Root = node.Root.GetReal() + config.Nodes[nodeID].AssetKey = node.AssetKey.GetReal() config.Nodes[nodeID].Discoverable = node.Discoverable.GetRealB() @@ -159,6 +160,7 @@ func (config *nodeYaml) ProfileUpdate(profile NodeInfo) error { config.NodeProfiles[profileID].RuntimeOverlay = profile.RuntimeOverlay.GetReal() config.NodeProfiles[profileID].SystemOverlay = profile.SystemOverlay.GetReal() config.NodeProfiles[profileID].Root = profile.Root.GetReal() + config.NodeProfiles[profileID].AssetKey = profile.AssetKey.GetReal() config.NodeProfiles[profileID].Discoverable = profile.Discoverable.GetRealB() diff --git a/internal/pkg/warewulfd/container.go b/internal/pkg/warewulfd/container.go index 5eff5dc0..7e1e6dd5 100644 --- a/internal/pkg/warewulfd/container.go +++ b/internal/pkg/warewulfd/container.go @@ -8,12 +8,25 @@ import ( ) func ContainerSend(w http.ResponseWriter, req *http.Request) { - node, err := getSanity(req) + rinfo, err := parseReq(req) if err != nil { w.WriteHeader(404) daemonLogf("ERROR: %s\n", err) return } + node, err := GetNode(rinfo.hwaddr) + if err != nil { + w.WriteHeader(403) + daemonLogf("ERROR(%s): %s\n", rinfo.hwaddr, err) + return + } + + if node.AssetKey.Defined() && node.AssetKey.Get() != rinfo.assetkey { + w.WriteHeader(404) + daemonLogf("ERROR: Incorrect asset key for node: %s\n", node.Id.Get()) + updateStatus(node.Id.Get(), "CONTAINER", "BAD_ASSET", rinfo.ipaddr) + return + } if node.ContainerName.Defined() { containerImage := container.ImageFile(node.ContainerName.Get()) diff --git a/internal/pkg/warewulfd/daemon.go b/internal/pkg/warewulfd/daemon.go index acb04ac8..3025bbde 100644 --- a/internal/pkg/warewulfd/daemon.go +++ b/internal/pkg/warewulfd/daemon.go @@ -3,13 +3,17 @@ package warewulfd import ( "fmt" "io/ioutil" + "log" + "log/syslog" "os" "os/exec" "strconv" "syscall" + "time" "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/version" + "github.com/hpcng/warewulf/internal/pkg/warewulfconf" "github.com/pkg/errors" ) @@ -18,6 +22,39 @@ const ( WAREWULFD_LOGFILE = "/var/log/warewulfd.log" ) +var logwriter *syslog.Writer +var loginit bool + +func daemonLogf(message string, a ...interface{}) { + conf, err := warewulfconf.New() + if err != nil { + fmt.Printf("ERROR: Could not read Warewulf configuration file: %s\n", err) + return + } + + if conf.Warewulf.Syslog { + if !loginit { + var err error + + logwriter, err = syslog.New(syslog.LOG_NOTICE, "warewulfd") + if err != nil { + return + } + log.SetOutput(logwriter) + loginit = true + + log.SetFlags(0) + log.SetPrefix("") + } + + log.Printf(message, a...) + + } else { + prefix := fmt.Sprintf("[%s] ", time.Now().Format(time.UnixDate)) + fmt.Printf(prefix+message, a...) + } +} + func DaemonStart() error { if os.Getenv("WAREWULFD_BACKGROUND") == "1" { err := RunServer() diff --git a/internal/pkg/warewulfd/ipxe.go b/internal/pkg/warewulfd/ipxe.go index c7abadfa..84c11808 100644 --- a/internal/pkg/warewulfd/ipxe.go +++ b/internal/pkg/warewulfd/ipxe.go @@ -8,7 +8,7 @@ import ( "text/template" "github.com/hpcng/warewulf/internal/pkg/buildconfig" - "github.com/hpcng/warewulf/internal/pkg/node" + nodepkg "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/overlay" "github.com/hpcng/warewulf/internal/pkg/warewulfconf" "github.com/hpcng/warewulf/internal/pkg/wwlog" @@ -30,18 +30,6 @@ type iPxeTemplate struct { } func IpxeSend(w http.ResponseWriter, req *http.Request) { - - url := strings.Split(req.URL.Path, "/") - var unconfiguredNode bool - - if url[2] == "" { - daemonLogf("ERROR: Bad iPXE request from %s\n", req.RemoteAddr) - w.WriteHeader(404) - return - } - - hwaddr := strings.ReplaceAll(url[2], "-", ":") - conf, err := warewulfconf.New() if err != nil { daemonLogf("ERROR: Could not open Warewulf configuration: %s\n", err) @@ -49,44 +37,51 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) { return } - nodeobj, err := GetNode(hwaddr) + rinfo, err := parseReq(req) + if err != nil { + w.WriteHeader(404) + daemonLogf("ERROR: %s\n", err) + return + } + node, err := GetNode(rinfo.hwaddr) if err != nil { // If we failed to find a node, let's see if we can add one... var netdev string + var unconfiguredNode bool - nodeDB, err := node.New() + daemonLogf("IPXEREQ: %s (node not configured)\n", rinfo.hwaddr) + + nodeDB, err := nodepkg.New() if err != nil { daemonLogf("Could not read node configuration file: %s\n", err) w.WriteHeader(503) return } - daemonLogf("IPXEREQ: %s (node not configured)\n", hwaddr) - n, netdev, err := nodeDB.FindDiscoverableNode() if err != nil { unconfiguredNode = true } else { - n.NetDevs[netdev].Hwaddr.Set(hwaddr) + n.NetDevs[netdev].Hwaddr.Set(rinfo.hwaddr) n.Discoverable.SetB(false) err := nodeDB.NodeUpdate(n) if err != nil { - daemonLogf("IPXEREQ: %s (failed to set node configuration)\n", hwaddr) + daemonLogf("IPXEREQ: %s (failed to set node configuration)\n", rinfo.hwaddr) unconfiguredNode = true } else { err := nodeDB.Persist() if err != nil { - daemonLogf("IPXEREQ: %s (failed to persist node configuration)\n", hwaddr) + daemonLogf("IPXEREQ: %s (failed to persist node configuration)\n", rinfo.hwaddr) unconfiguredNode = true } else { - nodeobj = n - _ = overlay.BuildAllOverlays([]node.NodeInfo{n}) + node = n + _ = overlay.BuildAllOverlays([]nodepkg.NodeInfo{n}) - daemonLogf("IPXEREQ: %s (node automatically configured)\n", hwaddr) + daemonLogf("IPXEREQ: %s (node automatically configured)\n", rinfo.hwaddr) err := LoadNodeDB() if err != nil { @@ -96,60 +91,65 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) { } } } + if unconfiguredNode { + daemonLogf("IPXEREQ: %s (unknown/unconfigured node)\n", rinfo.hwaddr) + + tmpl, err := template.ParseFiles(path.Join(buildconfig.SYSCONFDIR(), "/warewulf/ipxe/unconfigured.ipxe")) + if err != nil { + daemonLogf("ERROR: Could not parse unconfigured node IPXE template: %s\n", err) + return + } + + var replace iPxeTemplate + + replace.Hwaddr = rinfo.hwaddr + + err = tmpl.Execute(w, replace) + if err != nil { + daemonLogf("ERROR: Could not update unconfigured node IPXE template: %s\n", err) + return + } + + return + } } - if unconfiguredNode { - daemonLogf("IPXEREQ: %s (unknown/unconfigured node)\n", hwaddr) - - tmpl, err := template.ParseFiles(path.Join(buildconfig.SYSCONFDIR(), "/warewulf/ipxe/unconfigured.ipxe")) - if err != nil { - daemonLogf("ERROR: Could not parse unconfigured node IPXE template: %s\n", err) - return - } - - var replace iPxeTemplate - - replace.Hwaddr = hwaddr - - err = tmpl.Execute(w, replace) - if err != nil { - daemonLogf("ERROR: Could not update unconfigured node IPXE template: %s\n", err) - return - } - + if node.AssetKey.Defined() && node.AssetKey.Get() != rinfo.assetkey { + w.WriteHeader(404) + daemonLogf("ERROR: Incorrect asset key for node: %s\n", node.Id.Get()) + updateStatus(node.Id.Get(), "IPXE", "BAD_ASSET", rinfo.ipaddr) return - - } else { - - ipxeTemplate := path.Join(buildconfig.SYSCONFDIR(), "warewulf/ipxe/"+nodeobj.Ipxe.Get()+".ipxe") - - tmpl, err := template.ParseFiles(ipxeTemplate) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - return - } - - var replace iPxeTemplate - - replace.Id = nodeobj.Id.Get() - replace.Cluster = nodeobj.ClusterName.Get() - replace.Fqdn = nodeobj.Id.Get() - replace.Ipaddr = conf.Ipaddr - replace.Port = strconv.Itoa(conf.Warewulf.Port) - replace.Hostname = nodeobj.Id.Get() - replace.Hwaddr = url[2] - replace.ContainerName = nodeobj.ContainerName.Get() - replace.KernelArgs = nodeobj.KernelArgs.Get() - replace.KernelVersion = nodeobj.KernelVersion.Get() - - err = tmpl.Execute(w, replace) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - return - } - - daemonLogf("SEND: %15s: %s\n", nodeobj.Id.Get(), ipxeTemplate) - - updateStatus(nodeobj.Id.Get(), "IPXE_TEMPLATE", nodeobj.Ipxe.Get()+".ipxe", strings.Split(req.RemoteAddr, ":")[0]) } + + ipxeTemplate := path.Join(buildconfig.SYSCONFDIR(), "warewulf/ipxe/"+node.Ipxe.Get()+".ipxe") + + tmpl, err := template.ParseFiles(ipxeTemplate) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + return + } + + var replace iPxeTemplate + + replace.Id = node.Id.Get() + replace.Cluster = node.ClusterName.Get() + replace.Fqdn = node.Id.Get() + replace.Ipaddr = conf.Ipaddr + replace.Port = strconv.Itoa(conf.Warewulf.Port) + replace.Hostname = node.Id.Get() + replace.Hwaddr = rinfo.hwaddr + replace.ContainerName = node.ContainerName.Get() + replace.KernelArgs = node.KernelArgs.Get() + replace.KernelVersion = node.KernelVersion.Get() + + err = tmpl.Execute(w, replace) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + return + } + + daemonLogf("SEND: %15s: %s\n", node.Id.Get(), ipxeTemplate) + + updateStatus(node.Id.Get(), "IPXE", node.Ipxe.Get()+".ipxe", strings.Split(req.RemoteAddr, ":")[0]) + } diff --git a/internal/pkg/warewulfd/kernel.go b/internal/pkg/warewulfd/kernel.go index 73f54369..3e5837e3 100644 --- a/internal/pkg/warewulfd/kernel.go +++ b/internal/pkg/warewulfd/kernel.go @@ -8,12 +8,25 @@ import ( ) func KernelSend(w http.ResponseWriter, req *http.Request) { - node, err := getSanity(req) + rinfo, err := parseReq(req) if err != nil { w.WriteHeader(404) daemonLogf("ERROR: %s\n", err) return } + node, err := GetNode(rinfo.hwaddr) + if err != nil { + w.WriteHeader(403) + daemonLogf("ERROR(%s): %s\n", rinfo.hwaddr, err) + return + } + + if node.AssetKey.Defined() && node.AssetKey.Get() != rinfo.assetkey { + w.WriteHeader(404) + daemonLogf("ERROR: Incorrect asset key for node: %s\n", node.Id.Get()) + updateStatus(node.Id.Get(), "KERNEL", "BAD_ASSET", rinfo.ipaddr) + return + } if node.KernelVersion.Defined() { fileName := kernel.KernelImage(node.KernelVersion.Get()) diff --git a/internal/pkg/warewulfd/kmods.go b/internal/pkg/warewulfd/kmods.go index 801f0a7d..aee88f24 100644 --- a/internal/pkg/warewulfd/kmods.go +++ b/internal/pkg/warewulfd/kmods.go @@ -8,13 +8,25 @@ import ( ) func KmodsSend(w http.ResponseWriter, req *http.Request) { - - node, err := getSanity(req) + rinfo, err := parseReq(req) if err != nil { w.WriteHeader(404) daemonLogf("ERROR: %s\n", err) return } + node, err := GetNode(rinfo.hwaddr) + if err != nil { + w.WriteHeader(403) + daemonLogf("ERROR(%s): %s\n", rinfo.hwaddr, err) + return + } + + if node.AssetKey.Defined() && node.AssetKey.Get() != rinfo.assetkey { + w.WriteHeader(404) + daemonLogf("ERROR: Incorrect asset key for node: %s\n", node.Id.Get()) + updateStatus(node.Id.Get(), "KMODS_OVERLAY", "BAD_ASSET", rinfo.ipaddr) + return + } if node.KernelVersion.Defined() { fileName := kernel.KmodsImage(node.KernelVersion.Get()) diff --git a/internal/pkg/warewulfd/parser.go b/internal/pkg/warewulfd/parser.go new file mode 100644 index 00000000..a98c3808 --- /dev/null +++ b/internal/pkg/warewulfd/parser.go @@ -0,0 +1,50 @@ +package warewulfd + +import ( + "net/http" + "strconv" + "strings" + + "github.com/pkg/errors" +) + +type parserInfo struct { + hwaddr string + ipaddr string + remoteport int + assetkey string + uuid string +} + +func parseReq(req *http.Request) (parserInfo, error) { + var ret parserInfo + + url := strings.Split(req.URL.Path, "?")[0] + hwaddr := strings.Split(url, "/")[2] + hwaddr = strings.ReplaceAll(hwaddr, "-", ":") + hwaddr = strings.ToUpper(hwaddr) + + ret.hwaddr = hwaddr + ret.ipaddr = strings.Split(req.RemoteAddr, ":")[0] + ret.remoteport, _ = strconv.Atoi(strings.Split(req.RemoteAddr, ":")[1]) + + if len(req.URL.Query()["assetkey"]) > 0 { + ret.assetkey = req.URL.Query()["assetkey"][0] + } + + if len(req.URL.Query()["uuid"]) > 0 { + ret.uuid = req.URL.Query()["uuid"][0] + } + + if ret.hwaddr == "" { + return ret, errors.New("no hwaddr encoded in GET") + } + if ret.ipaddr == "" { + return ret, errors.New("could not obtain ipaddr from HTTP request") + } + if ret.remoteport == 0 { + return ret, errors.New("could not obtain remote port from HTTP request: " + req.RemoteAddr) + } + + return ret, nil +} diff --git a/internal/pkg/warewulfd/runtime.go b/internal/pkg/warewulfd/runtime.go index 371aa725..a8b1d170 100644 --- a/internal/pkg/warewulfd/runtime.go +++ b/internal/pkg/warewulfd/runtime.go @@ -2,16 +2,35 @@ package warewulfd import ( "net/http" - "strconv" "strings" - "github.com/hpcng/warewulf/internal/pkg/node" + nodepkg "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/overlay" "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/warewulfconf" ) func RuntimeOverlaySend(w http.ResponseWriter, req *http.Request) { + rinfo, err := parseReq(req) + if err != nil { + w.WriteHeader(404) + daemonLogf("ERROR: %s\n", err) + return + } + node, err := GetNode(rinfo.hwaddr) + if err != nil { + w.WriteHeader(403) + daemonLogf("ERROR(%s): %s\n", rinfo.hwaddr, err) + return + } + + if node.AssetKey.Defined() && node.AssetKey.Get() != rinfo.assetkey { + w.WriteHeader(404) + daemonLogf("ERROR: Incorrect asset key for node: %s\n", node.Id.Get()) + updateStatus(node.Id.Get(), "RUNTIME_OVERLAY", "BAD_ASSET", rinfo.ipaddr) + return + } + conf, err := warewulfconf.New() if err != nil { daemonLogf("ERROR: Could not read Warewulf configuration file: %s\n", err) @@ -19,68 +38,33 @@ func RuntimeOverlaySend(w http.ResponseWriter, req *http.Request) { return } - nodes, err := node.New() - if err != nil { - daemonLogf("ERROR: Could not read node configuration file: %s\n", err) - w.WriteHeader(503) - return - } - - remote := strings.Split(req.RemoteAddr, ":") - port, err := strconv.Atoi(remote[1]) - if err != nil { - daemonLogf("ERROR: Could not convert port to integer: %s\n", remote[1]) - w.WriteHeader(503) - return - } - - if err != nil { - daemonLogf("ERROR: Could not load configuration file: %s\n", err) - return - } - if conf.Warewulf.Secure { - if port >= 1024 { + if rinfo.remoteport >= 1024 { daemonLogf("DENIED: Connection coming from non-privledged port: %s\n", req.RemoteAddr) w.WriteHeader(401) return } } - n, err := nodes.FindByIpaddr(remote[0]) - if err != nil { - daemonLogf("WARNING: Could not find node by IP address: %s\n", remote[0]) - w.WriteHeader(404) - return - } - - if !n.Id.Defined() { - daemonLogf("REQ: %15s: %s (unknown/unconfigured node)\n", n.Id.Get(), req.URL.Path) - w.WriteHeader(404) - return - } else { - daemonLogf("REQ: %15s: %s\n", n.Id.Get(), req.URL.Path) - } - - if n.RuntimeOverlay.Defined() { - fileName := overlay.OverlayImage(n.Id.Get(), n.RuntimeOverlay.Get()) + if node.RuntimeOverlay.Defined() { + fileName := overlay.OverlayImage(node.Id.Get(), node.RuntimeOverlay.Get()) if conf.Warewulf.AutobuildOverlays { - if !util.IsFile(fileName) || util.PathIsNewer(fileName, node.ConfigFile) || util.PathIsNewer(fileName, overlay.OverlaySourceDir(n.RuntimeOverlay.Get())) { - daemonLogf("BUILD: %15s: Runtime Overlay\n", n.Id.Get()) - _ = overlay.BuildOverlay(n, n.RuntimeOverlay.Get()) + if !util.IsFile(fileName) || util.PathIsNewer(fileName, nodepkg.ConfigFile) || util.PathIsNewer(fileName, overlay.OverlaySourceDir(node.RuntimeOverlay.Get())) { + daemonLogf("BUILD: %15s: Runtime Overlay\n", node.Id.Get()) + _ = overlay.BuildOverlay(node, node.RuntimeOverlay.Get()) } } - err := sendFile(w, fileName, n.Id.Get()) + err := sendFile(w, fileName, node.Id.Get()) if err != nil { daemonLogf("ERROR: %s\n", err) } - updateStatus(n.Id.Get(), "RUNTIME_OVERLAY", n.RuntimeOverlay.Get()+".img", strings.Split(req.RemoteAddr, ":")[0]) + updateStatus(node.Id.Get(), "RUNTIME_OVERLAY", node.RuntimeOverlay.Get()+".img", strings.Split(req.RemoteAddr, ":")[0]) } else { w.WriteHeader(503) - daemonLogf("WARNING: No 'runtime system-overlay' set for node %s\n", n.Id.Get()) + daemonLogf("WARNING: No 'runtime overlay' set for node %s\n", node.Id.Get()) } } diff --git a/internal/pkg/warewulfd/system.go b/internal/pkg/warewulfd/system.go index 918f768a..c30ed353 100644 --- a/internal/pkg/warewulfd/system.go +++ b/internal/pkg/warewulfd/system.go @@ -4,13 +4,33 @@ import ( "net/http" "strings" - "github.com/hpcng/warewulf/internal/pkg/node" + nodepkg "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/overlay" "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/warewulfconf" ) func SystemOverlaySend(w http.ResponseWriter, req *http.Request) { + rinfo, err := parseReq(req) + if err != nil { + w.WriteHeader(404) + daemonLogf("ERROR: %s\n", err) + return + } + node, err := GetNode(rinfo.hwaddr) + if err != nil { + w.WriteHeader(403) + daemonLogf("ERROR(%s): %s\n", rinfo.hwaddr, err) + return + } + + if node.AssetKey.Defined() && node.AssetKey.Get() != rinfo.assetkey { + w.WriteHeader(404) + daemonLogf("ERROR: Incorrect asset key for node: %s\n", node.Id.Get()) + updateStatus(node.Id.Get(), "SYSTEM_OVERLAY", "BAD_ASSET", rinfo.ipaddr) + return + } + conf, err := warewulfconf.New() if err != nil { daemonLogf("ERROR: Could not read Warewulf configuration file: %s\n", err) @@ -18,32 +38,25 @@ func SystemOverlaySend(w http.ResponseWriter, req *http.Request) { return } - n, err := getSanity(req) - if err != nil { - w.WriteHeader(404) - daemonLogf("ERROR: %s\n", err) - return - } - - if n.SystemOverlay.Defined() { - fileName := overlay.OverlayImage(n.Id.Get(), n.SystemOverlay.Get()) + if node.SystemOverlay.Defined() { + fileName := overlay.OverlayImage(node.Id.Get(), node.SystemOverlay.Get()) if conf.Warewulf.AutobuildOverlays { - if !util.IsFile(fileName) || util.PathIsNewer(fileName, node.ConfigFile) || util.PathIsNewer(fileName, overlay.OverlaySourceDir(n.SystemOverlay.Get())) { - daemonLogf("BUILD: %15s: System Overlay\n", n.Id.Get()) - _ = overlay.BuildOverlay(n, n.SystemOverlay.Get()) + if !util.IsFile(fileName) || util.PathIsNewer(fileName, nodepkg.ConfigFile) || util.PathIsNewer(fileName, overlay.OverlaySourceDir(node.SystemOverlay.Get())) { + daemonLogf("BUILD: %15s: System Overlay\n", node.Id.Get()) + _ = overlay.BuildOverlay(node, node.SystemOverlay.Get()) } } - err := sendFile(w, fileName, n.Id.Get()) + err := sendFile(w, fileName, node.Id.Get()) if err != nil { daemonLogf("ERROR: %s\n", err) } - updateStatus(n.Id.Get(), "SYSTEM_OVERLAY", n.SystemOverlay.Get()+".img", strings.Split(req.RemoteAddr, ":")[0]) + updateStatus(node.Id.Get(), "SYSTEM_OVERLAY", node.SystemOverlay.Get()+".img", strings.Split(req.RemoteAddr, ":")[0]) } else { w.WriteHeader(503) - daemonLogf("WARNING: No 'system system-overlay' set for node %s\n", n.Id.Get()) + daemonLogf("WARNING: No 'system system-overlay' set for node %s\n", node.Id.Get()) } } diff --git a/internal/pkg/warewulfd/util.go b/internal/pkg/warewulfd/util.go index be8214f8..57cf3b92 100644 --- a/internal/pkg/warewulfd/util.go +++ b/internal/pkg/warewulfd/util.go @@ -1,54 +1,16 @@ package warewulfd import ( - "fmt" "io" - "log" - "log/syslog" "net/http" "os" "strconv" "strings" - "time" "github.com/hpcng/warewulf/internal/pkg/node" - "github.com/hpcng/warewulf/internal/pkg/warewulfconf" "github.com/pkg/errors" ) -var logwriter *syslog.Writer -var loginit bool - -func daemonLogf(message string, a ...interface{}) { - conf, err := warewulfconf.New() - if err != nil { - fmt.Printf("ERROR: Could not read Warewulf configuration file: %s\n", err) - return - } - - if conf.Warewulf.Syslog { - if !loginit { - var err error - - logwriter, err = syslog.New(syslog.LOG_NOTICE, "warewulfd") - if err != nil { - return - } - log.SetOutput(logwriter) - loginit = true - - log.SetFlags(0) - log.SetPrefix("") - } - - log.Printf(message, a...) - - } else { - prefix := fmt.Sprintf("[%s] ", time.Now().Format(time.UnixDate)) - fmt.Printf(prefix+message, a...) - } -} - func getSanity(req *http.Request) (node.NodeInfo, error) { url := strings.Split(req.URL.Path, "/") From 5083e929f0ce2eaba82b8a49568e3a707c823b69 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Mon, 24 Jan 2022 00:44:07 +0000 Subject: [PATCH 2/7] Add asset tag and uuid support to wwclient --- cmd/wwclient/wwclient.go | 9 ++++++++- go.mod | 1 + go.sum | 5 +++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/cmd/wwclient/wwclient.go b/cmd/wwclient/wwclient.go index 40018f9b..85999468 100644 --- a/cmd/wwclient/wwclient.go +++ b/cmd/wwclient/wwclient.go @@ -11,6 +11,7 @@ import ( "github.com/hpcng/warewulf/internal/pkg/warewulfconf" "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/talos-systems/go-smbios/smbios" ) func main() { @@ -67,6 +68,12 @@ func main() { }, } + smbiosDump, _ := smbios.New() + sysinfoDump := smbiosDump.SystemInformation() + localUUID, _ := sysinfoDump.UUID() + x := smbiosDump.SystemEnclosure() + tag := x.AssetTagNumber() + for { var resp *http.Response counter := 0 @@ -74,7 +81,7 @@ func main() { for { var err error - getString := fmt.Sprintf("http://%s:%d/overlay-runtime", conf.Ipaddr, conf.Warewulf.Port) + getString := fmt.Sprintf("http://%s:%d/overlay-runtime?assetkey=%s&uuid=%s", conf.Ipaddr, conf.Warewulf.Port, tag, localUUID) resp, err = webclient.Get(getString) if err == nil { break diff --git a/go.mod b/go.mod index 4e7f2a4c..bdda8a46 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/opencontainers/umoci v0.4.6 github.com/pkg/errors v0.9.1 github.com/spf13/cobra v1.1.1 + github.com/talos-systems/go-smbios v0.1.1 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index 9b1b98db..36920bdd 100644 --- a/go.sum +++ b/go.sum @@ -227,6 +227,8 @@ github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8l github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e h1:vUmf0yezR0y7jJ5pceLHthLaYf4bA5T14B6q39S4q2Q= +github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e/go.mod h1:YTIHhz/QFSYnu/EhlF2SpU2Uk+32abacUYA5ZPljz1A= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= @@ -354,6 +356,7 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= @@ -674,6 +677,8 @@ github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/talos-systems/go-smbios v0.1.1 h1:Au6obB/Pp0i0JHhvPlzONk5aoNseosO2BUsmvWWi7y8= +github.com/talos-systems/go-smbios v0.1.1/go.mod h1:vk76naUSZaWE8Z95wbDn51FgH0goECM4oK3KY2hYSMU= github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/tchap/go-patricia v2.3.0+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= From b068c187aff651b066bb9cafa6e7e7b3832200b4 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Mon, 24 Jan 2022 01:29:05 +0000 Subject: [PATCH 3/7] Update wwclient to send hwaddr and asset/uuid tags --- cmd/wwclient/wwclient.go | 26 ++++++++++++++++++++++---- etc/ipxe/arm_image.ipxe | 2 +- etc/ipxe/default.ipxe | 2 +- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/cmd/wwclient/wwclient.go b/cmd/wwclient/wwclient.go index 85999468..c0f7cf3b 100644 --- a/cmd/wwclient/wwclient.go +++ b/cmd/wwclient/wwclient.go @@ -7,6 +7,7 @@ import ( "net/http" "os" "os/exec" + "strings" "time" "github.com/hpcng/warewulf/internal/pkg/warewulfconf" @@ -49,8 +50,7 @@ func main() { if conf.Warewulf.Secure { // Setup local port to something privileged (<1024) localTCPAddr.Port = 987 - } else { - fmt.Printf("INFO: Running from an insecure port\n") + wwlog.Printf(wwlog.INFO, "Running from trusted port\n") } webclient := &http.Client{ @@ -68,12 +68,30 @@ func main() { }, } - smbiosDump, _ := smbios.New() + smbiosDump, err := smbios.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not get SMBIOS info: %s\n", err) + os.Exit(1) + } sysinfoDump := smbiosDump.SystemInformation() localUUID, _ := sysinfoDump.UUID() x := smbiosDump.SystemEnclosure() tag := x.AssetTagNumber() + cmdline, err := os.ReadFile("/proc/cmdline") + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not read from /proc/cmdline: %s\n", err) + os.Exit(1) + } + + wwid_tmp := strings.Split(string(cmdline), "wwid=") + if len(wwid_tmp) < 2 { + wwlog.Printf(wwlog.ERROR, "'wwid' is not defined in /proc/cmdline\n") + os.Exit(1) + } + + wwid := strings.Split(wwid_tmp[1], " ")[0] + for { var resp *http.Response counter := 0 @@ -81,7 +99,7 @@ func main() { for { var err error - getString := fmt.Sprintf("http://%s:%d/overlay-runtime?assetkey=%s&uuid=%s", conf.Ipaddr, conf.Warewulf.Port, tag, localUUID) + getString := fmt.Sprintf("http://%s:%d/overlay-runtime/%s?assetkey=%s&uuid=%s", conf.Ipaddr, conf.Warewulf.Port, wwid, tag, localUUID) resp, err = webclient.Get(getString) if err == nil { break diff --git a/etc/ipxe/arm_image.ipxe b/etc/ipxe/arm_image.ipxe index ee5da3cc..5014dec5 100644 --- a/etc/ipxe/arm_image.ipxe +++ b/etc/ipxe/arm_image.ipxe @@ -17,7 +17,7 @@ initrd --name kmods ${base}/kmods/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} initrd --name system ${base}/overlay-system/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot initrd --name runtime ${base}/overlay-runtime/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot -boot kernel initrd=container initrd=kmods initrd=system initrd=runtime {{.KernelArgs}} || goto reboot +boot kernel initrd=container initrd=kmods initrd=system initrd=runtime wwid={{.Hwaddr}} {{.KernelArgs}} || goto reboot :reboot echo diff --git a/etc/ipxe/default.ipxe b/etc/ipxe/default.ipxe index c5123134..4512d637 100644 --- a/etc/ipxe/default.ipxe +++ b/etc/ipxe/default.ipxe @@ -17,7 +17,7 @@ imgextract --name kmods ${base}/kmods/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} imgextract --name system ${base}/overlay-system/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot imgextract --name runtime ${base}/overlay-runtime/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot -boot kernel initrd=container initrd=kmods initrd=system initrd=runtime {{.KernelArgs}} || goto reboot +boot kernel initrd=container initrd=kmods initrd=system initrd=runtime wwid={{.Hwaddr}} {{.KernelArgs}} || goto reboot :reboot echo From 1bc1d7e34fab26eb4571934b0c5fa3214e3717c5 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Mon, 24 Jan 2022 01:31:27 +0000 Subject: [PATCH 4/7] removed unused function --- internal/pkg/warewulfd/util.go | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/internal/pkg/warewulfd/util.go b/internal/pkg/warewulfd/util.go index 57cf3b92..02958602 100644 --- a/internal/pkg/warewulfd/util.go +++ b/internal/pkg/warewulfd/util.go @@ -5,28 +5,10 @@ import ( "net/http" "os" "strconv" - "strings" - "github.com/hpcng/warewulf/internal/pkg/node" "github.com/pkg/errors" ) -func getSanity(req *http.Request) (node.NodeInfo, error) { - url := strings.Split(req.URL.Path, "/") - - hwaddr := strings.ReplaceAll(url[2], "-", ":") - - nodeobj, err := GetNode(hwaddr) - if err != nil { - var ret node.NodeInfo - return ret, errors.New("Could not find node by HW address: " + req.URL.Path) - } - - daemonLogf("REQ: %15s: %s\n", nodeobj.Id.Get(), req.URL.Path) - - return nodeobj, nil -} - func sendFile(w http.ResponseWriter, filename string, sendto string) error { fd, err := os.Open(filename) if err != nil { From f02961d4a29bd18a4631ad28bb4af15b4eea2535 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Mon, 24 Jan 2022 01:35:30 +0000 Subject: [PATCH 5/7] use ioutil.ReadFile() instead of os.ReadFile() --- cmd/wwclient/wwclient.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/wwclient/wwclient.go b/cmd/wwclient/wwclient.go index c0f7cf3b..b51c9aca 100644 --- a/cmd/wwclient/wwclient.go +++ b/cmd/wwclient/wwclient.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "io/ioutil" "log" "net" "net/http" @@ -78,7 +79,7 @@ func main() { x := smbiosDump.SystemEnclosure() tag := x.AssetTagNumber() - cmdline, err := os.ReadFile("/proc/cmdline") + cmdline, err := ioutil.ReadFile("/proc/cmdline") if err != nil { wwlog.Printf(wwlog.ERROR, "Could not read from /proc/cmdline: %s\n", err) os.Exit(1) From 84b618fb7bbfd3e5e378f5992e8fb770c391b813 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Wed, 26 Jan 2022 01:59:34 +0000 Subject: [PATCH 6/7] Fixed booting issues with `/bin` directory existing in overlay. --- Makefile | 4 ++-- etc/ipxe/{arm_image.ipxe => bigimage.ipxe} | 8 ++++---- etc/ipxe/default.ipxe | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) rename etc/ipxe/{arm_image.ipxe => bigimage.ipxe} (58%) diff --git a/Makefile b/Makefile index bdd53e22..194d3fc0 100644 --- a/Makefile +++ b/Makefile @@ -136,7 +136,6 @@ files: all install -d -m 0755 $(DESTDIR)$(WWCHROOTDIR) install -d -m 0755 $(DESTDIR)$(WWPROVISIONDIR) install -d -m 0755 $(DESTDIR)$(WWOVERLAYDIR) - install -d -m 0755 $(DESTDIR)$(WWOVERLAYDIR)/wwinit/bin/ install -d -m 0755 $(DESTDIR)$(WWOVERLAYDIR)/wwinit/warewulf/bin/ install -d -m 0755 $(DESTDIR)$(SYSCONFDIR)/warewulf/ install -d -m 0755 $(DESTDIR)$(SYSCONFDIR)/warewulf/ipxe @@ -152,6 +151,7 @@ files: all cp -r etc/ipxe $(DESTDIR)$(SYSCONFDIR)/warewulf/ cp -r overlays/* $(DESTDIR)$(WWOVERLAYDIR)/ chmod 755 $(DESTDIR)$(WWOVERLAYDIR)/wwinit/init + chmod 755 $(DESTDIR)$(WWOVERLAYDIR)/wwinit/warewulf/wwinit chmod 600 $(DESTDIR)$(WWOVERLAYDIR)/wwinit/etc/ssh/ssh* chmod 644 $(DESTDIR)$(WWOVERLAYDIR)/wwinit/etc/ssh/ssh*.pub.ww install -m 0755 wwctl $(DESTDIR)$(BINDIR) @@ -180,7 +180,7 @@ wwclient: cd cmd/wwclient; CGO_ENABLED=0 GOOS=linux go build -mod vendor -a -ldflags '-extldflags -static' -o ../../wwclient install_wwclient: wwclient - install -m 0755 wwclient $(DESTDIR)$(WWOVERLAYDIR)/wwinit/bin/wwclient + install -m 0755 wwclient $(DESTDIR)$(WWOVERLAYDIR)/wwinit/warewulf/bin/wwclient bash_completion: diff --git a/etc/ipxe/arm_image.ipxe b/etc/ipxe/bigimage.ipxe similarity index 58% rename from etc/ipxe/arm_image.ipxe rename to etc/ipxe/bigimage.ipxe index 5014dec5..1308b998 100644 --- a/etc/ipxe/arm_image.ipxe +++ b/etc/ipxe/bigimage.ipxe @@ -12,10 +12,10 @@ echo set base http://{{.Ipaddr}}:{{.Port}} kernel --name kernel ${base}/kernel/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot -initrd --name container ${base}/container/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot -initrd --name kmods ${base}/kmods/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot -initrd --name system ${base}/overlay-system/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot -initrd --name runtime ${base}/overlay-runtime/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot +imgextract --name container ${base}/container/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot +imgextract --name kmods ${base}/kmods/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot +imgextract --name system ${base}/overlay-system/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot +imgextract --name runtime ${base}/overlay-runtime/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot boot kernel initrd=container initrd=kmods initrd=system initrd=runtime wwid={{.Hwaddr}} {{.KernelArgs}} || goto reboot diff --git a/etc/ipxe/default.ipxe b/etc/ipxe/default.ipxe index 4512d637..32868718 100644 --- a/etc/ipxe/default.ipxe +++ b/etc/ipxe/default.ipxe @@ -12,10 +12,10 @@ echo set base http://{{.Ipaddr}}:{{.Port}} kernel --name kernel ${base}/kernel/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot -imgextract --name container ${base}/container/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot -imgextract --name kmods ${base}/kmods/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot -imgextract --name system ${base}/overlay-system/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot -imgextract --name runtime ${base}/overlay-runtime/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot +initrd --name container ${base}/container/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot +initrd --name kmods ${base}/kmods/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot +initrd --name system ${base}/overlay-system/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot +initrd --name runtime ${base}/overlay-runtime/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot boot kernel initrd=container initrd=kmods initrd=system initrd=runtime wwid={{.Hwaddr}} {{.KernelArgs}} || goto reboot From 9e943101ecc040376432dfe0675dfeadad272093 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Wed, 26 Jan 2022 04:02:30 +0000 Subject: [PATCH 7/7] Always use lowercase for hw addresses --- internal/app/wwctl/node/set/main.go | 2 +- internal/pkg/warewulfd/parser.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/app/wwctl/node/set/main.go b/internal/app/wwctl/node/set/main.go index 5302245e..c4a69f48 100644 --- a/internal/app/wwctl/node/set/main.go +++ b/internal/app/wwctl/node/set/main.go @@ -237,7 +237,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting HW address to: %s\n", n.Id.Get(), SetNetName, SetHwaddr) - n.NetDevs[SetNetName].Hwaddr.Set(SetHwaddr) + n.NetDevs[SetNetName].Hwaddr.Set(strings.ToLower(SetHwaddr)) } if SetType != "" { diff --git a/internal/pkg/warewulfd/parser.go b/internal/pkg/warewulfd/parser.go index a98c3808..a473f22d 100644 --- a/internal/pkg/warewulfd/parser.go +++ b/internal/pkg/warewulfd/parser.go @@ -22,7 +22,7 @@ func parseReq(req *http.Request) (parserInfo, error) { url := strings.Split(req.URL.Path, "?")[0] hwaddr := strings.Split(url, "/")[2] hwaddr = strings.ReplaceAll(hwaddr, "-", ":") - hwaddr = strings.ToUpper(hwaddr) + hwaddr = strings.ToLower(hwaddr) ret.hwaddr = hwaddr ret.ipaddr = strings.Split(req.RemoteAddr, ":")[0]