2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-07-31 10:09:40 +00:00

Merge pull request #7638 from VersatusHPC/harvest/apache-security-hardening

fix(httpd): harden the xCAT Apache configuration
This commit is contained in:
Daniel Hilst
2026-07-28 11:05:42 -03:00
committed by GitHub
19 changed files with 276 additions and 13 deletions
@@ -23,13 +23,27 @@ provisioning scripts crawl recursively.
**Apache 2.4** (RHEL 7+, SLES 12+, Ubuntu 16.04+)::
# /etc/httpd/conf.d/xcat.conf
ServerTokens Prod
<Directory "/tftpboot">
Options FollowSymLinks Includes MultiViews
Options FollowSymLinks
<IfModule mod_headers.c>
Header always set X-Frame-Options SAMEORIGIN
Header always set X-Content-Type-Options nosniff
Header always set Content-Security-Policy "script-src 'self' 'unsafe-eval'"
Header always set X-Permitted-Cross-Domain-Policies none
</IfModule>
AllowOverride None
Require all granted
</Directory>
<Directory "/install">
Options FollowSymLinks Includes MultiViews
Options FollowSymLinks
<IfModule mod_headers.c>
Header always set X-Frame-Options SAMEORIGIN
Header always set X-Content-Type-Options nosniff
Header always set Content-Security-Policy "script-src 'self' 'unsafe-eval'"
Header always set X-Permitted-Cross-Domain-Policies none
</IfModule>
AllowOverride None
Require all granted
</Directory>
@@ -47,14 +61,28 @@ provisioning scripts crawl recursively.
**Apache 2.2** (RHEL 6, SLES 11)::
# /etc/httpd/conf.d/xcat.conf
ServerTokens Prod
<Directory "/tftpboot">
Options FollowSymLinks Includes MultiViews
Options FollowSymLinks
<IfModule mod_headers.c>
Header always set X-Frame-Options SAMEORIGIN
Header always set X-Content-Type-Options nosniff
Header always set Content-Security-Policy "script-src 'self' 'unsafe-eval'"
Header always set X-Permitted-Cross-Domain-Policies none
</IfModule>
AllowOverride None
Order allow,deny
Allow from all
</Directory>
<Directory "/install">
Options FollowSymLinks Includes MultiViews
Options FollowSymLinks
<IfModule mod_headers.c>
Header always set X-Frame-Options SAMEORIGIN
Header always set X-Content-Type-Options nosniff
Header always set Content-Security-Policy "script-src 'self' 'unsafe-eval'"
Header always set X-Permitted-Cross-Domain-Policies none
</IfModule>
AllowOverride None
Order allow,deny
Allow from all
@@ -79,6 +107,23 @@ provisioning scripts crawl recursively.
download all files from these directories and depend on Apache directory
listings to discover file paths.
Security Response Headers and Server Banner
-------------------------------------------
xCAT configures ``ServerTokens Prod`` to omit the Apache version and operating
system from the HTTP ``Server`` header. It also applies the following response
headers to ``/install`` and ``/tftpboot``:
* ``X-Frame-Options: SAMEORIGIN``
* ``X-Content-Type-Options: nosniff``
* ``Content-Security-Policy: script-src 'self' 'unsafe-eval'``
* ``X-Permitted-Cross-Domain-Policies: none``
These directives require ``mod_headers``. The xCAT packages enable that module
on distributions where it is not loaded by default and activate the updated
configuration during installation or upgrade. Keep the ``Header always set``
directives when adding local access-control rules to either directory.
Sensitive Directories
---------------------
@@ -141,7 +186,13 @@ For additional protection, restrict access to the provisioning subnet::
# Apache 2.4+
<Directory "/install">
Options FollowSymLinks Includes MultiViews
Options FollowSymLinks
<IfModule mod_headers.c>
Header always set X-Frame-Options SAMEORIGIN
Header always set X-Content-Type-Options nosniff
Header always set Content-Security-Policy "script-src 'self' 'unsafe-eval'"
Header always set X-Permitted-Cross-Domain-Policies none
</IfModule>
AllowOverride None
Require ip 10.0.0.0/16
</Directory>
@@ -100,6 +100,9 @@ gettab_key_table
getmacs_d
getmacs_f_D
getmacs_noderange
httpd_security_headers_install
httpd_security_headers_tftpboot
httpd_server_banner_masked
tabdump_servicenode
lsdef_a
lsdef_null
@@ -106,6 +106,9 @@ gettab_H
gettab_err
gettab_h
gettab_key_table
httpd_security_headers_install
httpd_security_headers_tftpboot
httpd_server_banner_masked
lsdef_a
lsdef_null
lsdef_t
@@ -106,6 +106,9 @@ gettab_H
gettab_err
gettab_h
gettab_key_table
httpd_security_headers_install
httpd_security_headers_tftpboot
httpd_server_banner_masked
lsdef_a
lsdef_null
lsdef_t
@@ -68,6 +68,9 @@ gettab_H
gettab_err
gettab_h
gettab_key_table
httpd_security_headers_install
httpd_security_headers_tftpboot
httpd_server_banner_masked
lsdef_a
lsdef_null
lsdef_t
@@ -72,6 +72,9 @@ gettab_H
gettab_err
gettab_h
gettab_key_table
httpd_security_headers_install
httpd_security_headers_tftpboot
httpd_server_banner_masked
lsdef_a
lsdef_null
lsdef_t
@@ -72,6 +72,9 @@ gettab_H
gettab_err
gettab_h
gettab_key_table
httpd_security_headers_install
httpd_security_headers_tftpboot
httpd_server_banner_masked
lsdef_a
lsdef_null
lsdef_t
@@ -48,6 +48,9 @@ gettab_H
gettab_err
gettab_h
gettab_key_table
httpd_security_headers_install
httpd_security_headers_tftpboot
httpd_server_banner_masked
lsdef_a
lsdef_null
lsdef_t
@@ -48,6 +48,9 @@ gettab_H
gettab_err
gettab_h
gettab_key_table
httpd_security_headers_install
httpd_security_headers_tftpboot
httpd_server_banner_masked
lsdef_a
lsdef_null
lsdef_t
+30
View File
@@ -0,0 +1,30 @@
start:httpd_security_headers_install
description:verify xcat.conf sets the security response headers on /install
label:mn_only,ci_test,httpd
cmd:curl -sSI --max-time 15 http://localhost/install/ 2>&1
check:rc==0
check:output=~X-Frame-Options:\s*SAMEORIGIN
check:output=~X-Content-Type-Options:\s*nosniff
check:output=~Content-Security-Policy:\s*script-src
check:output=~X-Permitted-Cross-Domain-Policies:\s*none
end
start:httpd_security_headers_tftpboot
description:verify xcat.conf sets the security response headers on /tftpboot
label:mn_only,ci_test,httpd
cmd:curl -sSI --max-time 15 http://localhost/tftpboot/ 2>&1
check:rc==0
check:output=~X-Frame-Options:\s*SAMEORIGIN
check:output=~X-Content-Type-Options:\s*nosniff
check:output=~Content-Security-Policy:\s*script-src
check:output=~X-Permitted-Cross-Domain-Policies:\s*none
end
start:httpd_server_banner_masked
description:verify ServerTokens Prod masks the Apache version in the Server header
label:mn_only,ci_test,httpd
cmd:curl -sSI --max-time 15 http://localhost/install/ 2>&1
check:rc==0
check:output=~Server:\s*Apache
check:output!~Apache/[0-9]
end
+51
View File
@@ -0,0 +1,51 @@
#!/usr/bin/env perl
use strict;
use warnings;
use File::Spec;
use FindBin;
use Test::More;
my $repo_root = File::Spec->catdir( $FindBin::Bin, '..', '..' );
sub read_file {
my ($relative_path) = @_;
my $path = File::Spec->catfile( $repo_root, split( '/', $relative_path ) );
open( my $fh, '<', $path ) or die "Unable to read $path: $!";
my $contents = do { local $/; <$fh> };
close($fh);
return $contents;
}
my $xcat_spec = read_file('xCAT/xCAT.spec');
like( $xcat_spec, qr{a2enmod headers},
'management RPM enables mod_headers where Apache requires it' );
like( $xcat_spec,
qr{if \[ "\$1" = "1" \]; then.*?xcatconfig -i.*?else.*?xcatconfig -u -V.*?systemctl is-active --quiet "\$apachedaemon".*?systemctl reload "\$apachedaemon".*?/etc/init\.d/\$apachedaemon reload}s,
'management RPM reloads an active Apache service after upgrades' );
like( $xcat_spec, qr{apachedaemon='httpd'.*?apachedaemon='apache2'}s,
'management RPM covers both EL and SUSE Apache service names' );
like( $xcat_spec,
qr{/proc/1/root/\. 2>/dev/null.*?systemctl is-active --quiet "\$apachedaemon"}s,
'management RPM skips service management inside image chroots' );
my $xcatsn_spec = read_file('xCATsn/xCATsn.spec');
like( $xcatsn_spec, qr{a2enmod headers},
'service-node RPM enables mod_headers where Apache requires it' );
like( $xcatsn_spec,
qr{apacheserviceunit='httpd\.service'.*?apacheserviceunit='apache2\.service'}s,
'service-node RPM covers both EL and SUSE Apache service units' );
like( $xcatsn_spec,
qr{# for install or upgrade restart the daemon.*?/etc/init\.d/\$apachedaemon reload.*?systemctl reload \$apacheserviceunit}s,
'service-node RPM reloads Apache after installs and upgrades' );
my $xcat_postinst = read_file('xCAT/debian/postinst');
like( $xcat_postinst, qr{a2enmod -q headers.*?/etc/init\.d/apache2 restart}s,
'management Debian package enables mod_headers before restarting Apache' );
my $xcatsn_postinst = read_file('xCATsn/debian/postinst');
like( $xcatsn_postinst,
qr{a2enmod -q headers.*?/etc/init\.d/\$apachedaemon reload}s,
'service-node Debian package enables mod_headers before reloading Apache' );
done_testing();
+8
View File
@@ -45,6 +45,14 @@ case "$1" in
ln -s -f /etc/apache2/conf-available/xcat.conf.apach24 /etc/apache2/conf-enabled/xcat.conf
# xcat.conf sets security response headers via mod_headers, which is
# not enabled by default on Debian/Ubuntu. Enable it so the headers
# take effect (the directives are wrapped in <IfModule mod_headers.c>
# so a missing module never breaks the apache restart below).
if command -v a2enmod >/dev/null 2>&1; then
a2enmod -q headers >/dev/null 2>&1 || :
fi
/etc/init.d/apache2 restart
# Let rsyslogd perform close of any open files
+27
View File
@@ -225,6 +225,13 @@ then
cp /etc/%httpconfigdir/conf.orig/xcat.conf.apach24 /etc/apache2/conf.d/xcat.conf
fi
# On SUSE apache2, mod_headers is not loaded by default; enable it so the
# security response headers in xcat.conf take effect (a no-op where a2enmod
# is absent, e.g. httpd on EL where mod_headers is already loaded).
if [ -e /etc/apache2/conf.d/xcat.conf ] && command -v a2enmod >/dev/null 2>&1; then
a2enmod headers >/dev/null 2>&1 || :
fi
# Let rsyslogd perform close of any open files
if [ -e /var/run/rsyslogd.pid ]; then
kill -HUP $(</var/run/rsyslogd.pid) >/dev/null 2>&1 || :
@@ -258,6 +265,26 @@ fi
mkdir -p /var/log/xcat
date >> /var/log/xcat/upgrade.log
$RPM_INSTALL_PREFIX0/sbin/xcatconfig -u -V >> /var/log/xcat/upgrade.log 2>&1
# The package replaces xcat.conf before this upgrade path runs. Reload an
# active web server so the new security headers and ServerTokens setting take
# effect immediately, but do not try to manage services while building an
# image in a chroot.
if [ -f "/proc/cmdline" ] && [ "x$(stat -c '%i %d' /)" == "x$(stat -c '%i %d' /proc/1/root/. 2>/dev/null)" ]; then
if [ -e "/etc/redhat-release" ]; then
apachedaemon='httpd'
else
apachedaemon='apache2'
fi
if command -v systemctl >/dev/null 2>&1; then
if systemctl is-active --quiet "$apachedaemon"; then
systemctl reload "$apachedaemon" >/dev/null 2>&1 || :
fi
elif [ -x "/etc/init.d/$apachedaemon" ]; then
/etc/init.d/$apachedaemon reload >/dev/null 2>&1 || :
fi
fi
fi
exit 0
+16 -2
View File
@@ -4,17 +4,31 @@
# http://localhost/xcat-doc/
# Updates to xCAT/xcat.conf should also be made to xCATsn/xcat.conf
#
ServerTokens Prod
AliasMatch ^/install/(.*)$ "/install/$1"
AliasMatch ^/tftpboot/(.*)$ "/tftpboot/$1"
<Directory "/tftpboot">
Options FollowSymLinks Includes MultiViews
Options FollowSymLinks
<IfModule mod_headers.c>
Header always set X-Frame-Options SAMEORIGIN
Header always set X-Content-Type-Options nosniff
Header always set Content-Security-Policy "script-src 'self' 'unsafe-eval'"
Header always set X-Permitted-Cross-Domain-Policies none
</IfModule>
AllowOverride None
Order allow,deny
Allow from all
</Directory>
<Directory "/install">
Options FollowSymLinks Includes MultiViews
Options FollowSymLinks
<IfModule mod_headers.c>
Header always set X-Frame-Options SAMEORIGIN
Header always set X-Content-Type-Options nosniff
Header always set Content-Security-Policy "script-src 'self' 'unsafe-eval'"
Header always set X-Permitted-Cross-Domain-Policies none
</IfModule>
AllowOverride None
Order allow,deny
Allow from all
+16 -2
View File
@@ -4,16 +4,30 @@
# http://localhost/xcat-doc/
# Updates to xCAT/xcat.conf should also be made to xCATsn/xcat.conf
#
ServerTokens Prod
AliasMatch ^/install/(.*)$ "/install/$1"
AliasMatch ^/tftpboot/(.*)$ "/tftpboot/$1"
<Directory "/tftpboot">
Options FollowSymLinks Includes MultiViews
Options FollowSymLinks
<IfModule mod_headers.c>
Header always set X-Frame-Options SAMEORIGIN
Header always set X-Content-Type-Options nosniff
Header always set Content-Security-Policy "script-src 'self' 'unsafe-eval'"
Header always set X-Permitted-Cross-Domain-Policies none
</IfModule>
AllowOverride None
Require all granted
</Directory>
<Directory "/install">
Options FollowSymLinks Includes MultiViews
Options FollowSymLinks
<IfModule mod_headers.c>
Header always set X-Frame-Options SAMEORIGIN
Header always set X-Content-Type-Options nosniff
Header always set Content-Security-Policy "script-src 'self' 'unsafe-eval'"
Header always set X-Permitted-Cross-Domain-Policies none
</IfModule>
AllowOverride None
Require all granted
</Directory>
+8
View File
@@ -56,6 +56,14 @@ case "$1" in
update-rc.d $apachedaemon enable
# xcat.conf sets security response headers via mod_headers, which is not
# enabled by default on Debian/Ubuntu. Enable it so the headers take
# effect (directives are wrapped in <IfModule mod_headers.c> so a missing
# module never breaks the apache reload below).
if command -v a2enmod >/dev/null 2>&1; then
a2enmod -q headers >/dev/null 2>&1 || :
fi
if [ -f "/proc/cmdline" ]; then # prevent running it during install into chroot image
if [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1; then
systemctl start xcatd.service
+8
View File
@@ -169,6 +169,13 @@ if [ -n "$version" ]; then
fi
fi
# On SUSE apache2, mod_headers is not loaded by default; enable it so the
# security response headers in xcat.conf take effect (a no-op where a2enmod
# is absent, e.g. httpd on EL where mod_headers is already loaded).
if [ -e /etc/apache2/conf.d/xcat.conf ] && command -v a2enmod >/dev/null 2>&1; then
a2enmod headers >/dev/null 2>&1 || :
fi
# Let rsyslogd perform close of any open files
if [ -e /var/run/rsyslogd.pid ]; then
@@ -219,6 +226,7 @@ if [ -e "/etc/redhat-release" ]; then
apacheserviceunit='httpd.service'
else # SuSE
apachedaemon='apache2'
apacheserviceunit='apache2.service'
fi
# enable and reload the web server on linux
[ -e "/etc/init.d/$apachedaemon" ] && chkconfig $apachedaemon on
+16 -2
View File
@@ -4,17 +4,31 @@
# http://localhost/xcat-doc/
# Updates to xCAT/xcat.conf should also be made to xCATsn/xcat.conf
#
ServerTokens Prod
AliasMatch ^/install/(.*)$ "/install/$1"
AliasMatch ^/tftpboot/(.*)$ "/tftpboot/$1"
<Directory "/tftpboot">
Options FollowSymLinks Includes MultiViews
Options FollowSymLinks
<IfModule mod_headers.c>
Header always set X-Frame-Options SAMEORIGIN
Header always set X-Content-Type-Options nosniff
Header always set Content-Security-Policy "script-src 'self' 'unsafe-eval'"
Header always set X-Permitted-Cross-Domain-Policies none
</IfModule>
AllowOverride None
Order allow,deny
Allow from all
</Directory>
<Directory "/install">
Options FollowSymLinks Includes MultiViews
Options FollowSymLinks
<IfModule mod_headers.c>
Header always set X-Frame-Options SAMEORIGIN
Header always set X-Content-Type-Options nosniff
Header always set Content-Security-Policy "script-src 'self' 'unsafe-eval'"
Header always set X-Permitted-Cross-Domain-Policies none
</IfModule>
AllowOverride None
Order allow,deny
Allow from all
+16 -2
View File
@@ -4,16 +4,30 @@
# http://localhost/xcat-doc/
# Updates to xCAT/xcat.conf should also be made to xCATsn/xcat.conf
#
ServerTokens Prod
AliasMatch ^/install/(.*)$ "/install/$1"
AliasMatch ^/tftpboot/(.*)$ "/tftpboot/$1"
<Directory "/tftpboot">
Options FollowSymLinks Includes MultiViews
Options FollowSymLinks
<IfModule mod_headers.c>
Header always set X-Frame-Options SAMEORIGIN
Header always set X-Content-Type-Options nosniff
Header always set Content-Security-Policy "script-src 'self' 'unsafe-eval'"
Header always set X-Permitted-Cross-Domain-Policies none
</IfModule>
AllowOverride None
Require all granted
</Directory>
<Directory "/install">
Options FollowSymLinks Includes MultiViews
Options FollowSymLinks
<IfModule mod_headers.c>
Header always set X-Frame-Options SAMEORIGIN
Header always set X-Content-Type-Options nosniff
Header always set Content-Security-Policy "script-src 'self' 'unsafe-eval'"
Header always set X-Permitted-Cross-Domain-Policies none
</IfModule>
AllowOverride None
Require all granted
</Directory>