Merge pull request #2055 from anderbubble/handle-configure-tftp-selinux
Manage selinux context of tftp directory
This commit is contained in:
@@ -11,6 +11,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
- Renamed debian.interfaces overlay to ifupdown
|
||||
- Change the DHCP server package used on openeuler 24.03 to dnsmasq
|
||||
- Added configurable Serial over LAN speed via IPMI `bit-rate` tag in `50-ipmi` template
|
||||
- Manage SELinux context of TFTP directory. #1997
|
||||
- Dynamically write `$tftpdir/warewulf/grub.cfg` to the configured value from `warewulf.conf`
|
||||
- Absolute paths specified with `{{ file }}` in an overlay now write to that absolute path.
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
@@ -263,6 +263,12 @@ The dependencies and their licenses are as follows:
|
||||
|
||||
**License URL:** <https://github.com/opencontainers/runtime-spec/blob/v1.2.0/LICENSE>
|
||||
|
||||
## github.com/opencontainers/selinux
|
||||
|
||||
**License:** Apache-2.0
|
||||
|
||||
**License URL:** <https://github.com/opencontainers/selinux/blob/v1.11.1/LICENSE>
|
||||
|
||||
## github.com/opencontainers/umoci
|
||||
|
||||
**License:** Apache-2.0
|
||||
|
||||
1
Makefile
1
Makefile
@@ -204,7 +204,6 @@ install: build docs ## Install Warewulf from source
|
||||
for f in etc/ipxe/*.ipxe; do install -m 0644 $$f $(DESTDIR)$(WWCONFIGDIR)/ipxe/; done
|
||||
for f in lib/warewulf/bmc/*.tmpl; do install -m 0644 $$f $(DESTDIR)$(DATADIR)/warewulf/bmc; done
|
||||
install -m 0644 etc/grub/grub.cfg.ww $(DESTDIR)$(WWCONFIGDIR)/grub/grub.cfg.ww
|
||||
install -m 0644 etc/grub/chainload.ww $(DESTDIR)$(DATADIR)/warewulf/overlays/host/rootfs$(TFTPDIR)/warewulf/grub.cfg.ww
|
||||
install -m 0644 etc/logrotate.d/warewulfd.conf $(DESTDIR)$(LOGROTATEDIR)/warewulfd.conf
|
||||
(cd overlays && find * -path '*/internal' -prune -o -type f -exec install -D -m 0644 {} $(DESTDIR)$(DATADIR)/warewulf/overlays/{} \;)
|
||||
(cd overlays && find * -path '*/internal' -prune -o -type d -exec mkdir -pv $(DESTDIR)$(DATADIR)/warewulf/overlays/{} \;)
|
||||
|
||||
39
etc/warewulf.conf-el10
Normal file
39
etc/warewulf.conf-el10
Normal file
@@ -0,0 +1,39 @@
|
||||
ipaddr: 10.0.0.1
|
||||
netmask: 255.255.252.0
|
||||
warewulf:
|
||||
secure: false
|
||||
update interval: 60
|
||||
autobuild overlays: true
|
||||
host overlay: true
|
||||
systemd name: warewulfd
|
||||
dhcp:
|
||||
enabled: true
|
||||
range start: 10.0.1.1
|
||||
range end: 10.0.1.255
|
||||
systemd name: dnsmasq
|
||||
template: default
|
||||
tftp:
|
||||
enabled: true
|
||||
systemd name: dnsmasq
|
||||
ipxe:
|
||||
00:09: ipxe-snponly-x86_64.efi
|
||||
00:00: undionly.kpxe
|
||||
00:0B: arm64-efi/snponly.efi
|
||||
00:07: ipxe-snponly-x86_64.efi
|
||||
nfs:
|
||||
enabled: true
|
||||
export paths:
|
||||
- path: /home
|
||||
export options: rw,sync
|
||||
- path: /opt
|
||||
export options: ro,sync,no_root_squash
|
||||
systemd name: nfs-server
|
||||
image mounts:
|
||||
- source: /etc/resolv.conf
|
||||
dest: /etc/resolv.conf
|
||||
readonly: true
|
||||
ssh:
|
||||
key types:
|
||||
- ed25519
|
||||
- ecdsa
|
||||
- rsa
|
||||
40
etc/warewulf.conf-suse
Normal file
40
etc/warewulf.conf-suse
Normal file
@@ -0,0 +1,40 @@
|
||||
ipaddr: 10.0.0.1
|
||||
netmask: 255.255.252.0
|
||||
warewulf:
|
||||
secure: false
|
||||
update interval: 60
|
||||
autobuild overlays: true
|
||||
host overlay: true
|
||||
systemd name: warewulfd
|
||||
dhcp:
|
||||
enabled: true
|
||||
range start: 10.0.1.1
|
||||
range end: 10.0.1.255
|
||||
systemd name: dhcpd
|
||||
template: default
|
||||
tftp:
|
||||
enabled: true
|
||||
systemd name: tftp
|
||||
ipxe:
|
||||
00:00: undionly.kpxe
|
||||
00:07: ipxe-x86_64.efi
|
||||
00:09: ipxe-x86_64.efi
|
||||
00:0B: snp-arm64.efi
|
||||
nfs:
|
||||
enabled: true
|
||||
export paths:
|
||||
- path: /home
|
||||
export options: rw,sync
|
||||
- path: /opt
|
||||
export options: ro,sync,no_root_squash
|
||||
systemd name: nfs-server
|
||||
image mounts:
|
||||
- source: /etc/resolv.conf
|
||||
dest: /etc/resolv.conf
|
||||
readonly: true
|
||||
ssh:
|
||||
key types:
|
||||
- ed25519
|
||||
- ecdsa
|
||||
- rsa
|
||||
- dsa
|
||||
1
go.mod
1
go.mod
@@ -25,6 +25,7 @@ require (
|
||||
github.com/manifoldco/promptui v0.9.0
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||
github.com/opencontainers/image-spec v1.1.0
|
||||
github.com/opencontainers/selinux v1.11.1
|
||||
github.com/opencontainers/umoci v0.4.7
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/spf13/cobra v1.9.1
|
||||
|
||||
2
go.sum
2
go.sum
@@ -296,6 +296,8 @@ github.com/opencontainers/runc v1.1.14/go.mod h1:E4C2z+7BxR7GHXp0hAY53mek+x49X1L
|
||||
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
|
||||
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/selinux v1.11.1 h1:nHFvthhM0qY8/m+vfhJylliSshm8G1jJ2jDMcgULaH8=
|
||||
github.com/opencontainers/selinux v1.11.1/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
|
||||
github.com/opencontainers/umoci v0.4.7 h1:mbIbtMpZ3v9oMpKaLopnWoLykgmnixeLzq51EzAX5nQ=
|
||||
github.com/opencontainers/umoci v0.4.7/go.mod h1:lgJ4bnwJezsN1o/5d7t/xdRPvmf8TvBko5kKYJsYvgo=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
|
||||
@@ -24,6 +24,12 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = configure.TFTP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = configure.DHCP()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -39,10 +45,6 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = configure.TFTP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = configure.Hostfile()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -13,9 +13,22 @@ import (
|
||||
|
||||
func TFTP() (err error) {
|
||||
controller := warewulfconf.Get()
|
||||
var tftpdir string = path.Join(controller.TFTP.TftpRoot, "warewulf")
|
||||
oldMask := unix.Umask(0)
|
||||
defer unix.Umask(oldMask)
|
||||
|
||||
// Check if TftpRoot exists, create and restore context if needed
|
||||
if _, err := os.Stat(controller.TFTP.TftpRoot); err != nil {
|
||||
err = os.MkdirAll(controller.TFTP.TftpRoot, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := util.RestoreSELinuxContext(controller.TFTP.TftpRoot); err != nil {
|
||||
wwlog.Warn("failed to restore SELinux context for %s: %s", controller.TFTP.TftpRoot, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create tftpdir if needed
|
||||
var tftpdir string = path.Join(controller.TFTP.TftpRoot, "warewulf")
|
||||
err = os.MkdirAll(tftpdir, 0755)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -43,6 +56,7 @@ func TFTP() (err error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !controller.TFTP.Enabled() {
|
||||
wwlog.Warn("Warewulf does not auto start TFTP services due to disable by warewulf.conf")
|
||||
return nil
|
||||
|
||||
@@ -571,7 +571,20 @@ func BuildOverlayIndir(nodeData node.Node, allNodes []node.Node, overlayNames []
|
||||
}
|
||||
fileBuffer.Reset()
|
||||
}
|
||||
outputPath = path.Join(path.Dir(originalOutputPath), filenameFromTemplate[0][1])
|
||||
if path.IsAbs(filenameFromTemplate[0][1]) {
|
||||
outputPath = filenameFromTemplate[0][1]
|
||||
// Create parent directory for absolute paths
|
||||
parentDir := path.Dir(outputPath)
|
||||
sourceDirInfo, err := os.Stat(path.Dir(walkPath))
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not stat source directory: %w", err)
|
||||
}
|
||||
if err := os.MkdirAll(parentDir, sourceDirInfo.Mode()); err != nil {
|
||||
return fmt.Errorf("could not create parent directory for absolute path: %w", err)
|
||||
}
|
||||
} else {
|
||||
outputPath = path.Join(path.Dir(originalOutputPath), filenameFromTemplate[0][1])
|
||||
}
|
||||
writingToNamedFile = true
|
||||
isLink = false
|
||||
} else {
|
||||
|
||||
34
internal/pkg/util/selinux.go
Normal file
34
internal/pkg/util/selinux.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/opencontainers/selinux/go-selinux"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
// RestoreSELinuxContext restores the SELinux context for a path and all its children
|
||||
// based on the system's SELinux policy, equivalent to running restorecon -R
|
||||
func RestoreSELinuxContext(rootPath string) error {
|
||||
if !selinux.GetEnabled() {
|
||||
wwlog.Debug("SELinux not enabled, skipping context restoration")
|
||||
return nil
|
||||
}
|
||||
|
||||
wwlog.Info("Restoring SELinux contexts for: %s", rootPath)
|
||||
|
||||
cmd := exec.Command("restorecon", "-vR", rootPath)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("restorecon failed: %w: %s", err, string(output))
|
||||
}
|
||||
|
||||
for _, line := range strings.Split(strings.TrimSpace(string(output)), "\n") {
|
||||
if line != "" {
|
||||
wwlog.Debug("restorecon output: %s", line)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
{{ file (print .Tftp.TftpRoot "/warewulf/grub.cfg") }}
|
||||
# This file is autogenerated by warewulf
|
||||
# Host: {{ .BuildHost }}
|
||||
# Time: {{ .BuildTime }}
|
||||
@@ -1,11 +1,25 @@
|
||||
%global debug_package %{nil}
|
||||
|
||||
%if 0%{?suse_version}
|
||||
# feature macros
|
||||
%if 0%{?rhel} >= 10 || 0%{?openEuler}
|
||||
%global use_dnsmasq 1
|
||||
%else
|
||||
%global use_dnsmasq 0
|
||||
%endif
|
||||
|
||||
%if 0%{?suse_version} || 0%{?sle_version}
|
||||
%global is_suse 1
|
||||
%else
|
||||
%global is_suse 0
|
||||
%endif
|
||||
|
||||
# Set tftpdir based on distribution
|
||||
%if 0%{?is_suse}
|
||||
%global tftpdir /srv/tftpboot
|
||||
%else
|
||||
# Assume Fedora-based OS if not SUSE-based
|
||||
%global tftpdir /var/lib/tftpboot
|
||||
%endif
|
||||
|
||||
%global srvdir %{_sharedstatedir}
|
||||
|
||||
%global wwgroup warewulf
|
||||
@@ -35,27 +49,21 @@ Conflicts: warewulf-vnfs
|
||||
Conflicts: warewulf-provision
|
||||
Conflicts: warewulf-ipmi
|
||||
|
||||
%if 0%{?suse_version} || 0%{?sle_version}
|
||||
%if 0%{?is_suse}
|
||||
BuildRequires: distribution-release
|
||||
BuildRequires: systemd-rpm-macros
|
||||
BuildRequires: go >= 1.22
|
||||
BuildRequires: firewall-macros
|
||||
BuildRequires: firewalld
|
||||
BuildRequires: tftp
|
||||
BuildRequires: yq
|
||||
Requires: tftp
|
||||
Requires: nfs-kernel-server
|
||||
Requires: firewalld
|
||||
Requires: ipxe-bootimgs
|
||||
%else
|
||||
# Assume Red Hat/Fedora build
|
||||
# Assume Red Hat/Fedora
|
||||
BuildRequires: system-release
|
||||
BuildRequires: systemd
|
||||
BuildRequires: golang >= 1.22
|
||||
BuildRequires: firewalld-filesystem
|
||||
%if ! (0%{?rhel} >= 10)
|
||||
Requires: tftp-server
|
||||
%endif
|
||||
Requires: nfs-utils
|
||||
%if 0%{?rhel} < 8
|
||||
Requires: ipxe-bootimgs
|
||||
@@ -65,13 +73,18 @@ Requires: ipxe-bootimgs-aarch64
|
||||
%endif
|
||||
%endif
|
||||
|
||||
%if 0%{?rhel} >= 10 || 0%{?openEuler}
|
||||
# dhcp/tftp requirements
|
||||
%if 0%{?is_suse}
|
||||
BuildRequires: tftp
|
||||
Requires: tftp
|
||||
%elif 0%{?use_dnsmasq}
|
||||
Requires: dnsmasq
|
||||
%else
|
||||
%if 0%{?rhel} >= 8 || 0%{?suse_version} || 0%{?fedora}
|
||||
# Assume Red Hat/Fedora
|
||||
Requires: tftp-server
|
||||
%if 0%{?rhel} >= 8 || 0%{?fedora}
|
||||
Requires: dhcp-server
|
||||
%else
|
||||
# rhel < 8 and others
|
||||
Requires: dhcp
|
||||
%endif
|
||||
%endif
|
||||
@@ -126,21 +139,12 @@ make install \
|
||||
DESTDIR=%{buildroot}
|
||||
|
||||
%if 0%{?rhel} >= 10 || 0%{?openEuler}
|
||||
sed -i '
|
||||
s/systemd name: dhcpd/systemd name: dnsmasq/
|
||||
s/systemd name: tftp/systemd name: dnsmasq/
|
||||
/- dsa/d' \
|
||||
-i %{buildroot}%{_sysconfdir}/warewulf/warewulf.conf
|
||||
cp -f etc/warewulf.conf-el10 %{buildroot}%{_sysconfdir}/warewulf/warewulf.conf
|
||||
%elif 0%{?is_suse}
|
||||
cp -f etc/warewulf.conf-suse %{buildroot}%{_sysconfdir}/warewulf/warewulf.conf
|
||||
%endif
|
||||
|
||||
%if 0%{?suse_version} || 0%{?sle_version}
|
||||
yq e '
|
||||
.tftp.ipxe."00:00" = "undionly.kpxe" |
|
||||
.tftp.ipxe."00:07" = "ipxe-x86_64.efi" |
|
||||
.tftp.ipxe."00:09" = "ipxe-x86_64.efi" |
|
||||
.tftp.ipxe."00:0B" = "snp-arm64.efi" ' \
|
||||
-i %{buildroot}%{_sysconfdir}/warewulf/warewulf.conf
|
||||
%else
|
||||
%if ! 0%{?is_suse}
|
||||
make install-sos \
|
||||
DESTDIR=%{buildroot}
|
||||
%endif
|
||||
@@ -229,8 +233,7 @@ Summary: dracut module for loading a Warewulf image
|
||||
BuildArch: noarch
|
||||
|
||||
Requires: dracut
|
||||
%if 0%{?suse_version}
|
||||
%else
|
||||
%if ! 0%{?is_suse}
|
||||
Requires: dracut-network
|
||||
%endif
|
||||
Requires: curl
|
||||
@@ -249,8 +252,7 @@ initramfs that can fetch and boot a Warewulf node image from a Warewulf server.
|
||||
%{_prefix}/lib/dracut/modules.d/90wwinit
|
||||
|
||||
|
||||
%if 0%{?suse_version} || 0%{?sle_version}
|
||||
%else
|
||||
%if ! 0%{?is_suse}
|
||||
%package sos
|
||||
Summary: sos plugin for Warewulf
|
||||
BuildArch: noarch
|
||||
@@ -270,6 +272,9 @@ about Warewulf in an sos report.
|
||||
|
||||
|
||||
%changelog
|
||||
* Tue Oct 28 2025 Jonathon Anderson <janderson@ciq.com>
|
||||
- Use static variants for warewulf.conf-suse and warewulf.conf-el10
|
||||
|
||||
* Thu Sep 4 2025 Jonathon Anderson <janderson@ciq.com>
|
||||
- Update golang BuildRequires to 1.22
|
||||
- Exclude overlay files from brp-mangle-shebangs
|
||||
|
||||
Reference in New Issue
Block a user