# Kickstart file for PAW machine # Note: minimum amount of RAM successfully tested for installation: 2048 MiB from network - 1024 MiB from local media # Install with commandline (see below for comments): # elevator=deadline inst.ks=https://dangerous.ovirt.life/hvp-repos/el7/ks/hvp-paw-c7.ks # Note: only one network interface is supported for workstation-type machines, with DHCP available on the connected network # Note: to force custom/fixed nic names add ifname=netN:AA:BB:CC:DD:EE:FF where netN is the desired nic name and AA:BB:CC:DD:EE:FF is the MAC address of the corresponding network interface # Note: alternatively, to force legacy nic names (ethN), add biosdevname=0 net.ifnames=0 # Note: alternatively burn this kickstart into your DVD image and append to default commandline: # elevator=deadline inst.ks=cdrom:/dev/cdrom:/ks/ks.cfg # Note: to access the running installation by SSH (beware of publishing the access informations specified with the sshpw directive below) add the option inst.sshd # Note: to force static nic name-to-MAC mapping add the option hvp_nicmacfix=true # Note: to allow installing on a virtual machine add the option hvp_test_mode=true # Note: to skip installing/configuring local virtualization support irrespective of hardware capabilities add hvp_novirt=true # Note: to skip installing custom versions of Gluster/oVirt/Samba packages add hvp_orthodox=true # Note: to allow installing snapshot/nightly versions of oVirt packages add hvp_ovirt_nightly=true # Note: to force custom host naming add hvp_myname=myhostname where myhostname is the unqualified (ie without domain name part) hostname # Note: to force custom network domain naming add hvp_domainname=mynet.name where mynet.name is the domain name # Note: to force custom AD subdomain naming add hvp_ad_subdomainname=myprefix where myprefix is the subdomain name # Note: to force custom domain action add hvp_joindomain=bool where bool is either "true" (join an AD domain) or "false" (do not join an AD domain) # Note: to force custom domain join OU add hvp_joinou="OU=AAA,OU=BBB" where OU=AAA,OU=BBB is the LDAP name of the target OU (relative to domain root) - make sure to add double quotes around the argument # Note: to force custom domain join username add hvp_joinuser=myjoinadmin where myjoinadmin is the AD domain join username # Note: to force custom domain join password add hvp_joinpwd=myjoinsecret where myjoinsecret is the AD domain join user password # Note: to force custom NTP server names/IPs add hvp_ntpservers=ntp0,ntp1,ntp2,ntp3 where ntpN are the NTP servers fully qualified domain names or IPs (when joining AD this will use the PDC-emulator role holder) # Note: to force custom SMTP relay server name/IP add hvp_smtpserver=smtpname where smtpname is the SMTP server fully qualified domain name or IP (used only on nodes and vms) # Note: to force custom SMTP relay server to use SMTPS add hvp_smtps=true (used only on nodes and vms) # Note: to force custom root password add hvp_rootpwd=mysecret where mysecret is the root user password # Note: to force custom LUKS passphrase add hvp_lukspassphrase=mysupersecret where mysupersecret is the LUKS passphrase # Note: to force custom LUKS additional passphrase add hvp_luksaddpassphrase=mysupersecret2 where mysupersecret2 is the LUKS passphrase # Note: to force custom LUKS Tang servers list add hvp_lukstangservers=TangURL1,TangURL2,... where TangURL1,TangURL2,... is the list of (maximum 7) Tang server URLs # Note: to force custom admin username add hvp_adminname=myadmin where myadmin is the admin username # Note: to force custom admin password add hvp_adminpwd=myothersecret where myothersecret is the admin user password # Note: to force custom email address for notification receiver add hvp_receiver_email=name@domain where name@domain is the email address # Note: to force custom log retention time add hvp_logretention=MMM where MMM is the number of weeks for which the logs should be retained # Note: to force installation files retention add hvp_debug=true # Note: to force custom keyboard layout add hvp_kblayout=cc where cc is the country code # Note: to force custom system language add hvp_language=ii where ii is the language code (enacted only for heresiarch and virtual desktop installations) # Note: to force custom local timezone add hvp_timezone=VV where VV is the timezone specification # Note: to force custom oVirt version add hvp_ovirt_version=OO where OO is the version (either 4.1, 4.2, 4.3 or master) # Note: to force custom Yum retries on failures add hvp_yum_retries=RR where RR is the number of retries # Note: to force custom Yum sleep time on failures add hvp_yum_sleep_time=SS where SS is the number of seconds between retries after each failure # Note: to force custom repo base URL for repo reponame add hvp_reponame_baseurl=HHHHH where HHHHH is the base URL (including variables like $releasever and $basearch) # Note: to force custom repo GPG key URL for repo reponame add hvp_reponame_gpgkey=GGGGG where GGGGG is the GPG key URL # Note: the default behaviour involves inhibiting installation if detecting a virtual machine environment (for security reasons) # Note: the default behaviour involves installing/configuring local virtualization support when virtualization hardware capabilities are detected # Note: the default behaviour involves installing custom versions of Gluster/oVirt/Samba packages # Note: the default behaviour involves ignoring snapshot/nightly versions of oVirt packages # Note: the default behaviour does not register fixed nic name-to-MAC mapping # Note: the default host naming uses the "My Little Pony" character name snails # Note: the default domain name is assumed to be mgmt.private # Note: the default AD subdomain name is assumed to be ad # Note: the default domain action is "false" (do not join an AD domain) # Note: the default domain join OU is empty (do not specify a custom OU during domain join) # Note: the default domain join username is the same as the admin username with the string "paw" prefixed # Note: the default domain join user password is HVP_dem0 # Note: the default NTP server names are assumed to be 0.centos.pool.ntp.org 1.centos.pool.ntp.org 2.centos.pool.ntp.org 3.centos.pool.ntp.org (when joining AD this will use the PDC-emulator role holder) # Note: the default SMTP server name is assumed to be empty and the mail relaying will happen locally # Note: the default SMTP server connection is assumed to be plaintext with STARTTLS # Note: the default root user password is HVP_dem0 # Note: the default LUKS passphrase is HVP_dem0 # Note: the default LUKS additional passphrase is hvpdemo # Note: the default LUKS Tang servers list is empty # Note: the default admin username is hvpadmin # Note: the default admin user password is HVP_dem0 # Note: the default notification email address for receiver is monitoring@localhost # Note: the default log retention time is 312 weeks (6 years) # Note: the default installation files retention policy is "false" (remove all installation files/logs since they could contain security-sensitive details) # Note: the default keyboard layout is us # Note: the default system language is en_US.UTF-8 # Note: the default local timezone is UTC # Note: the default oVirt version is 4.2 # Note: the default number of retries after a Yum failure is 10 # Note: the default sleep time between retries after a Yum failure is 10 seconds # Note: the default repo base URL for each required repo is that which is included into the default .repo file from the latest release package for each repo # Note: the default repo GPG key URL for each required repo is that which is included into the default .repo file from the latest release package for each repo # Note: to work around a known kernel commandline length limitation, all hvp_* parameters above can be omitted and proper default values (overriding the hardcoded ones) can be placed in Bash-syntax variables-definition files placed alongside the kickstart file - the name of the files retrieved and sourced (in the exact order) is: hvp_parameters.sh hvp_parameters_paw.sh hvp_parameters_hh:hh:hh:hh:hh:hh.sh (where hh:hh:hh:hh:hh:hh is the MAC address of the nic used to retrieve the kickstart file) # Perform an installation (as opposed to an "upgrade") install # Avoid asking interactive confirmation for unsupported hardware unsupported_hardware # Uncomment the line below to receive debug messages on a syslog server # logging --host=192.168.229.1 --level=info # Use text mode (as opposed to "cmdline", "graphical" or "vnc") text # Uncomment the line below to automatically reboot at the end of installation # (must be sure that system does not try to loop-install again and again) # Note: this is needed for proper installation automation by means of virt-install reboot # Installation source configuration dynamically generated in pre section below %include /tmp/full-installsource # System localization configuration dynamically generated in pre section below %include /tmp/full-localization # Network interface configuration dynamically generated in pre section below %include /tmp/full-network # Control "First Boot" interactive tool execution # TODO: the following seems to be started anyway even if disabled manually in post section below - see https://bugzilla.redhat.com/show_bug.cgi?id=1213114 firstboot --disable # EULA is implicitly accepted eula --agreed # Do not configure X Windows (as opposed to an "xconfig" line) #skipx # Fail safe X Windows configuration xconfig --defaultdesktop=GNOME --startxonboot # Control automatically enabled/disabled services for OS-supplied packages services --disabled="mdmonitor,multipathd,lm_sensors,iscsid,iscsiuio,fcoe,fcoe-target,lldpad,iptables,ip6tables,ksm,ksmtuned,tuned,libvirtd,libvirt-guests,qpidd,tog-pegasus,cups,portreserve,postfix,nfs,nfs-lock,rpcbind,rpc-idmapd,rpc-gssd,rpc-svcgssd,pcscd,avahi-daemon,network,bluetooth,gpm,vsftpd,vncserver,slapd,dnsmasq,ipmi,ipmievd,nscd,psacct,rdisc,rwhod,saslauthd,smb,nmb,snmptrapd,svnserve,winbind,oddjobd,autofs,wpa_supplicant,kdump,iprdump,iprinit,iprupdate,snmpd" --enabled="firewalld,NetworkManager,NetworkManager-wait-online,ntpdate,chronyd" # Users configuration dynamically generated in pre section below %include /tmp/full-users # Firewall (firewalld) enabled # Note: further configuration performed in post section below firewall --enabled # Configure authentication mode authconfig --enableshadow --passalgo=sha512 # Leave SELinux on (default will be "targeted" mode) selinux --enforcing # Disable kdump %addon com_redhat_kdump --disable %end # Disk configuration dynamically generated in pre section below %include /tmp/full-disk # Packages list - package groups are preceded by an "@" sign - excluded packages by an "-" sign # Note: some virtualization technologies (Parallels, VirtualBox) require gcc, kernel-devel and dkms (from external repo) packages %packages @system-admin-tools @console-internet @core @base @large-systems @performance @network-file-system-client @graphical-admin-tools gdm @x11 xorg-x11-server-Xorg xorg-x11-drivers -gnome-boxes -perl-homedir # Note: the following is needed since ifconfig/route is still required by some software net-tools policycoreutils-python policycoreutils-newrole mcstrans stunnel clevis-dracut -xinetd -ntp # Note: the following seems to be missing by default and we explicitly include it to allow efficient updates deltarpm rdate symlinks dos2unix unix2dos screen minicom telnet ftp tree audit iptraf iptstate device-mapper-multipath lm_sensors OpenIPMI ipmitool hdparm sdparm lsscsi xfsprogs xfsdump firefox nss-tools patch expect ksh ncompress libnl redhat-lsb vim-X11 tigervnc tigervnc-server freerdp xterm -zsh -nmap -xdelta -bluez -bluez-libs -fetchmail -mutt -pam_pkcs11 -coolkey -finger -conman %end # Pre-installation script (run with bash from stage2.img immediately after parsing this kickstart file) %pre ( # Run the entire pre section as a subshell for logging. # Discover exact pre-stage environment echo "PRE env" >> /tmp/pre.out env >> /tmp/pre.out echo "PRE devs" >> /tmp/pre.out ls -l /dev/* >> /tmp/pre.out echo "PRE block" >> /tmp/pre.out ls -l /sys/block/* >> /tmp/pre.out echo "PRE mounts" >> /tmp/pre.out df -h >> /tmp/pre.out echo "PRE progs" >> /tmp/pre.out for pathdir in $(echo "${PATH}" | sed -e 's/:/ /'); do if [ -d "${pathdir}" ]; then ls "${pathdir}"/* >> /tmp/pre.out fi done # A simple regex matching IP addresses IPregex='[0-9]*[.][0-9]*[.][0-9]*[.][0-9]*' # A general IP add/subtract function to allow classless subnets +/- offsets # Note: derived from https://stackoverflow.com/questions/33056385/increment-ip-address-in-a-shell-script # TODO: add support for IPv6 ipmat() { local given_ip=$1 local given_diff=$2 local given_op=$3 # TODO: perform better checking on parameters if [ -z "${given_ip}" -o -z "${given_diff}" -o -z "${given_op}" ]; then echo "" return 255 fi local given_ip_hex=$(printf '%.2X%.2X%.2X%.2X' $(echo "${given_ip}" | sed -e 's/\./ /g')) local given_diff_hex=$(printf '%.8X' "${given_diff}") local result_ip_hex=$(printf '%.8X' $(echo $(( 0x${given_ip_hex} ${given_op} 0x${given_diff_hex} )))) local result_ip=$(printf '%d.%d.%d.%d' $(echo "${result_ip_hex}" | sed -r 's/(..)/0x\1 /g')) echo "${result_ip}" return 0 } # Define all default network data unset test_mode unset nolocalvirt unset my_domain_name unset ad_subdomain_prefix unset domain_join unset domain_join_ou unset domain_join_user unset domain_join_password unset my_name unset my_ntpservers unset luks_passphrase unset root_password unset admin_username unset admin_password unset notification_receiver unset debug_mode unset keyboard_layout unset system_language unset local_timezone unset hvp_repo_baseurl unset hvp_repo_gpgkey # Hardcoded defaults test_mode="false" nolocalvirt="false" declare -A hvp_repo_baseurl declare -A hvp_repo_gpgkey my_domain_name="mgmt.private" ad_subdomain_prefix="ad" domain_join="false" domain_join_ou="" my_name="snails" my_ntpservers="0.centos.pool.ntp.org,1.centos.pool.ntp.org,2.centos.pool.ntp.org,3.centos.pool.ntp.org" luks_passphrase="HVP_dem0" # Note: passwords must meet the AD complexity requirements root_password="HVP_dem0" admin_username="hvpadmin" admin_password="HVP_dem0" domain_join_password="HVP_dem0" keyboard_layout="us" system_language="en_US.UTF-8" local_timezone="UTC" notification_receiver="monitoring@localhost" debug_mode="false" # Detect any configuration fragments and load them into the pre environment # Note: incomplete (no device or filename), BIOS based devices, UUID, file and DHCP methods are unsupported ks_custom_frags="hvp_parameters.sh hvp_parameters_paw.sh" mkdir /tmp/kscfg-pre mkdir /tmp/kscfg-pre/mnt ks_source="$(cat /proc/cmdline | sed -n -e 's/^.*\s*inst\.ks=\(\S*\)\s*.*$/\1/p')" if [ -z "${ks_source}" ]; then # Note: if we are here and no Kickstart has been explicitly specified, then it must have been found by OEMDRV method (needs CentOS >= 7.2) ks_source='hd:LABEL=OEMDRV' fi if [ -n "${ks_source}" ]; then ks_dev="" if echo "${ks_source}" | grep -q '^floppy' ; then # Note: hardcoded device name for floppy disk ks_dev="/dev/fd0" # Note: filesystem type on floppy disk autodetected ks_fstype="*" ks_fsopt="ro" ks_path="$(echo ${ks_source} | awk -F: '{print $2}')" if [ -z "${ks_path}" ]; then ks_path="/ks.cfg" fi ks_dir="$(echo ${ks_path} | sed -e 's%/[^/]*$%%')" elif echo "${ks_source}" | grep -q '^cdrom' ; then # Note: cdrom gets accessed as real device name which must be detected - assuming it is the first removable device # Note: hardcoded possible device names for CD/DVD - should cover all reasonable cases # Note: on RHEL>=6 even IDE/ATAPI devices have SCSI device names for dev in /dev/sd[a-z] /dev/sr[0-9]; do if [ -b "${dev}" ]; then is_removable="$(cat /sys/block/$(basename ${dev})/removable 2>/dev/null)" if [ "${is_removable}" = "1" ]; then ks_dev="${dev}" ks_fstype="iso9660" ks_fsopt="ro" ks_path="$(echo ${ks_source} | awk -F: '{print $2}')" if [ -z "${ks_path}" ]; then ks_path="/ks.cfg" ks_dir="/" else ks_dir="$(echo ${ks_path} | sed -e 's%/[^/]*$%%')" fi break fi fi done elif echo "${ks_source}" | grep -q '^hd:' ; then # Note: blindly extracting device name from Kickstart commandline ks_spec="$(echo ${ks_source} | awk -F: '{print $2}')" ks_dev="/dev/${ks_spec}" # Detect LABEL-based device selection if echo "${ks_spec}" | grep -q '^LABEL=' ; then ks_label="$(echo ${ks_spec} | awk -F= '{print $2}')" if [ -z "${ks_label}" ]; then echo "Invalid definition of Kickstart labeled device" 1>&2 ks_dev="" else ks_dev=/dev/$(lsblk -r -n -o name,label | awk "/\\<$(echo ${ks_label} | sed -e 's%\([./*\\]\)%\\\1%g')\\>/ {print \$1}" | head -1) fi fi # Note: filesystem type on local drive autodetected ks_fstype="*" ks_fsopt="ro" ks_path="$(echo ${ks_source} | awk -F: '{print $3}')" if [ -z "${ks_path}" ]; then ks_path="/ks.cfg" ks_dir="/" else ks_dir="$(echo ${ks_path} | sed -e 's%/[^/]*$%%')" fi elif echo "${ks_source}" | grep -q '^nfs:' ; then # Note: blindly extracting NFS server from Kickstart commandline ks_host="$(echo ${ks_source} | awk -F: '{print $2}')" ks_fstype="nfs" # TODO: support NFS options ks_fsopt="ro,nolock" ks_path="$(echo ${ks_source} | awk -F: '{print $3}')" if [ -z "${ks_path}" ]; then echo "Unable to determine Kickstart NFS source path" 1>&2 ks_dev="" else ks_dev="${ks_host}:$(echo ${ks_path} | sed -e 's%/[^/]*$%%')}" ks_dir="/" fi elif echo "${ks_source}" | egrep -q '^(http|https|ftp):' ; then # Note: blindly extracting URL from Kickstart commandline ks_host="$(echo ${ks_source} | sed -e 's%^.*//%%' -e 's%/.*$%%')" ks_dev="$(echo ${ks_source} | sed -e 's%/[^/]*$%%')" ks_fstype="url" else echo "Unsupported Kickstart source detected" 1>&2 fi if [ -z "${ks_dev}" ]; then echo "Unable to extract Kickstart source - skipping configuration fragments retrieval" 1>&2 else # Note: for network-based kickstart retrieval methods we extract the relevant nic MAC address to get the machine-specific fragment if [ "${ks_fstype}" = "url" -o "${ks_fstype}" = "nfs" ]; then # Note: we detect the nic device name as the one detaining the route towards the host holding the kickstart script # Note: regarding the kickstart host: we assume that if it is not already been given as an IP address then it is a DNS fqdn if ! echo "${ks_host}" | grep -q "${IPregex}" ; then ks_host_ip=$(nslookup "${ks_host}" | tail -n +3 | awk '/^Address/ {print $2}' | head -1) else ks_host_ip="${ks_host}" fi ks_nic=$(ip route get "${ks_host_ip}" | sed -n -e 's/^.*\s\+dev\s\+\(\S\+\)\s\+.*$/\1/p') if [ -f "/sys/class/net/${ks_nic}/address" ]; then ks_custom_frags="${ks_custom_frags} hvp_parameters_$(cat /sys/class/net/${ks_nic}/address).sh" fi fi if [ "${ks_fstype}" = "url" ]; then for custom_frag in ${ks_custom_frags} ; do echo "Attempting network retrieval of ${ks_dev}/${custom_frag}" 1>&2 wget -P /tmp/kscfg-pre "${ks_dev}/${custom_frag}" done else # Note: filesystem type autodetected mount -o ${ks_fsopt} ${ks_dev} /tmp/kscfg-pre/mnt for custom_frag in ${ks_custom_frags} ; do echo "Attempting filesystem retrieval of ${custom_frag}" 1>&2 if [ -f "/tmp/kscfg-pre/mnt${ks_dir}/${custom_frag}" ]; then cp "/tmp/kscfg-pre/mnt${ks_dir}/${custom_frag}" /tmp/kscfg-pre fi done umount /tmp/kscfg-pre/mnt fi fi fi # Load any configuration fragment found, in the proper order # Note: configuration-fragment defaults will override hardcoded defaults # Note: commandline parameters will override configuration-fragment and hardcoded defaults # Note: configuration fragments get executed with full privileges and no further controls beside a bare syntax check: obvious security implications must be taken care of (use HTTPS for network-retrieved kickstart and fragments) pushd /tmp/kscfg-pre for custom_frag in ${ks_custom_frags} ; do if [ -f "${custom_frag}" ]; then # Perform a configuration fragment sanity check before loading bash -n "${custom_frag}" > /dev/null 2>&1 res=$? if [ ${res} -ne 0 ]; then # Report invalid configuration fragment and skip it logger -s -p "local7.err" -t "kickstart-pre" "Skipping invalid remote configuration fragment ${custom_frag}" continue fi source "./${custom_frag}" fi done popd # TODO: perform better consistency check on all commandline-given parameters # Determine test mode given_testmode=$(sed -n -e 's/^.*hvp_test_mode=\(\S*\).*$/\1/p' /proc/cmdline) if echo "${given_testmode}" | egrep -q '^(true|false)$' ; then test_mode="${given_testmode}" fi # Determine root password given_root_password=$(sed -n -e "s/^.*hvp_rootpwd=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_root_password}" ]; then root_password="${given_root_password}" fi # Determine LUKS passphrase given_luks_passphrase=$(sed -n -e "s/^.*hvp_lukspassphrase=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_luks_passphrase}" ]; then if [ "${given_luks_passphrase}" = '""' -o "${given_luks_passphrase}" = "''" ]; then luks_passphrase="" else luks_passphrase="${given_luks_passphrase}" fi elif grep -w -q 'hvp_lukspassphrase=' /proc/cmdline; then luks_passphrase="" fi # Determine admin username given_admin_username=$(sed -n -e "s/^.*hvp_adminname=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_admin_username}" ]; then admin_username="${given_admin_username}" fi # Determine admin password given_admin_password=$(sed -n -e "s/^.*hvp_adminpwd=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_admin_password}" ]; then admin_password="${given_admin_password}" fi # Determine domain join username given_domain_join_user=$(sed -n -e "s/^.*hvp_joinuser=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_domain_join_user}" ]; then domain_join_user="${given_domain_join_user}" fi if [ -z "${domain_join_user}" ]; then domain_join_user="paw${admin_username}" fi # Determine domain join password given_domain_join_password=$(sed -n -e "s/^.*hvp_joinpwd=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_domain_join_password}" ]; then domain_join_password="${given_domain_join_password}" fi # Determine keyboard layout given_keyboard_layout=$(sed -n -e "s/^.*hvp_kblayout=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_keyboard_layout}" ]; then keyboard_layout="${given_keyboard_layout}" fi # Determine system language given_system_language=$(sed -n -e "s/^.*hvp_language=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_system_language}" ]; then system_language="${given_system_language}" fi # Determine local timezone given_local_timezone=$(sed -n -e "s/^.*hvp_timezone=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_local_timezone}" ]; then local_timezone="${given_local_timezone}" fi # Determine notification receiver email address given_receiver_email=$(sed -n -e "s/^.*hvp_receiver_email=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_receiver_email}" ]; then notification_receiver="${given_receiver_email}" fi # Determine installation files retention given_debug_mode=$(sed -n -e 's/^.*hvp_debug=\(\S*\).*$/\1/p' /proc/cmdline) if echo "${given_debug_mode}" | egrep -q '^(true|false)$' ; then debug_mode="${given_debug_mode}" fi # Determine hostname given_hostname=$(sed -n -e 's/^.*hvp_myname=\(\S*\).*$/\1/p' /proc/cmdline) if echo "${given_hostname}" | grep -q '^[[:alnum:]]\+$' ; then my_name="${given_hostname}" fi # Determine domain name given_domainname=$(sed -n -e "s/^.*hvp_domainname=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_domainname}" ]; then my_domain_name="${given_domainname}" fi # Determine AD subdomain name given_ad_subdomainname=$(sed -n -e "s/^.*hvp_ad_subdomainname=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_ad_subdomainname}" ]; then ad_subdomain_prefix="${given_ad_subdomainname}" fi # Determine domain action given_joindomain=$(sed -n -e 's/^.*hvp_joindomain=\(\S*\).*$/\1/p' /proc/cmdline) if echo "${given_joindomain}" | egrep -q '^(true|false)$' ; then domain_join="${given_joindomain}" fi # Determine domain OU given_joinou=$(sed -n -e 's/^.*hvp_joinou="\([^"]*\)".*$/\1/p' /proc/cmdline) if [ -n "${given_joinou}" ]; then if [ "${given_joinou}" = '""' -o "${given_joinou}" = "''" ]; then domain_join_ou="" else domain_join_ou="${given_joinou}" fi elif grep -w -q 'hvp_joinou=' /proc/cmdline; then domain_join_ou="" fi # Determine choice of skipping local virtualization support given_nolocalvirt=$(sed -n -e 's/^.*hvp_novirt=\(\S*\).*$/\1/p' /proc/cmdline) if echo "${given_nolocalvirt}" | egrep -q '^(true|false)$' ; then nolocalvirt="${given_nolocalvirt}" fi if ! egrep -q '^flags.*(vmx|svm)' /proc/cpuinfo ; then nolocalvirt="true" fi # Determine NTP servers addresses given_ntpservers=$(sed -n -e "s/^.*hvp_ntpservers=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_ntpservers}" ]; then my_ntpservers="${given_ntpservers}" fi # Validate test mode # Note: for security reasons, a PAW should be physical (optionally, a regular workstation can be a vm guest inside the PAW) if cat /sys/class/dmi/id/sys_vendor | egrep -q "(Microsoft|VMware|innotek|Parallels|Red.*Hat|oVirt|Xen)" ; then if [ "${test_mode}" != "true" ]; then ( exec < /dev/tty6 > /dev/tty6 chvt 6 echo "" echo "" echo "" echo "" echo "- Virtual platform detected and test mode not requested - halting installation -" while [ ! -f /tmp/i_really_want_to_go_on_and_i_do_not_like_kernel_cmdline ]; do sleep 10 done chvt 1 ) fi fi # Create network setup fragment # Note: device name cannot be easily guessed - either generate network lines dynamically in pre section or use link parameter (if only one nic is present) # Note: we cannot rely on the network device used for kickstart retrieval since it could have been retrieved burned-in from CD or elsewhere (not from network) # Note: using a simple heuristic: first interface found with link up is the external one cat << EOF > /tmp/full-network # Network device configuration - dynamic (DHCP) version (always verify that your nic is supported by install kernel/modules) # Use a "void" configuration to make sure anaconda quickly steps over "onboot=no" devices EOF first_nic_found="false" for nic_name in $(ls /sys/class/net/ 2>/dev/null | egrep -v '^(bonding_masters|lo|sit[0-9])$' | sort); do if [ "${first_nic_found}" = "false" ]; then # Note: the file below will contain 1 for link up, 0 for link down or will result inaccessible for interface disabled if [ "$(cat /sys/class/net/${nic_name}/carrier 2>/dev/null)" = "1" ]; then further_options="--onboot=yes --activate" if [ "${domain_join}" = "true" ]; then further_options="${further_options} --hostname=${my_name}.${ad_subdomain_prefix}.${my_domain_name}" else further_options="${further_options} --hostname=${my_name}.${my_domain_name}" fi first_nic_found="true" else further_options="--onboot=no" fi else further_options="--onboot=no" fi # Single (plain) interface cat <<- EOF >> /tmp/full-network network --device=${nic_name} --bootproto=dhcp ${further_options} EOF done # Create users setup fragment cat << EOF > /tmp/full-users # Use given username and password for SSH access to installation # Note: you must add inst.sshd to installation commandline for the following to have any effect sshpw --username=${admin_username} ${admin_password} --plaintext # Define root password rootpw ${root_password} # Create an unprivileged user # Note: demanded to post section to allow for preconfigured default settings #user --name=${admin_username} --password=${admin_password} --plaintext --gecos=Admin EOF # Prepare users configuration script to be run at first boot mkdir -p /tmp/hvp-users-conf cat << EOF > /tmp/hvp-users-conf/rc.users-setup #!/bin/bash # Create local user for maintenance work # Note: unprivileged user created here to account for default settings useradd -c "Admin" ${admin_username} echo '${admin_password}' | passwd --stdin ${admin_username} # Note: if not joined to AD then administrative access is only local if [ "${domain_join}" != "true" ]; then # Lock root account passwd -l root # Deny root login from SSH # Note: if not joined to AD then no LAPS is in place so there is no point in allowing direct root login sed -i -e 's/^#\\s*PermitRootLogin.*\$/PermitRootLogin no/' /etc/ssh/sshd_config # Create local group for administrators # Note: this group is meant to policy local access to virtualization functions and USBGuard administration groupadd "alldelegatedadmins" # Create local group for PAW administrators # Note: this group is meant to policy local access to sudo use groupadd "pawadmins" usermod -a -G pawadmins ${admin_username} # Allow local PAW admins group liberal use of sudo echo '%pawadmins ALL=(ALL) ALL' > /etc/sudoers.d/administrators chmod 440 /etc/sudoers.d/administrators else # Lock local admin user account # Note: if joined to AD then root access is controlled by LAPS and users access is controlled by GPOs passwd -l ${admin_username} # Allow root login from SSH using password (stored in AD by LAPS) sed -i -e 's/^#\s*PermitRootLogin.*$/PermitRootLogin yes/' /etc/ssh/sshd_config fi systemctl reload sshd # Note: if not joined to AD then all local users (but root) can login # Configure email aliases # Note: root email not redirected to allow all members of the admin group to access it # Divert local notification emails to root account if echo "${notification_receiver}" | grep -q '@localhost\$' ; then alias=\$(echo "${notification_receiver}" | sed -e 's/@localhost\$//') cat <<- EOM >> /etc/aliases # Email alias for server monitoring \${alias}: root EOM newaliases fi EOF # Create localization setup fragment if [ "${keyboard_layout}" != "us" ]; then # TODO: GNOME3 seems not to respect the keyboard layout preference order (US is always the default) - even when removing additional layout xlayouts="'${keyboard_layout}','us'" else xlayouts="'us'" fi cat << EOF > /tmp/full-localization # System language, additional languages can be enabled installing the appropriate packages below lang ${system_language} # Keyboard layout keyboard --vckeymap=${keyboard_layout} --xlayouts=${xlayouts} # Configure time zone (NTP details demanded to post section) timezone ${local_timezone} --isUtc EOF # Create disk setup fragment # TODO: find a better way to detect emulated/VirtIO devices all_devices="$(list-harddrives | egrep -v '^(fd|sr)[[:digit:]]*[[:space:]]' | awk '{print $1}' | sort)" in_use_devices=$(mount | awk '/^\/dev/ {print gensub("/dev/","","g",$1)}') kickstart_device=$(echo "${ks_dev}" | sed -e 's%^/dev/%%') if [ -b /dev/vda ]; then disk_device_name="vda" elif [ -b /dev/xvda ]; then disk_device_name="xvda" else disk_device_name="sda" fi # Determine LUKS setup if [ -n "${luks_passphrase}" ]; then luks_options="--encrypted --passphrase=${luks_passphrase}" else luks_options="" fi cat << EOF > /tmp/full-disk # Simple disk configuration: single SCSI/SATA/VirtIO disk # Initialize partition table (GPT) on selected disk clearpart --drives=${disk_device_name} --all --initlabel --disklabel=gpt # Bootloader placed on MBR, with 3 seconds waiting and with password protection bootloader --location=mbr --timeout=3 --password=${root_password} --boot-drive=${disk_device_name} --driveorder=${disk_device_name} # Ignore further disks ignoredisk --only-use=${disk_device_name} # Automatically create UEFI or BIOS boot partition depending on hardware capabilities reqpart --add-boot # Note: the following uses only the first disk as PV and leaves other disks unused if the first one is sufficiently big, otherwise starts using other disks too part pv.01 --size=64000 --grow ${luks_options} # Create a VG volgroup PAWVG pv.01 # Define swap space logvol swap --vgname=PAWVG --name=swap --fstype=swap --recommended --hibernation # Define further filesystems logvol / --vgname=PAWVG --name=root --size=6000 --grow logvol /var --vgname=PAWVG --name=var --size=2000 logvol /var/cache --vgname=PAWVG --name=var_cache --size=5000 logvol /var/crash --vgname=PAWVG --name=var_crash --size=12000 logvol /var/lib --vgname=PAWVG --name=var_lib --size=10000 --grow logvol /var/log --vgname=PAWVG --name=var_log --size=10000 logvol /var/log/audit --vgname=PAWVG --name=var_log_audit --size=2000 logvol /var/spool --vgname=PAWVG --name=var_spool --size=3000 logvol /var/tmp --vgname=PAWVG --name=var_tmp --size=2000 --fsoptions=noexec,nosuid,nodev logvol /home --vgname=PAWVG --name=home --size=1000 --grow --fsoptions=noexec,nosuid,nodev logvol /tmp --vgname=PAWVG --name=tmp --size=2000 --fsoptions=noexec,nosuid,nodev EOF # Clean up disks from any previous LVM setup # Note: it seems that simply zeroing out below is not enough vgscan -v for vg_name in $(vgs --noheadings -o vg_name); do vgremove -v -y "${vg_name}" udevadm settle --timeout=5 done for pv_name in $(pvs --noheadings -o pv_name); do pvremove -v -ff -y "${pv_name}" udevadm settle --timeout=5 done # Clean up disks from any previous software-RAID (Linux or BIOS based) setup # TODO: this does not work on CentOS7 (it would need some sort of late disk-status refresh induced inside anaconda) - workaround by manually zeroing-out the first 10 MiBs from a rescue boot before starting the install process (or simply restarting when installation stops/hangs at storage setup) # Note: skipping this on a virtual machine to avoid inflating a thin-provisioned virtual disk # Note: dmidecode command may no longer be available in pre environment if cat /sys/class/dmi/id/sys_vendor | egrep -q -v "(Microsoft|VMware|innotek|Parallels|Red.*Hat|oVirt|Xen)" ; then # Note: resetting all disk devices since leftover configurations may interfer with installation and/or setup later on for current_device in ${all_devices}; do # Skipping devices in active use if [ "${current_device}" = "${kickstart_device}" ] || echo "${in_use_devices}" | grep -q -w "${current_device}" ; then continue fi dd if=/dev/zero of=/dev/${current_device} bs=1M count=10 dd if=/dev/zero of=/dev/${current_device} bs=1M count=10 seek=$(($(blockdev --getsize64 /dev/${current_device}) / (1024 * 1024) - 10)) done partprobe udevadm settle --timeout=5 fi # Create install source selection fragment # Note: we use a non-local (hd:) stage2 location as indicator of network boot given_stage2=$(sed -n -e 's/^.*inst\.stage2=\(\S*\).*$/\1/p' /proc/cmdline) # Define proper network source os_baseurl="http://mirror.centos.org/centos/7/os/x86_64" # Prefer custom OS repo URL, if any given_os_baseurl=$(sed -n -e 's/^.*hvp_base_baseurl=\(\S*\).*$/\1/p' /proc/cmdline) if [ -n "${given_os_baseurl}" ]; then # Correctly detect an empty (disabled) repo URL if [ "${given_os_baseurl}" = '""' -o "${given_os_baseurl}" = "''" ]; then unset hvp_repo_baseurl['base'] else hvp_repo_baseurl['base']="${given_os_baseurl}" fi elif grep -w -q "hvp_base_baseurl=" /proc/cmdline; then unset hvp_repo_baseurl['base'] fi if [ -n "${hvp_repo_baseurl['base']}" ]; then os_baseurl="${hvp_repo_baseurl['base']}" fi if echo "${given_stage2}" | grep -q '^hd:' ; then # Detect use of NetInstall media if [ -d /run/install/repo/repodata ]; then # Note: we know that the local stage2 comes from a Full/Minimal image (Packages repo included) cat <<- EOF > /tmp/full-installsource # Use the inserted optical media as in: cdrom # alternatively specify a NFS network share as in: # nfs --opts=nolock --server NfsFqdnServerName --dir /path/to/CentOS/base/dir/copied/from/DVD/media # or an HTTP/FTP area as in: # url --url http://mirror.centos.org/centos/7/os/x86_64 # Explicitly list further repositories #repo --name="Local-Media" --baseurl=cdrom:sr0 --cost=1001 # Note: network repo added anyway to avoid installation failures when using a Minimal image repo --name="CentOS-Mirror" --baseurl=${os_baseurl} --cost=1001 EOF else # Note: since we detected use of NetInstall media (no local repo) we directly use a network install source cat <<- EOF > /tmp/full-installsource # Specify a NFS network share as in: # nfs --opts=nolock --server NfsFqdnServerName --dir /path/to/CentOS/base/dir/copied/from/DVD/media # or an HTTP/FTP area as in: url --url ${os_baseurl} # alternatively use the inserted optical media as in: # cdrom EOF fi else # Note: we assume that a remote stage2 has been copied preserving the default Full/Minimal image structure # TODO: we assume a HTTP/FTP area - add support for NFS cat <<- EOF > /tmp/full-installsource # Specify a NFS network share as in: # nfs --opts=nolock --server NfsFqdnServerName --dir /path/to/CentOS/base/dir/copied/from/DVD/media # or an HTTP/FTP area as in: url --url ${given_stage2} # alternatively use the inserted optical media as in: # cdrom # Explicitly list further repositories # Note: network repo added anyway to avoid installation failures when a Minimal image has been copied repo --name="CentOS-Mirror" --baseurl=${os_baseurl} --cost=1001 EOF fi # Prepare NTPdate and Chrony configuration fragments to be appended later on below mkdir -p /tmp/hvp-ntpd-conf pushd /tmp/hvp-ntpd-conf if [ "${domain_join}" = "true" ]; then # Make sure to sync also with the proper time reference (emulate Windows behaviour, using as reference the AD domain name to get back the DC holding the PDC emulator FSMO role) ntp_server="${ad_subdomain_prefix}.${my_domain_name}" echo "${ntp_server}" > step-tickers cat <<- EOF > chrony.conf server ${ntp_server} iburst EOF fi # Note: since this could be a laptop, unconditionally add also generic time reference servers for server in $(echo "${my_ntpservers}" | sed -e 's/,/ /g'); do echo "${server}" >> step-tickers echo "server ${server} iburst" >> chrony.conf done popd # Prepare TCP wrappers custom lines to be appended later on # Note: current logic is: only SSH is allowed (must be manually enabled in systemd and firewalld too) mkdir -p /tmp/hvp-tcp_wrappers-conf cat << EOF > /tmp/hvp-tcp_wrappers-conf/hosts.allow sshd: ALL EOF # TODO: Create virtual guest setup script if [ "${nolocalvirt}" != "true" ]; then mkdir -p /tmp/hvp-guest-setup pushd /tmp/hvp-guest-setup cat <<- EOF > rc.guest-setup #!/bin/bash # TODO: create vm from hvp-wks-c7.ks kickstart exit 0 EOF popd fi # Create AD domain joining script if [ "${domain_join}" = "true" ]; then mkdir -p /tmp/hvp-domain-join pushd /tmp/hvp-domain-join realm_name=$(echo ${ad_subdomain_prefix}.${my_domain_name} | awk '{print toupper($0)}') if [ -n "${domain_join_ou}" ]; then join_ou_option="--computer-ou=OU='${domain_join_ou}'" else join_ou_option="" fi cat <<- EOF > rc.domain-join #!/bin/bash # Setup krb5.conf properly sed -i -e "s/^\\\\(\\\\s*\\\\)\\\\(dns_lookup_realm\\\\s*=.*\\\\)\\$/\\\\1\\\\2\n\\\\1dns_lookup_kdc = true\\\\n\\\\1default_realm = ${realm_name}/" /etc/krb5.conf # Note: since on a PAW will be allowed to login only administrative accounts with the sensitive attribute, the Kerberos configuration must specify the non-forwardable option otherwise logons will fail sed -i -e "/forwardable/s/true/false/" /etc/krb5.conf # Perform Kerberos authentication to allow unattended join below # Note: since domain join uses and administrative account with the sensitive attribute, the preliminary kinit must specify the non-forwardable option otherwise it fails cat << EOM | expect -f - set force_conservative 1 if {\\\$force_conservative} { set send_slow {1 .1} proc send {ignore arg} { sleep .1 exp_send -s -- \\\$arg } } set timeout -1 spawn "kinit" "-F" "${domain_join_user}@${realm_name}" match_max 100000 expect -re "Password for.*:.*\\\$" send -- "${domain_join_password}\\\\r" expect eof EOM res=\$? if [ \${res} -ne 0 ]; then # Report script ending logger -s -p "local7.err" -t "rc.domain-join" "Exiting join (failed Kerberos authentication with join credentials)" exit \${res} else klist realm join -v --unattended --os-name=\$(lsb_release -si) --os-version=\$(lsb_release -sr) ${join_ou_option} --automatic-id-mapping=no ${ad_subdomain_prefix}.${my_domain_name} # Note: no further SPNs needed on a PAW kdestroy # Limit access from AD accounts # Note: the following nested document-here does not need the <<- notation since document-here must have only tabs in front and the outer one will remove all making this block left-aligned cat << EOM >> /etc/sssd/sssd.conf ad_gpo_access_control = enforcing EOM # Complete SSSD configuration for AD # Note: GDM login fails otherwise as per https://bugzilla.redhat.com/show_bug.cgi?id=1231833 sed -i -e '/services/s/\$/, pac/' -e '/^use_fully_qualified_names/s/True/False/' -e '/^fallback_homedir/s>%u@%d>local/%u>' /etc/sssd/sssd.conf # Note: the following nested document-here does not need the <<- notation since document-here must have only tabs in front and the outer one will remove all making this block left-aligned cat << EOM >> /etc/sssd/sssd.conf auto_private_groups = True auth_provider = ad chpass_provider = ad EOM # Note: no autofs needed on a PAW # Note: no LDAP/AD integrated sudo on a PAW (use LAPS) # Note: no SSO for SSH on a PAW # Enable LAPS current_ad_dc_uris=\$(adcli info ${ad_subdomain_prefix}.${my_domain_name} | awk '/^domain-controllers/ { \$1 = ""; \$2 = ""; print \$0 }') cp -a /etc/laps/laps.conf.example /etc/laps/laps.conf cp -a /etc/laps/lapsldap.conf.example /etc/laps/lapsldap.conf sed -i -e '/^LAPS_USER=/s/toor/root/' /etc/laps/laps.conf sed -i -e "/^URI/s%^.*\\\$%URI \$(for server in \${current_ad_dc_uris}; do echo -n " ldap://\${server}"; done)%" -e '/^BASE/s/^.*\$/BASE dc=$(echo "${ad_subdomain_prefix}.${my_domain_name}" | sed -e "s/[.]/,dc=/g")/' /etc/laps/lapsldap.conf # TODO: LAPS default options do not work - remove when fixed upstream sed -i -e 's/ -O maxssf=0//g' -e 's/kinit-host/kinit-host.disabled/g' /etc/laps/laps.conf # TODO: LAPS package does not reflect its dependency package bgscripts-core actual filesystem layout - remove when fixed upstream ln -s /usr/libexec/bgscripts/framework.sh /usr/share/bgscripts/ # Note: we need to initialize the local LAPS process by manually forcing the first random password change /usr/share/laps/laps.sh -f fi EOF popd fi # Create installation cleanup script mkdir -p /tmp/hvp-install-cleanup pushd /tmp/hvp-install-cleanup cat << EOF > rc.install-cleanup #!/bin/bash # Cleanup installation-related files and logs which could contain security sensitive data if [ "${debug_mode}" != "true" ]; then sensitive_dirs="/root/etc /root/log /var/log/anaconda" for dir in \${sensitive_dirs}; do if [ -d "\${dir}" ]; then find "\${dir}" -type f -delete fi done sensitive_files="/etc/rc.d/rc.*-*" for file in \${sensitive_files}; do /bin/rm -f "\${file}" done fi EOF popd ) 2>&1 | tee /tmp/kickstart_pre.log %end # Post-installation script (run with bash from installation image at the end of installation) %post --nochroot --log /dev/console ( # Run the entire post section as a subshell for logging purposes. # Copy configuration parameters files (generated in pre section above) into installed system (to be loaded during chrooted post section below) mkdir -p ${ANA_INSTALL_PATH}/root/etc/kscfg-pre for custom_frag in /tmp/kscfg-pre/*.sh ; do if [ -f "${custom_frag}" ]; then cp "${custom_frag}" ${ANA_INSTALL_PATH}/root/etc/kscfg-pre/ fi done ) 2>&1 | tee /tmp/kickstart_post_0.log %end # Post-installation script (run with bash from chroot after the first post section) # Note: console logging to support commandline virt-install invocation %post --log /dev/console ( # Run the entire post section as a subshell for logging purposes. script_version="2020100901" # Report kickstart version for reference purposes logger -s -p "local7.info" -t "kickstart-post" "Kickstarting for $(cat /etc/system-release) - version ${script_version}" # Report kernel commandline for reference purposes logger -s -p "local7.info" -t "kickstart-post" "Kickstarting with kernel commandline: $(cat /proc/cmdline)" # Note: NetworkManager correctly updates /etc/resolv.conf inside the installation root even when in DHCP mode # Note: no need to explicitly set machine time with newer systemd/chrony installation environment # Force sane language defaults for safe command output parsing export LANG=C LC_ALL=C # Set the hostname for apps that need it # Note: hostnamectl would not work inside the installation chroot export HOSTNAME=$(cat /etc/hostname) hostname ${HOSTNAME} # Set the homedir for apps that need it export HOME="/root" # Discover exact post-stage environment echo "POST env" >> /tmp/post.out env >> /tmp/post.out echo "POST devs" >> /tmp/post.out ls -l /dev/* >> /tmp/post.out echo "POST block" >> /tmp/post.out ls -l /sys/block/* >> /tmp/post.out echo "POST mounts" >> /tmp/post.out df -h >> /tmp/post.out echo "POST progs" >> /tmp/post.out for pathdir in $(echo "${PATH}" | sed -e 's/:/ /'); do if [ -d "${pathdir}" ]; then ls "${pathdir}"/* >> /tmp/post.out fi done echo "POST resolv.conf" >> /tmp/post.out cat /etc/resolv.conf >> /tmp/post.out echo "POST hosts" >> /tmp/post.out cat /etc/hosts >> /tmp/post.out # Hardcoded defaults unset nicmacfix unset luks_passphrase unset luks_passphrase2 unset luks_tangservers unset nolocalvirt unset orthodox_mode unset ovirt_nightly_mode unset ovirt_version unset my_smtpserver unset use_smtps unset notification_receiver unset yum_sleep_time unset yum_retries unset custom_yum_conf unset hvp_repo_baseurl unset hvp_repo_gpgkey unset log_retention_weeks # Define associative arrays declare -A hvp_repo_baseurl declare -A hvp_repo_gpgkey my_smtpserver="" use_smtps="false" luks_passphrase="HVP_dem0" luks_passphrase2="hvpdemo" declare -a luks_tangservers nicmacfix="false" nolocalvirt="false" orthodox_mode="false" ovirt_nightly_mode="false" ovirt_version="4.2" yum_sleep_time="10" yum_retries="10" custom_yum_conf="false" notification_receiver="monitoring@localhost" log_retention_weeks="312" # A wrapper for Yum to make it more robust against network/mirror failures yum() { local result local retries_left /usr/bin/yum "$@" result=$? retries_left=${yum_retries} while [ ${result} -ne 0 -a ${retries_left} -gt 0 ]; do sleep ${yum_sleep_time} echo "Retrying yum operation (${retries_left} retries left at $(date '+%Y-%m-%d %H:%M:%S')) after failure (exit code ${result})" 1>&2 # Note: it seems that NetworkManager may break down if updated inside chroot - attempting workaround here nmcli dev nmcli connection nmcli connection reload nmcli dev nmcli connection # Note: adding resolution/ping of some well-known public hosts to force wake-up of buggy DNS/gateway implementations (VMware Workstation 12 suspected) for target in www.google.com www.centos.org mirrorlist.centos.org ; do /bin/nslookup "${target}" /bin/ping -c 4 "${target}" done # Note: adding a complete cleanup before retrying /usr/bin/yum clean all /usr/bin/yum "$@" result=$? retries_left=$((retries_left - 1)) done return ${result} } # Load configuration parameters files (generated in pre section above) ks_custom_frags="hvp_parameters.sh hvp_parameters_paw.sh hvp_parameters_*:*.sh" pushd /root/etc/kscfg-pre for custom_frag in ${ks_custom_frags} ; do if [ -f "${custom_frag}" ]; then # Perform a configuration fragment sanity check before loading bash -n "${custom_frag}" > /dev/null 2>&1 res=$? if [ ${res} -ne 0 ]; then # Report invalid configuration fragment and skip it logger -s -p "local7.err" -t "kickstart-post" "Skipping invalid remote configuration fragment ${custom_frag}" continue fi source "./${custom_frag}" fi done popd # Determine choice of nic MAC fixed assignment given_nicmacfix=$(sed -n -e 's/^.*hvp_nicmacfix=\(\S*\).*$/\1/p' /proc/cmdline) if echo "${given_nicmacfix}" | egrep -q '^(true|false)$' ; then nicmacfix="${given_nicmacfix}" fi # Determine choice of skipping local virtualization support given_nolocalvirt=$(sed -n -e 's/^.*hvp_novirt=\(\S*\).*$/\1/p' /proc/cmdline) if echo "${given_nolocalvirt}" | egrep -q '^(true|false)$' ; then nolocalvirt="${given_nolocalvirt}" fi if ! egrep -q '^flags.*(vmx|svm)' /proc/cpuinfo ; then nolocalvirt="true" fi # Determine choice of skipping custom packages installation given_orthodox=$(sed -n -e 's/^.*hvp_orthodox=\(\S*\).*$/\1/p' /proc/cmdline) if echo "${given_orthodox}" | egrep -q '^(true|false)$' ; then orthodox_mode="${given_orthodox}" fi # Determine choice of allowing snapshot/nightly oVirt packages installation given_nightly=$(sed -n -e 's/^.*hvp_ovirt_nightly=\(\S*\).*$/\1/p' /proc/cmdline) if echo "${given_nightly}" | egrep -q '^(true|false)$' ; then ovirt_nightly_mode="${given_nightly}" fi # Determine oVirt version given_ovirt_version=$(sed -n -e "s/^.*hvp_ovirt_version=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_ovirt_version}" ]; then ovirt_version="${given_ovirt_version}" fi # Determine LUKS passphrase given_luks_passphrase=$(sed -n -e "s/^.*hvp_lukspassphrase=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_luks_passphrase}" ]; then if [ "${given_luks_passphrase}" = '""' -o "${given_luks_passphrase}" = "''" ]; then luks_passphrase="" else luks_passphrase="${given_luks_passphrase}" fi elif grep -w -q 'hvp_lukspassphrase=' /proc/cmdline; then luks_passphrase="" fi # Determine LUKS additional passphrase given_luks_passphrase2=$(sed -n -e "s/^.*hvp_luksaddpassphrase=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_luks_passphrase2}" ]; then if [ "${given_luks_passphrase2}" = '""' -o "${given_luks_passphrase2}" = "''" ]; then luks_passphrase2="" else luks_passphrase2="${given_luks_passphrase2}" fi elif grep -w -q 'hvp_luksaddpassphrase=' /proc/cmdline; then luks_passphrase2="" fi # Determine number of weeks for log retention given_log_retention=$(sed -n -e 's/^.*hvp_logretention=\(\S*\).*$/\1/p' /proc/cmdline) if echo "${given_log_retention}" | grep -q '^[[:digit:]]\+$' ; then log_retention_weeks="${given_log_retention}" fi # Determine number of Yum retries on failure given_yum_retries=$(sed -n -e 's/^.*hvp_yum_retries=\(\S*\).*$/\1/p' /proc/cmdline) if echo "${given_yum_retries}" | grep -q '^[[:digit:]]\+$' ; then yum_retries="${given_yum_retries}" fi # Determine sleep time between Yum retries on failure given_yum_sleep_time=$(sed -n -e 's/^.*hvp_yum_sleep_time=\(\S*\).*$/\1/p' /proc/cmdline) if echo "${given_yum_sleep_time}" | grep -q '^[[:digit:]]\+$' ; then yum_sleep_time="${given_yum_sleep_time}" fi # Determine custom URLs for repositories and GPG keys for repo_name in $(egrep -o 'hvp_[^=]*_(baseurl|gpgkey)' /proc/cmdline | sed -e 's/^hvp_//' -e 's/_baseurl$//' -e 's/_gpgkey$//' | sort -u); do # Take URLs from kernel commandline given_repo_baseurl=$(sed -n -e "s/^.*hvp_${repo_name}_baseurl=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_repo_baseurl}" ]; then # Correctly detect an empty (disabled) repo URL if [ "${given_repo_baseurl}" = '""' -o "${given_repo_baseurl}" = "''" ]; then unset hvp_repo_baseurl[${repo_name}] else hvp_repo_baseurl[${repo_name}]="${given_repo_baseurl}" fi elif grep -w -q "hvp_${repo_name}_baseurl=" /proc/cmdline; then unset hvp_repo_baseurl[${repo_name}] fi given_repo_gpgkey=$(sed -n -e "s/^.*hvp_${repo_name}_gpgkey=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_repo_gpgkey}" ]; then # Correctly detect an empty (disabled) gpgkey URL if [ "${given_repo_gpgkey}" = '""' -o "${given_repo_gpgkey}" = "''" ]; then unset hvp_repo_gpgkey[${repo_name}] else hvp_repo_gpgkey[${repo_name}]="${given_repo_gpgkey}" fi elif grep -w -q "hvp_${repo_name}_gpgkey=" /proc/cmdline; then unset hvp_repo_gpgkey[${repo_name}] fi done # Verify whether a custom conf has been established (either from commandline parsing or from parameter configuration files) url_count="${#hvp_repo_baseurl[@]}" key_count="${#hvp_repo_gpgkey[@]}" ref_count=$((url_count + key_count)) if [ "${ref_count}" -gt 1 ]; then custom_yum_conf="true" fi # Determine notification receiver email address given_receiver_email=$(sed -n -e "s/^.*hvp_receiver_email=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_receiver_email}" ]; then notification_receiver="${given_receiver_email}" fi # Determine SMTP server address given_smtpserver=$(sed -n -e "s/^.*hvp_smtpserver=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_smtpserver}" ]; then my_smtpserver="${given_smtpserver}" fi # Determine choice of forcing SMTPS given_smtps=$(sed -n -e 's/^.*hvp_smtps=\(\S*\).*$/\1/p' /proc/cmdline) if echo "${given_smtps}" | egrep -q '^(true|false)$' ; then use_smtps="${given_smtps}" fi # Determine LUKS Tang servers list given_luks_tangservers=$(sed -n -e "s/^.*hvp_lukstangservers=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_luks_tangservers}" ]; then if [ "${given_luks_tangservers}" = '""' -o "${given_luks_tangservers}" = "''" ] || grep -q -w 'hvp_lukstangservers=' /proc/cmdline ; then unset luks_tangservers declare -a luks_tangservers else i="0" for tang_url in $(echo "${luks_tangservers}" | sed -e 's/,/ /g'); do luks_tangservers[${i}]="${tang_url}" i="$((${i} + 1))" done fi fi # Create /dev/root symlink for grubby (must differentiate for use of LVM or MD based "/") # TODO: Open a Bugzilla notification # TODO: remove when grubby gets fixed mp=$(grep -w "/" /etc/fstab | sed -e 's/ .*//') if echo "$mp" | grep -q "^UUID=" then uuid=$(echo "$mp" | sed -e 's/UUID=//') rootdisk=$(blkid -U $uuid) elif echo "$mp" | grep -q "^/dev/" then rootdisk=$mp fi ln -sf $rootdisk /dev/root # Correctly initialize YUM cache to avoid 404 errors # Note: following advice in https://access.redhat.com/articles/1320623 # TODO: remove when fixed upstream rm -rf /var/cache/yum/* yum --enablerepo '*' clean all # Comment out mirrorlist directives and uncomment the baseurl ones when using custom URLs for repos # Note: done here to cater for those repos already installed by default if [ "${custom_yum_conf}" = "true" ]; then for repofile in /etc/yum.repos.d/*.repo; do if egrep -q '^(mirrorlist|metalink)' "${repofile}"; then sed -i -e 's/^mirrorlist/#mirrorlist/g' "${repofile}" sed -i -e 's/^metalink/#metalink/g' "${repofile}" sed -i -e 's/^#baseurl/baseurl/g' "${repofile}" fi done # Disable fastestmirror yum plugin too sed -i -e 's/^enabled.*/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf # Allow specifying custom base URLs for repositories and GPG keys # Note: done here to cater for those repos already installed by default for repo_name in $(yum-config-manager --enablerepo '*' | grep '\[.*\]' | tr -d '[]' | grep -v -w 'main'); do repo_baseurl="${hvp_repo_baseurl[${repo_name}]}" repo_gpgkey="${hvp_repo_gpgkey[${repo_name}]}" # Force any custom URLs if [ -n "${repo_baseurl}" ]; then yum-config-manager --save --setopt="${repo_name}.baseurl=${repo_baseurl}" > /dev/null fi if [ -n "${repo_gpgkey}" ]; then yum-config-manager --save --setopt="${repo_name}.gpgkey=${repo_gpgkey}" > /dev/null fi done fi # Add YUM priorities plugin yum -y install yum-plugin-priorities # Add support for CentOS CR repository (to allow up-to-date upgrade later) # Note: a partially populated CR repo may introduce dependency-related errors - better leave this to post-installation manual choices #yum-config-manager --enable cr > /dev/null # Add HVP custom repo # Define proper network source hvp_baseurl="https://dangerous.ovirt.life/hvp-repos/el$(rpm -q --queryformat '%{version}' centos-release)/hvp/" # Prefer custom HVP repo URL, if any if [ -n "${hvp_repo_baseurl['hvp']}" ]; then hvp_baseurl=$(echo "${hvp_repo_baseurl['hvp']}" | sed -e 's/\$releasever/'$(rpm -q --queryformat '%{version}' centos-release)'/g' -e 's/\$basearch/'$(uname -m)'/g') fi yum -y --nogpgcheck install ${hvp_baseurl}/hvp-release-latest.noarch.rpm # If not explicitly denied, make sure that we prefer HVP own rebuild repos # Note: HVP RHGS latest packages are newer but get rid of Python2 subpackages and so inhibit installation of other dependent packages - enabling only for ansible packages if [ "${orthodox_mode}" = "false" ]; then yum-config-manager --enable hvp-rhv-rebuild > /dev/null yum-config-manager --save --setopt='hvp-rhv-rebuild.priority=50' > /dev/null yum-config-manager --enable hvp-rhgs-rebuild > /dev/null yum-config-manager --save --setopt 'hvp-rhgs-rebuild.includepkgs=gluster-ansible*' > /dev/null yum-config-manager --enable hvp-ansible-rebuild > /dev/null yum-config-manager --save --setopt='hvp-ansible-rebuild.priority=50' > /dev/null else # Note: HVP RHGS rebuild must be enabled anyway to allow access to otherwise unavailable packages yum-config-manager --enable hvp-rhgs-rebuild > /dev/null yum-config-manager --save --setopt 'hvp-rhgs-rebuild.includepkgs=gluster-ansible*' > /dev/null fi # Comment out mirrorlist directives and uncomment the baseurl ones when using custom URLs for repos if [ "${custom_yum_conf}" = "true" ]; then for repofile in /etc/yum.repos.d/*.repo; do if egrep -q '^(mirrorlist|metalink)' "${repofile}"; then sed -i -e 's/^mirrorlist/#mirrorlist/g' "${repofile}" sed -i -e 's/^metalink/#metalink/g' "${repofile}" sed -i -e 's/^#baseurl/baseurl/g' "${repofile}" fi done # Allow specifying custom base URLs for repositories and GPG keys # Note: done here to cater for those repos installed above for repo_name in $(yum-config-manager --enablerepo '*' | grep '\[.*\]' | tr -d '[]' | grep -v -w 'main'); do repo_baseurl="${hvp_repo_baseurl[${repo_name}]}" repo_gpgkey="${hvp_repo_gpgkey[${repo_name}]}" # Force any custom URLs if [ -n "${repo_baseurl}" ]; then yum-config-manager --save --setopt="${repo_name}.baseurl=${repo_baseurl}" > /dev/null fi if [ -n "${repo_gpgkey}" ]; then yum-config-manager --save --setopt="${repo_name}.gpgkey=${repo_gpgkey}" > /dev/null fi done fi # Add EPEL repository definition yum -y install epel-release # Comment out mirrorlist directives and uncomment the baseurl ones when using custom URLs for repos if [ "${custom_yum_conf}" = "true" ]; then for repofile in /etc/yum.repos.d/*.repo; do if egrep -q '^(mirrorlist|metalink)' "${repofile}"; then sed -i -e 's/^mirrorlist/#mirrorlist/g' "${repofile}" sed -i -e 's/^metalink/#metalink/g' "${repofile}" sed -i -e 's/^#baseurl/baseurl/g' "${repofile}" fi done # Allow specifying custom base URLs for repositories and GPG keys # Note: done here to cater for those repos installed above for repo_name in $(yum-config-manager --enablerepo '*' | grep '\[.*\]' | tr -d '[]' | grep -v -w 'main'); do repo_baseurl="${hvp_repo_baseurl[${repo_name}]}" repo_gpgkey="${hvp_repo_gpgkey[${repo_name}]}" # Force any custom URLs if [ -n "${repo_baseurl}" ]; then yum-config-manager --save --setopt="${repo_name}.baseurl=${repo_baseurl}" > /dev/null fi if [ -n "${repo_gpgkey}" ]; then yum-config-manager --save --setopt="${repo_name}.gpgkey=${repo_gpgkey}" > /dev/null fi done fi # Add oVirt repository definition ovirt_release_package_suffix=$(echo "${ovirt_version}" | sed -e 's/[.]//g') if [ "${ovirt_release_package_suffix}" = "master" ]; then ovirt_release_package_suffix="-master" fi # Define proper network source ovirt_baseurl="http://resources.ovirt.org/pub/yum-repo/" # Prefer custom oVirt repo URL, if any if [ -n "${hvp_repo_baseurl[ovirt-${ovirt_version}]}" ]; then ovirt_baseurl=$(echo "${hvp_repo_baseurl[ovirt-${ovirt_version}]}" | sed -e 's/\$releasever/'$(rpm -q --queryformat '%{version}' centos-release)'/g' -e 's/\$basearch/'$(uname -m)'/g') fi yum -y install ${ovirt_baseurl}ovirt-release${ovirt_release_package_suffix}.rpm # If explicitly allowed, make sure that we use oVirt snapshot/nightly repos # Note: when nightly mode gets enabled we assume that we are late in the selected-oVirt-version lifecycle and some repositories and release packages may have disappeared - working around here if [ "${ovirt_nightly_mode}" = "true" ]; then # Marking CentOS-hosted repositories as skip_if_unavailable for repo_name in $(grep -o '\[ovirt-.*centos.*\]' /etc/yum.repos.d/ovirt-*-dependencies.repo | tr -d '[]'); do yum-config-manager --save --setopt="${repo_name}.skip_if_unavailable=1" > /dev/null done # Manually add snapshot repositories # Note: adding these manually since the release package may have disappeared # Note: adding skip_if_unavailable since the repos too seem to disappear after a while cat <<- EOF > "/etc/yum.repos.d/ovirt-${ovirt_version}-snapshot.repo" [ovirt-${ovirt_version}-snapshot] name=oVirt ${ovirt_version} - Nightly snapshot baseurl=https://resources.ovirt.org/pub/ovirt-${ovirt_version}-snapshot/rpm/el\$releasever/ gpgcheck=0 enabled=1 skip_if_unavailable=1 [ovirt-${ovirt_version}-snapshot-static] name=oVirt ${ovirt_version} - Nightly snapshot static baseurl=https://resources.ovirt.org/pub/ovirt-${ovirt_version}-snapshot-static/rpm/el\$releasever/ gpgcheck=0 enabled=1 skip_if_unavailable=1 EOF chmod 644 "/etc/yum.repos.d/ovirt-${ovirt_version}-snapshot.repo" fi # Comment out mirrorlist directives and uncomment the baseurl ones when using custom URLs for repos if [ "${custom_yum_conf}" = "true" ]; then for repofile in /etc/yum.repos.d/*.repo; do if egrep -q '^(mirrorlist|metalink)' "${repofile}"; then sed -i -e 's/^mirrorlist/#mirrorlist/g' "${repofile}" sed -i -e 's/^metalink/#metalink/g' "${repofile}" sed -i -e 's/^#baseurl/baseurl/g' "${repofile}" fi done # Allow specifying custom base URLs for repositories and GPG keys # Note: done here to cater for those repos installed above for repo_name in $(yum-config-manager --enablerepo '*' | grep '\[.*\]' | tr -d '[]' | grep -v -w 'main'); do repo_baseurl="${hvp_repo_baseurl[${repo_name}]}" repo_gpgkey="${hvp_repo_gpgkey[${repo_name}]}" # Force any custom URLs if [ -n "${repo_baseurl}" ]; then yum-config-manager --save --setopt="${repo_name}.baseurl=${repo_baseurl}" > /dev/null fi if [ -n "${repo_gpgkey}" ]; then yum-config-manager --save --setopt="${repo_name}.gpgkey=${repo_gpgkey}" > /dev/null fi done fi # Add bgstack15 stackrpms repo # Define proper network source stackrpms_baseurl="https://download.copr.fedorainfracloud.org/results/bgstack15/stackrpms/epel-7-$(uname -m)/" stackrpms_gpgkey="https://download.copr.fedorainfracloud.org/results/bgstack15/stackrpms/pubkey.gpg" # Prefer custom stackrpms repo URL, if any if [ -n "${hvp_repo_baseurl['stackrpms']}" ]; then stackrpms_baseurl=$(echo "${hvp_repo_baseurl['stackrpms']}" | sed -e 's/\$releasever/'$(rpm -q --queryformat '%{version}' centos-release)'/g' -e 's/\$basearch/'$(uname -m)'/g') fi if [ -n "${hvp_repo_gpgkey['stackrpms']}" ]; then stackrpms_gpgkey=$(echo "${hvp_repo_gpgkey['stackrpms']}" | sed -e 's/\$releasever/'$(rpm -q --queryformat '%{version}' centos-release)'/g' -e 's/\$basearch/'$(uname -m)'/g') fi cat << EOF > /etc/yum.repos.d/stackrpms.repo [stackrpms] name=Copr repo for stackrpms owned by bgstack15 baseurl=${stackrpms_baseurl} type=rpm-md skip_if_unavailable=True gpgcheck=1 gpgkey=${stackrpms_gpgkey} repo_gpgcheck=0 enabled=1 enabled_metadata=1 EOF chmod 644 /etc/yum.repos.d/stackrpms.repo # Add Firejail repository definition # Define proper network source firejail_baseurl="https://copr.fedorainfracloud.org/coprs/heikoada/firejail/repo/epel-7/" # Prefer custom Firejail base URL, if any if [ -n "${hvp_repo_baseurl['firejail']}" ]; then firejail_baseurl="${hvp_repo_baseurl['firejail']}" fi wget -P /etc/yum.repos.d "${firejail_baseurl}heikoada-firejail-epel-7.repo" # Comment out mirrorlist directives and uncomment the baseurl ones when using custom URLs for repos if [ "${custom_yum_conf}" = "true" ]; then for repofile in /etc/yum.repos.d/*.repo; do if egrep -q '^(mirrorlist|metalink)' "${repofile}"; then sed -i -e 's/^mirrorlist/#mirrorlist/g' "${repofile}" sed -i -e 's/^metalink/#metalink/g' "${repofile}" sed -i -e 's/^#baseurl/baseurl/g' "${repofile}" fi done # Allow specifying custom base URLs for repositories and GPG keys # Note: done here to cater for those repos installed above for repo_name in $(yum-config-manager --enablerepo '*' | grep '\[.*\]' | tr -d '[]' | grep -v -w 'main'); do repo_baseurl="${hvp_repo_baseurl[${repo_name}]}" repo_gpgkey="${hvp_repo_gpgkey[${repo_name}]}" # Force any custom URLs if [ -n "${repo_baseurl}" ]; then yum-config-manager --save --setopt="${repo_name}.baseurl=${repo_baseurl}" > /dev/null fi if [ -n "${repo_gpgkey}" ]; then yum-config-manager --save --setopt="${repo_name}.gpgkey=${repo_gpgkey}" > /dev/null fi done fi # Add Microsoft repository definition # Define proper network source microsoftprod_baseurl="https://packages.microsoft.com/config/rhel/7/" # Prefer custom Microsoft base URL, if any if [ -n "${hvp_repo_baseurl['packages-microsoft-com-prod']}" ]; then microsoftprod_baseurl="${hvp_repo_baseurl['packages-microsoft-com-prod']}" fi wget -P /etc/yum.repos.d "${microsoftprod_baseurl}prod.repo" # Comment out mirrorlist directives and uncomment the baseurl ones when using custom URLs for repos if [ "${custom_yum_conf}" = "true" ]; then for repofile in /etc/yum.repos.d/*.repo; do if egrep -q '^(mirrorlist|metalink)' "${repofile}"; then sed -i -e 's/^mirrorlist/#mirrorlist/g' "${repofile}" sed -i -e 's/^metalink/#metalink/g' "${repofile}" sed -i -e 's/^#baseurl/baseurl/g' "${repofile}" fi done # Allow specifying custom base URLs for repositories and GPG keys # Note: done here to cater for those repos installed above for repo_name in $(yum-config-manager --enablerepo '*' | grep '\[.*\]' | tr -d '[]' | grep -v -w 'main'); do repo_baseurl="${hvp_repo_baseurl[${repo_name}]}" repo_gpgkey="${hvp_repo_gpgkey[${repo_name}]}" # Force any custom URLs if [ -n "${repo_baseurl}" ]; then yum-config-manager --save --setopt="${repo_name}.baseurl=${repo_baseurl}" > /dev/null fi if [ -n "${repo_gpgkey}" ]; then yum-config-manager --save --setopt="${repo_name}.gpgkey=${repo_gpgkey}" > /dev/null fi done fi # Add Enterprise Virtualization repo if [ "${nolocalvirt}" != "true" ]; then yum -y install centos-release-qemu-ev # Comment out mirrorlist directives and uncomment the baseurl ones when using custom URLs for repos if [ "${custom_yum_conf}" = "true" ]; then for repofile in /etc/yum.repos.d/*.repo; do if egrep -q '^(mirrorlist|metalink)' "${repofile}"; then sed -i -e 's/^mirrorlist/#mirrorlist/g' "${repofile}" sed -i -e 's/^metalink/#metalink/g' "${repofile}" sed -i -e 's/^#baseurl/baseurl/g' "${repofile}" fi done # Allow specifying custom base URLs for repositories and GPG keys # Note: done here to cater for those repos installed above for repo_name in $(yum-config-manager --enablerepo '*' | grep '\[.*\]' | tr -d '[]' | grep -v -w 'main'); do repo_baseurl="${hvp_repo_baseurl[${repo_name}]}" repo_gpgkey="${hvp_repo_gpgkey[${repo_name}]}" # Force any custom URLs if [ -n "${repo_baseurl}" ]; then yum-config-manager --save --setopt="${repo_name}.baseurl=${repo_baseurl}" > /dev/null fi if [ -n "${repo_gpgkey}" ]; then yum-config-manager --save --setopt="${repo_name}.gpgkey=${repo_gpgkey}" > /dev/null fi done fi fi # Marking CentOS-hosted oVirt repositories as higher priority than others (mainly to prevent EPEL from replacing oVirt-specific packages) but less than our own (when not in orthodox mode) for repo_name in $(grep -o '\[ovirt-.*centos.*\]' /etc/yum.repos.d/ovirt-*-dependencies.repo | tr -d '[]'); do yum-config-manager --save --setopt="${repo_name}.priority=75" > /dev/null done # Marking CentOS Base repositories as higher priority than others (mainly to prevent CentOS-hosted oVirt repositories from masking newer packages in base/updates/extras) but less than our own (when not in orthodox mode) for repo_name in base updates extras; do yum-config-manager --save --setopt="${repo_name}.priority=75" > /dev/null done # Enable use of delta rpms since we are not using a local mirror # Note: this may introduce HTTP 416 errors - better leave this to post-installation manual choices yum-config-manager --save --setopt='deltarpm=0' > /dev/null # Correctly initialize YUM cache again before actual bulk installations/upgrades # Note: following advice in https://access.redhat.com/articles/1320623 # TODO: remove when fixed upstream rm -rf /var/cache/yum/* yum --enablerepo '*' clean all # Update OS (with "upgrade" to allow package obsoletion) non-interactively ("-y" yum option) # Note: any repo file involved in release package upgrades would be in .rpmnew so no need to reapply customizations now yum -y upgrade # TODO: Make sure that the latest installed kernel is the default # TODO: Kernel upgrade in kickstart post phase does not seem to set the latest installed kernel as boot default # TODO: Open a Bugzilla notification # TODO: Remove when fixed upstream # TODO: the following works only with re-instated CentOS6 fix above grubby --set-default=/boot/vmlinuz-$(rpm -q --last kernel | head -1 | cut -f 1 -d ' ' | sed -e 's/kernel-//') # Install HAVEGEd # Note: even in presence of an actual/virtualized hardware random number generator (managed by rngd) we install haveged as a safety measure yum -y install haveged # Install YUM-cron, YUM-plugin-ps, Gdisk, PWGen, HPing, 7Zip and ARJ yum -y install hping3 p7zip{,-{gui,plugins}} arj pwgen yum -y install yum-cron yum-plugin-ps gdisk # Install Nmon and Dstat yum -y install nmon dstat # Install Logcheck yum -y install logcheck # Install needed packages to join AD domain yum -y install sssd sssd-ad realmd adcli oddjob{,-mkhomedir} krb5-workstation samba-common{,-tools} sssd-tools ldb-tools tdb-tools # Install LAPS support # TODO: open RFE or submit patch to add GPO support to https://gitlab.com/bgstack15/laps yum -y install laps # Install XRDP yum -y install xrdp xrdp-selinux # Install PDSH yum -y install pdsh pdsh-rcmd-ssh # Install Midnight Commander yum -y install mc # Install Java browser and Virt-Viewer support yum -y install icedtea-web virt-viewer spice-xpi # Install graphical bootsplash theme yum -y install plymouth-theme-charge # Install desktop packages # Install LXDE (LXQt actually) packages # TODO: switch to a group install method as soon as it will be available yum -y install lxqt-about lxqt-common lxqt-config lxqt-globalkeys lxqt-l10n lxqt-notificationd lxqt-openssh-askpass lxqt-panel lxqt-policykit lxqt-powermanagement lxqt-qtplugin lxqt-runner lxqt-session lxqt-sudo lxqt-wallet network-manager-applet nm-connection-editor pcmanfm-qt qterminal-qt5 lximage-qt openbox pavucontrol-qt{,-l10n} qpdfview file-roller # Install additional workstation software yum -y install ntfs-3g fuse-dislocker dislocker brasero chromium filezilla putty google-noto-sans-bengali-ui-fonts keepass kpcli # Install X2Go clients yum -y install x2goclient pyhoca-{cli,gui} # Install end-user tools yum -y install vlock mozilla-{ublock-origin,noscript} remmina{,-plugins-{exec,nx,rdp,spice,st,vnc,www,xdmcp}} firewall-{config,applet} firejail strongswan NetworkManager-strongswan{,-gnome} # Install security-related tools yum -y install luksmeta clevis-{luks,udisks2,systemd} cryptsetup-reencrypt aide usbguard{,-tools} scap-security-guide openscap-{scanner,utils} opensc opencryptoki # Install management tools # Note: Set this variable in order to avoid interactive questions from Microsoft postinst scripts export ACCEPT_EULA=Y yum -y install net-snmp-utils samba-client openldap-clients pykickstart ike-scan powershell mssql-tools mariadb postgresql sqlite bareos-tools msktutil adtool # Install automation tools yum -y install ansible gdeploy ovirt-engine-sdk-python python2-jmespath python-netaddr python-dns python-psycopg2 libselinux-python libsemanage-python rhel-system-roles ovirt-ansible-roles gluster-ansible-roles ovirt-ansible-repositories NetworkManager-glib python-passlib ansible-lint ## Download AppImage management tools ## TODO: find/provide an rpm version of these tools ## TODO: disabled since they seem to be incompatible with RHEL/CentOS 7 (requiring newer glibc) #wget -P /usr/local/bin/ https://github.com/AppImage/appimaged/releases/download/continuous/appimaged-x86_64.AppImage #wget -P /usr/local/bin/ https://github.com/AppImage/AppImageUpdate/releases/download/continuous/AppImageUpdate-x86_64.AppImage ## Download AD management tools provided only as an AppImage from https://appimage.github.io/admin-tools/ #wget -P /usr/local/bin/ https://download.opensuse.org/repositories/home:/dmulder:/YaST:/AppImage/AppImage/admin-tools-latest-x86_64.AppImage #chmod a+rx /usr/local/bin/* # Install Bareos client (file daemon + console) # TODO: using HVP repo to bring in recompiled packages from Bareos stable GIT tree - remove when regularly published upstream yum -y install bareos-client # Install virtualization tools support packages # TODO: find a way to enable some virtualization technologies (Parallels, VirtualBox) on a server machine without development support packages if dmidecode -s system-manufacturer | egrep -q "(innotek|Parallels)" ; then # Install dkms for virtualization tools support # TODO: configure virtualization tools under dkms # TODO: disabled since required development packages cannot be installed #yum -y install dkms echo "DKMS unsupported" elif dmidecode -s system-manufacturer | grep -q "Red.*Hat" ; then yum -y install qemu-guest-agent spice-vdagent elif dmidecode -s system-manufacturer | grep -q "oVirt" ; then yum -y install ovirt-guest-agent spice-vdagent elif dmidecode -s system-manufacturer | grep -q "Microsoft" ; then yum -y install hyperv-daemons elif dmidecode -s system-manufacturer | grep -q "VMware" ; then # Note: VMware basic support installed here (since it is included in base distro now) yum -y install open-vm-tools open-vm-tools-desktop fuse fi # Tune package list to underlying platform if dmidecode -s system-manufacturer | egrep -q "(Microsoft|VMware|innotek|Parallels|Red.*Hat|oVirt|Xen)" ; then # Exclude CPU microcode updates to avoid errors on virtualized platform yum -y erase microcode_ctl else # Install Memtest86+ # Note: open source memtest86+ does not support UEFI if [ ! -d /sys/firmware/efi ]; then yum -y install memtest86+ fi # Install MCE logging/management service yum -y install mcelog fi # Add virtualization support on suitable platforms if [ "${nolocalvirt}" != "true" ]; then yum -y install qemu-kvm qemu-img virt-manager libvirt libvirt-python libvirt-client virt-install virt-viewer virt-top libguestfs numpy virtio-win OVMF # Explicitly add package requirements to allow NGN development as per https://gerrit.ovirt.org/gitweb?p=ovirt-node-ng.git;a=blob;f=README yum -y install lorax libvirt libvirt-daemon-kvm virt-install libguestfs-tools fi # Clean up after all installations yum --enablerepo '*' clean all # Remove package update leftovers find /etc -type f -name '*.rpmnew' -exec rename .rpmnew "" '{}' ';' find /etc -type f -name '*.rpmsave' -exec rm -f '{}' ';' # Comment out mirrorlist directives and uncomment the baseurl ones when using custom URLs for repos # Note: done here to cater for modified repos from the upgrade above if [ "${custom_yum_conf}" = "true" ]; then for repofile in /etc/yum.repos.d/*.repo; do if egrep -q '^(mirrorlist|metalink)' "${repofile}"; then sed -i -e 's/^mirrorlist/#mirrorlist/g' "${repofile}" sed -i -e 's/^metalink/#metalink/g' "${repofile}" sed -i -e 's/^#baseurl/baseurl/g' "${repofile}" fi done # Reapply all yum settings sed -i -e 's/^enabled.*/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf yum-config-manager --save --setopt='deltarpm=0' > /dev/null for repo_name in base updates extras; do yum-config-manager --save --setopt="${repo_name}.priority=75" > /dev/null done for repo_name in $(grep -o '\[ovirt-.*centos.*\]' /etc/yum.repos.d/ovirt-*-dependencies.repo | tr -d '[]'); do yum-config-manager --save --setopt="${repo_name}.priority=75" > /dev/null done if [ "${ovirt_nightly_mode}" = "true" ]; then for repo_name in $(grep -o '\[ovirt-.*centos.*\]' /etc/yum.repos.d/ovirt-*-dependencies.repo | tr -d '[]'); do yum-config-manager --save --setopt="${repo_name}.skip_if_unavailable=1" > /dev/null done fi if [ "${orthodox_mode}" = "false" ]; then yum-config-manager --enable hvp-rhv-rebuild > /dev/null yum-config-manager --save --setopt='hvp-rhv-rebuild.priority=50' > /dev/null yum-config-manager --enable hvp-rhgs-rebuild > /dev/null yum-config-manager --save --setopt 'hvp-rhgs-rebuild.includepkgs=gluster-ansible*' > /dev/null yum-config-manager --enable hvp-ansible-rebuild > /dev/null yum-config-manager --save --setopt='hvp-ansible-rebuild.priority=50' > /dev/null else yum-config-manager --enable hvp-rhgs-rebuild > /dev/null yum-config-manager --save --setopt 'hvp-rhgs-rebuild.includepkgs=gluster-ansible*' > /dev/null fi # Allow specifying custom base URLs for repositories and GPG keys # Note: done here to cater for those repos already installed by default for repo_name in $(yum-config-manager --enablerepo '*' | grep '\[.*\]' | tr -d '[]' | grep -v -w 'main'); do repo_baseurl="${hvp_repo_baseurl[${repo_name}]}" repo_gpgkey="${hvp_repo_gpgkey[${repo_name}]}" # Force any custom URLs if [ -n "${repo_baseurl}" ]; then yum-config-manager --save --setopt="${repo_name}.baseurl=${repo_baseurl}" > /dev/null fi if [ -n "${repo_gpgkey}" ]; then yum-config-manager --save --setopt="${repo_name}.gpgkey=${repo_gpgkey}" > /dev/null fi done fi # Now configure the base OS # TODO: Decide which part to configure here and which part to demand to Ansible # Setup auto-update via yum-cron (ala CentOS4, replacement for yum-updatesd in CentOS5) # Note: Updates left to the administrator manual intervention sed -i -e 's/^update_messages\s.*$/update_messages = no/' -e 's/^download_updates\s.*$/download_updates = no/' -e 's/^apply_updates\s.*$/apply_updates = no/' -e 's/^emit_via\s.*$/emit_via = None/' /etc/yum/yum-cron*.conf systemctl disable yum-cron # Limit retained old kernels to 3 (as in CentOS5 default) yum-config-manager --save --setopt='installonly_limit=3' > /dev/null # Autodetecting BIOS/UEFI # Note: the following identifies the symlink under /etc to abstract from BIOS/UEFI actual file placement if [ -d /sys/firmware/efi ]; then grub2_cfg_file="/etc/grub2-efi.cfg" else grub2_cfg_file="/etc/grub2.cfg" fi # Configure GRUB2 boot loader (force a well-known graphical mode, be silent and do not wait for manual override, set graphical Plymouth theme) sed -i -e 's/^GRUB_TIMEOUT=.*$/GRUB_TIMEOUT="0"\nGRUB_HIDDEN_TIMEOUT="3"\nGRUB_HIDDEN_TIMEOUT_QUIET="true"/' /etc/default/grub plymouth-set-default-theme -R charge # TODO: we must manually rebuild the initramfs due to a known plymouth bug (https://bugzilla.redhat.com/show_bug.cgi?id=891039) - remove when fixed upstream dracut -f /boot/initramfs-$(uname -r).img $(uname -r) # TODO: Setup a serial terminal # TODO: find a way to detect serial port use by other software (like ovirt-guest-agent) and skip for console #serial_found="false" #for link in /sys/class/tty/*/device/driver ; do # if stat -c '%N' ${link} | grep -q 'serial' ; then # if [ -n "$(setserial -g -b /dev/$(echo ${link} | sed -e 's%^.*/tty/\([^/]*\)/.*$%\1%'))" ]; then # serial_found="true" # break # fi # fi #done #if [ "${serial_found}" = "true" ]; then # sed -i -e '/^GRUB_CMDLINE_LINUX/s/quiet/quiet console=tty0 console=ttyS0,115200n8/' /etc/default/grub # cat <<- EOF >> /etc/default/grub # GRUB_TERMINAL="console serial" # GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1" # EOF # grub2-mkconfig -o "${grub2_cfg_file}" #fi # Conditionally add memory test entry to boot loader if dmidecode -s system-manufacturer | egrep -q -v "(Microsoft|VMware|innotek|Parallels|Red.*Hat|oVirt|Xen)" ; then # Note: open source memtest86+ does not support UEFI if [ ! -d /sys/firmware/efi ]; then memtest-setup grub2-mkconfig -o "${grub2_cfg_file}" fi fi # Configure kernel I/O scheduler policy sed -i -e '/^GRUB_CMDLINE_LINUX/s/\selevator=[^[:space:]"]*//' -e '/^GRUB_CMDLINE_LINUX/s/"$/ elevator=deadline"/' /etc/default/grub grub2-mkconfig -o "${grub2_cfg_file}" # Configuration of session/system management (ignore power actions initiated by keyboard etc.) # Note: interactive startup is disabled by default (enable with systemd.confirm_spawn=true on kernel commandline) and single user mode uses sulogin by default if dmidecode -s system-manufacturer | egrep -q -v "(Microsoft|VMware|innotek|Parallels|Red.*Hat|oVirt|Xen)" ; then sed -i -e '/Handle[^=]*=[^i]/s/^#\(Handle[^=]*\)=.*$/\1=ignore/' /etc/systemd/logind.conf fi # Configure kernel behaviour # Console verbosity # TODO: check kernel cmdline option loglevel cat << EOF > /etc/sysctl.d/console-log.conf # Controls the severity level of kernel messages on local consoles kernel.printk = 1 EOF chmod 644 /etc/sysctl.d/console-log.conf # Reboot on panic cat << EOF > /etc/sysctl.d/panic.conf # Controls the timeout for automatic reboot on panic kernel.panic = 5 EOF chmod 644 /etc/sysctl.d/panic.conf # Conditionally add virtual guest optimizations # TODO: verify wether we can skip this and delegate to tuned if dmidecode -s system-manufacturer | egrep -q "(Microsoft|VMware|innotek|Parallels|Red.*Hat|oVirt|Xen)" ; then # Configure block devices for a virtual guest # Configure timeout for Qemu devices # Note: VirtIO devices do not need this (neither do they expose any timeout parameter) cat <<- EOF > /etc/udev/rules.d/99-qemu-block-timeout.rules # # Qemu block devices timeout settings # ACTION=="add|change", SUBSYSTEMS=="block", ATTRS{model}=="QEMU_HARDDISK", RUN+="/bin/sh -c 'echo 180 >/sys\$DEVPATH/timeout'" EOF chmod 644 /etc/udev/rules.d/99-qemu-block-timeout.rules # Configure readahead and requests for VirtIO devices cat <<- EOF > /etc/udev/rules.d/99-virtio-block.rules # # VirtIO block devices settings # ACTION=="add|change", KERNEL=="vd*[!0-9]", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ATTR{queue/nr_requests}="8" ACTION=="add|change", KERNEL=="vd*[!0-9]", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ATTR{bdi/read_ahead_kb}="4096" EOF chmod 644 /etc/udev/rules.d/99-virtio-block.rules # Configure scheduler and memory for a virtual guest cat <<- EOF > /etc/sysctl.d/virtualguest.conf # Tune for a KVM virtualization guest kernel.sched_min_granularity_ns = 10000000 kernel.sched_wakeup_granularity_ns = 15000000 vm.dirty_background_ratio = 10 vm.dirty_ratio = 40 vm.dirty_expire_centisecs = 500 vm.dirty_writeback_centisecs = 100 vm.swappiness = 30 kernel.sched_migration_cost_ns = 5000000 EOF chmod 644 /etc/sysctl.d/virtualguest.conf fi # Configure log rotation (keep the specified weeks of logs, compressed) sed -i -e "s/^rotate.*\$/rotate ${log_retention_weeks}/" -e 's/^#\s*compress.*$/compress/' /etc/logrotate.conf # Enable HAVEGEd systemctl enable haveged # Note: users configuration script generated in pre section above and copied in third post section below # Conditionally force static the nic name<->MAC mapping to work around hardware bugs (eg nic "autoshifting" on some HP MicroServer G7) if [ "${nicmacfix}" = "true" ] ; then for nic_cfg in /etc/sysconfig/network-scripts/ifcfg-* ; do eval $(grep '^DEVICE=' "${nic_cfg}") nic_name="${DEVICE}" if echo "${nic_name}" | egrep -q '^(bond|lo|br|sit)' ; then continue fi nic_mac=$(cat "/sys/class/net/${nic_name}/address" 2>/dev/null) # Detect bonding slaves (real MAC address must be specially extracted) if [ -L "/sys/class/net/${nic_name}/master" ]; then # Note: the following regex does not catch all stat-printf output characters #nic_master=$(stat --printf="%N" "/sys/class/net/${nic_name}/master" | sed -e "s%^.*-> \`.*/net/\\([^']*\\)'.*\$%\\1%") nic_master=$(stat --printf="%N" "/sys/class/net/${nic_name}/master" | sed -e "s%^.*->.*/net/\\([[:alnum:]]*\\).*\$%\\1%") # Note: all bonding slaves take the apparent MAC address from the bonding master device (which usually takes it from the first slave) - extract the real one nic_mac=$(cat /proc/net/bonding/${nic_master} | awk 'BEGIN {IGNORECASE=1; found="false"}; /^Slave Interface:[[:space:]]*'${nic_name}'[[:space:]]*/ {found="true"}; /^Permanent HW addr:[[:space:]]*/ {if (found == "true") {print $4; exit}}') fi if [ -n "${nic_mac}" ]; then if ! grep -q '^HWADDR=' "${nic_cfg}" ; then echo "HWADDR=\"${nic_mac}\"" >> "${nic_cfg}" fi fi done fi # System clock configuration # Note: systemd sets clock to UTC by default #echo 'UTC' >> /etc/adjtime # Configure NTP time synchronization (immediate hardware sync) # Note: further configuration fragment created in pre section above and copied in post section below sed -i -e 's/^SYNC_HWCLOCK=.*$/SYNC_HWCLOCK="yes"/' /etc/sysconfig/ntpdate # Allow NTPdate hardware clock sync through SELinux # Note: obtained by means of: cat /var/log/audit/audit.log | audit2allow -M myntpdate # TODO: remove when SELinux policy fixed upstream mkdir -p /etc/selinux/local cat << EOF > /etc/selinux/local/myntpdate.te module myntpdate 9.0; require { type chronyc_t; type kernel_t; type ntpd_t; type hwclock_exec_t; type adjtime_t; class system module_request; class file { open read write execute execute_no_trans getattr }; class netlink_audit_socket create; } #============= chronyc_t ============== allow chronyc_t kernel_t:system module_request; #============= ntpd_t ============== allow ntpd_t hwclock_exec_t:file { open read execute execute_no_trans getattr }; allow ntpd_t self:netlink_audit_socket create; allow ntpd_t adjtime_t:file { open read getattr write }; EOF chmod 644 /etc/selinux/local/myntpdate.te pushd /etc/selinux/local checkmodule -M -m -o myntpdate.mod myntpdate.te semodule_package -o myntpdate.pp -m myntpdate.mod semodule -i myntpdate.pp popd # Configure Chrony # Note: configuration fragment created in pre section above and appended in post section below # Enable Chrony systemctl enable chronyd # Note: Configured TCP wrappers allow file in pre above and copied in second post below echo "ALL: ALL" >> /etc/hosts.deny # Configure SSH (show legal banner, limit authentication tries, no DNS tracing of incoming connections) sed -i -e 's/^#\s*MaxAuthTries.*$/MaxAuthTries 3/' -e 's/^#\s*UseDNS.*$/UseDNS no/' -e 's%^#\s*Banner.*$%Banner /etc/issue.net%' /etc/ssh/sshd_config # Force security-conscious length of host keys by pre-creating them here # Note: ED25519 keys have a fixed length so they are not created here # Note: using haveged to ensure enough entropy (but rngd could be already running from installation environment) # Note: starting service manually since systemd inside a chroot would need special treatment haveged -w 1024 -F & haveged_pid=$! ssh-keygen -b 4096 -t rsa -N "" -f /etc/ssh/ssh_host_rsa_key ssh-keygen -b 1024 -t dsa -N "" -f /etc/ssh/ssh_host_dsa_key ssh-keygen -b 521 -t ecdsa -N "" -f /etc/ssh/ssh_host_ecdsa_key chgrp ssh_keys /etc/ssh/ssh_host_{rsa,dsa,ecdsa}_key chmod 640 /etc/ssh/ssh_host_{rsa,dsa,ecdsa}_key # Stopping haveged started above kill ${haveged_pid} # Disable SSH by default # Note: if enabling remember to reopen the ssh service in firewalld firewall-offline-cmd --remove-service=ssh systemctl disable sshd # Disable multicast DNS systemctl disable avahi-daemon.socket systemctl disable avahi-daemon.service # Configure use of at/cron facilities (allow only listed users) rm -f /etc/{at,cron}.deny cat << EOF > /etc/at.allow root EOF chmod 600 /etc/at.allow cat << EOF > /etc/cron.allow root EOF chmod 600 /etc/cron.allow # Configure legal warning messages cat << EOF > /etc/issue WARNING: THIS CONSOLE IS RESERVED FOR SYSTEM ADMINISTRATION ONLY. EVERY ACCESS IS THOROUGHLY LOGGED. THERE IS NO PRIVACY PROTECTION ON LOGGED DATA. VIOLATIONS WILL BE PROSECUTED. ACCESS IMPLIES ACCEPTANCE OF THE ABOVE CONDITIONS. EOF cat << EOF > /etc/issue.net Access is reserved to explicitly authorized personnel only. Violations will be prosecuted. Every access is thoroughly logged. This access service provides no privacy protection on logged data. Access through this service implies acceptance of the above conditions. EOF cat << EOF > /etc/motd WARNING This computer is the private property of his owners. Permission of use must be individually and explicitly obtained in written form. If you have not been authorized, you must immediately terminate your connection. Violations will be prosecuted. Use of this computer is thoroughly logged. There is no privacy protection on logged data. Continued use of this computer implies acceptance of the above conditions. EOF chmod 644 /etc/{issue*,motd} # Configure SMTP relay if [ -n "${my_smtpserver}" ]; then if [ "${use_smtps}" = "true" ]; then # Configure SMTPS smart host by means of systemd-controlled stunnel service # Note: no service section is allowed in inetd mode cat <<- EOF > /etc/stunnel/relay-smtps.conf setuid = nobody setgid = nobody pid = client = yes connect = ${my_smtpserver}:465 fips = no EOF chmod 644 /etc/stunnel/relay-smtps.conf # Configure relay-smtps as a systemd-controlled socket-activated service # Note: Accept=yes (inetd-style) forces us to create a template service below cat <<- EOF > /etc/systemd/system/relay-smtps.socket [Socket] ListenStream=127.0.0.1:11125 Accept=yes [Install] WantedBy=sockets.target EOF chmod 644 /etc/systemd/system/relay-smtps.socket # Note: inetd-style means that stdin/stdout must go through socket # TODO: modify to run unprivileged (use nobody here and remove setuid/setgid from stunnel configuration above) cat <<- EOF > /etc/systemd/system/relay-smtps@.service [Service] ExecStart=/usr/bin/stunnel /etc/stunnel/relay-smtps.conf StandardInput=socket Type=forking User=root PrivateTmp=true EOF chmod 644 /etc/systemd/system/relay-smtps@.service # Enable relay-smtps as a systemd-controlled socket-activated service systemctl enable relay-smtps.socket # Relay Postfix client connections through stunnel postconf -e 'smtp_use_tls = no' postconf -e 'relayhost = [127.0.0.1]:11125' else # Directly relay through the specified server postconf -e "relayhost = ${my_smtpserver}" fi fi # Enable persistent Journal logs mkdir -p /var/log/journal # Note: email aliases configured through script created in pre section above and copied in third post section below # TODO: Send all log messages to our internal syslog server # TODO: enable TCP service on internal syslog/firewall servers then uncomment here # TODO: switch to encrypted/guaranteed delivery (RELP with SSL/Kerberos) when available #cat << EOF > /etc/rsyslog.d/centralized.conf ## ### begin forwarding rule ### ## The statement between the begin ... end define a SINGLE forwarding ## rule. They belong together, do NOT split them. If you create multiple ## forwarding rules, duplicate the whole block! ## Remote Logging (we use TCP for reliable delivery) ## ## An on-disk queue is created for this action. If the remote host is ## down, messages are spooled to disk and sent when it is up again. #\$WorkDirectory /var/lib/rsyslog # where to place spool files #\$ActionQueueFileName VRLRule1 # unique name prefix for spool files #\$ActionQueueMaxDiskSpace 1g # 1gb space limit (use as much as possible) #\$ActionQueueSaveOnShutdown on # save messages to disk on shutdown #\$ActionQueueType LinkedList # run asynchronously #\$ActionResumeRetryCount -1 # infinite retries if host is down ## remote host is: name/ip:port, e.g. 192.168.0.1:514, port optional #*.* @@syslog.${my_domain_name}:514 ## ### end of the forwarding rule ### #EOF #chmod 644 /etc/rsyslog.d/centralized.conf # Configure Logcheck sed -i -e "/^SENDMAILTO=/s/logcheck/${notification_receiver}/" /etc/logcheck/logcheck.conf for rule in kernel systemd; do ln -s ../ignore.d.server/${rule} /etc/logcheck/violations.ignore.d/ done # TODO: reconfigure syslog files for Logcheck as per https://bugzilla.redhat.com/show_bug.cgi?id=1062147 - remove when fixed upstream sed -i -e 's/^\(\s*\)\(missingok.*\)$/\1\2\n\1create 0640 root adm/' /etc/logrotate.d/syslog touch /var/log/{messages,secure,cron,maillog,spooler} chown root:adm /var/log/{messages,secure,cron,maillog,spooler} chmod 640 /var/log/{messages,secure,cron,maillog,spooler} # Configure ABRTd # Keep crash info even for non-rpm-packaged programs but exclude users writable paths sed -i -e 's/^ProcessUnpackaged.*$/ProcessUnpackaged = yes/' -e 's%\(BlackListedPaths.*\)$%\1, /home*, /tmp/*, /var/tmp/*%' /etc/abrt/abrt-action-save-package-data.conf # Allow reports for signed packages from 3rd-party repos by adding their keys under /etc/pki/rpm-gpg/ for repokeyurl in $(grep -h '^gpgkey' /etc/yum.repos.d/*.repo | grep -v 'file:///' | sed -e 's/^gpgkey\s*=\s*//' -e 's/\s*$//' -e 's/\$releasever/'$(rpm -q --queryformat '%{version}' centos-release)'/g' | sort | uniq); do key_file="$(echo ${repokeyurl} | sed -e 's%^.*/\([^/]*\)$%\1%')" if [ ! -f "/etc/pki/rpm-gpg/${key_file}" ]; then wget -P /etc/pki/rpm-gpg/ "${repokeyurl}" fi done # Disable automatic reporting by email sed -i -e 's/^/#/' /etc/libreport/events.d/mailx_event.conf # Disable SMARTd on a virtual machine if dmidecode -s system-manufacturer | egrep -q "(Microsoft|VMware|innotek|Parallels|Red.*Hat|oVirt|Xen)" ; then systemctl disable smartd fi # Remove unwanted firewalld behaviour sed -i -e '/AllowZoneDrifting/s/yes/no/' /etc/firewalld/firewalld.conf # TODO: Debug - enable verbose logging in firewalld - maybe disable for production use? firewall-offline-cmd --set-log-denied=all # Enable Postfix systemctl enable postfix # Define GNOME3 global settings (mandatory/defaults) # Note: schema inspected on a live GNOME session using "gsettings list-recursively" # Note: pre-seeding values with gsettings as root works for root user only and needs dbus running - using dconf instead # Note: clock panel applet under GNOME3 takes all settings from system defaults (location, time format, display etc.) # Disable user list and add banner message for GNOME login greeter cat << EOF > /etc/dconf/db/gdm.d/01-hvp-settings # Custom settings for GNOME login screen [org/gnome/login-screen] disable-user-list=true banner-message-enable=true banner-message-text='Access is reserved to explicitly authorized personnel only.\nViolations will be prosecuted.\nEvery access is thoroughly logged.\nThis access service provides no privacy protection on logged data.\nAccess through this service implies acceptance of the above conditions.' EOF chmod 644 /etc/dconf/db/gdm.d/01-hvp-settings # Apply all GNOME3 GDM settings specified above rm -f /etc/dconf/db/gdm dconf update # Disable autorun for external media # TODO: verify under GNOME 3.14 / CentOS 7.2 cat << EOF > /etc/dconf/db/local.d/01-autorun-settings # Custom settings for GNOME autorun [org/gnome/desktop/media-handling] autorun-never=true EOF chmod 644 /etc/dconf/db/local.d/01-autorun-settings # Disable switch user # TODO: verify under GNOME 3.14 / CentOS 7.2 cat << EOF > /etc/dconf/db/local.d/01-switchuser-settings # Custom settings for GNOME user session switching [org/gnome/desktop/lockdown] disable-user-switching=true EOF chmod 644 /etc/dconf/db/local.d/01-switchuser-settings # Note: GNOME3 (or newer CUPS) does not show other user print jobs by default # TODO: verify # Disable online account providers cat << EOF > /etc/dconf/db/local.d/01-goa-settings # Custom settings for GNOME online account providers [org/gnome/online-accounts] whitelisted-providers=[''] EOF chmod 644 /etc/dconf/db/local.d/01-goa-settings # Conditionally apply custom defaults to screensaver under GNOME3 (do not start on idle, do not lock) if dmidecode -s system-manufacturer | egrep -q "(Microsoft|VMware|innotek|Parallels|Red.*Hat|oVirt|Xen)" ; then cat <<- EOF > /etc/dconf/db/local.d/01-screensaver-settings # Custom settings for GNOME screensaver [org/gnome/desktop/lockdown] disable-lock-screen=true [org/gnome/settings-daemon/plugins/media-keys] screensaver='' [org/gnome/desktop/screensaver] idle-activation-enabled=false lock-enabled=false lock-delay=uint32 0 [org/gnome/desktop/session] idle-delay=uint32 0 [org/gnome/session] idle-delay=uint32 0 [org/gnome/settings-daemon/plugins/power] sleep-display-ac=0 sleep-display-battery=0 sleep-inactive-ac-timeout=0 sleep-inactive-battery-timeout=0 sleep-inactive-battery-type='nothing' sleep-inactive-ac-type='nothing' EOF chmod 644 /etc/dconf/db/local.d/01-screensaver-settings # Lock our custom defaults applied above cat <<- EOF > /etc/dconf/db/local.d/locks/01-screensaver-settings-locks /org/gnome/desktop/lockdown/disable-lock-screen /org/gnome/settings-daemon/plugins/media-keys/screensaver /org/gnome/desktop/screensaver/idle-activation-enabled /org/gnome/desktop/screensaver/lock-enabled /org/gnome/desktop/screensaver/lock-delay /org/gnome/desktop/session/idle-delay /org/gnome/session/idle-delay /org/gnome/settings-daemon/plugins/power/sleep-display-ac /org/gnome/settings-daemon/plugins/power/sleep-display-battery /org/gnome/settings-daemon/plugins/power/sleep-inactive-ac-timeout /org/gnome/settings-daemon/plugins/power/sleep-inactive-battery-timeout /org/gnome/settings-daemon/plugins/power/sleep-inactive-ac-type /org/gnome/settings-daemon/plugins/power/sleep-inactive-battery-type EOF chmod 644 /etc/dconf/db/local.d/locks/01-screensaver-settings-locks # Disable power management (blanking) on the X server side too cat <<- EOF > /etc/X11/xorg.conf.d/01-dpms.conf Section "ServerFlags" Option "BlankTime" "0" Option "StandbyTime" "0" Option "SuspendTime" "0" Option "OffTime" "0" EndSection EOF chmod 644 /etc/X11/xorg.conf.d/01-dpms.conf fi # Note: filemanager under GNOME3 does not use spatial mode by default # TODO: GDM lacks any sort of configuration settings and fills logs because of this - adding empty settings as a workaround - report upstream and remove when fixed mkdir -p /etc/dconf/db/gdm.d/locks # Apply all GNOME3 settings specified above rm -f /etc/dconf/db/local dconf update # Disable graphical initial system setup sed -i -e 's/^\(\[daemon\].*\)$/\1\nInitialSetupEnable=False/' /etc/gdm/custom.conf # Disable GNOME initial setup # TODO: there is no way to globally disable this: faking an already performed initial setup - remove when fixed upstream mkdir -m 700 /etc/skel/.config echo "yes" > /etc/skel/.config/gnome-initial-setup-done chmod 644 /etc/skel/.config/gnome-initial-setup-done # TODO: there is a known inconsistency (personal bin directories not in path) in the PATH setting for a terminal opened through Nautilus "Open in Terminal" menu entry # TODO: adding workaround here (http://seven.centos.org/2014/04/path-inconsistency-in-el7/) - remove when fixed upstream cat << EOF > /etc/profile.d/consistent-user-path.sh #!/bin/sh # Fix broken nautilus-open-terminal if ! echo "\${PATH}" | grep -q "\${HOME}/bin" ; then PATH=\${PATH}:\${HOME}/.local/bin:\${HOME}/bin export PATH fi EOF chmod 644 /etc/profile.d/consistent-user-path.sh # Note: users configuration script created in pre section above and copied in third post section below # Exclude /var/tmp from systemd-tmpfiles (equivalent of tmpwatch in CentOS <= 6) mkdir -p /etc/tmpfiles.d cp /usr/lib/tmpfiles.d/tmp.conf /etc/tmpfiles.d sed -i -e 's>^\(.\s*/var/tmp.*\)$>#\1>' /etc/tmpfiles.d/tmp.conf # Configure XRDP # Prepare default (self-signed) certificate # Note: using haveged to ensure enough entropy (but rngd could be already running from installation environment) # Note: starting service manually since systemd inside a chroot would need special treatment haveged -w 1024 -F & haveged_pid=$! # Prepare default (self-signed) certificate openssl genrsa 2048 > /etc/pki/tls/private/localhost.key cat << EOF | openssl req -new -sha256 -key /etc/pki/tls/private/localhost.key -x509 -days 3650 -out /etc/pki/tls/certs/localhost.crt IT Lombardia Bergamo HVP Heretic oVirt Project Demo Infrastructure ${HOSTNAME} root@${HOSTNAME} EOF chmod 600 /etc/pki/tls/{private,certs}/localhost.* # Create custom DH parameters openssl dhparam -out /etc/pki/tls/dhparams.pem 2048 chmod 644 /etc/pki/tls/dhparams.pem # Stopping haveged started above kill ${haveged_pid} # Configure XRDP to use a custom certificate cat /etc/pki/tls/private/localhost.key > /etc/xrdp/key.pem cat /etc/pki/tls/certs/localhost.crt > /etc/xrdp/cert.pem # Leave XRDP disabled by default # Note: if enabling remember to open the ms-wbt service in firewalld systemctl disable xrdp # Leave network filesystem client services disabled by default systemctl disable nfs-client.target systemctl disable remote-fs.target # Conditionally enable MCE logging/management service if dmidecode -s system-manufacturer | egrep -q -v "(Microsoft|VMware|innotek|Parallels|Red.*Hat|oVirt|Xen)" ; then systemctl enable mcelog fi # Configure Tang servers for NBDE support # TODO: allow for a TPM-based LUKS setup as per https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec-policy-based_decryption mkdir -p /root/etc/tang pushd /root/etc/tang tang_server_found="false" for ((i=0;i<${#luks_tangservers[@]};i=i+1)); do # Verify Tang server availability if wget -O - "${luks_tangservers[${i}]}/adv" > /dev/null 2>&1; then tang_server_found="true" wget -O "adv${i}.jws" "${luks_tangservers[${i}]}/adv" else unset luks_tangservers[${i}] fi done if [ "${tang_server_found}" = "true" ]; then # Setup Tang keys # Note: we keep the fixed internal passphrase as a safety net for luks_device in $(lsblk -l -o NAME,FSTYPE | awk '/crypto_LUKS/ {print $1}'); do for i in "${!luks_tangservers[@]}"; do echo "${luks_passphrase}" | clevis luks bind -f -k - -d /dev/${luks_device} tang '{"url":"${luks_tangservers[${i}]}","adv":"adv${i}.jws"}' done done fi popd # Setup initramfs environment for NBDE # Function to convert from prefix to netmask - taken from https://stackoverflow.com/questions/20762575/explanation-of-convertor-of-cidr-to-netmask-in-linux-shell-netmask2cdir-and-cdir cdr2mask () { # Number of args to shift, 255..255, first non-255 byte, zeroes set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0 [ $1 -gt 1 ] && shift $1 || shift echo ${1-0}.${2-0}.${3-0}.${4-0} } # Note: dracut would import its own and override NetworkManager config - applying workaround as per https://access.redhat.com/solutions/3017441#comment-1622491 main_ifcfg=$(grep -l '^DEFROUTE=.*yes' /etc/sysconfig/network-scripts/ifcfg-*) source "${main_ifcfg}" cat << EOF > /etc/dracut.conf.d/clevis-nbde.conf # DHCP for a specific interface kernel_cmdline="ip=${DEVICE}:dhcp" # Don't create /etc/sysconfig/network-scripts/ifcfg-* files during boot omit_dracutmodules+="ifcfg" EOF chmod 644 /etc/dracut.conf.d/clevis-nbde.conf dracut -f --regenerate-all # Note: dracut would not reset its config anyway - creating custom template unit to discard it cat << EOF > /etc/systemd/system/flush-dracut-network@.service [Unit] Description=Remove dracut network configuration for %I Before=network-pre.target Wants=network-pre.target [Service] ExecStartPre=/usr/sbin/ip address show %i ExecStart=/usr/sbin/ip -statistics address flush dev %i [Install] WantedBy=default.target EOF chmod 644 /etc/systemd/system/flush-dracut-network@.service systemctl enable flush-dracut-network@${DEVICE} # Add further LUKS passphrase # Note: use case is adding a user-known passphrase for offsite usage eg on a laptop if [ -n "${luks_passphrase2}" ]; then for luks_device in $(lsblk -l -o NAME,FSTYPE | awk '/crypto_LUKS/ {print $1}'); do # Note: the new additional passphrase cannot be fed from stdin - using pipe workaround as per https://unix.stackexchange.com/questions/225108/how-to-automate-cryptsetup-luksaddkey-with-passphrase # TODO: verify whether there are free slots (Tang servers may have exhausted the slots) mkfifo "new_passphrase_${luks_device}" echo -n "${luks_passphrase2}" > "new_passphrase_${luks_device}" & echo -n "${luks_passphrase}" | cryptsetup -q luksAddKey --key-file=- "/dev/${luks_device}" "new_passphrase_${luks_device}" rm -f "new_passphrase_${luks_device}" done fi popd # Configure libvirt # Note: libvirtd service is automatically enabled on installation if [ "${nolocalvirt}" != "true" ]; then # Set default uri for root (other users cannot read /etc/libvirt/libvirt.conf) sed -i -e 's%^#*uri_default\s.*$%uri_default = "qemu:///system"%' /etc/libvirt/libvirt.conf # Setup KVM as default driver for Libvirt (avoid using "-c qemu:///system" on each virsh command) # Note: useful only if you plan to use virsh from non-root accounts # TODO: use qemu:///session and discard polkit customizations below - each user will need to create its own guest vms cat <<- EOF > /etc/profile.d/libvirt.sh # Set environment variable to override Libvirt driver autodetection LIBVIRT_DEFAULT_URI="qemu:///system" export LIBVIRT_DEFAULT_URI EOF cat <<- EOF > /etc/profile.d/libvirt.csh # Set environment variable to override Libvirt driver autodetection setenv LIBVIRT_DEFAULT_URI qemu:///system EOF chmod 644 /etc/profile.d/libvirt.*sh # Grant full libvirt access to administrators group sed -e '/['"]libvirt["']/s/libvirt/alldelegatedadmins/g' /usr/share/polkit-1/rules.d/50-libvirt.rules > /etc/polkit-1/rules.d/90-libvirt.rules chmod 644 /etc/polkit-1/rules.d/90-libvirt.rules fi # Configure desktop # TODO: try to set the preferred desktop environment as a global default de_start_command="/usr/bin/startlxqt" cat << EOF > /etc/sysconfig/desktop PREFERRED="${de_start_command}" EOF ## Enable AppImage management tools ## TODO: disabled since they seem to be incompatible with RHEL/CentOS 7 (requiring newer glibc) #/usr/local/bin/appimaged-x86_64.AppImage --install # Prepare requirements and commands to create isolated Kerberos environment (allow working with multiple different Kerberos identities in different shell sessions) mkdir /etc/skel/.tmp chmod 700 /etc/skel/.tmp cat << EOF > /etc/profile.d/isolated_krb5_mgmt.sh alias prepare_new_krb5_identity="export KRB5CCNAME=FILE:\\\$(mktemp \\\${HOME}/.tmp/krb5cc_temp_XXXXXXXXXX)" alias destroy_new_krb5_identity="kdestroy ; unset KRB5CCNAME" EOF chmod 644 /etc/profile.d/isolated_krb5_mgmt.sh cat << EOF > /etc/profile.d/isolated_krb5_mgmt.csh alias prepare_new_krb5_identity setenv KRB5CCNAME FILE:\\\`mktemp \\\${HOME}/.tmp/krb5cc_temp_XXXXXXXXXX\\\` alias destroy_new_krb5_identity kdestroy ; unsetenv KRB5CCNAME EOF chmod 644 /etc/profile.d/isolated_krb5_mgmt.csh # TODO: Configure Bareos # Create HVP standard directory for machine-specific application dumps mkdir -p /var/local/backup chown root:root /var/local/backup chmod 750 /var/local/backup # Create HVP standard script for machine-specific application dumps cat << EOF > /usr/local/sbin/dump2backup #!/bin/bash # Nothing to do for a PAW exit 0 EOF chown root:root /usr/local/sbin/dump2backup chmod 750 /usr/local/sbin/dump2backup # TODO: Enable Bareos systemctl disable bareos-fd # Configure scheduled update of RHSA OVAL definitions for OpenSCAP mkdir -p /var/lib/openscap cat << EOF > /etc/cron.daily/oval-update #!/bin/bash pushd /var/lib/openscap result=\$(/usr/bin/wget https://www.redhat.com/security/data/oval/v2/RHEL$(rpm -q --queryformat '%{version}' centos-release)/rhel-$(rpm -q --queryformat '%{version}' centos-release).oval.xml.bz2 2>&1) code=\$? if [ "\${code}" -eq 0 ]; then if echo "\${result}" | grep -q -v '304 Not Modified File' ; then /usr/bin/bzip2 --decompress rhel-$(rpm -q --queryformat '%{version}' centos-release).oval.xml.bz2 > rhel-$(rpm -q --queryformat '%{version}' centos-release).oval.xml fi fi popd EOF chmod 755 /etc/cron.daily/oval-update # TODO: download and install internal CA cert (if domain-joined: our AD DCs should host a CA) # Configure root home dir (with utility scripts for basic configuration/log backup) mkdir -p /root/{etc,bin,log,tmp,backup} cat << EOF > /root/bin/backup-log #!/bin/bash tar -czf /root/backup/\$(hostname)-\$(date '+%Y-%m-%d')-log.tar.gz /root/etc /root/log \$(find /var/log/ -type f ! -iname '*z' -print) EOF chmod 755 /root/bin/backup-log cat << EOF > /root/bin/backup-conf #!/bin/bash tar -czf /root/backup/\$(hostname)-\$(date '+%Y-%m-%d')-conf.tar.gz \$(cat /root/etc/backup.list) EOF chmod 755 /root/bin/backup-conf cat << EOF > /root/etc/backup.list /boot/grub2 /etc /var/www/html /usr/local/bin /usr/local/sbin /usr/local/etc /root/bin /root/etc /root/log /root/.[^ekmn]?* EOF # Initialize administration log journal cat << EOF > /root/log/sysadm.log $(date '+%Y/%m/%d') *) installed $(lsb_release -i -r -s) $(uname -m) from kickstart EOF # Allow first boot configuration through SELinux # Note: obtained by means of: cat /var/log/audit/audit.log | audit2allow -M myks1stboot # TODO: remove when SELinux policy fixed upstream mkdir -p /etc/selinux/local cat << EOF > /etc/selinux/local/myks1stboot.te module myks1stboot 3.0; require { type sendmail_t; type postfix_master_t; type admin_home_t; type setfiles_t; type ifconfig_t; type initrc_t; type systemd_hostnamed_t; class dbus send_msg; class file { getattr write }; } #============= ifconfig_t ============== allow ifconfig_t admin_home_t:file write; #============= sendmail_t ============== allow sendmail_t admin_home_t:file write; #============= postfix_master_t ============== allow postfix_master_t admin_home_t:file { getattr write }; #============= setfiles_t ============== allow setfiles_t admin_home_t:file write; #============= systemd_hostnamed_t ============== allow systemd_hostnamed_t initrc_t:dbus send_msg; EOF chmod 644 /etc/selinux/local/myks1stboot.te pushd /etc/selinux/local checkmodule -M -m -o myks1stboot.mod myks1stboot.te semodule_package -o myks1stboot.pp -m myks1stboot.mod semodule -i myks1stboot.pp popd # Set up "first-boot" configuration script (steps that require a fully up system) cat << EOF > /etc/rc.d/rc.ks1stboot #!/bin/bash # Conditionally enable either IPMI or LMsensors monitoring # TODO: configure IPMI options # TODO: find a way to ignore partial IPMI implementations (e.g. those needing a [missing] add-on card) if dmidecode -s system-manufacturer | egrep -q -v "(Microsoft|VMware|innotek|Parallels|Red.*Hat|oVirt|Xen)" ; then if dmidecode --type 38 | grep -q 'IPMI' ; then systemctl --now enable ipmi systemctl --now enable ipmievd else sensors-detect --auto systemctl --now enable lm_sensors fi fi # Setup virtualization tools (Hyper-V/KVM/VMware/VirtualBox/Parallels supported) # TODO: Verify that VirtIO drivers get used for Xen/KVM, warn otherwise # TODO: disable kernel updating or configure dkms (if not already done above or by tools installation) pushd /tmp need_reboot="no" if dmidecode -s system-manufacturer | grep -q "Microsoft" ; then # TODO: configure Hyper-V integration agents systemctl --now enable hypervkvpd hypervvssd hypervfcopyd elif dmidecode -s system-manufacturer | grep -q 'Xen' ; then # Enable ARP notifications for vm migrations cat <<- EOM > /etc/sysctl.d/99-xen-guest.conf net.ipv4.conf.all.arp_notify=1 EOM chmod 644 /etc/sysctl.d/99-xen-guest.conf sysctl -p wget https://dangerous.ovirt.life/support/Xen/xe-guest-utilities*.rpm yum -y --nogpgcheck install ./xe-guest-utilities*.rpm rm -f xe-guest-utilities*.rpm elif dmidecode -s system-manufacturer | grep -q "VMware" ; then # Note: VMware basic support uses distro-provided packages installed during post phase # Note: adding nofail to avoid making it fail the remote-fs.target if unavailable # TODO: adding network dependency to break possible systemd ordering cycle - investigate further and remove it cat <<- EOM > /etc/systemd/system/mnt-hgfs.mount [Unit] Description=VMware shared folders After=network.target network-online.target vmtoolsd.service Requires=network.target network-online.target vmtoolsd.service Before=multi-user.target Conflicts=umount.target [Mount] What=.host:/ Where=/mnt/hgfs Type=fuse.vmhgfs-fuse Options=allow_other,auto_unmount,nofail TimeoutSec=50s [Install] WantedBy=multi-user.target EOM chmod 644 /etc/systemd/system/mnt-hgfs.mount systemctl daemon-reload systemctl --now enable mnt-hgfs.mount need_reboot="no" elif dmidecode -s system-manufacturer | grep -q "innotek" ; then wget https://dangerous.ovirt.life/support/VirtualBox/VBoxLinuxAdditions.run chmod a+rx VBoxLinuxAdditions.run ./VBoxLinuxAdditions.run --nox11 usermod -a -G vboxsf mwtouser rm -f VBoxLinuxAdditions.run need_reboot="yes" elif dmidecode -s system-manufacturer | grep -q "Parallels" ; then wget https://dangerous.ovirt.life/support/Parallels/ParallelsTools.tar.gz | tar xzf - pushd parallels-tools-distrib ./install --install-unattended-with-deps popd rm -rf parallels-tools-distrib need_reboot="yes" elif dmidecode -s system-manufacturer | grep -q "Red.*Hat" ; then # TODO: configure Qemu agent systemctl --now enable qemu-guest-agent elif dmidecode -s system-manufacturer | grep -q "oVirt" ; then # TODO: configure oVirt agent systemctl --now enable qemu-guest-agent ovirt-guest-agent fi popd # Note: CentOS 7 persistent net device naming means that MAC addresses are not statically registered by default anymore EOF # Saving installation instructions # Note: done in rc.ks1stboot since this seems to get created after all post scripts are run # TODO: something tries to load /root/anaconda-ks.cfg - find out what/why - seems related to https://bugzilla.redhat.com/show_bug.cgi?id=1213114 # TODO: it seems that a side effect of not moving it is the unconditional execution of the graphical firstboot phase - restoring file moving as a workaround # TODO: it seems that the graphical firstboot phase happens anyway and at the end creates a /root/initial-ks.cfg cat << EOF >> /etc/rc.d/rc.ks1stboot mv /root/*-ks.cfg /root/etc EOF cat << EOF >> /etc/rc.d/rc.ks1stboot # Run dynamically determined users configuration actions if [ -x /etc/rc.d/rc.users-setup ]; then /etc/rc.d/rc.users-setup fi # Check/modify hostname for uniqueness main_interface=\$(ip route show | awk '/^default/ {print \$5}' | head -1) main_ip=\$(ip address show dev \${main_interface} primary | awk '/inet[[:space:]]/ {print \$2}' | cut -d/ -f1) current_name=\$(hostname -s) target_domain=\$(hostname -d) multi_instance_max="500" check_ip="\$(dig \${current_name}.\${target_domain} A +short)" # Check whether name resolves and does not match with IP address if [ -n "\${check_ip}" -a "\${check_ip}" != "\${main_ip}" ]; then # Name does not match: modify (starting from suffix 2) and resolve it till it is either unknown or matching with configured IP tentative_name_found="false" current_base_name=\$(echo \${current_name} | sed -e 's/-[^-]*\$//') current_name_suffix=\$(echo \${current_name} | sed -n -e 's/^.*\\(-[^-]*\\)\$/\\1/p') for ((name_increment=2;name_increment<=\${multi_instance_max}+1;name_increment=name_increment+1)); do # In case of decorated names use increment only on the base name tentative_name="\${current_base_name}\${name_increment}\${current_name_suffix}" check_ip="\$(dig \${tentative_name}.\${target_domain} A +short)" if [ -z "\${check_ip}" -o "\${check_ip}" = "\${main_ip}" ]; then tentative_name_found="true" break fi done if [ "\${tentative_name_found}" = "true" ]; then # Enact new hostname hostnamectl set-hostname \${tentative_name}.\${target_domain} # Prepare default (self-signed) certificate # Note: certificate must be recreated to reflect new hostname openssl genrsa 2048 > /etc/pki/tls/private/localhost.key cat <<- EOM | openssl req -new -sha256 -key /etc/pki/tls/private/localhost.key -x509 -days 3650 -out /etc/pki/tls/certs/localhost.crt IT Lombardia Bergamo HVP Heretic oVirt Project Demo Infrastructure \$(hostname) root@\$(hostname) EOM cat /etc/pki/tls/dhparams.pem >> /etc/pki/tls/certs/localhost.crt # Restart services to pick up new certificates cat /etc/pki/tls/private/localhost.key > /etc/xrdp/key.pem cat /etc/pki/tls/certs/localhost.crt > /etc/xrdp/cert.pem #systemctl restart xrdp fi fi # Run AD domain joining script if [ -x /etc/rc.d/rc.domain-join ]; then /etc/rc.d/rc.domain-join fi # Run virtual guests setup script if [ -x /etc/rc.d/rc.guest-setup ]; then /etc/rc.d/rc.guest-setup fi # Initialize USBGuard rules usbguard generate-policy > /etc/usbguard/rules.conf # Configure USBGuard usbguard add-user -g alldelegatedadmins --devices=modify,list,listen --policy=list --exceptions=listen # Enable and start USBGuard systemctl --now enable usbguard.service # Put the firewall in lockdown mode firewall-cmd --lockdown-on # Run installation files cleanup script if [ -x /etc/rc.d/rc.install-cleanup ]; then /etc/rc.d/rc.install-cleanup fi # Disable further executions of this script from systemd systemctl disable ks1stboot.service # Schedule a daily AIDE scan cat << EOM > /etc/cron.daily/aide #!/bin/bash /usr/sbin/aide --check EOM chmod 755 /etc/cron.daily/aide # Customize AIDE classifications sed -i -e 's%/etc/resolv\\.conf%/etc/resolv.conf.*%' -e '/root.*PERMS/s%^.*\$%/root/\\\\.bash_history\\\$ PERMS\\n/root/\\\\.lesshst\\\$ PERMS\\n/root/\\\\.rnd\\\$ PERMS\\n/root/\\\\.viminfo\\\$ PERMS\\n/root/\\\\.cache.* PERMS\\n/root/\\\\.local.* PERMS%' /etc/aide.conf # Initialize AIDE database aide --init # Make the new AIDE database authoritative mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz # Perform reboot after virtualization tools installation if [ "\${need_reboot}" = "yes" ]; then shutdown -r +1 # Note: the command above exits immediately - wait for the most part of the remaining minute sleep 57 fi exit 0 EOF chmod 750 /etc/rc.d/rc.ks1stboot # Prepare first-boot execution through systemd # TODO: find a way to actually block logins till this unit exits cat << EOF > /etc/systemd/system/ks1stboot.service [Unit] Description=Post Kickstart first boot configurations After=network.target network.service Requires=network.target network.service Before=getty.target sshd.service display-manager.service [Service] Type=oneshot RemainAfterExit=true ExecStart=/usr/bin/bash -c '/etc/rc.d/rc.ks1stboot > /root/log/rc.ks1stboot.log 2>&1' [Install] RequiredBy=getty.target sshd.service display-manager.service EOF chmod 644 /etc/systemd/system/ks1stboot.service systemctl enable ks1stboot.service # TODO: forcibly disable execution of graphical firstboot tool - kickstart directive on top seems to be ignored and moving away anaconda-ks.cfg is not enough - remove when fixed upstream - see https://bugzilla.redhat.com/show_bug.cgi?id=1213114 systemctl mask firstboot-graphical systemctl mask initial-setup-graphical systemctl mask initial-setup-text systemctl mask initial-setup # TODO: sometimes it seems that an haveged process lingers on, blocking the end of the post phase # TODO: killing any surviving haveged process as a workaround pkill -KILL -f havege ) 2>&1 | tee /root/kickstart_post_1.log %end # Post-installation script (run with bash from installation image after the second post section) %post --nochroot ( # Run the entire post section as a subshell for logging purposes. # Copy NTPdate configuration file (generated in pre section above) into installed system if [ -s /tmp/hvp-ntpd-conf/step-tickers ]; then cat /tmp/hvp-ntpd-conf/step-tickers > ${ANA_INSTALL_PATH}/etc/ntp/step-tickers chmod 644 ${ANA_INSTALL_PATH}/etc/ntp/step-tickers chown root:root ${ANA_INSTALL_PATH}/etc/ntp/step-tickers fi # Append Chrony configuration fragment (generated in pre section above) into installed system # Note: if we specify additional Chrony configuration, then all default servers get disabled if [ -s /tmp/hvp-ntpd-conf/chrony.conf ]; then sed -i -e '/^server\s/s/^/#/g' ${ANA_INSTALL_PATH}/etc/chrony.conf cat /tmp/hvp-ntpd-conf/chrony.conf >> ${ANA_INSTALL_PATH}/etc/chrony.conf fi # Copy users setup script (generated in pre section above) into installed system if [ -f /tmp/hvp-users-conf/rc.users-setup ]; then cp /tmp/hvp-users-conf/rc.users-setup ${ANA_INSTALL_PATH}/etc/rc.d/rc.users-setup # Note: cleartext passwords contained - must restrict access chmod 700 ${ANA_INSTALL_PATH}/etc/rc.d/rc.users-setup chown root:root ${ANA_INSTALL_PATH}/etc/rc.d/rc.users-setup fi # Copy virtual guests setup script (generated in pre section above) into installed system if [ -s /tmp/hvp-guest-setup/rc.guest-setup ]; then cp /tmp/hvp-guest-setup/rc.guest-setup ${ANA_INSTALL_PATH}/etc/rc.d/rc.guest-setup # Note: cleartext passwords contained - must restrict access chmod 700 ${ANA_INSTALL_PATH}/etc/rc.d/rc.guest-setup chown root:root ${ANA_INSTALL_PATH}/etc/rc.d/rc.guest-setup fi # Copy AD domain joining script (generated in pre section above) into installed system if [ -s /tmp/hvp-domain-join/rc.domain-join ]; then cp /tmp/hvp-domain-join/rc.domain-join ${ANA_INSTALL_PATH}/etc/rc.d/rc.domain-join # Note: cleartext passwords contained - must restrict access chmod 700 ${ANA_INSTALL_PATH}/etc/rc.d/rc.domain-join chown root:root ${ANA_INSTALL_PATH}/etc/rc.d/rc.domain-join fi # Copy installation files cleanup script (generated in pre section above) into installed system if [ -s /tmp/hvp-install-cleanup/rc.install-cleanup ]; then cp /tmp/hvp-install-cleanup/rc.install-cleanup ${ANA_INSTALL_PATH}/etc/rc.d/rc.install-cleanup chmod 755 ${ANA_INSTALL_PATH}/etc/rc.d/rc.install-cleanup chown root:root ${ANA_INSTALL_PATH}/etc/rc.d/rc.install-cleanup fi # Copy TCP wrappers configuration (generated in pre section above) into installed system if [ -f /tmp/hvp-tcp_wrappers-conf/hosts.allow ]; then cat /tmp/hvp-tcp_wrappers-conf/hosts.allow >> ${ANA_INSTALL_PATH}/etc/hosts.allow fi # Save exact pre-stage environment if [ -f /tmp/pre.out ]; then cp /tmp/pre.out ${ANA_INSTALL_PATH}/root/log/pre.out fi # Save exact post-stage environment if [ -f ${ANA_INSTALL_PATH}/tmp/post.out ]; then cp ${ANA_INSTALL_PATH}/tmp/post.out ${ANA_INSTALL_PATH}/root/log/post.out fi # Save installation instructions/logs # Note: installation logs are now saved under /var/log/anaconda/ by default cp /run/install/ks.cfg ${ANA_INSTALL_PATH}/root/etc for full_frag in /tmp/full-* ; do if [ -f "${full_frag}" ]; then cp "${full_frag}" ${ANA_INSTALL_PATH}/root/etc fi done cp /tmp/kickstart_*.log ${ANA_INSTALL_PATH}/root/log mv ${ANA_INSTALL_PATH}/root/kickstart_post*.log ${ANA_INSTALL_PATH}/root/log ) 2>&1 | tee ${ANA_INSTALL_PATH}/root/log/kickstart_post_2.log %end # Post-installation script (run with bash from chroot after the third post section) %post ( # Run the entire post section as a subshell for logging purposes. # Relabel filesystem # This has to be the last post action to catch any files we have created/modified # TODO: verify whether the following is actually needed (latest Anaconda seems to perform a final relabel anyway) setfiles -F -e /proc -e /sys -e /dev -e /selinux /etc/selinux/targeted/contexts/files/file_contexts / setfiles -F /etc/selinux/targeted/contexts/files/file_contexts.homedirs /home/ /root/ ) 2>&1 | tee /root/log/kickstart_post_3.log %end