Manage selinux context of tftp directory

- Fixes: #1997

Signed-off-by: Jonathon Anderson <janderson@ciq.com>
This commit is contained in:
Jonathon Anderson
2025-10-29 13:09:30 -06:00
parent 9a94d1f2b1
commit be97ef15a0
10 changed files with 179 additions and 35 deletions

View File

@@ -11,6 +11,7 @@ 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
### Fixed

View File

@@ -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

39
etc/warewulf.conf-el10 Normal file
View 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
View 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
View File

@@ -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
View File

@@ -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=

View File

@@ -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

View File

@@ -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

View 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
}

View File

@@ -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