# Kickstart file for AD domain controller server # 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): # nomodeset elevator=deadline inst.ks=https://dangerous.ovirt.life/hvp-repos/el7/ks/hvp-dc-c7.ks # Note: DHCP must be available on at least one network (autodetected, albeit with a noticeable delay) and the kickstart/install server must be reachable from the DHCP networks, otherwise the ip=nicname:dhcp option must be added, where nicname is the name of the network interface to be used for installation (eg: ens32) # 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 force custom host naming add hvp_myname=myhostname where myhostname is the unqualified (ie without domain name part) hostname # Note: to force custom addressing add hvp_{mgmt,lan}=x.x.x.x/yy where x.x.x.x may either be the machine IP or the network address on the given network and yy is the prefix on the given network (distinct physical networks cannot be logically conflated) # Note: to force custom IPs add hvp_{mgmt,lan}_my_ip=t.t.t.t where t.t.t.t is the chosen IP on the given network # Note: to force custom network MTU add hvp_{mgmt,lan}_mtu=zzzz where zzzz is the MTU value # Note: to force custom network domain naming add hvp_{mgmt,lan}_domainname=mynet.name where mynet.name is the domain name (if distinct physical networks have conflated domain names, host names will be decorated with a "-zonename" suffix) # Note: to force custom multi-instance limit for each vm type (kickstart) add hvp_maxinstances=A where A is the maximum number of instances # Note: to force custom AD subdomain naming add hvp_ad_subdomainname=myprefix where myprefix is the subdomain name # Note: to force custom NetBIOS domain naming add hvp_netbiosdomain=MYDOM where MYDOM is the NetBIOS domain name # Note: to force custom domain action add hvp_joindomain=bool where bool is either "true" (join an existing domain) or "false" (create a new domain/forest) # Note: to force custom domain site add hvp_joinsite=my-site-name where my-site-name is the name of an existing site to specify when joining an existing domain # Note: to force custom domain controller read-only mode add hvp_joinasrodc=bool where bool is either "true" (join as a read-only domain controller) or "false" (join as a read-write domain controller) when joining an existing domain # Note: to force custom sysvol replication password add hvp_sysvolpassword=mysysvolsecret where mysysvolsecret is the sysvol replication password # Note: to force custom nameserver IP (during installation) add hvp_nameserver=w.w.w.w where w.w.w.w is the nameserver IP (for further DCs this should be an existing AD DC) # Note: to force custom forwarders IPs add hvp_forwarders=forw0,forw1,forw2 where forwN are the forwarders IPs # 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 (for first DC only - further DCs 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 gateway IP add hvp_gateway=n.n.n.n where n.n.n.n is the gateway IP # Note: to force custom Gluster node count add hvp_nodecount=N where N is the number of nodes in the cluster # Note: to force custom Gluster storage naming add hvp_storagename=mystoragename where mystoragename is the unqualified (ie without domain name part) hostname of the storage # Note: to force custom Gluster storage IPs add hvp_storage_offset=o where o is the storage IPs base offset on mgmt/lan networks # Note: to force custom Gluster NFS-shares base volume naming add hvp_unixshare_volumename=myvolumename where myvolumename is the volume name # Note: to force custom storage shares DFS hosting add (multiple) hvp_dfs_mysharename=mystoragename1\path1,mystoragename2\path2\subpath2,... where mysharename is the DFS share name and mystoragename1\path1,... are the network paths # 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 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 AD main admin password add hvp_adrootpwd=mywinsecret where mywinsecret is the main AD admin user password # Note: to force custom AD admin username add hvp_adadminname=myadadmin where myadadmin is the further AD admin username # Note: to force custom AD admin password add hvp_adadminpwd=mywinothersecret where mywinothersecret is the further AD admin user password # Note: to force custom AD server admin username add hvp_serveradminname=myserveradmin where myserveradmin is the further servers admin username # Note: to force custom AD server admin password add hvp_serveradminpwd=mywinothersecret where mywinothersecret is the further servers admin user password # Note: to force custom AD workstation admin username add hvp_workstationadminname=myworkstationadmin where myworkstationadmin is the further workstations admin username # Note: to force custom AD workstation admin password add hvp_workstationadminpwd=mywinothersecret where mywinothersecret is the further workstations admin user password # Note: to force custom AD PAW admin username add hvp_pawadminname=mypawadmin where mypawadmin is the further PAWs admin username # Note: to force custom AD PAW admin password add hvp_pawadminpwd=mywinothersecret where mywinothersecret is the further PAWs admin user password # Note: to force custom AD user admin username add hvp_useradminname=myuseradmin where myuseradmin is the further users admin username # Note: to force custom AD user admin password add hvp_useradminpwd=mywinothersecret where mywinothersecret is the further users admin user password # Note: to force custom AD infrastructure admin username add hvp_infraadminname=myinfraadmin where myinfraadmin is the further infrastructure admin username # Note: to force custom AD infrastructure admin password add hvp_infraadminpwd=mywinothersecret where mywinothersecret is the further infrastructure admin user password # Note: to force custom AD service user accounts and SPNs add (multiple) hvp_spn_myaccountname=myservice1/service1.fqdn.domain,myservice2/service2.fqdn.domain... where myaccountname is the service username and myservice1/service1... are the SPNs # Note: to force custom AD service user account passwords add (multiple) hvp_pwd_myaccountname=myservicepassword where myservicepassword is the service password # Note: to force custom AD unconstrained delegation rights for service user accounts add hvp_ucdelegations=myaccountname1,myaccountname2... where myaccountname1... are the service usernames to be Kerberos-delegated for any service # Note: to force custom AD constrained delegation rights for service user accounts add hvp_delegation_myaccountname=myservice1/service1.fqdn.domain,myservice2/service2.fqdn.domain... where myaccountname is the service username and myservice1/service1... are the Kerberos-delegated SPNs # Note: to force custom AD any-protocol delegation rights for service user accounts add hvp_apdelegations=myaccountname1,myaccountname2... where myaccountname1... are the service usernames to be Kerberos-delegated for any protocol # Note: to force custom AD LDAP bind username add hvp_adbindname=mybinduser where mybinduser is the AD LDAP bind username # Note: to force custom AD LDAP bind password add hvp_adbindpwd=mybindpassword where mybindpassword is the AD LDAP bind user password # Note: to force custom keyboard layout add hvp_kblayout=cc where cc is the country code # Note: to force custom local timezone add hvp_timezone=VV where VV is the timezone specification # 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 does not register fixed nic name-to-MAC mapping # Note: the default host naming uses the "My Little Pony" character name spike # Note: the default addressing on connected networks is assumed to be 172.20.{10,12}.0/24 on {mgmt,lan} # Note: the default MTU is assumed to be 1500 on {mgmt,lan} # Note: the default machine IPs are assumed to be the 220th IPs available (network address + 220) on each connected network # Note: the default domain names are assumed to be {mgmt,lan}.private # Note: the default multi-instance limit is assumed to be 9 # Note: the default AD subdomain name is assumed to be ad # Note: the default NetBIOS domain name is equal to the first part of the AD DNS subdomain name (on the lan network, or mgmt if there is only one network) in uppercase # Note: the default domain action is "false" (create a new domain/forest) # Note: the default domain site is empty (use default site when joining an existing domain) # Note: the default domain controller read-only mode is "false" (join an existing domain as a read-write domain controller) # Note: the default sysvol replication password is HVP_dem0 # Note: the default nameserver IP is assumed to be 8.8.8.8 during installation (afterwards it will be switched to 127.0.0.1 unconditionally) # Note: the default forwarder IP is assumed to be 8.8.8.8 # 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 (for first DC only - further DCs 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 gateway IP is assumed to be equal to the test IP on the mgmt network # Note: the default node count is 3 # Note: the default Gluster storage naming uses an empty string to disable default configuration of the storage service # Note: the default Gluster storage IPs base offset on mgmt/lan networks is assumed to be the network address plus 30 # Note: the default Gluster NFS-shares base volume naming uses the name unixshare # Note: the default storage shares DFS hosting configuration is empty # Note: the default root user password is HVP_dem0 # Note: the default LUKS passphrase is HVP_dem0 # 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 AD main admin user password is HVP_dem0 # Note: the default AD admin username is the same as the admin username with the string "ad" prefixed # Note: the default AD admin user password is HVP_dem0 # Note: the default AD server admin username is the same as the admin username with the string "srv" prefixed # Note: the default AD server admin user password is HVP_dem0 # Note: the default AD workstation admin username is the same as the admin username with the string "wks" prefixed # Note: the default AD workstation admin user password is HVP_dem0 # Note: the default AD PAW admin username is the same as the admin username with the string "paw" prefixed # Note: the default AD PAW admin user password is HVP_dem0 # Note: the default AD user admin username is the same as the admin username with the string "usr" prefixed # Note: the default AD user admin user password is HVP_dem0 # Note: the default AD infrastructure admin username is the same as the admin username with the string "infra" prefixed # Note: the default AD infrastructure admin user password is HVP_dem0 # Note: the default AD service account user list is empty # Note: the default AD service account password list is empty (autogenerated random password for any service account) # Note: the default AD unconstrained delegation list for service account users is empty # Note: the default AD constrained delegation list for service account users is empty # Note: the default AD any-protocol delegation list for service account users is empty # Note: the default AD LDAP bind username is binduser # Note: the default AD LDAP bind user password is BindPassw0rd # Note: the default keyboard layout is us # Note: the default local timezone is UTC # 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_dc.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,ntpd" # 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 --ssh # 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 -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 # Note: the following is required for AD-integrated signed NTP replies # TODO: investigate usage of Chrony together with Samba AD DC and restore chronyd as NTP server solution as soon as it becomes viable ntp -chrony # 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 nss-tools patch expect ksh ncompress libnl redhat-lsb clevis-dracut -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 node_count unset network unset netmask unset network_base unset mtu unset domain_name unset ad_subdomain_prefix unset netbios_domain_name unset domain_join unset domain_site unset domain_join_as_rodc unset sysvolrepl_password unset reverse_domain_name unset test_ip unset test_ip_offset unset storage_name unset storage_ip_offset unset dfs_shares unset gluster_vol_name unset my_ip_offset unset multi_instance_max unset my_name unset my_nameserver unset my_forwarders unset my_gateway unset my_ntpservers unset luks_passphrase unset root_password unset admin_username unset admin_password unset notification_receiver unset debug_mode unset adroot_password unset adadmin_username unset adadmin_password unset serveradmin_username unset serveradmin_password unset workstationadmin_username unset workstationadmin_password unset pawadmin_username unset pawadmin_password unset useradmin_username unset useradmin_password unset infraadmin_username unset infraadmin_password unset template_username unset service_spns unset service_pwds unset service_delegations unset service_apdelegations unset adbind_username unset adbind_password unset keyboard_layout unset local_timezone unset hvp_repo_baseurl unset hvp_repo_gpgkey # Hardcoded defaults default_node_count="3" storage_name="" declare -A dfs_shares declare -A gluster_vol_name gluster_vol_name['unixshare']="unixshare" declare -A hvp_repo_baseurl declare -A hvp_repo_gpgkey # Note: IP offsets below get used to automatically derive IP addresses # Note: no need to allow offset overriding from commandline if the IP address itself can be specified # Note: the following can be overridden from commandline test_ip_offset="1" my_ip_offset="220" multi_instance_max="9" # TODO: verify whether the final addresses (network+offset+index) lie inside the network boundaries # TODO: verify whether the final addresses (network+offset+index) overlap with base node addresses # Note: the following can be overridden from commandline storage_ip_offset="30" declare -A network netmask network_base mtu network['mgmt']="172.20.10.0" netmask['mgmt']="255.255.255.0" network_base['mgmt']="172.20.10" mtu['mgmt']="1500" network['lan']="172.20.12.0" netmask['lan']="255.255.255.0" network_base['lan']="172.20.12" mtu['lan']="1500" declare -A domain_name domain_name['mgmt']="mgmt.private" domain_name['lan']="lan.private" domain_join="false" domain_site="" domain_join_as_rodc="false" sysvolrepl_password="HVP_dem0" # Note: no need to define reverse network domain names since they get automatically defined below declare -A reverse_domain_name ad_subdomain_prefix="ad" declare -A test_ip # Note: default values for test_ip derived below - defined here to allow loading as configuration parameters my_nameserver="8.8.8.8" my_forwarders="8.8.8.8" my_name="spike" 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" template_username="templateaduser" # Note: passwords must meet the AD complexity requirements root_password="HVP_dem0" admin_username="hvpadmin" admin_password="HVP_dem0" adroot_password="HVP_dem0" adadmin_password="HVP_dem0" serveradmin_password="HVP_dem0" workstationadmin_password="HVP_dem0" pawadmin_password="HVP_dem0" useradmin_password="HVP_dem0" infraadmin_password="HVP_dem0" declare -A service_spns declare -A service_pwds declare -A service_delegations declare -A service_apdelegations adbind_username="binduser" adbind_password="BindPassw0rd" keyboard_layout="us" 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_dc.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 cluster members number given_node_count=$(sed -n -e 's/^.*hvp_nodecount=\(\S*\).*$/\1/p' /proc/cmdline) if ! echo "${given_node_count}" | grep -q '^[[:digit:]]\+$' ; then node_count="${default_node_count}" else node_count="${given_node_count}" fi # Define number of active storage members # Note: if we have three nodes only, then one (the last one) will be an all-arbiter no-I/O node if [ "${node_count}" -eq 3 ]; then active_storage_node_count="2" else active_storage_node_count="${node_count}" fi # Determine storage name given_storage_name=$(sed -n -e 's/^.*hvp_storagename=\(\S*\).*$/\1/p' /proc/cmdline) if [ -n "${given_storage_name}" ]; then # Correctly detect an empty (disabled) storage name if [ "${given_storage_name}" = '""' -o "${given_storage_name}" = "''" ]; then storage_name="" elif echo "${given_storage_name}" | grep -q '^[-[:alnum:]]\+$' ; then storage_name="${given_storage_name}" fi fi # Determine DFS share names and paths given_dfs_shares="$(grep -o 'hvp_dfs_[^[:space:]]*' /proc/cmdline)" if [ -n "${given_dfs_shares}" ]; then for dfs_entry in ${given_dfs_shares} ; do given_sharename=$(echo "${dfs_entry}" | sed -e 's/^hvp_dfs_//' -e 's/=.*$//') given_paths=$(echo "${dfs_entry}" | sed -e 's/^[^=]*=//') if [ -n "${given_sharename}" ]; then if [ "${given_paths}" = '""' -o "${given_paths}" = "''" -o -z "${given_paths}" ]; then unset dfs_shares["${given_sharename}"] else dfs_shares["${given_sharename}"]="${given_paths}" fi fi done 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 AD main admin password given_adroot_password=$(sed -n -e "s/^.*hvp_adrootpwd=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_adroot_password}" ]; then adroot_password="${given_adroot_password}" fi # Determine AD admin username given_adadmin_username=$(sed -n -e "s/^.*hvp_adadminname=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_adadmin_username}" ]; then adadmin_username="${given_adadmin_username}" fi if [ -z "${adadmin_username}" ]; then adadmin_username="ad${admin_username}" fi # Determine AD admin password given_adadmin_password=$(sed -n -e "s/^.*hvp_adadminpwd=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_adadmin_password}" ]; then adadmin_password="${given_adadmin_password}" fi # Determine AD servers admin username given_serveradmin_username=$(sed -n -e "s/^.*hvp_serveradminname=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_serveradmin_username}" ]; then serveradmin_username="${given_serveradmin_username}" fi if [ -z "${serveradmin_username}" ]; then serveradmin_username="srv${admin_username}" fi # Determine AD servers admin password given_serveradmin_password=$(sed -n -e "s/^.*hvp_serveradminpwd=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_serveradmin_password}" ]; then serveradmin_password="${given_serveradmin_password}" fi # Determine AD workstations admin username given_workstationadmin_username=$(sed -n -e "s/^.*hvp_workstationadminname=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_workstationadmin_username}" ]; then workstationadmin_username="${given_workstationadmin_username}" fi if [ -z "${workstationadmin_username}" ]; then workstationadmin_username="wks${admin_username}" fi # Determine AD workstations admin password given_workstationadmin_password=$(sed -n -e "s/^.*hvp_workstationadminpwd=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_workstationadmin_password}" ]; then workstationadmin_password="${given_workstationadmin_password}" fi # Determine AD PAWs admin username given_pawadmin_username=$(sed -n -e "s/^.*hvp_pawadminname=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_pawadmin_username}" ]; then pawadmin_username="${given_pawadmin_username}" fi if [ -z "${pawadmin_username}" ]; then pawadmin_username="paw${admin_username}" fi # Determine AD PAWs admin password given_pawadmin_password=$(sed -n -e "s/^.*hvp_pawadminpwd=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_pawadmin_password}" ]; then pawadmin_password="${given_pawadmin_password}" fi # Determine AD users admin username given_useradmin_username=$(sed -n -e "s/^.*hvp_useradminname=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_useradmin_username}" ]; then useradmin_username="${given_useradmin_username}" fi if [ -z "${useradmin_username}" ]; then useradmin_username="usr${admin_username}" fi # Determine AD users admin password given_useradmin_password=$(sed -n -e "s/^.*hvp_useradminpwd=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_useradmin_password}" ]; then useradmin_password="${given_useradmin_password}" fi # Determine AD infrastructure admin username given_infraadmin_username=$(sed -n -e "s/^.*hvp_infraadminname=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_infraadmin_username}" ]; then infraadmin_username="${given_infraadmin_username}" fi if [ -z "${infraadmin_username}" ]; then infraadmin_username="infra${admin_username}" fi # Determine AD infrastructure admin password given_infraadmin_password=$(sed -n -e "s/^.*hvp_infraadminpwd=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_infraadmin_password}" ]; then infraadmin_password="${given_infraadmin_password}" fi # Determine AD service accounts names and SPNs given_service_spns="$(grep -o 'hvp_spn_[^[:space:]]*' /proc/cmdline)" if [ -n "${given_service_spns}" ]; then for service_entry in ${given_service_spns} ; do given_username=$(echo "${service_entry}" | sed -e 's/^hvp_spn_//' -e 's/=.*$//') given_spns=$(echo "${service_entry}" | sed -e 's/^[^=]*=//') if [ -n "${given_username}" ]; then if [ "${given_spns}" = '""' -o "${given_spns}" = "''" ]; then unset service_spns["${given_username}"] else service_spns["${given_username}"]="${given_spns}" fi fi done fi # Determine AD service account password given_service_pwds="$(grep -o 'hvp_pwd_[^[:space:]]*' /proc/cmdline)" if [ -n "${given_service_pwds}" ]; then for service_entry in ${given_service_pwds} ; do given_username=$(echo "${service_entry}" | sed -e 's/^hvp_pwd_//' -e 's/=.*$//') given_pwd=$(echo "${service_entry}" | sed -e 's/^[^=]*=//') if [ -n "${given_username}" ]; then if [ "${given_pwds}" = '""' -o "${given_pwds}" = "''" ]; then unset service_pwds["${given_username}"] else service_pwds["${given_username}"]="${given_pwd}" fi fi done fi # Determine AD unconstrained delegation rights for service accounts given_delegations=$(sed -n -e "s/^.*hvp_ucdelegations=\\(\\S*\\).*\$/\\1/p" -e 's/,/ /g' /proc/cmdline) if [ -n "${given_delegations}" ]; then for given_username in ${given_delegations}; do if [ -n "${service_spns[${given_username}]}" ]; then service_delegations["${given_username}"]="unconstrained" fi done fi # Determine AD constrained delegation rights for service accounts given_delegation_spns="$(grep -o 'hvp_delegation_[^[:space:]]*' /proc/cmdline)" if [ -n "${given_delegation_spns}" ]; then for delegation_entry in ${given_delegation_spns} ; do given_username=$(echo "${delegation_entry}" | sed -e 's/^hvp_delegation_//' -e 's/=.*$//') given_spns=$(echo "${delegation_entry}" | sed -e 's/^[^=]*=//') if [ -n "${given_username}" ]; then if [ "${given_spns}" = '""' -o "${given_spns}" = "''" ]; then unset service_delegations["${given_username}"] else service_delegations["${given_username}"]="${given_spns}" fi fi done fi # Determine AD any-protocol delegation option for service accounts given_apdelegations=$(sed -n -e "s/^.*hvp_apdelegations=\\(\\S*\\).*\$/\\1/p" -e 's/,/ /g' /proc/cmdline) if [ -n "${given_apdelegations}" ]; then for given_username in ${given_delegations}; do if [ -n "${service_spns[${given_username}]}" ]; then service_apdelegations["${given_username}"]="true" fi done fi # Determine AD LDAP bind username given_adbind_username=$(sed -n -e "s/^.*hvp_adbindname=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_adbind_username}" ]; then adbind_username="${given_adbind_username}" fi # Determine AD LDAP bind password given_adbind_password=$(sed -n -e "s/^.*hvp_adbindpwd=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_adbind_password}" ]; then adbind_password="${given_adbind_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 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 storage IPs offset base given_storage_offset=$(sed -n -e 's/^.*hvp_storage_offset=\(\S*\).*$/\1/p' /proc/cmdline) if echo "${given_storage_offset}" | grep -q '^[[:digit:]]\+$' ; then storage_ip_offset="${given_storage_offset}" fi # Determine Gluster NFS-shares volume name given_volume_name=$(sed -n -e "s/^.*hvp_unixshare_volumename=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_volume_name}" ]; then gluster_vol_name['unixshare']="${given_volume_name}" 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 multi-instance limit given_multi_instance_max=$(sed -n -e 's/^.*hvp_maxinstances=\(\S*\).*$/\1/p' /proc/cmdline) if echo "${given_multi_instance_max}" | grep -q '^[[:digit:]]\+$' ; then multi_instance_max="${given_multi_instance_max}" 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 NetBIOS domain name given_netbiosdomain=$(sed -n -e 's/^.*hvp_netbiosdomain=\(\S*\).*$/\1/p' /proc/cmdline) if echo "${given_netbiosdomain}" | grep -q '^[[:alnum:]]\+$' ; then netbios_domain_name=$(echo "${given_netbiosdomain}" | awk '{print toupper($0)}') 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 site to join given_joinsite=$(sed -n -e "s/^.*hvp_joinsite=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_joinsite}" ]; then if [ "${given_joinsite}" = '""' -o "${given_joinsite}" = "''" ]; then domain_site="" else domain_site="${given_joinsite}" fi elif grep -w -q 'hvp_joinsite=' /proc/cmdline; then domain_site="" fi # Determine domain controller join mode given_joinrodcmode=$(sed -n -e 's/^.*hvp_joinasrodc=\(\S*\).*$/\1/p' /proc/cmdline) if echo "${given_joinrodcmode}" | egrep -q '^(true|false)$' ; then domain_join_as_rodc="${given_joinrodcmode}" fi # Determine sysvol replication password given_sysvolrepl_password=$(sed -n -e "s/^.*hvp_sysvolpassword=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_sysvolrepl_password}" ]; then sysvolrepl_password="${given_sysvolrepl_password}" fi # Determine nameserver address given_nameserver=$(sed -n -e "s/^.*hvp_nameserver=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_nameserver}" ]; then my_nameserver="${given_nameserver}" fi # Determine forwarders addresses given_forwarders=$(sed -n -e "s/^.*hvp_forwarders=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_forwarders}" ]; then my_forwarders="${given_forwarders}" 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 # Determine gateway address given_gateway=$(sed -n -e "s/^.*hvp_gateway=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_gateway}" ]; then my_gateway="${given_gateway}" fi # Determine network segments parameters unset my_ip declare -A my_ip for zone in "${!network[@]}" ; do given_network_domain_name=$(sed -n -e "s/^.*hvp_${zone}_domainname=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_network_domain_name}" ]; then domain_name["${zone}"]="${given_network_domain_name}" fi given_network_mtu=$(sed -n -e "s/^.*hvp_${zone}_mtu=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_network_mtu}" ]; then mtu["${zone}"]="${given_network_mtu}" fi given_network=$(sed -n -e "s/^.*hvp_${zone}=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) unset NETWORK NETMASK eval $(ipcalc -s -n "${given_network}") eval $(ipcalc -s -m "${given_network}") if [ -n "${NETWORK}" -a -n "${NETMASK}" ]; then network["${zone}"]="${NETWORK}" netmask["${zone}"]="${NETMASK}" fi NETWORK=${network["${zone}"]} NETMASK=${netmask["${zone}"]} given_network_my_ip=$(sed -n -e "s/^.*hvp_${zone}_my_ip=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_network_my_ip}" ]; then my_ip["${zone}"]="${given_network_my_ip}" else unset IPADDR IPADDR=$(echo "${given_network}" | sed -n -e 's>^\([^/]*\)/.*$>\1>p') if [ -n "${IPADDR}" -a "${IPADDR}" != "${NETWORK}" ]; then my_ip["${zone}"]="${IPADDR}" else my_ip["${zone}"]=$(ipmat ${NETWORK} ${my_ip_offset} +) fi fi given_network_test_ip=$(sed -n -e "s/^.*hvp_${zone}_test_ip=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_network_test_ip}" ]; then test_ip["${zone}"]="${given_network_test_ip}" fi if [ -z "${test_ip[${zone}]}" ]; then test_ip["${zone}"]=$(ipmat ${NETWORK} ${test_ip_offset} +) fi unset PREFIX eval $(ipcalc -s -p "${NETWORK}" "${NETMASK}") if [ "${PREFIX}" -ge 24 ]; then reverse_domain_name["${zone}"]=$(echo ${NETWORK} | awk -F. 'BEGIN {OFS="."}; {print $3,$2,$1}').in-addr.arpa network_base["${zone}"]=$(echo ${NETWORK} | awk -F. 'BEGIN {OFS="."}; {print $1,$2,$3}') elif [ "${PREFIX}" -ge 16 ]; then reverse_domain_name["${zone}"]=$(echo ${NETWORK} | awk -F. 'BEGIN {OFS="."}; {print $2,$1}').in-addr.arpa network_base["${zone}"]=$(echo ${NETWORK} | awk -F. 'BEGIN {OFS="."}; {print $1,$2}') elif [ "${PREFIX}" -ge 8 ]; then reverse_domain_name["${zone}"]=$(echo ${NETWORK} | awk -F. 'BEGIN {OFS="."}; {print $1}').in-addr.arpa network_base["${zone}"]=$(echo ${NETWORK} | awk -F. 'BEGIN {OFS="."}; {print $1}') fi done # Disable any interface configured by NetworkManager # Note: NetworkManager may interfer with interface assignment autodetection logic below # Note: interfaces will be explicitly activated again by our dynamically created network configuration fragment for nic_device_name in $(nmcli -t device show | awk -F: '/^GENERAL\.DEVICE:/ {print $2}' | egrep -v '^(bonding_masters|lo|sit[0-9])$' | sort); do if nmcli -t device show "${nic_device_name}" | grep -q '^GENERAL\.STATE:.*(connected)' ; then nmcli device disconnect "${nic_device_name}" ip addr flush dev "${nic_device_name}" ip link set mtu 1500 dev "${nic_device_name}" fi done for connection_name in $(nmcli -t connection show | awk -F: '{print $1}' | sort); do nmcli connection delete "${connection_name}" done # Determine network interface assignment # Note: unconnected nics will be disabled unset nics declare -A nics for nic_name in $(ls /sys/class/net/ 2>/dev/null | egrep -v '^(bonding_masters|lo|sit[0-9])$' | sort); do # 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 ip addr flush dev "${nic_name}" nic_assigned='false' for zone in "${!network[@]}" ; do # Note: check whether the desired MTU setting can be obtained or not - skip if it fails ip link set mtu "${mtu[${zone}]}" dev "${nic_name}" res=$? effective_mtu=$(cat /sys/class/net/${nic_name}/mtu 2>/dev/null) if [ ${res} -ne 0 -o "${effective_mtu}" != "${mtu[${zone}]}" ] ; then ip addr flush dev "${nic_name}" ip link set mtu 1500 dev "${nic_name}" continue fi unset PREFIX eval $(ipcalc -s -p "${network[${zone}]}" "${netmask[${zone}]}") # Perform duplicate IP detection and increment IP till it is unique tentative_ip_found="false" for ((ip_increment=0;ip_increment<=${multi_instance_max};ip_increment=ip_increment+1)); do tentative_ip=$(ipmat ${my_ip[${zone}]} ${ip_increment} +) if arping -q -c 2 -w 3 -D -I ${nic_name} ${tentative_ip} ; then # No collision detected: try to use this IP address tentative_ip_found="true" break fi done if [ "${tentative_ip_found}" = "false" ]; then # All IP addresses already taken - skip continue fi ip addr add "${tentative_ip}/${PREFIX}" dev "${nic_name}" res=$? if [ ${res} -ne 0 ] ; then # There has been a problem in assigning the IP address - skip ip addr flush dev "${nic_name}" ip link set mtu 1500 dev "${nic_name}" continue fi # Note: adding extra sleep and ping to work around possible hardware delays sleep 2 ping -c 3 -w 8 -i 2 "${test_ip[${zone}]}" > /dev/null 2>&1 if ping -c 3 -w 8 -i 2 "${test_ip[${zone}]}" > /dev/null 2>&1 ; then nics["${zone}"]="${nics[${zone}]} ${nic_name}" nic_assigned='true' # Note: we keep IP addresses aligned on all zones # Note: IP/name coherence check and correction demanded to post-install rc.ks1stboot script for zone_to_align in "${!network[@]}" ; do my_ip[${zone_to_align}]=$(ipmat ${my_ip[${zone_to_align}]} ${ip_increment} +) done ip addr flush dev "${nic_name}" ip link set mtu 1500 dev "${nic_name}" break fi ip addr flush dev "${nic_name}" ip link set mtu 1500 dev "${nic_name}" done if [ "${nic_assigned}" = "false" ]; then # Disable unassignable nics nics['unused']="${nics['unused']} ${nic_name}" fi else # Disable unconnected nics nics['unused']="${nics['unused']} ${nic_name}" fi done # TODO: Perform nic connections consistency check # TODO: either offer service on all networks or keep mgmt as trusted if there is at least another one # Remove my_ip/test_ip, network/netmask/network_base/mtu and domain_name/reverse_domain_name entries for non-existent networks for zone in "${!network[@]}" ; do if [ -z "${nics[${zone}]}" ]; then unset my_ip[${zone}] unset test_ip[${zone}] unset network[${zone}] unset netmask[${zone}] unset network_base[${zone}] unset mtu[${zone}] unset domain_name[${zone}] unset reverse_domain_name[${zone}] fi done # Determine network segment identity and parameters if [ -n "${nics['lan']}" ]; then my_zone="lan" elif [ -n "${nics['mgmt']}" ]; then my_zone="mgmt" fi if [ -z "${my_gateway}" ]; then my_gateway="${test_ip[${my_zone}]}" fi # Define default NetBIOS domain name if not specified if [ -z "${netbios_domain_name}" ]; then netbios_domain_name=$(echo ${ad_subdomain_prefix}.${domain_name[${my_zone}]} | awk -F. '{print toupper($1)}') fi # Perform check to detect conflated domain name spaces # Note: in presence even of a couple of conflated domain name spaces we will force hostname suffixes on all subnets use_hostname_decoration="false" added_zones="" for zone in "${!network[@]}" ; do if echo "${added_zones}" | grep -q -w $(echo "${domain_name[${zone}]}" | sed -e 's/[.]/\\./g') ; then use_hostname_decoration="true" break fi added_zones="${added_zones} ${domain_name[${zone}]}" done # Create network setup fragment # Note: dynamically created here to make use of full autodiscovery above # Note: defining statically configured access to autodetected networks # TODO: Anaconda/NetworkManager do not add DEFROUTE="no" and MTU="xxxx" parameters - adding workarounds here - remove when fixed upstream mkdir -p /tmp/hvp-networkmanager-conf pushd /tmp/hvp-networkmanager-conf cat << EOF > /tmp/full-network # Network device configuration - static 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 for zone in "${!network[@]}" ; do if [ -n "${nics[${zone}]}" ]; then nic_names=$(echo ${nics[${zone}]} | sed -e 's/^\s*//' -e 's/\s*$//') further_options="" # Add gateway and nameserver options only if the default gateway is on this network unset NETWORK eval $(ipcalc -s -n "${my_gateway}" "${netmask[${zone}]}") if [ "${NETWORK}" = "${network[${zone}]}" ]; then further_options="${further_options} --gateway=${my_gateway} --nameserver=${my_nameserver}" # TODO: workaround for Anaconda/NetworkManager bug - remove when fixed upstream echo 'DEFROUTE="yes"' >> ifcfg-${nic_names} else further_options="${further_options} --nodefroute" # TODO: workaround for Anaconda/NetworkManager bug - remove when fixed upstream echo 'DEFROUTE="no"' >> ifcfg-${nic_names} fi # Add hostname option on the trusted zone only if [ "${zone}" = "${my_zone}" ]; then further_options="${further_options} --hostname=${my_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${zone}" ; fi).${ad_subdomain_prefix}.${domain_name[${zone}]}" fi # Single (plain) interface # TODO: support multiple interfaces per zone (mainly for the physical machine case) - introduce bondopts for each zone cat <<- EOF >> /tmp/full-network network --device=${nic_names} --activate --onboot=yes --bootproto=static --ip=${my_ip[${zone}]} --netmask=${netmask[${zone}]} --mtu=${mtu[${zone}]} ${further_options} EOF # TODO: workaround for Anaconda/NetworkManager bug - remove when fixed upstream echo "MTU=\"${mtu[${zone}]}\"" >> ifcfg-${nic_names} fi done for nic_name in ${nics['unused']} ; do # TODO: the following makes anaconda crash because of https://bugzilla.redhat.com/show_bug.cgi?id=1418289 # TODO: restore when fixed upstream #network --device=${nic_name} --no-activate --nodefroute --onboot=no --noipv4 --noipv6 cat <<- EOF >> /tmp/full-network network --device=${nic_name} --no-activate --nodefroute --onboot=no EOF done popd # 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 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 # Lock root account passwd -l root # Deny root login from SSH sed -i -e 's/^#\\s*PermitRootLogin.*\$/PermitRootLogin no/' /etc/ssh/sshd_config # TODO: reload hangs - working around with background reload systemctl reload sshd & # Add local admin user to wheel group to allow liberal use of sudo # Note: AD DC servers must remain manageable even if AD is non-functional usermod -a -G wheel ${admin_username} # 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 cat << EOF > /tmp/full-localization # Default system language, additional languages can be enabled installing the appropriate packages below lang en_US.UTF-8 # Keyboard layout keyboard --vckeymap=${keyboard_layout} # 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} --append="nomodeset" # 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 DCVG pv.01 # Define swap space logvol swap --vgname=DCVG --name=swap --fstype=swap --recommended # Define further filesystems logvol / --vgname=DCVG --name=root --size=6000 logvol /var --vgname=DCVG --name=var --size=2000 logvol /var/cache --vgname=DCVG --name=var_cache --size=5000 logvol /var/crash --vgname=DCVG --name=var_crash --size=12000 logvol /var/lib --vgname=DCVG --name=var_lib --size=10000 --grow logvol /var/log --vgname=DCVG --name=var_log --size=10000 logvol /var/log/audit --vgname=DCVG --name=var_log_audit --size=2000 logvol /var/spool --vgname=DCVG --name=var_spool --size=3000 logvol /var/tmp --vgname=DCVG --name=var_tmp --size=2000 --fsoptions=noexec,nosuid,nodev logvol /home --vgname=DCVG --name=home --size=1000 --fsoptions=noexec,nosuid,nodev logvol /tmp --vgname=DCVG --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 NTPd/NTPdate configuration fragment to be appended later on below # Note: using generic configuration - for non-PDC-emulator DCs the domain-setup script and/or a cron job will change it mkdir -p /tmp/hvp-ntpd-conf pushd /tmp/hvp-ntpd-conf for server in $(echo "${my_ntpservers}" | sed -e 's/,/ /g'); do echo "${server}" >> step-tickers echo "server ${server} iburst" >> ntp.conf done cat << EOF >> ntp.conf restrict ${network[${my_zone}]} mask ${netmask[${my_zone}]} nomodify notrap EOF popd # Prepare hosts file to be copied later on below mkdir -p /tmp/hvp-bind-zones pushd /tmp/hvp-bind-zones cat << EOF > hosts # Static hostnames EOF for zone in "${!network[@]}" ; do if [ "${zone}" = "${my_zone}" ]; then cat <<- EOF >> hosts ${my_ip[${zone}]} ${my_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${zone}" ; fi).${ad_subdomain_prefix}.${domain_name[${zone}]} ${my_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${zone}" ; fi) EOF else cat <<- EOF >> hosts ${my_ip[${zone}]} ${my_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${zone}" ; fi).${domain_name[${zone}]} EOF fi done popd # Prepare TCP wrappers custom lines to be appended later on # TODO: in presence of more than one network, distinguish services to be offered on all from those restricted to the trusted one # TODO: align firewalld zones/rules with this logic mkdir -p /tmp/hvp-tcp_wrappers-conf allowed_addr="127.0.0.1" for zone in "${!network[@]}" ; do if [ -n "${nics[${zone}]}" ]; then allowed_addr="${network[${zone}]}/${netmask[${zone}]} ${allowed_addr}" fi done cat << EOF > /tmp/hvp-tcp_wrappers-conf/hosts.allow ALL: ${allowed_addr} EOF # Create Samba AD DC domain joining/provisioning script mkdir -p /tmp/hvp-samba-conf pushd /tmp/hvp-samba-conf realm_name=$(echo ${ad_subdomain_prefix}.${domain_name[${my_zone}]} | awk '{print toupper($0)}') # Adapt joining options to specified custom AD site # TODO: allow to detect a custom AD site from assigned IP subnet if [ -n "${domain_site}" ]; then site_option="--site=${domain_site}" else site_option="" fi # Adapt join mode to specified option if [ "${domain_join_as_rodc}" = "true" ]; then dc_type="RODC" else dc_type="DC" fi cat << EOF > rc.samba-dc #!/bin/bash # Create secrets file for sysvol and DFS-root replication cat << EOM > /etc/samba/rsync-sysvol-dfsroot.secret root:${sysvolrepl_password} EOM chmod 600 /etc/samba/rsync-sysvol-dfsroot.secret chown root:root /etc/samba/rsync-sysvol-dfsroot.secret nic_names="$(echo ${nics[${my_zone}]} | sed -e 's/^\s*//' -e 's/\s*$//')" if [ "${domain_join}" = "true" ]; then action="joining" # Make sure to sync only with the proper time reference (emulate Windows behaviour, using as reference the DC holding the PDC emulator FSMO role) domain_pdc_emulator=\$(dig _ldap._tcp.pdc._msdcs.${ad_subdomain_prefix}.${domain_name[${my_zone}]} SRV +short | awk '{print \$4}' | sed -e 's/[.]\$//') # Note: if we failed to get the PDC emulator, then assume that the given nameserver (which should be an existing AD DC) is a proper reference if [ -z "\${domain_pdc_emulator}" ]; then domain_pdc_emulator="${my_nameserver}" fi echo "\${domain_pdc_emulator}" > /etc/ntp/step-tickers sed -i -e '/^server\\s/s/^/#/g' /etc/ntp.conf cat <<- EOM >> /etc/ntp.conf # Always sync with our currrent PDC emulator DC server only server \${domain_pdc_emulator} iburst EOM # Stop NTPd systemctl stop ntpd # Resync time with PDC emulator AD DC systemctl restart ntpdate # Restart NTPd systemctl start ntpd # Setup krb5.conf properly sed -i -e '/^\\s*includedir/s/^/#/g' -e "s/^\\\\(\\\\s*\\\\)\\\\(dns_lookup_realm\\\\s*=.*\\\\)\\$/\\\\1\\\\2\n\\\\1dns_lookup_kdc = true\\\\n\\\\1default_realm = ${realm_name}/" /etc/krb5.conf # Clean up any previous Samba settings rm -f /etc/samba/smb.conf # Perform domain joining # TODO: detect and adapt RFC2307 option samba-tool domain join ${ad_subdomain_prefix}.${domain_name[${my_zone}]} ${dc_type} --dns-backend=SAMBA_INTERNAL ${site_option} --option="interfaces = lo \${nic_names}" --option="bind interfaces only = yes" --option='idmap_ldb:use rfc2307 = yes' --option="kerberos method = secrets and keytab" --option="dedicated keytab file = /etc/krb5.keytab" -U administrator@${realm_name} --password='${adroot_password}' res=\$? else action="provisioning" # Clean up any previous Kerberos/Samba settings rm -f /etc/krb5.* /etc/samba/smb.conf # Perform domain provisioning samba-tool domain provision --use-rfc2307 --realm=${realm_name} --domain=${netbios_domain_name} --server-role=dc --dns-backend=SAMBA_INTERNAL --option="interfaces = lo \${nic_names}" --option="bind interfaces only = yes" --option="kerberos method = secrets and keytab" --option="dedicated keytab file = /etc/krb5.keytab" --adminpass='${adroot_password}' res=\$? fi if [ \${res} -eq 0 ]; then # Add DNS forwarders sed -i -e '/^\s*dns\s*forwarder\s*=/d' /etc/samba/smb.conf sed -i -e "s/^\\(\\s*\\)\\(server\\s*role.*\\)\$/\\1\\2\\n\\1dns forwarder = $(echo ${my_forwarders} | sed -e 's/,/ /g')/" /etc/samba/smb.conf # Configure Winbindd parameters # Note: Winbind on a DC cannot read POSIX parameters from AD besides uids and gids # Note: forcing special admin-style homedir paths since only AD admins can login on a DC sed -i -e '/^\s*template\s*homedir\s*=/d' /etc/samba/smb.conf sed -i -e "s>^\\(\\s*\\)\\(server\\s*role.*\\)\$>\\1\\2\\n\\1template homedir = /home/local/%U>" /etc/samba/smb.conf sed -i -e '/^\s*template\s*shell\s*=/d' /etc/samba/smb.conf sed -i -e "s%^\\(\\s*\\)\\(server\\s*role.*\\)\$%\\1\\2\\n\\1template shell = /bin/bash%" /etc/samba/smb.conf # Disable anonymous connections sed -i -e '/^\s*restrict\s*anonymous\s*=/d' /etc/samba/smb.conf sed -i -e "s/^\\(\\s*\\)\\(server\\s*role.*\\)\$/\\1\\2\\n\\1restrict anonymous = 2/" /etc/samba/smb.conf # Disable printing support sed -i -e "s%^\\(\\s*\\)\\(server\\s*role.*\\)\$%\\1\\2\\n\\1load printers = no\\n\\1printing = bsd\\n\\1printcap name = /dev/null\\n\\1disable spoolss = yes\\n\\1show add printer wizard = no\\n\\1cups options = raw%" /etc/samba/smb.conf # Add NTLMv1 (only when using MSCHAPv2) support required by FreeRADIUS as per https://wiki.samba.org/index.php/Authenticating_Freeradius_against_Active_Directory sed -i -e '/^\s*ntlm\s*auth\s*=/d' /etc/samba/smb.conf sed -i -e "s/^\\(\\s*\\)\\(server\\s*role.*\\)\$/\\1\\2\\n\\1ntlm auth = mschapv2-and-ntlmv2-only/" /etc/samba/smb.conf # Add search ACL support required by LAPS # TODO: verify whether this brings errors as per https://bugzilla.samba.org/show_bug.cgi?id=9788 sed -i -e '/^\s*acl:search\s*=/d' /etc/samba/smb.conf sed -i -e "s/^\\(\\s*\\)\\(server\\s*role.*\\)\$/\\1\\2\\n\\1acl:search = yes/" /etc/samba/smb.conf # Add domain-based DFS support # Note: lowercase limitations as per https://wiki.samba.org/index.php/Distributed_File_System_(DFS)#Configure_domain-based_DFS_in_Samba # Note: this must be explicitly configured on all DCs sed -i -e '/^\s*host\s*msdfs\s*=/d' /etc/samba/smb.conf sed -i -e "s/^\\(\\s*\\)\\(server\\s*role.*\\)\$/\\1\\2\\n\\1host msdfs = yes/" /etc/samba/smb.conf cat <<- EOM >> /etc/samba/smb.conf [dfs] path = /var/lib/samba/dfsroot msdfs root = yes vfs object = dfs_samba4 EOM mkdir -p /var/lib/samba/dfsroot EOF if [ "${domain_join}" != "true" ]; then # Unconditionally add basic shares if Gluster storage has been configured if [ -n "${storage_name}" ]; then cat <<- EOF >> rc.samba-dc ln -s 'msdfs:\\\\${storage_name}.${ad_subdomain_prefix}.${domain_name[${my_zone}]}\\users' /var/lib/samba/dfsroot/users ln -s 'msdfs:\\\\${storage_name}.${ad_subdomain_prefix}.${domain_name[${my_zone}]}\\profiles' /var/lib/samba/dfsroot/profiles ln -s 'msdfs:\\\\${storage_name}.${ad_subdomain_prefix}.${domain_name[${my_zone}]}\\groups' /var/lib/samba/dfsroot/groups ln -s 'msdfs:\\\\${storage_name}.${ad_subdomain_prefix}.${domain_name[${my_zone}]}\\software' /var/lib/samba/dfsroot/software EOF fi # Add custom shares for dfs_sharename in "${!dfs_shares[@]}"; do cat <<- EOF >> rc.samba-dc ln -s 'msdfs:$( echo "${dfs_shares[${dfs_sharename}]}" | sed -e 's/\\/\\\\/g')' /var/lib/samba/dfsroot/${dfs_sharename} EOF done fi cat << EOF >> rc.samba-dc # Make global Kerberos configuration equal to Samba custom configuration # Note: autogenerated custom krb5.conf does not enable forwardable tickets cp /var/lib/samba/private/krb5.conf /etc/krb5.conf # Enable signed NTP replies cat <<- EOM >> /etc/ntp.conf # Signed responses for Windows AD members ntpsigndsocket /var/lib/samba/ntp_signd/ restrict default mssntp EOM # Always provide reference to clients cat <<- EOM >> /etc/ntp.conf # Always provide reference to clients server 127.127.1.0 fudge 127.127.1.0 stratum 8 EOM if [ "${domain_join}" != "true" ]; then # Define generally useful values nis_domain="$(echo ${ad_subdomain_prefix}.${domain_name[${my_zone}]} | awk -F. '{print $1}')" domain_top_dn=\$(ldbsearch -H /var/lib/samba/private/sam.ldb -s base dn | awk '/^dn:/ {print \$2}') # Modify AD schema for basic POSIX attributes replication in GC cat <<- EOM > /etc/samba/gc_add_uid.ldif dn: CN=UidNumber,CN=Schema,CN=Configuration,\${domain_top_dn} changetype: modify replace: isMemberOfPartialAttributeSet isMemberOfPartialAttributeSet: TRUE EOM cat <<- EOM > /etc/samba/gc_add_gid.ldif dn: CN=GidNumber,CN=Schema,CN=Configuration,\${domain_top_dn} changetype: modify replace: isMemberOfPartialAttributeSet isMemberOfPartialAttributeSet: TRUE EOM ldbmodify -H /var/lib/samba/private/sam.ldb /etc/samba/gc_add_uid.ldif --option="dsdb:schema update allowed"=true ldbmodify -H /var/lib/samba/private/sam.ldb /etc/samba/gc_add_gid.ldif --option="dsdb:schema update allowed"=true # Modify AD schema for automounter maps support cat <<- EOM > /etc/samba/automount_attrs.ldif dn: CN=automountMapName,CN=Schema,CN=Configuration,\${domain_top_dn} objectClass: top objectClass: attributeSchema attributeID: 1.3.6.1.1.1.1.31 schemaIdGuid:: SQGtFScvaoDZ8hUMHirmCw== cn: automountMapName name: automountMapName lDAPDisplayName: automountMapName description: Automount Map Name attributeSyntax: 2.5.5.5 oMSyntax: 22 isSingleValued: TRUE dn: CN=automountKey,CN=Schema,CN=Configuration,\${domain_top_dn} objectClass: top objectClass: attributeSchema attributeID: 1.3.6.1.1.1.1.32 schemaIdGuid:: qGFH0ubAc2p2pJgxor8N7A== cn: automountKey name: automountKey lDAPDisplayName: automountKey description: Automount Key value attributeSyntax: 2.5.5.5 oMSyntax: 22 isSingleValued: TRUE dn: CN=automountInformation,CN=Schema,CN=Configuration,\${domain_top_dn} objectClass: top objectClass: attributeSchema attributeID: 1.3.6.1.1.1.1.33 schemaIdGuid:: WJnCqDrTLttu+RyBBWWpPQ== cn: automountInformation name: automountInformation lDAPDisplayName: automountInformation description: Automount information attributeSyntax: 2.5.5.5 oMSyntax: 22 isSingleValued: TRUE EOM cat <<- EOM > /etc/samba/automount_classes.ldif dn: CN=automountMap,CN=Schema,CN=Configuration,\${domain_top_dn} objectClass: top objectClass: classSchema governsID: 1.3.6.1.1.1.2.16 schemaIdGuid:: d51ct3yZs79jXxoAG2zfHA== cn: automountMap name: automountMap lDAPDisplayName: automountMap subClassOf: top objectClassCategory: 3 mustContain: automountMapName mayContain: description defaultObjectCategory: CN=automountMap,CN=Schema,CN=Configuration,\${domain_top_dn} dn: CN=automount,CN=Schema,CN=Configuration,\${domain_top_dn} objectClass: top objectClass: classSchema governsID: 1.3.6.1.1.1.2.17 schemaIdGuid:: LKPdMpqFmsHw2t6Ewsj9Rw== cn: automount name: automount lDAPDisplayName: automount subClassOf: top objectClassCategory: 3 description: Automount information mustContain: automountKey mustContain: automountInformation mayContain: description defaultObjectCategory: CN=automount,CN=Schema,CN=Configuration,\${domain_top_dn} EOM ldbmodify -H /var/lib/samba/private/sam.ldb /etc/samba/automount_attrs.ldif --option="dsdb:schema update allowed"=true ldbmodify -H /var/lib/samba/private/sam.ldb /etc/samba/automount_classes.ldif --option="dsdb:schema update allowed"=true # Modify AD schema for sudo rules support cat <<- EOM > /etc/samba/sudo_attrs.ldif dn: CN=sudoUser,CN=Schema,CN=Configuration,\${domain_top_dn} changetype: add objectClass: top objectClass: attributeSchema cn: sudoUser distinguishedName: CN=sudoUser,CN=Schema,CN=Configuration,\${domain_top_dn} instanceType: 4 attributeID: 1.3.6.1.4.1.15953.9.1.1 attributeSyntax: 2.5.5.5 isSingleValued: FALSE showInAdvancedViewOnly: FALSE adminDisplayName: sudoUser adminDescription: User(s) who may run sudo oMSyntax: 22 searchFlags: 1 lDAPDisplayName: sudoUser name: sudoUser schemaIDGUID:: JrGcaKpnoU+0s+HgeFjAbg== objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,\${domain_top_dn} dn: CN=sudoHost,CN=Schema,CN=Configuration,\${domain_top_dn} changetype: add objectClass: top objectClass: attributeSchema cn: sudoHost distinguishedName: CN=sudoHost,CN=Schema,CN=Configuration,\${domain_top_dn} instanceType: 4 attributeID: 1.3.6.1.4.1.15953.9.1.2 attributeSyntax: 2.5.5.5 isSingleValued: FALSE showInAdvancedViewOnly: FALSE adminDisplayName: sudoHost adminDescription: Host(s) who may run sudo oMSyntax: 22 lDAPDisplayName: sudoHost name: sudoHost schemaIDGUID:: d0TTjg+Y6U28g/Y+ns2k4w== objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,\${domain_top_dn} dn: CN=sudoCommand,CN=Schema,CN=Configuration,\${domain_top_dn} changetype: add objectClass: top objectClass: attributeSchema cn: sudoCommand distinguishedName: CN=sudoCommand,CN=Schema,CN=Configuration,\${domain_top_dn} instanceType: 4 attributeID: 1.3.6.1.4.1.15953.9.1.3 attributeSyntax: 2.5.5.5 isSingleValued: FALSE showInAdvancedViewOnly: FALSE adminDisplayName: sudoCommand adminDescription: Command(s) to be executed by sudo oMSyntax: 22 lDAPDisplayName: sudoCommand name: sudoCommand schemaIDGUID:: D6QR4P5UyUen3RGYJCHCPg== objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,\${domain_top_dn} dn: CN=sudoRunAs,CN=Schema,CN=Configuration,\${domain_top_dn} changetype: add objectClass: top objectClass: attributeSchema cn: sudoRunAs distinguishedName: CN=sudoRunAs,CN=Schema,CN=Configuration,\${domain_top_dn} instanceType: 4 attributeID: 1.3.6.1.4.1.15953.9.1.4 attributeSyntax: 2.5.5.5 isSingleValued: FALSE showInAdvancedViewOnly: FALSE adminDisplayName: sudoRunAs adminDescription: User(s) impersonated by sudo (deprecated) oMSyntax: 22 lDAPDisplayName: sudoRunAs name: sudoRunAs schemaIDGUID:: CP98mCQTyUKKxGrQeM80hQ== objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,\${domain_top_dn} dn: CN=sudoOption,CN=Schema,CN=Configuration,\${domain_top_dn} changetype: add objectClass: top objectClass: attributeSchema cn: sudoOption distinguishedName: CN=sudoOption,CN=Schema,CN=Configuration,\${domain_top_dn} instanceType: 4 attributeID: 1.3.6.1.4.1.15953.9.1.5 attributeSyntax: 2.5.5.5 isSingleValued: FALSE showInAdvancedViewOnly: FALSE adminDisplayName: sudoOption adminDescription: Option(s) followed by sudo oMSyntax: 22 lDAPDisplayName: sudoOption name: sudoOption schemaIDGUID:: ojaPzBBlAEmsvrHxQctLnA== objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,\${domain_top_dn} dn: CN=sudoRunAsUser,CN=Schema,CN=Configuration,\${domain_top_dn} changetype: add objectClass: top objectClass: attributeSchema cn: sudoRunAsUser distinguishedName: CN=sudoRunAsUser,CN=Schema,CN=Configuration,\${domain_top_dn} instanceType: 4 attributeID: 1.3.6.1.4.1.15953.9.1.6 attributeSyntax: 2.5.5.5 isSingleValued: FALSE showInAdvancedViewOnly: FALSE adminDisplayName: sudoRunAsUser adminDescription: User(s) impersonated by sudo oMSyntax: 22 lDAPDisplayName: sudoRunAsUser name: sudoRunAsUser schemaIDGUID:: 9C52yPYd3RG3jMR2VtiVkw== objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,\${domain_top_dn} dn: CN=sudoRunAsGroup,CN=Schema,CN=Configuration,\${domain_top_dn} changetype: add objectClass: top objectClass: attributeSchema cn: sudoRunAsGroup distinguishedName: CN=sudoRunAsGroup,CN=Schema,CN=Configuration,\${domain_top_dn} instanceType: 4 attributeID: 1.3.6.1.4.1.15953.9.1.7 attributeSyntax: 2.5.5.5 isSingleValued: FALSE showInAdvancedViewOnly: FALSE adminDisplayName: sudoRunAsGroup adminDescription: Groups(s) impersonated by sudo oMSyntax: 22 lDAPDisplayName: sudoRunAsGroup name: sudoRunAsGroup schemaIDGUID:: xJhSt/Yd3RGJPTB1VtiVkw== objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,\${domain_top_dn} dn: CN=sudoNotBefore,CN=Schema,CN=Configuration,\${domain_top_dn} changetype: add objectClass: top objectClass: attributeSchema cn: sudoNotBefore distinguishedName: CN=sudoNotBefore,CN=Schema,CN=Configuration,\${domain_top_dn} instanceType: 4 attributeID: 1.3.6.1.4.1.15953.9.1.8 attributeSyntax: 2.5.5.11 isSingleValued: TRUE showInAdvancedViewOnly: FALSE adminDisplayName: sudoNotBefore adminDescription: Start of time interval for which the entry is valid oMSyntax: 24 lDAPDisplayName: sudoNotBefore name: sudoNotBefore schemaIDGUID:: dm1HnRfY4RGf4gopYYhwmw== objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,\${domain_top_dn} dn: CN=sudoNotAfter,CN=Schema,CN=Configuration,\${domain_top_dn} changetype: add objectClass: top objectClass: attributeSchema cn: sudoNotAfter distinguishedName: CN=sudoNotAfter,CN=Schema,CN=Configuration,\${domain_top_dn} instanceType: 4 attributeID: 1.3.6.1.4.1.15953.9.1.9 attributeSyntax: 2.5.5.11 isSingleValued: TRUE showInAdvancedViewOnly: FALSE adminDisplayName: sudoNotAfter adminDescription: End of time interval for which the entry is valid oMSyntax: 24 lDAPDisplayName: sudoNotAfter name: sudoNotAfter schemaIDGUID:: OAr/pBfY4RG9dBIpYYhwmw== objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,\${domain_top_dn} dn: CN=sudoOrder,CN=Schema,CN=Configuration,\${domain_top_dn} changetype: add objectClass: top objectClass: attributeSchema cn: sudoOrder distinguishedName: CN=sudoOrder,CN=Schema,CN=Configuration,\${domain_top_dn} instanceType: 4 attributeID: 1.3.6.1.4.1.15953.9.1.10 attributeSyntax: 2.5.5.9 isSingleValued: TRUE showInAdvancedViewOnly: FALSE adminDisplayName: sudoOrder adminDescription: an integer to order the sudoRole entries oMSyntax: 2 lDAPDisplayName: sudoOrder name: sudoOrder schemaIDGUID:: 0J8yrRfY4RGIYBUpYYhwmw== objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,\${domain_top_dn} EOM cat <<- EOM > /etc/samba/sudo_classes.ldif dn: CN=sudoRole,CN=Schema,CN=Configuration,\${domain_top_dn} changetype: add objectClass: top objectClass: classSchema cn: sudoRole distinguishedName: CN=sudoRole,CN=Schema,CN=Configuration,\${domain_top_dn} instanceType: 4 possSuperiors: container possSuperiors: top subClassOf: top governsID: 1.3.6.1.4.1.15953.9.2.1 mayContain: sudoCommand mayContain: sudoHost mayContain: sudoOption mayContain: sudoRunAs mayContain: sudoRunAsUser mayContain: sudoRunAsGroup mayContain: sudoUser mayContain: sudoNotBefore mayContain: sudoNotAfter mayContain: sudoOrder rDNAttID: cn showInAdvancedViewOnly: FALSE adminDisplayName: sudoRole adminDescription: Sudoer Entries objectClassCategory: 1 lDAPDisplayName: sudoRole name: sudoRole schemaIDGUID:: SQn432lnZ0+ukbdh3+gN3w== systemOnly: FALSE objectCategory: CN=Class-Schema,CN=Schema,CN=Configuration,\${domain_top_dn} defaultObjectCategory: CN=sudoRole,CN=Schema,CN=Configuration,\${domain_top_dn} EOM ldbmodify -H /var/lib/samba/private/sam.ldb /etc/samba/sudo_attrs.ldif --option="dsdb:schema update allowed"=true ldbmodify -H /var/lib/samba/private/sam.ldb /etc/samba/sudo_classes.ldif --option="dsdb:schema update allowed"=true # Modify AD schema for LAPS support # Note: as per LAPS-compatibile AdmPwd https://github.com/GreyCorbel/admpwd/blob/master/Main/_Other/AD_Schema/AdmPwd_SchemaUpdate.ldf cat <<- EOM > /etc/samba/laps_attrs.ldif dn: CN=ms-MCS-AdmPwd,CN=Schema,cn=configuration,\${domain_top_dn} changetype: add objectClass: attributeSchema ldapDisplayName: ms-MCS-AdmPwd adminDisplayName: ms-MCS-AdmPwd adminDescription: Stores password of local Administrator account on workstation attributeId: 1.2.840.113556.1.8000.2554.50051.45980.28112.18903.35903.6685103.1224907.2.1 attributeSyntax: 2.5.5.5 omSyntax: 19 isSingleValued: TRUE systemOnly: FALSE searchFlags: 904 isMemberOfPartialAttributeSet: FALSE showInAdvancedViewOnly: FALSE dn: CN=ms-MCS-AdmPwdExpirationTime,CN=Schema,cn=configuration,\${domain_top_dn} changetype: add objectClass: attributeSchema ldapDisplayName: ms-MCS-AdmPwdExpirationTime adminDisplayName: ms-MCS-AdmPwdExpirationTime adminDescription: Stores timestamp of last password change attributeId: 1.2.840.113556.1.8000.2554.50051.45980.28112.18903.35903.6685103.1224907.2.2 attributeSyntax: 2.5.5.16 omSyntax: 65 isSingleValued: TRUE systemOnly: FALSE searchFlags: 0 isMemberOfPartialAttributeSet: FALSE showInAdvancedViewOnly: FALSE EOM cat <<- EOM > /etc/samba/laps_class.ldif dn: CN=computer,CN=Schema,cn=configuration,\${domain_top_dn} changetype: modify add: mayContain mayContain: ms-MCS-AdmPwd mayContain: ms-MCS-AdmPwdExpirationTime EOM ldbmodify -H /var/lib/samba/private/sam.ldb /etc/samba/laps_attrs.ldif --option="dsdb:schema update allowed"=true ldbmodify -H /var/lib/samba/private/sam.ldb /etc/samba/laps_class.ldif --option="dsdb:schema update allowed"=true # Modify AD schema for 389-ds compatibility # Note: adapted from https://fy.blackhats.net.au/blog/html/2018/04/18/making_samba_4_the_default_ldap_server.html cat <<- EOM > /etc/samba/389ds_nsuniqueid_compat.ldif dn: CN=nsUniqueId,CN=Schema,CN=Configuration,\${domain_top_dn} changetype: add objectClass: top objectClass: attributeSchema attributeID: 2.16.840.1.113730.3.1.542 cn: nsUniqueId name: nsUniqueId lDAPDisplayName: nsUniqueId description: MANDATORY: nsUniqueId compatibility attributeSyntax: 2.5.5.10 oMSyntax: 4 isSingleValued: TRUE searchFlags: 9 EOM cat <<- EOM > /etc/samba/389ds_nsorgperson_compat.ldif dn: CN=nsOrgPerson,CN=Schema,CN=Configuration,\${domain_top_dn} changetype: add objectClass: top objectClass: classSchema governsID: 2.16.840.1.113730.3.2.334 cn: nsOrgPerson name: nsOrgPerson description: MANDATORY: Netscape DS compat person lDAPDisplayName: nsOrgPerson subClassOf: top objectClassCategory: 3 defaultObjectCategory: CN=nsOrgPerson,CN=Schema,CN=Configuration,\${domain_top_dn} mayContain: nsUniqueId EOM cat <<- EOM > /etc/samba/389ds_user_compat.ldif dn: CN=User,CN=Schema,CN=Configuration,\${domain_top_dn} changetype: modify replace: auxiliaryClass auxiliaryClass: posixAccount auxiliaryClass: shadowAccount auxiliaryClass: nsOrgPerson EOM ldbmodify -H /var/lib/samba/private/sam.ldb /etc/samba/389ds_nsuniqueid_compat.ldif --option="dsdb:schema update allowed"=true ldbmodify -H /var/lib/samba/private/sam.ldb /etc/samba/389ds_nsorgperson_compat.ldif --option="dsdb:schema update allowed"=true ldbmodify -H /var/lib/samba/private/sam.ldb /etc/samba/389ds_user_compat.ldif --option="dsdb:schema update allowed"=true # Modify AD schema for standard LDAPS password-changing apps compatibility (eg Nextcloud) # Note: adapted from https://kiljan.org/2017/12/22/setting-up-a-lightweight-authentication-back-end/ samba-tool forest directory_service dsheuristics '000000001' --option="dsdb:schema update allowed"=true # Modify MachineAccountQuota (unprivileged users rights to join machines to the domain) # Note: for security reasons this is better set to 0 to disable it completely (default is 10) cat <<- EOM > /etc/samba/disable_maq.ldif dn: \${domain_top_dn} changetype: modify replace: ms-DS-MachineAccountQuota ms-DS-MachineAccountQuota: 0 EOM ldbmodify -H /var/lib/samba/private/sam.ldb /etc/samba/disable_maq.ldif --option="dsdb:schema update allowed"=true # Add indexing, tombstone and copy flags on POSIX attributes # Note: adapted from https://fy.blackhats.net.au/blog/html/2018/04/18/making_samba_4_the_default_ldap_server.html samba-tool schema attribute modify uid --searchflags="fATTINDEX,fPRESERVEONDELETE" --option="dsdb:schema update allowed"=true samba-tool schema attribute modify uidnumber --searchflags="fATTINDEX,fPRESERVEONDELETE" --option="dsdb:schema update allowed"=true samba-tool schema attribute modify gidnumber --searchflags="fATTINDEX,fPRESERVEONDELETE" --option="dsdb:schema update allowed"=true samba-tool schema attribute modify x509-cert --searchflags="fPRESERVEONDELETE" --option="dsdb:schema update allowed"=true samba-tool schema attribute modify gecos --searchflags="fPRESERVEONDELETE" --option="dsdb:schema update allowed"=true samba-tool schema attribute modify loginShell --searchflags="fPRESERVEONDELETE" --option="dsdb:schema update allowed"=true samba-tool schema attribute modify home-directory --searchflags="fCOPY,fPRESERVEONDELETE" --option="dsdb:schema update allowed"=true fi # Enable and start Samba AD DC systemctl --now enable samba # Make sure that samba is actually running max_steps="30" for ((i=0;i<\${max_steps};i=i+1)); do sleep 3 if systemctl -q is-active samba ; then break fi done # Restart NTPd systemctl restart ntpd # Reconfigure NSS/PAM to use also Winbind (useful for administrative login access, "getent" use and filesystem listings) authconfig --kickstart --update --nostart --enablelocauthorize --enablewinbind --enablewinbindauth --enablemkhomedir # Note: disabling Winbind NSS module for the shadow database since it is unsupported and potentially harmful (according to official advice on Samba mailing list) sed -i -e '/^shadow:\s/s/\s*winbind//g' /etc/nsswitch.conf # Note: disabling independent Winbind service since an internal Winbindd service is automatically started by Samba in AD DC mode systemctl --now disable winbind sed -i -c -e '/pam_oddjob_mkhomedir\.so/s%pam_oddjob_mkhomedir\.so.*$%pam_oddjob_mkhomedir.so umask=0077 skel=/etc/skel%' /etc/pam.d/{system,password}-auth systemctl --now enable oddjobd # Configure Kerberos ticket acquisition at logon sed -i -e "/^\\\\[global\\\\]/,/^\\\\[.*\\\\]/s/^[;#]*\\\\s*krb5_auth\\\\s*=.*\\\$/krb5_auth = yes/" -e "/^\\\\[global\\\\]/,/^\\\\[.*\\\\]/s/^[;#]*\\\\s*krb5_ccache_type\\\\s*=.*\\\$/krb5_ccache_type = FILE/" /etc/security/pam_winbind.conf # TODO: Limit access from AD accounts using GPOs # TODO: GPOs must be created to limit access # TODO: using groups to limit access - remove when GPO limits get implemented in Winbind upstream # Note: the "Domain Controllers" group must be added to allow SSH access for tunneling sysvol/dfs rsync connections sed -i -e "/^\\\\[global\\\\]/,/^\\\\[.*\\\\]/s/^[;#]*\\\\s*require_membership_of\\\\s*=.*\\\$/require_membership_of = \\\\${netbios_domain_name}\\\\\\\\AD Admins,\\\\${netbios_domain_name}\\\\\\\\Domain Controllers/" /etc/security/pam_winbind.conf # TODO: find a way to configure sudo for AD-integrated LDAP rules using Winbind # TODO: using local sudo rules as a workaround cat <<- EOM > /etc/sudoers.d/administrators %\${netbios_domain_name}\\\\\\\\AD\\\\ Admins ALL=(ALL) NOPASSWD: ALL EOM chmod 440 /etc/sudoers.d/administrators # Configure SSH server and client for Kerberos SSO sed -i -e 's/^#GSSAPIKeyExchange\\s.*\$/GSSAPIKeyExchange yes\\nGSSAPIStoreCredentialsOnRekey yes/' /etc/ssh/sshd_config sed -i -e 's/^\\(\\s*\\)\\(GSSAPIAuthentication\\s*yes\\).*\$/\\1\\2\\n\\1GSSAPIDelegateCredentials yes\\n\\1GSSAPIKeyExchange yes\\n\\1GSSAPIRenewalForcesRekey yes/' /etc/ssh/ssh_config # TODO: restart hangs blocking rc.domain-join indefinitely - working around with stop + start # TODO: start hangs too - working around with background start systemctl stop sshd sleep 5 systemctl start sshd & # Reconfigure networking to use localhost DNS # TODO: with more than one domain controller, each should primarily point to another one as DNS server for nic_cfg_file in /etc/sysconfig/network-scripts/ifcfg-* ; do eval \$(grep '^DEVICE=' "\${nic_cfg_file}") nic_name="\${DEVICE}" if echo "\${nic_name}" | egrep -q '^(lo|sit)' ; then continue fi sed -i -e '/^PEERDNS=/s/=.*\$/="no"/' -e '/^DNS[0-9]/d' -e '/^DOMAIN=/d' "\${nic_cfg_file}" echo "DNS1=127.0.0.1" >> "\${nic_cfg_file}" echo "DOMAIN=${ad_subdomain_prefix}.${domain_name[${my_zone}]}" >> "\${nic_cfg_file}" nmcli connection reload nmcli connection up "\${nic_name}" done # Customize the rsyncd service for sysvol and DFS-root replication # Note: adapted from https://wiki.samba.org/index.php/Rsync_based_SysVol_replication_workaround # Note: using an rsyncd-over-ssh-tunnel approach using the DC machine identity for kerberized SSH SSO as in https://unix.stackexchange.com/questions/14312/how-to-restrict-an-ssh-user-to-only-allow-ssh-tunneling for authenticity/integrity reasons # TODO: find an equivalent solution for a Windows-based PDC emulator - see https://wiki.samba.org/index.php/Robocopy_based_SysVol_replication_workaround # TODO: find a way to bidirectionally synchronize files - see https://wiki.samba.org/index.php/Bidirectional_Rsync/Unison_based_SysVol_replication_workaround or https://dev.tranquil.it/samba/en/samba_advanced_methods/samba_tis_sysvolsync.html#samba-tis-sysvolsync # TODO: find an efficient way to propagate synchronized files without overloading the PDC emulator (maybe using KCC topology) mkdir -p /etc/systemd/system/rsyncd.service.d cat <<- EOM > /etc/systemd/system/rsyncd.service.d/custom-scheduling.conf [Service] IOSchedulingClass = idle Nice = 10 CPUSchedulingPolicy = idle EOM chmod 644 /etc/systemd/system/rsync*.d/*.conf chown root:root /etc/systemd/system/rsync*.d/*.conf # Allow through SELinux # TODO: define a more fine grained rule to allow access only to the required subtrees setsebool -P rsync_export_all_ro on # Create Rsync configuration for sysvol and DFS-root replication # Note: the second sysvol section will be used only once for each further DC to initially align BUILTIN ids cat <<- EOM > /etc/rsyncd.conf [global] uid = root gid = root read only = yes address = 127.0.0.1 auth users = root secrets file = /etc/samba/rsync-sysvol-dfsroot.secret [SysVol] path = /var/lib/samba/sysvol/ comment = Samba Sysvol Share [SysVolRepl] path = /var/lib/samba/sysvolrepl/ comment = Samba Sysvol Replication Support Share [DFSroot] path = /var/lib/samba/dfsroot/ comment = Samba DFS root share EOM chmod 644 /etc/rsyncd.conf chown root:root /etc/rsyncd.conf # Apply rsyncd systemd configuration systemctl daemon-reload systemctl --now enable rsyncd.service # Customize start uid/gid numbers for RFC2307bis # Note: there is no builtin mechanism to automatically allocate uniqe uis and gids in the whole forest - using an offset based on domain index # TODO: currently the Samba AD DC does not support multidomain forests, so the index is fixed at 1 - review when support will be implemented upstream # Note: the "automatic user private group" feature of SSSD requires that a gid equal to the uid of each user is kept free - using uid blocks 1000x the size of gid blocks # Note: to give DCs unique uid based on their machine object RID, we use a block of uids before the start of user uid range on each domain # Note: internally generated xid numbers seem to start from around 3000000 rfc2307_domain_index="1" rfc2307_uid_block_length="10000000" rfc2307_gid_block_length="10000" rfc2307_dc_uid_block_length="10000" rfc2307_start_uid=\$(((\${rfc2307_domain_index} * \${rfc2307_uid_block_length}) + 1)) rfc2307_start_gid=\$(((\${rfc2307_domain_index} * \${rfc2307_gid_block_length}) + 1)) rfc2307_dc_uid_base=\$((\${rfc2307_start_uid} - \${rfc2307_dc_uid_block_length} - 1)) # Perform Kerberos authentication to allow privileged operations below 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" "Administrator@${realm_name}" match_max 100000 expect -re "Password for.*:.*\\\$" send -- "${adroot_password}\\\\r" expect eof EOM # TODO: despite adding keytab options to domain provisioning commandline, the system keytab does not get created - creating manually - remove when fixed upstream net ads keytab create -k if [ "${domain_join}" != "true" ]; then # Note: it seems that we need to allow some time for the internal DNS to come up sleep 30 # Manage Sites # TODO: add support for creating additional sites and subnets as soon as links are supported by samba-tool sites subcommand unset PREFIX eval $(ipcalc -s -p "${network[${my_zone}]}" "${netmask[${my_zone}]}") samba-tool sites subnet create "${network[${my_zone}]}/${PREFIX}" "Default-First-Site-Name" --username=administrator --password='${adroot_password}' # Manage OUs # Create default OUs for HVP computers # Note: we assume an hyperconverged software-defined infrastructure, so that virtualization, storage and network equipment can be conflated as generic infrastructure equipment samba-tool ou create 'OU=Servers' --description='Container for servers' --username=administrator --password='${adroot_password}' samba-tool ou create 'OU=Database Servers,OU=Servers' --description='Container for database servers' --username=administrator --password='${adroot_password}' samba-tool ou create 'OU=Print Servers,OU=Servers' --description='Container for printer servers' --username=administrator --password='${adroot_password}' samba-tool ou create 'OU=Remote Desktop Servers,OU=Servers' --description='Container for remote desktop servers' --username=administrator --password='${adroot_password}' samba-tool ou create 'OU=Web Servers,OU=Servers' --description='Container for web servers' --username=administrator --password='${adroot_password}' samba-tool ou create 'OU=Application Servers,OU=Servers' --description='Container for application servers' --username=administrator --password='${adroot_password}' samba-tool ou create 'OU=Gateway Servers,OU=Servers' --description='Container for gateway servers' --username=administrator --password='${adroot_password}' samba-tool ou create 'OU=Workstations' --description='Container for workstations' --username=administrator --password='${adroot_password}' samba-tool ou create 'OU=PAWs' --description='Container for privileged access workstations' --username=administrator --password='${adroot_password}' samba-tool ou create 'OU=Infrastructures' --description='Container for infrastructure equipment' --username=administrator --password='${adroot_password}' # Create default OUs for HVP administrators # Note: we assume an hyperconverged software-defined infrastructure, so that virtualization admins, storage admins and network admins coincide with infrastructure admins samba-tool ou create 'OU=Admin Users' --description='Container for administrators' --username=administrator --password='${adroot_password}' samba-tool ou create 'OU=Allpowerful Admins,OU=Admin Users' --description='Container for builtin all-powerful administrators' --username=administrator --password='${adroot_password}' samba-tool ou create 'OU=AD Admins,OU=Admin Users' --description='Container for AD administrators' --username=administrator --password='${adroot_password}' samba-tool ou create 'OU=Server Admins,OU=Admin Users' --description='Container for server administrators' --username=administrator --password='${adroot_password}' samba-tool ou create 'OU=Workstation Admins,OU=Admin Users' --description='Container for workstation administrators' --username=administrator --password='${adroot_password}' samba-tool ou create 'OU=PAW Admins,OU=Admin Users' --description='Container for PAW administrators' --username=administrator --password='${adroot_password}' samba-tool ou create 'OU=User Admins,OU=Admin Users' --description='Container for user administrators' --username=administrator --password='${adroot_password}' samba-tool ou create 'OU=Infrastructure Admins,OU=Admin Users' --description='Container for infrastructure administrators' --username=administrator --password='${adroot_password}' # Create default OUs for HVP users samba-tool ou create 'OU=Unprivileged Users' --description='Container for common users' --username=administrator --password='${adroot_password}' samba-tool ou create 'OU=Service Users' --description='Container for service users' --username=administrator --password='${adroot_password}' # Redirect new users/computers default location to the custom OUs Workstations and "Unprivileged Users" created above # Note: see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/5a00c890-6be5-4575-93c4-8bf8be0ca8d8 cat <<- EOM > /etc/samba/modify_default_containers.ldif dn: \${domain_top_dn} changetype: modify delete: wellKnownObjects wellKnownObjects: B:32:AA312825768811D1ADED00C04FD8D5CD:CN=Computers,\${domain_top_dn} dn: \${domain_top_dn} changetype: modify add: wellKnownObjects wellKnownObjects: B:32:AA312825768811D1ADED00C04FD8D5CD:OU=Workstations,\${domain_top_dn} dn: \${domain_top_dn} changetype: modify delete: wellKnownObjects wellKnownObjects: B:32:A9D1CA15768811D1ADED00C04FD8D5CD:CN=Users,\${domain_top_dn} dn: \${domain_top_dn} changetype: modify add: wellKnownObjects wellKnownObjects: B:32:A9D1CA15768811D1ADED00C04FD8D5CD:OU=Unprivileged Users,\${domain_top_dn} dn: CN=Computers,\${domain_top_dn} changetype: modify replace: systemFlags systemFlags: 0 dn: OU=Workstations,\${domain_top_dn} changetype: modify replace: systemFlags systemFlags: -1946157056 dn: CN=Users,\${domain_top_dn} changetype: modify replace: systemFlags systemFlags: 0 dn: OU=Unprivileged Users,\${domain_top_dn} changetype: modify replace: systemFlags systemFlags: -1946157056 EOM ldbmodify -H /var/lib/samba/private/sam.ldb /etc/samba/modify_default_containers.ldif --option="dsdb:schema update allowed"=true # Manage users and groups # Manage groups # Add gidNumber to "Domain Users" # Note: by default the "Domain Users" group has no gidNumber and so would not be visible/usable on Linux member machines in RFC2307bis idmapping mode # Note: do not add gidNumber to builtin "Domain Admins" - having a gidNumber on "Domain Admins" would interfer with sysvol files ownership (the group must be used as user-owner to emulate Windows behaviour) - https://www.spinics.net/lists/samba/msg143752.html rfc2307_gid="\${rfc2307_start_gid}" cat <<- EOM | ldbmodify -H /var/lib/samba/private/sam.ldb -i \$(ldbsearch -H /var/lib/samba/private/sam.ldb objectsid=\$(wbinfo --name-to-sid "Domain Users" | awk '{print \$1}') | grep '^dn:') changetype: modify add: gidNumber gidNumber: \${rfc2307_gid} EOM domain_users_gid="\${rfc2307_gid}" rfc2307_gid="\$((\${rfc2307_gid} + 1))" # Add gidNumber to "Domain Controllers" # Note: this is needed to allow kerberized SSH logons using the identity of a domain controller cat <<- EOM | ldbmodify -H /var/lib/samba/private/sam.ldb -i \$(ldbsearch -H /var/lib/samba/private/sam.ldb objectsid=\$(wbinfo --name-to-sid "Domain Controllers" | awk '{print \$1}') | grep '^dn:') changetype: modify add: gidNumber gidNumber: \${rfc2307_gid} EOM rfc2307_gid="\$((\${rfc2307_gid} + 1))" # Add gidNumber to "Domain Computers" # Note: this is needed to allow multiuser kerberized mounts of CIFs shares on Linux domain members cat <<- EOM | ldbmodify -H /var/lib/samba/private/sam.ldb -i \$(ldbsearch -H /var/lib/samba/private/sam.ldb objectsid=\$(wbinfo --name-to-sid "Domain Computers" | awk '{print \$1}') | grep '^dn:') changetype: modify add: gidNumber gidNumber: \${rfc2307_gid} EOM rfc2307_gid="\$((\${rfc2307_gid} + 1))" # Add admin/user groups with Unix attributes # Note: we use the standard builtin "Domain Admins" group for unconstrained domain administration but since they cannot login anywhere we will use the "AD Admins" group for login on PAWs # Note: we make "Server Admins" capable of administering DNS # AD admins group samba-tool group add "AD Admins" --group-type=Security --groupou='OU=AD Admins,OU=Admin Users' --group-scope=Global --description='AD administrators' --nis-domain=\${nis_domain} --gid-number=\${rfc2307_gid} --username=administrator --password='${adroot_password}' rfc2307_gid="\$((\${rfc2307_gid} + 1))" # Server admins group samba-tool group add "Server Admins" --group-type=Security --groupou='OU=Server Admins,OU=Admin Users' --group-scope=Global --description='Server administrators' --nis-domain=\${nis_domain} --gid-number=\${rfc2307_gid} --username=administrator --password='${adroot_password}' samba-tool group addmembers "DnsAdmins" "Server Admins" rfc2307_gid="\$((\${rfc2307_gid} + 1))" # Workstation admins group samba-tool group add "Workstation Admins" --group-type=Security --groupou='OU=Workstation Admins,OU=Admin Users' --group-scope=Global --description='Workstation administrators' --nis-domain=\${nis_domain} --gid-number=\${rfc2307_gid} --username=administrator --password='${adroot_password}' rfc2307_gid="\$((\${rfc2307_gid} + 1))" # PAW admins group samba-tool group add "PAW Admins" --group-type=Security --groupou='OU=PAW Admins,OU=Admin Users' --group-scope=Global --description='PAW administrators' --nis-domain=\${nis_domain} --gid-number=\${rfc2307_gid} --username=administrator --password='${adroot_password}' rfc2307_gid="\$((\${rfc2307_gid} + 1))" # User admins group samba-tool group add "User Admins" --group-type=Security --groupou='OU=User Admins,OU=Admin Users' --group-scope=Global --description='User administrators' --nis-domain=\${nis_domain} --gid-number=\${rfc2307_gid} --username=administrator --password='${adroot_password}' rfc2307_gid="\$((\${rfc2307_gid} + 1))" # Infrastructure admins group samba-tool group add "Infrastructure Admins" --group-type=Security --groupou='OU=Infrastructure Admins,OU=Admin Users' --group-scope=Global --description='Infrastructure administrators' --nis-domain=\${nis_domain} --gid-number=\${rfc2307_gid} --username=administrator --password='${adroot_password}' rfc2307_gid="\$((\${rfc2307_gid} + 1))" # All custom admins group # Note: this is meant as an help to apply GPOs and permissions/settings to all custom (not builtin) admin groups at once samba-tool group add "AllDelegatedAdmins" --group-type=Security --groupou='OU=Admin Users' --group-scope=Global --description='All delegated/restricted administrators' --nis-domain=\${nis_domain} --gid-number=\${rfc2307_gid} --username=administrator --password='${adroot_password}' for custom_group in "AD Admins" "Server Admins" "Workstation Admins" "PAW Admins" "User Admins" "Infrastructure Admins"; do samba-tool group addmembers "AllDelegatedAdmins" "\${custom_group}" done rfc2307_gid="\$((\${rfc2307_gid} + 1))" # All builtin unrestricted admins group # Note: this is meant as an help to apply GPOs and permissions/settings to all builtin admin groups at once samba-tool group add "Allpowerful Admins" --group-type=Security --groupou='OU=Allpowerful Admins,OU=Admin Users' --group-scope=Global --description='Allpowerful builtin administrators' --nis-domain=\${nis_domain} --gid-number=\${rfc2307_gid} --username=administrator --password='HVP_dem0' for builtin_group in "Enterprise Admins" "Domain Admins" "Schema Admins" "Administrators" "Domain Controllers" "Read-Only Domain Controllers" "Group Policy Creator Owners" "Account Operators" "Backup Operators" "Print Operators" "Server Operators" "Cryptographic Operators"; do samba-tool group addmembers "Allpowerful Admins" "\${builtin_group}" done rfc2307_gid="\$((\${rfc2307_gid} + 1))" # Service users group samba-tool group add "Service Users" --group-type=Security --groupou='OU=Service Users' --group-scope=Global --description='Service Users' --nis-domain=\${nis_domain} --gid-number=\${rfc2307_gid} --username=administrator --password='${adroot_password}' rfc2307_gid="\$((\${rfc2307_gid} + 1))" # Make sure that the custom admins credentials are not cached in a RODC-only site samba-tool group addmembers "Denied RODC Password Replication Group" "AllDelegatedAdmins" # Unprivileged users group # Note: this is meant as an help to apply GPOs and permissions/settings to all builtin non-admin users at once samba-tool group add "Unprivileged Users" --group-type=Security --groupou='OU=Unprivileged Users' --group-scope=Global --description='Unprivileged users' --nis-domain=\${nis_domain} --gid-number=\${rfc2307_gid} --username=administrator --password='${adroot_password}' rfc2307_gid="\$((\${rfc2307_gid} + 1))" # Terminal Server (Remote Desktop) Access users group samba-tool group add "TerminalServerUsers" --group-type=Security --groupou='OU=Unprivileged Users' --group-scope=Global --description='Terminal Server users' --nis-domain=\${nis_domain} --gid-number=\${rfc2307_gid} --username=administrator --password='${adroot_password}' rfc2307_gid="\$((\${rfc2307_gid} + 1))" # Full Internet Access users group samba-tool group add "FullInternetAccess" --group-type=Security --groupou='OU=Unprivileged Users' --group-scope=Global --description='Full Internet access users' --nis-domain=\${nis_domain} --gid-number=\${rfc2307_gid} --username=administrator --password='${adroot_password}' rfc2307_gid="\$((\${rfc2307_gid} + 1))" # Filtered Internet Access users group samba-tool group add "FilteredInternetAccess" --group-type=Security --groupou='OU=Unprivileged Users' --group-scope=Global --description='Filtered Internet access users' --nis-domain=\${nis_domain} --gid-number=\${rfc2307_gid} --username=administrator --password='${adroot_password}' rfc2307_gid="\$((\${rfc2307_gid} + 1))" # Screened Internet Access users group samba-tool group add "ScreenedInternetAccess" --group-type=Security --groupou='OU=Unprivileged Users' --group-scope=Global --description='Screened Internet access users' --nis-domain=\${nis_domain} --gid-number=\${rfc2307_gid} --username=administrator --password='${adroot_password}' rfc2307_gid="\$((\${rfc2307_gid} + 1))" # Limited Internet Access users group samba-tool group add "LimitedInternetAccess" --group-type=Security --groupou='OU=Unprivileged Users' --group-scope=Global --description='Limited Internet access users' --nis-domain=\${nis_domain} --gid-number=\${rfc2307_gid} --username=administrator --password='${adroot_password}' rfc2307_gid="\$((\${rfc2307_gid} + 1))" # Denied Internet Access users group samba-tool group add "DeniedInternetAccess" --group-type=Security --groupou='OU=Unprivileged Users' --group-scope=Global --description='Denied Internet access users' --nis-domain=\${nis_domain} --gid-number=\${rfc2307_gid} --username=administrator --password='${adroot_password}' for denied_group in "Allpowerful Admins" "AllDelegatedAdmins" "Service Users"; do samba-tool group addmembers "DeniedInternetAccess" "\${denied_group}" done rfc2307_gid="\$((\${rfc2307_gid} + 1))" # VPN Access users group samba-tool group add "VPNAccess" --group-type=Security --groupou='OU=Unprivileged Users' --group-scope=Global --description='VPN access users' --nis-domain=\${nis_domain} --gid-number=\${rfc2307_gid} --username=administrator --password='${adroot_password}' rfc2307_gid="\$((\${rfc2307_gid} + 1))" # WiFi Access users group samba-tool group add "WiFiAccess" --group-type=Security --groupou='OU=Unprivileged Users' --group-scope=Global --description='WiFi access users' --nis-domain=\${nis_domain} --gid-number=\${rfc2307_gid} --username=administrator --password='${adroot_password}' rfc2307_gid="\$((\${rfc2307_gid} + 1))" # Make sure that the unprivileged and service users can be used in a RODC-only site even when connection is failing for essential_group in "Unprivileged Users" "Service Users"; do samba-tool group addmembers "Allowed RODC Password Replication Group" "\${essential_group}" done # Add delegation settings for custom restricted admin groups created above # Delegate the right of joining machines as per http://blog.stevecoinc.com/2017/04/delegating-domain-join-privileges-in.html # Note: delegate the right of managing RFC2307bis attributes to all the admin groups who must manage users/groups anywhere as per https://wiki.samba.org/index.php/Delegation/Account_management # TODO: make the custom OUs created above protected from accidental deletion using additional custom ACEs - see https://gallery.technet.microsoft.com/scriptcenter/c307540f-bd91-485f-b27e-995ae5cea1e2#content # TODO: ideally, each admin group should be able to manage RFC2307bis attributes only on the OUs containing users/groups under its control # Delegate the right of joining machines to "Server Admins" on the Servers OU group_sid="\$(wbinfo --name-to-sid 'Server Admins' | awk '{print \$1}')" samba-tool dsacl set --action=allow --objectdn="ou=Servers,\${domain_top_dn}" --sddl="(OA;CI;CCDC;BF967A86-0DE6-11D0-A285-00AA003049E2;;\${group_sid})(OA;CIIO;SWWP;F3A64788-5306-11D1-A9C5-0000F80367C1;BF967A86-0DE6-11D0-A285-00AA003049E2;\${group_sid})(OA;CIIO;SWRPWP;72E39547-7B18-11D1-ADEF-00C04FD8D5CD;BF967A86-0DE6-11D0-A285-00AA003049E2;\${group_sid})(OA;CIIO;RPWP;4C164200-20C0-11D0-A768-00AA006E0529;BF967A86-0DE6-11D0-A285-00AA003049E2;\${group_sid})(OA;CIIO;CR;00299570-246D-11D0-A768-00AA006E0529;BF967A86-0DE6-11D0-A285-00AA003049E2;\${group_sid})" # Delegate the right of managing users/groups to "Server Admins" on the "Server Admins" and "Service Users" OUs samba-tool dsacl set --action=allow --objectdn="ou=Server Admins,OU=Admin Users,\${domain_top_dn}" --sddl="(OA;CIIO;RPWPCRCCDCLCLORCWOWDSDDTSW;;bf967a9c-0de6-11d0-a285-00aa003049e2;\${group_sid})(OA;CI;CCDC;bf967a9c-0de6-11d0-a285-00aa003049e2;;\${group_sid})(OA;CIIO;RPWPCRCCDCLCLORCWOWDSDDTSW;;bf967aba-0de6-11d0-a285-00aa003049e2;\${group_sid})(OA;CI;CCDC;bf967aba-0de6-11d0-a285-00aa003049e2;;\${group_sid})" samba-tool dsacl set --action=allow --objectdn="ou=Service Users,\${domain_top_dn}" --sddl="(OA;CIIO;RPWPCRCCDCLCLORCWOWDSDDTSW;;bf967a9c-0de6-11d0-a285-00aa003049e2;\${group_sid})(OA;CI;CCDC;bf967a9c-0de6-11d0-a285-00aa003049e2;;\${group_sid})(OA;CIIO;RPWPCRCCDCLCLORCWOWDSDDTSW;;bf967aba-0de6-11d0-a285-00aa003049e2;\${group_sid})(OA;CI;CCDC;bf967aba-0de6-11d0-a285-00aa003049e2;;\${group_sid})" samba-tool dsacl set --action=allow --objectdn="cn=RpcServices,cn=System,\${domain_top_dn}" --sddl="(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;\${group_sid})" # Delegate the right of joining machines to "Workstation Admins" on the Workstations OU group_sid="\$(wbinfo --name-to-sid 'Workstation Admins' | awk '{print \$1}')" samba-tool dsacl set --action=allow --objectdn="ou=Workstations,\${domain_top_dn}" --sddl="(OA;CI;CCDC;BF967A86-0DE6-11D0-A285-00AA003049E2;;\${group_sid})(OA;CIIO;SWWP;F3A64788-5306-11D1-A9C5-0000F80367C1;BF967A86-0DE6-11D0-A285-00AA003049E2;\${group_sid})(OA;CIIO;SWRPWP;72E39547-7B18-11D1-ADEF-00C04FD8D5CD;BF967A86-0DE6-11D0-A285-00AA003049E2;\${group_sid})(OA;CIIO;RPWP;4C164200-20C0-11D0-A768-00AA006E0529;BF967A86-0DE6-11D0-A285-00AA003049E2;\${group_sid})(OA;CIIO;CR;00299570-246D-11D0-A768-00AA006E0529;BF967A86-0DE6-11D0-A285-00AA003049E2;\${group_sid})" # Delegate the right of managing users/groups to "Workstation Admins" on the "Workstation Admins" OU samba-tool dsacl set --action=allow --objectdn="ou=Workstation Admins,OU=Admin Users,\${domain_top_dn}" --sddl="(OA;CIIO;RPWPCRCCDCLCLORCWOWDSDDTSW;;bf967a9c-0de6-11d0-a285-00aa003049e2;\${group_sid})(OA;CI;CCDC;bf967a9c-0de6-11d0-a285-00aa003049e2;;\${group_sid})(OA;CIIO;RPWPCRCCDCLCLORCWOWDSDDTSW;;bf967aba-0de6-11d0-a285-00aa003049e2;\${group_sid})(OA;CI;CCDC;bf967aba-0de6-11d0-a285-00aa003049e2;;\${group_sid})" samba-tool dsacl set --action=allow --objectdn="cn=RpcServices,cn=System,\${domain_top_dn}" --sddl="(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;\${group_sid})" # Delegate the right of joining machines to "PAW Admins" on the PAWs OU group_sid="\$(wbinfo --name-to-sid 'PAW Admins' | awk '{print \$1}')" samba-tool dsacl set --action=allow --objectdn="ou=PAWs,\${domain_top_dn}" --sddl="(OA;CI;CCDC;BF967A86-0DE6-11D0-A285-00AA003049E2;;\${group_sid})(OA;CIIO;SWWP;F3A64788-5306-11D1-A9C5-0000F80367C1;BF967A86-0DE6-11D0-A285-00AA003049E2;\${group_sid})(OA;CIIO;SWRPWP;72E39547-7B18-11D1-ADEF-00C04FD8D5CD;BF967A86-0DE6-11D0-A285-00AA003049E2;\${group_sid})(OA;CIIO;RPWP;4C164200-20C0-11D0-A768-00AA006E0529;BF967A86-0DE6-11D0-A285-00AA003049E2;\${group_sid})(OA;CIIO;CR;00299570-246D-11D0-A768-00AA006E0529;BF967A86-0DE6-11D0-A285-00AA003049E2;\${group_sid})" # Delegate the right of managing users/groups to "PAW Admins" on the "PAW Admins" OU samba-tool dsacl set --action=allow --objectdn="ou=PAW Admins,OU=Admin Users,\${domain_top_dn}" --sddl="(OA;CIIO;RPWPCRCCDCLCLORCWOWDSDDTSW;;bf967a9c-0de6-11d0-a285-00aa003049e2;\${group_sid})(OA;CI;CCDC;bf967a9c-0de6-11d0-a285-00aa003049e2;;\${group_sid})(OA;CIIO;RPWPCRCCDCLCLORCWOWDSDDTSW;;bf967aba-0de6-11d0-a285-00aa003049e2;\${group_sid})(OA;CI;CCDC;bf967aba-0de6-11d0-a285-00aa003049e2;;\${group_sid})" samba-tool dsacl set --action=allow --objectdn="cn=RpcServices,cn=System,\${domain_top_dn}" --sddl="(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;\${group_sid})" # Delegate the right of managing users/groups to "User Admins" on the "User Admins" and "Unprivileged Users" OUs group_sid="\$(wbinfo --name-to-sid 'User Admins' | awk '{print \$1}')" samba-tool dsacl set --action=allow --objectdn="ou=User Admins,OU=Admin Users,\${domain_top_dn}" --sddl="(OA;CIIO;RPWPCRCCDCLCLORCWOWDSDDTSW;;bf967a9c-0de6-11d0-a285-00aa003049e2;\${group_sid})(OA;CI;CCDC;bf967a9c-0de6-11d0-a285-00aa003049e2;;\${group_sid})(OA;CIIO;RPWPCRCCDCLCLORCWOWDSDDTSW;;bf967aba-0de6-11d0-a285-00aa003049e2;\${group_sid})(OA;CI;CCDC;bf967aba-0de6-11d0-a285-00aa003049e2;;\${group_sid})" samba-tool dsacl set --action=allow --objectdn="ou=Unprivileged Users,\${domain_top_dn}" --sddl="(OA;CIIO;RPWPCRCCDCLCLORCWOWDSDDTSW;;bf967a9c-0de6-11d0-a285-00aa003049e2;\${group_sid})(OA;CI;CCDC;bf967a9c-0de6-11d0-a285-00aa003049e2;;\${group_sid})(OA;CIIO;RPWPCRCCDCLCLORCWOWDSDDTSW;;bf967aba-0de6-11d0-a285-00aa003049e2;\${group_sid})(OA;CI;CCDC;bf967aba-0de6-11d0-a285-00aa003049e2;;\${group_sid})" samba-tool dsacl set --action=allow --objectdn="cn=RpcServices,cn=System,\${domain_top_dn}" --sddl="(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;\${group_sid})" # Delegate the right of joining machines to "Infrastructure Admins" on the Infrastructures OU group_sid="\$(wbinfo --name-to-sid 'Infrastructure Admins' | awk '{print \$1}')" samba-tool dsacl set --action=allow --objectdn="ou=Infrastructures,\${domain_top_dn}" --sddl="(OA;CI;CCDC;BF967A86-0DE6-11D0-A285-00AA003049E2;;\${group_sid})(OA;CIIO;SWWP;F3A64788-5306-11D1-A9C5-0000F80367C1;BF967A86-0DE6-11D0-A285-00AA003049E2;\${group_sid})(OA;CIIO;SWRPWP;72E39547-7B18-11D1-ADEF-00C04FD8D5CD;BF967A86-0DE6-11D0-A285-00AA003049E2;\${group_sid})(OA;CIIO;RPWP;4C164200-20C0-11D0-A768-00AA006E0529;BF967A86-0DE6-11D0-A285-00AA003049E2;\${group_sid})(OA;CIIO;CR;00299570-246D-11D0-A768-00AA006E0529;BF967A86-0DE6-11D0-A285-00AA003049E2;\${group_sid})" # Delegate the right of managing users/groups to "Infrastructure Admins" on the "Infrastructure Admins" OU samba-tool dsacl set --action=allow --objectdn="ou=Infrastructure Admins,OU=Admin Users,\${domain_top_dn}" --sddl="(OA;CIIO;RPWPCRCCDCLCLORCWOWDSDDTSW;;bf967a9c-0de6-11d0-a285-00aa003049e2;\${group_sid})(OA;CI;CCDC;bf967a9c-0de6-11d0-a285-00aa003049e2;;\${group_sid})(OA;CIIO;RPWPCRCCDCLCLORCWOWDSDDTSW;;bf967aba-0de6-11d0-a285-00aa003049e2;\${group_sid})(OA;CI;CCDC;bf967aba-0de6-11d0-a285-00aa003049e2;;\${group_sid})" samba-tool dsacl set --action=allow --objectdn="cn=RpcServices,cn=System,\${domain_top_dn}" --sddl="(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;\${group_sid})" # Configure domain password settings and PSOs # TODO: allow changing all of these with install options # Global domain defaults # TODO: switch to GPOs for these settings and remove from here when upstream will support GPOs samba-tool domain passwordsettings set --complexity=on --store-plaintext=off --history-length=24 --min-pwd-length=8 --min-pwd-age=0 --max-pwd-age=180 --account-lockout-threshold=4 --account-lockout-duration=15 --reset-account-lockout-after=15 --username=administrator --password='${adroot_password}' # Custom PSOs for specific cases samba-tool domain passwordsettings pso create "PSOServiceUsers" "10" --complexity=on --store-plaintext=on --history-length=0 --min-pwd-length=16 --min-pwd-age=0 --max-pwd-age=0 --account-lockout-threshold=3 --account-lockout-duration=10 --reset-account-lockout-after=10 --username=administrator --password='${adroot_password}' samba-tool domain passwordsettings pso apply "PSOServiceUsers" "Service Users" --username=administrator --password='${adroot_password}' samba-tool domain passwordsettings pso create "PSOAllDelegatedAdmins" "10" --complexity=on --store-plaintext=off --history-length=24 --min-pwd-length=12 --min-pwd-age=1 --max-pwd-age=60 --account-lockout-threshold=3 --account-lockout-duration=30 --reset-account-lockout-after=30 --username=administrator --password='${adroot_password}' samba-tool domain passwordsettings pso apply "PSOAllDelegatedAdmins" "AllDelegatedAdmins" --username=administrator --password='${adroot_password}' samba-tool domain passwordsettings pso create "PSOAllpowerfuldAdmins" "10" --complexity=on --store-plaintext=off --history-length=24 --min-pwd-length=16 --min-pwd-age=1 --max-pwd-age=30 --account-lockout-threshold=2 --account-lockout-duration=60 --reset-account-lockout-after=60 --username=administrator --password='${adroot_password}' samba-tool domain passwordsettings pso apply "PSOAllpowerfulAdmins" "Allpowerful dAdmins" --username=administrator --password='${adroot_password}' # LAPS required settings # Allow LAPS attributes read and reset to "Server Admins" and write to SELF on the "Remote Desktop Servers" OU group_sid="\$(wbinfo --name-to-sid 'Server Admins' | awk '{print \$1}')" samba-tool dsacl set --action=allow --objectdn="ou=Remote Desktop Servers,ou=Servers,\${domain_top_dn}" --sddl="(OA;CIIO;RPWP;291d2a5e-5e44-477a-b6e2-0df177268770;bf967a86-0de6-11d0-a285-00aa003049e2;PS)(OA;CIIO;WP;9cd40b54-3bd6-46b2-a61c-4cb6efc6d034;bf967a86-0de6-11d0-a285-00aa003049e2;PS)(OA;CIIO;RPWP;291d2a5e-5e44-477a-b6e2-0df177268770;bf967a86-0de6-11d0-a285-00aa003049e2;\${group_sid})(OA;CIIO;RPCR;9cd40b54-3bd6-46b2-a61c-4cb6efc6d034;bf967a86-0de6-11d0-a285-00aa003049e2;\${group_sid})" # Allow LAPS attributes read and reset to "Workstation Admins" and write to SELF on the Workstations OU group_sid="\$(wbinfo --name-to-sid 'Workstation Admins' | awk '{print \$1}')" samba-tool dsacl set --action=allow --objectdn="ou=Workstations,\${domain_top_dn}" --sddl="(OA;CIIO;RPWP;291d2a5e-5e44-477a-b6e2-0df177268770;bf967a86-0de6-11d0-a285-00aa003049e2;PS)(OA;CIIO;WP;9cd40b54-3bd6-46b2-a61c-4cb6efc6d034;bf967a86-0de6-11d0-a285-00aa003049e2;PS)(OA;CIIO;RPWP;291d2a5e-5e44-477a-b6e2-0df177268770;bf967a86-0de6-11d0-a285-00aa003049e2;\${group_sid})(OA;CIIO;RPCR;9cd40b54-3bd6-46b2-a61c-4cb6efc6d034;bf967a86-0de6-11d0-a285-00aa003049e2;\${group_sid})" # Allow LAPS attributes read and reset to "PAW Admins" and write to SELF on the PAWs OU group_sid="\$(wbinfo --name-to-sid 'PAW Admins' | awk '{print \$1}')" samba-tool dsacl set --action=allow --objectdn="ou=PAWs,\${domain_top_dn}" --sddl="(OA;CIIO;RPWP;291d2a5e-5e44-477a-b6e2-0df177268770;bf967a86-0de6-11d0-a285-00aa003049e2;PS)(OA;CIIO;WP;9cd40b54-3bd6-46b2-a61c-4cb6efc6d034;bf967a86-0de6-11d0-a285-00aa003049e2;PS)(OA;CIIO;RPWP;291d2a5e-5e44-477a-b6e2-0df177268770;bf967a86-0de6-11d0-a285-00aa003049e2;\${group_sid})(OA;CIIO;RPCR;9cd40b54-3bd6-46b2-a61c-4cb6efc6d034;bf967a86-0de6-11d0-a285-00aa003049e2;\${group_sid})" # Manage users # Note: newly created users will have default AD primary group set to "Domain Users" (as per Windows AD default) # Note: whether AD or RFC2307bis primary group attribute has precedence depends on idmapping backend on clients (Winbind >= 4.6.0 has unix_primary_group parameter - no equivalent parameter available for SSSD) but we explicitly make those match anyway # Note: do not add uidNumber and gidNumber to builtin "Administrator" - see https://wiki.samba.org/index.php/Setting_up_Samba_as_a_Domain_Member#Mapping_the_Domain_Administrator_Account_to_the_Local_root_User # Note: all accounts will follow password expiration rules by default # Note: displayName (required by some apps, like Nextcloud) gets automatically set as surname appended to given-name when those are set # Add admin users with Unix attributes # Note: the builtin "Domain Admins" / "Enterprise Admins" user Administrator should not have extra Unix/Windows attributes since it should never be used for login # Note: all "Admin Users" should be able to login both on Unix and Windows, so all attributes should be set but with home/profile exclusively local (will be kept on PAWs/Servers) # Note: do not add given-name and surname since those must be unique across the directory and could inhibit user copy - manually adding displayname rfc2307_uid="\${rfc2307_start_uid}" # AD admin user samba-tool user create "${adadmin_username}" '${adadmin_password}' --mail-address=${adadmin_username}@${ad_subdomain_prefix}.${domain_name[${my_zone}]} --userou='OU=AD Admins,OU=Admin Users' --nis-domain=\${nis_domain} --uid-number=\${rfc2307_uid} --login-shell=/bin/bash --gid-number=\${domain_users_gid} --gecos='AD Admin' --unix-home="/home/local/${adadmin_username}" --username=administrator --password='${adroot_password}' cat <<- EOM | ldbmodify -H /var/lib/samba/private/sam.ldb -i \$(ldbsearch -H /var/lib/samba/private/sam.ldb objectsid=\$(wbinfo --name-to-sid "${adadmin_username}" | awk '{print \$1}') | grep '^dn:') changetype: modify add: displayName displayName: AD Admin EOM samba-tool group addmembers "AD Admins" "${adadmin_username}" rfc2307_uid="\$((\${rfc2307_uid} + 1))" # Servers admin user samba-tool user create "${serveradmin_username}" '${serveradmin_password}' --mail-address=${serveradmin_username}@${ad_subdomain_prefix}.${domain_name[${my_zone}]} --userou='OU=Server Admins,OU=Admin Users' --nis-domain=\${nis_domain} --uid-number=\${rfc2307_uid} --login-shell=/bin/bash --gid-number=\${domain_users_gid} --gecos='Servers Admin' --unix-home="/home/local/${serveradmin_username}" --username=administrator --password='${adroot_password}' cat <<- EOM | ldbmodify -H /var/lib/samba/private/sam.ldb -i \$(ldbsearch -H /var/lib/samba/private/sam.ldb objectsid=\$(wbinfo --name-to-sid "${serveradmin_username}" | awk '{print \$1}') | grep '^dn:') changetype: modify add: displayName displayName: Servers Admin EOM samba-tool group addmembers "Server Admins" "${serveradmin_username}" rfc2307_uid="\$((\${rfc2307_uid} + 1))" # Workstations admin user samba-tool user create "${workstationadmin_username}" '${workstationadmin_password}' --mail-address=${workstationadmin_username}@${ad_subdomain_prefix}.${domain_name[${my_zone}]} --userou='OU=Workstation Admins,OU=Admin Users' --nis-domain=\${nis_domain} --uid-number=\${rfc2307_uid} --login-shell=/bin/bash --gid-number=\${domain_users_gid} --gecos='Workstations Admin' --unix-home="/home/local/${workstationadmin_username}" --username=administrator --password='${adroot_password}' cat <<- EOM | ldbmodify -H /var/lib/samba/private/sam.ldb -i \$(ldbsearch -H /var/lib/samba/private/sam.ldb objectsid=\$(wbinfo --name-to-sid "${workstationadmin_username}" | awk '{print \$1}') | grep '^dn:') changetype: modify add: displayName displayName: Workstations Admin EOM samba-tool group addmembers "Workstation Admins" "${workstationadmin_username}" rfc2307_uid="\$((\${rfc2307_uid} + 1))" # PAWs admin user samba-tool user create "${pawadmin_username}" '${pawadmin_password}' --mail-address=${pawadmin_username}@${ad_subdomain_prefix}.${domain_name[${my_zone}]} --userou='OU=PAW Admins,OU=Admin Users' --nis-domain=\${nis_domain} --uid-number=\${rfc2307_uid} --login-shell=/bin/bash --gid-number=\${domain_users_gid} --gecos='PAWs Admin' --unix-home="/home/local/${pawadmin_username}" --username=administrator --password='${adroot_password}' cat <<- EOM | ldbmodify -H /var/lib/samba/private/sam.ldb -i \$(ldbsearch -H /var/lib/samba/private/sam.ldb objectsid=\$(wbinfo --name-to-sid "${pawadmin_username}" | awk '{print \$1}') | grep '^dn:') changetype: modify add: displayName displayName: PAWs Admin EOM samba-tool group addmembers "PAW Admins" "${pawadmin_username}" rfc2307_uid="\$((\${rfc2307_uid} + 1))" # Users admin user samba-tool user create "${useradmin_username}" '${useradmin_password}' --mail-address=${useradmin_username}@${ad_subdomain_prefix}.${domain_name[${my_zone}]} --userou='OU=User Admins,OU=Admin Users' --nis-domain=\${nis_domain} --uid-number=\${rfc2307_uid} --login-shell=/bin/bash --gid-number=\${domain_users_gid} --gecos='Users Admin' --unix-home="/home/local/${useradmin_username}" --username=administrator --password='${adroot_password}' cat <<- EOM | ldbmodify -H /var/lib/samba/private/sam.ldb -i \$(ldbsearch -H /var/lib/samba/private/sam.ldb objectsid=\$(wbinfo --name-to-sid "${useradmin_username}" | awk '{print \$1}') | grep '^dn:') changetype: modify add: displayName displayName: Users Admin EOM samba-tool group addmembers "User Admins" "${useradmin_username}" rfc2307_uid="\$((\${rfc2307_uid} + 1))" # Infrastructure admin user samba-tool user create "${infraadmin_username}" '${infraadmin_password}' --mail-address=${infraadmin_username}@${ad_subdomain_prefix}.${domain_name[${my_zone}]} --userou='OU=Infrastructure Admins,OU=Admin Users' --nis-domain=\${nis_domain} --uid-number=\${rfc2307_uid} --login-shell=/bin/bash --gid-number=\${domain_users_gid} --gecos='Infrastructure Admin' --unix-home="/home/local/${infraadmin_username}" --username=administrator --password='${adroot_password}' cat <<- EOM | ldbmodify -H /var/lib/samba/private/sam.ldb -i \$(ldbsearch -H /var/lib/samba/private/sam.ldb objectsid=\$(wbinfo --name-to-sid "${infraadmin_username}" | awk '{print \$1}') | grep '^dn:') changetype: modify add: displayName displayName: Infrastructure Admin EOM samba-tool group addmembers "Infrastructure Admins" "${infraadmin_username}" rfc2307_uid="\$((\${rfc2307_uid} + 1))" # Make sure that the default initial admin accounts (including the builtin one) have delegation disabled # TODO: the sensitive setting currently inhibits login on Windows as per https://bugzilla.samba.org/show_bug.cgi?id=13205 while with SSSD actually logons can succeed if forwardable tickets are disabled in krb5.conf - using custom patch in HVP samba-dc package while waiting for upstream resolution for myadmin in "Administrator" "${adadmin_username}" "${serveradmin_username}" "${workstationadmin_username}" "${pawadmin_username}" "${useradmin_username}" "${infraadmin_username}"; do samba-tool user sensitive "\${myadmin}" on --username=administrator --password='${adroot_password}' done # Make sure that the default initial builtin admin account never expires # Note: password expiration inspection and modification performed as per https://lists.samba.org/archive/samba/2017-March/207405.html for myadmin in "Administrator" ; do samba-tool user setexpiry "\${myadmin}" --noexpiry --username=administrator --password='${adroot_password}' done # Move builtin privileged administration users/groups to the custom OU created above for builtin_user in "Administrator"; do samba-tool user move "\${builtin_user}" "OU=Allpowerful Admins,OU=Admin Users" --username=administrator --password='${adroot_password}' done # TODO: the following builtin groups cannot be moved: "Administrators" "Account Operators" "Backup Operators" "Print Operators" "Server Operators" "Cryptographic Operators" - find a workaround or use a different strategy alltogether for builtin_group in "Enterprise Admins" "Domain Admins" "Schema Admins" "Domain Controllers" "Read-Only Domain Controllers" "Group Policy Creator Owners"; do samba-tool group move "\${builtin_group}" "OU=Allpowerful Admins,OU=Admin Users" --username=administrator --password='${adroot_password}' done # Add a template unprivileged user with all attributes # Note: all users should be able to login both on Unix and Windows, so all attributes should be set, with home/profile redirected to domain-based DFS paths (pointing to shared storage) # Note: the following user can be used as a template by invoking the "Copy..." context menu option from ADUC # Note: there still is no equivalent in samba-tool (something like "samba-tool user copy newusername newuserpassword --from-user=templateusername ...") # Note: do not add given-name and surname since those must be unique across the directory and could inhibit user copy - manually adding displayname if [ -n "${storage_name}" ]; then # Add settings reflecting base CIFS shares through domain-based DFS if Gluster storage has been configured windows_user_home_options="--home-drive=H --home-directory=\\\\\\\\${ad_subdomain_prefix}.${domain_name[${my_zone}]}\\\\Users\\\\${template_username} --profile-path=\\\\\\\\${ad_subdomain_prefix}.${domain_name[${my_zone}]}\\\\Profiles\\\\${template_username}" fi # Add generic POSIX home directory settings unix_user_home_options="--unix-home=/home/${ad_subdomain_prefix}.${domain_name[${my_zone}]}/${template_username}" samba-tool user create "${template_username}" --random-password --must-change-at-next-login \${windows_user_home_options} --job-title='Template Title' --department='Template Department' --company='Template Company' --telephone-number='123456789' --description="Template User" --mail-address=${template_username}@${ad_subdomain_prefix}.${domain_name[${my_zone}]} --userou='OU=Unprivileged Users' --nis-domain=\${nis_domain} \${unix_user_home_options} --uid-number=\${rfc2307_uid} --login-shell=/bin/bash --gid-number=\${domain_users_gid} --gecos='Template User' --username=administrator --password='${adroot_password}' samba-tool user disable "${template_username}" --username=administrator --password='${adroot_password}' # Add displayName (required by some apps, like Nextcloud) to the template user cat <<- EOM | ldbmodify -H /var/lib/samba/private/sam.ldb -i \$(ldbsearch -H /var/lib/samba/private/sam.ldb objectsid=\$(wbinfo --name-to-sid "${template_username}" | awk '{print \$1}') | grep '^dn:') changetype: modify add: displayName displayName: Template User EOM samba-tool group addmembers "Unprivileged Users" "${template_username}" rfc2307_uid="\$((\${rfc2307_uid} + 1))" # Restore GPO objects and links from the HVP custom example backup # Note: the following requires HVP custom samba-dc-gpo-addons package # TODO: define GPOs to deny interactive login anywhere to users/groups in "Allpowerful Admins" OU as per https://docs.microsoft.com/it-it/windows-server/identity/ad-ds/plan/security-best-practices/appendix-f--securing-domain-admins-groups-in-active-directory # Note: all custom Admins can locally login only on the member machines in the OU they administer and on PAWs # TODO: ideally there would be separated PAW OUs, one for each admin group ("User Admins", "AD Admins", "Server Admins", "Infrastructure Admins" and "Workstation Admins") with only "PAW Admins" allowed to logon on all # Note: Server Admins are member of the local Administrators group for member machines under the Servers OU, except for Remote Desktop Servers (for Windows servers - Linux servers controlled by LDAP-based sudo rules) # Note: LAPS GPOs force local Administrator password change on the Remote Desktop Servers, Workstations and PAWs OUs # Note: Server/Workstation/PAW Admins must manage Remote Desktop servers/workstation/PAW machines by means of their ability to read from AD the LAPS-controlled local Administrator passwords for member machines under the Remote Desktop Servers, Workstations and PAWs OUs gpo_restore_specialized -f /usr/share/samba/gpo/example-gpo-backup.tar.gz -k # Add a non-expiring service account user without Unix attributes for anonymous-like binding via LDAPS # TODO: use samba-tool dsacl to grant read permissions on the memberOf attribute for the whole directory to the bind user (optionally required by Nextcloud) samba-tool user create "${adbind_username}" '${adbind_password}' --userou='OU=Service Users' --description='AD LDAP bind service user' --username=administrator --password='${adroot_password}' samba-tool user setexpiry "${adbind_username}" --noexpiry --username=administrator --password='${adroot_password}' samba-tool group addmembers "Service Users" "${adbind_username}" # Add non-expiring service account users with Unix attributes and with custom SPNs and all encryption types for kerberized services # Note: do not add given-name and surname since those must be unique across the directory and could inhibit user copy - manually adding displayname EOF for service_username in "${!service_spns[@]}"; do if [ -n "${service_pwds[${service_username}]}" ]; then password_option="'${service_pwds[${service_username}]}'" else password_option="--random-password" fi cat <<- EOF >> rc.samba-dc samba-tool user create "${service_username}" ${password_option} --description='Service account' --userou='OU=Service Users' --nis-domain=\${nis_domain} --uid-number=\${rfc2307_uid} --login-shell=/bin/bash --gid-number=\${domain_users_gid} --gecos='Service account' --unix-home="/home/local/${service_username}" --username=administrator --password='${adroot_password}' samba-tool user setexpiry "${service_username}" --noexpiry --username=administrator --password='${adroot_password}' EOF for service_spn in $(echo "${service_spns[${service_username}]}" | sed -e 's/,/ /g'); do cat <<- EOF >> rc.samba-dc samba-tool spn add "${service_spn}" "${service_username}" --username=administrator --password='${adroot_password}' EOF done # Add unconstrained or constrained (list of SPNs) delegation # Note: constrained delegation has precedence and overrides the unconstrained one if [ "${service_delegations[${service_username}]}" = "unconstrained" ]; then cat <<- EOF >> rc.samba-dc samba-tool delegation for-any-service "${service_username}" on --username=administrator --password='${adroot_password}' EOF elif [ -n "${service_delegations[${service_username}]}" ]; then for service_spn in $(echo "${service_delegations[${service_username}]}" | sed -e 's/,/ /g'); do cat <<- EOF >> rc.samba-dc samba-tool delegation add-service "${service_username}" "${service_spn}" --username=administrator --password='${adroot_password}' EOF done fi # Add any-protocol (both Kerberos and NTLM) delegation rights if [ "${service_apdelegations[${service_username}]}" = "true" ]; then cat <<- EOF >> rc.samba-dc samba-tool delegation for-any-protocol "${service_username}" on --username=administrator --password='${adroot_password}' EOF fi cat <<- EOF >> rc.samba-dc # Add displayName (required by some apps, like Nextcloud) to the service user cat <<- EOM | ldbmodify -H /var/lib/samba/private/sam.ldb -i \$(ldbsearch -H /var/lib/samba/private/sam.ldb objectsid=\$(wbinfo --name-to-sid "${service_username}" | awk '{print \$1}') | grep '^dn:') changetype: modify add: displayName displayName: Service Account EOM # Note: unattended SPN enctypes manipulation requires Kerberos authentication net ads enctypes set "${service_username}" -k samba-tool group addmembers "Service Users" "${service_username}" rfc2307_uid="\$((\${rfc2307_uid} + 1))" EOF done cat << EOF >> rc.samba-dc # Saving the next available uid number for ADUC console # Note: RSAT for Windows 10/2016 and later do not support POSIX attributes dedicated tab anymore (was in NIS tools) cat <<- EOM | ldbmodify -H /var/lib/samba/private/sam.ldb -i dn: CN=\${nis_domain},CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System,\${domain_top_dn} changetype: Modify add: msSFU30MaxUidNumber msSFU30MaxUidNumber: \${rfc2307_uid} EOM # Saving the next available gid number for ADUC console # Note: RSAT for Windows 10/2016 and later do not support POSIX attributes dedicated tab anymore (was in NIS tools) cat <<- EOM | ldbmodify -H /var/lib/samba/private/sam.ldb -i dn: CN=\${nis_domain},CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System,\${domain_top_dn} changetype: Modify add: msSFU30MaxGidNumber msSFU30MaxGidNumber: \${rfc2307_gid} EOM # Manage DNS # Add DNS reverse zone samba-tool dns zonecreate ${my_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${my_zone}" ; fi).${ad_subdomain_prefix}.${domain_name[${my_zone}]} ${reverse_domain_name[${my_zone}]} --username=administrator --password='${adroot_password}' # Add DNS A and PTR records for known machines # Add DNS PTR record for ourselves samba-tool dns add ${my_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${my_zone}" ; fi).${ad_subdomain_prefix}.${domain_name[${my_zone}]} ${reverse_domain_name[${my_zone}]} $(echo ${my_ip[${my_zone}]} | sed -e "s/^$(echo ${network_base[${my_zone}]} | sed -e 's/[.]/\\./g')[.]//") PTR ${my_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${my_zone}" ; fi).${ad_subdomain_prefix}.${domain_name[${my_zone}]} --username=administrator --password='${adroot_password}' # Add entry for WPAD # Note: registration for this entry is blocked by default on Microsoft AD-integrated DNS - we emulate that by pre-creating here samba-tool dns add ${my_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${my_zone}" ; fi).${ad_subdomain_prefix}.${domain_name[${my_zone}]} ${ad_subdomain_prefix}.${domain_name[${my_zone}]} wpad A ${test_ip[${my_zone}]} --username=administrator --password='${adroot_password}' # Add dummy entry for ISATAP # Note: registration for this entry is blocked by default on Microsoft AD-integrated DNS - we emulate that by pre-creating here samba-tool dns add ${my_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${my_zone}" ; fi).${ad_subdomain_prefix}.${domain_name[${my_zone}]} ${ad_subdomain_prefix}.${domain_name[${my_zone}]} isatap A 127.0.0.1 --username=administrator --password='${adroot_password}' EOF if [ -n "${storage_name}" ]; then cat <<- EOF >> rc.samba-dc # TODO: joining for CTDB-controlled NFS/CIFS services fails while specifying a custom OU - preseeding here as a workaround - remove when fixed upstream samba-tool computer create $(echo ${storage_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${my_zone}" ; fi) | awk '{print toupper($0)}') --computerou="OU=Infrastructures" --username=administrator --password='${adroot_password}' # Add round-robin-resolved name for CTDB-controlled NFS/CIFS services # TODO: find a way to add A records with a TTL of 1 # TODO: remove from here and register during stoarge cluster AD join EOF for ((i=0;i<${active_storage_node_count};i=i+1)); do cat <<- EOF >> rc.samba-dc samba-tool dns add ${my_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${my_zone}" ; fi).${ad_subdomain_prefix}.${domain_name[${my_zone}]} ${ad_subdomain_prefix}.${domain_name[${my_zone}]} ${storage_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${my_zone}" ; fi) A $(ipmat $(ipmat $(ipmat ${my_ip[${my_zone}]} ${my_ip_offset} -) ${storage_ip_offset} +) ${i} +) --username=administrator --password='${adroot_password}' samba-tool dns add ${my_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${my_zone}" ; fi).${ad_subdomain_prefix}.${domain_name[${my_zone}]} ${reverse_domain_name[${my_zone}]} $(ipmat $(ipmat $(ipmat ${my_ip[${my_zone}]} ${my_ip_offset} -) ${storage_ip_offset} +) ${i} + | sed -e "s/^$(echo ${network_base[${my_zone}]} | sed -e 's/[.]/\\./g')[.]//") PTR ${storage_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${my_zone}" ; fi).${ad_subdomain_prefix}.${domain_name[${my_zone}]} --username=administrator --password='${adroot_password}' EOF done cat <<- EOF >> rc.samba-dc # Load automounter maps for HVP default NFS shares cat <<- EOM | ldbmodify -H /var/lib/samba/private/sam.ldb -i dn: ou=automount,\${domain_top_dn} changetype: add objectClass: top objectClass: organizationalUnit description: Container for Unix automounter maps ou: automount name: automount dn: ou=auto.master,ou=automount,\${domain_top_dn} changetype: add objectClass: top objectClass: organizationalUnit objectClass: automountMap ou: auto.master name: auto.master automountMapName: auto.master dn: cn=/-,ou=auto.master,ou=automount,\${domain_top_dn} changetype: add objectClass: top objectClass: automount objectClass: container cn: /- name: /- automountKey: /- automountInformation: auto.direct dn: ou=auto.direct,ou=automount,\${domain_top_dn} changetype: add objectClass: top objectClass: organizationalUnit objectClass: automountMap ou: auto.direct name: auto.direct automountMapName: auto.direct dn: cn=/home/${ad_subdomain_prefix}.${domain_name[${my_zone}]},ou=auto.direct,ou=automount,\${domain_top_dn} changetype: add objectClass: top objectClass: automount objectClass: container cn: /home/${ad_subdomain_prefix}.${domain_name[${my_zone}]} name: /home/${ad_subdomain_prefix}.${domain_name[${my_zone}]} automountKey: /home/${ad_subdomain_prefix}.${domain_name[${my_zone}]} automountInformation: -fstype=nfs,rw,noexec,nosuid,nodev ${storage_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${my_zone}" ; fi).${ad_subdomain_prefix}.${domain_name[${my_zone}]}:/${gluster_vol_name['unixshare']}/homes dn: cn=/home/groups,ou=auto.direct,ou=automount,\${domain_top_dn} changetype: add objectClass: top objectClass: automount objectClass: container cn: /home/groups name: /home/groups automountKey: /home/groups automountInformation: -fstype=nfs,rw,noexec,nosuid,nodev ${storage_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${my_zone}" ; fi).${ad_subdomain_prefix}.${domain_name[${my_zone}]}:/${gluster_vol_name['unixshare']}/groups dn: cn=/usr/local/software,ou=auto.direct,ou=automount,\${domain_top_dn} changetype: add objectClass: top objectClass: automount objectClass: container cn: /usr/local/software name: /usr/local/software automountKey: /usr/local/software automountInformation: -fstype=nfs,ro,exec,nosuid,nodev ${storage_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${my_zone}" ; fi).${ad_subdomain_prefix}.${domain_name[${my_zone}]}:/${gluster_vol_name['unixshare']}/software EOM EOF fi cat << EOF >> rc.samba-dc # Load sudo rules for HVP defaults and groups # TODO: find a way to restrict rules to machine groups mapping to AD OUs - eg: create/use NIS netgroups (corresponding to OUs) to be used as sudoHost - not an actual problem with the current setup (see note below) # Note: "Server Admins" can login on servers (where the sudo rules below apply, except on Remote Desktop servers where LAPS must be used) or on PAWs (where LDAP/AD sudo configuration is not enabled and administration must be performed by "PAW Admins" using LAPS) cat <<- EOM | ldbmodify -H /var/lib/samba/private/sam.ldb -i dn: ou=SUDOers,\${domain_top_dn} changetype: add objectClass: top objectClass: organizationalUnit description: Container for Unix sudo rules ou: SUDOers name: SUDOers dn: CN=defaults,OU=SUDOers,\${domain_top_dn} changetype: add objectClass: top objectClass: sudoRole cn: defaults name: defaults sudoOption: !authenticate sudoOption: env_keep+=SSH_AUTH_SOCK dn: CN=serveradminsrule,OU=SUDOers,\${domain_top_dn} changetype: add objectClass: top objectClass: sudoRole cn: serveradminsrule name: serveradminsrule sudoHost: ALL sudoCommand: ALL sudoRunAsUser: root sudoUser: %Server Admins EOM # Note: set proper ACLs on sudo entries (thanks to http://ghanima.net/doku.php?id=blog:sssdandsamba4aclgotcha) # Note: general intro about dsacl set can be found in https://kiljan.org/2017/12/22/setting-up-a-lightweight-authentication-back-end/ samba-tool dsacl set -H /var/lib/samba/private/sam.ldb --objectdn="OU=SUDOers,\${domain_top_dn}" --sddl="(A;CI;RPLCRC;;;DC)" # Prepare an idmap-db cold backup for further DCs (to keep BUILTIN ids aligned) tdbbackup -s .bak /var/lib/samba/private/idmap.ldb mkdir -p /var/lib/samba/sysvolrepl cp -a /var/lib/samba/private/idmap.ldb.bak /var/lib/samba/sysvolrepl/idmap.ldb else # Note: it seems that we need to allow some time for the internal DNS to come up sleep 30 # Add DNS PTR record for ourselves samba-tool dns add ${my_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${my_zone}" ; fi).${ad_subdomain_prefix}.${domain_name[${my_zone}]} ${reverse_domain_name[${my_zone}]} $(echo ${my_ip[${my_zone}]} | sed -e "s/^$(echo ${network_base[${my_zone}]} | sed -e 's/[.]/\\./g')[.]//") PTR ${my_name}$(if [ "${use_hostname_decoration}" = "true" ]; then echo "-${my_zone}" ; fi).${ad_subdomain_prefix}.${domain_name[${my_zone}]} --username=administrator --password='${adroot_password}' fi # Remove Kerberos identity acquired above kdestroy # Register uid and gid on the machine account object for this DC machine_account_name="\$(hostname -s | awk '{print toupper(\$0)}')\\\$" machine_account_sid=\$(wbinfo --name-to-sid "\${machine_account_name}" | awk '{print \$1}') machine_account_rid=\$(echo "\${machine_account_sid}" | awk -F- '{print \$NF}') machine_account_uid=\$((\${rfc2307_dc_uid_base} + \${machine_account_rid})) domain_controllers_gid=\$(getent group "Domain Controllers" | awk -F: '{print \$3}') cat <<- EOM | ldbmodify -H /var/lib/samba/private/sam.ldb -i \$(ldbsearch -H /var/lib/samba/private/sam.ldb objectsid=\${machine_account_sid} | grep '^dn:') changetype: modify add: uidNumber uidNumber: \${machine_account_uid} - add: gidNumber gidNumber: \${domain_controllers_gid} EOM # Initialize further domain controllers if [ "${domain_join}" = "true" ]; then # Copy /var/lib/samba/private/idmap.ldb from PDC emulator DC to keep BUILTIN ids aligned rm -f /var/lib/samba/private/idmap.ldb SSH_CONTROL=$(mktemp -u /run/samba/rsync-sysvol-dfsroot-control-socket.XXXXXXXXX) kinit -k $(hostname -s| awk '{print toupper($0)}')'$@${netbios_domain_name}' ssh -l $(hostname -s| awk '{print toupper($0)}')'$' -K -x -a -fN -o "ExitOnForwardFailure yes" -M -S ${SSH_CONTROL} -T -L 873:127.0.0.1:873 ${domain_pdc_emulator} rsync -XAavz --password-file=/etc/samba/rsync-sysvol-dfsroot.secret rsync://localhost:873/SysVolRepl/idmap.ldb /var/lib/samba/private/ kdestroy ssh -S ${SSH_CONTROL} -O exit ${domain_pdc_emulator} restorecon -v /var/lib/samba/private/idmap.ldb net cache flush # Set aside a copy to share in case we get promoted to PDC emulator later on mkdir -p /var/lib/samba/sysvolrepl cp -a /var/lib/samba/private/idmap.ldb /var/lib/samba/sysvolrepl/idmap.ldb # Force removal of gencache # TODO: maybe needed only when using winbindd, not winbind - remove the following line if it is so rm -f /var/cache/samba/gencache.tdb # Perform first-time rsync for sysvol and DFS-root replication /usr/local/sbin/sysvol-dfsroot-replication > /var/log/samba/sysvol-dfsroot-replication.log 2>&1 fi # Reset sysvol ACLs # Note: sysvol files/dirs belong to the Domain Admins group - see https://wiki.samba.org/index.php/Setting_up_Samba_as_a_Domain_Member#Setting_up_a_Basic_smb.conf_File - sysvol files ownership does not matter anyway # Note: needs samba running samba-tool ntacl sysvolreset # Setup a cron job to keep the current PDC emulator role holder DC as our time reference cat <<- EOM > /usr/local/sbin/update-time-reference #!/bin/bash # Script to switch our time reference to the DC holding the PDC emulator FSMO role # Define a lock-removing function function cleanup () { local owner_pid=\\\$(cat /run/samba/update-time-reference.lock 2>/dev/null) local my_pid=\\\$\\\$ [ "\\\${owner_pid}" = "\\\${my_pid}" ] && rm -f /run/samba/update-time-reference.lock } # Get the PID of the current owner of the lock owner_pid=\\\$(cat /run/samba/update-time-reference.lock 2>/dev/null) # Get our own PID my_pid=\\\$\\\$ # Try to acquire lock # Note: a lock will be cleared out if held for more than one hour lockfile -l 3600 /run/samba/update-time-reference.lock > /dev/null 2>&1 exitcode=\\\$? if [ "\\\${exitcode}" -ne "0" ]; then # Exit immediately if we did not get the lock exit 0 fi # Detect and terminate a stuck instance if [ -n "\\\${owner_pid}" ]; then # Note: there is the risk that the lock-holding instance simply died without removing the lock and then its PID is now held by a different innocent process - checking # TODO: this has the known problem of TOCTOU - find an atomic equivalent and replace here if [ -f "/proc/\\\${owner_pid}/cmdline" -a "\\\$(cat /proc/\\\${owner_pid}/cmdline | xargs -0 | awk '{print \\\$1}')" = "\\\${0}" ]; then pkill -KILL -P "\\\${owner_pid}" sleep 15 fi fi # Declare ownership of the lock echo "\\\${my_pid}" > /run/samba/update-time-reference.lock # Make sure to remove lock when terminating trap cleanup EXIT SIGHUP SIGTERM # Find the DC holding the PDC emulator FSMO role domain_pdc_emulator=\\\$(dig _ldap._tcp.pdc._msdcs.\\\$(dnsdomainname) SRV +short | awk '{print \\\$4}' | sed -e 's/[.]\\\$//') # Exit if PDC emulator role not found if [ -z "\\\${domain_pdc_emulator}" ]; then exit 255 fi # Define desired time references if [ "\\\${domain_pdc_emulator}" = "\\\$(hostname)" ]; then # Switch to pre-defined time references if PDC emulator role is residing on this DC time_reference_servers="$(echo ${my_ntpservers} | sed -e 's/,/\n/g' | sort -u | sed -e 's/\n/,/g')" else # Set the time reference to the PDC emulator otherwise time_reference_servers="\\\${domain_pdc_emulator}" fi # Get current time references current_step_tickers=\\\$(sort -u /etc/ntp/step-tickers | sed -e 's/\\n/,/g') current_ntp_servers=\\\$(awk '/^server[[:space:]]*/ {print \\$2}' /etc/ntp.conf | sed -e '/127[.]127[.]1[.]0/d' | sort -u | sed -e 's/\\n/,/g') # Apply time reference reconfiguration do_resync="false" if [ "\\\${current_step_tickers}" != "\\\${time_reference_servers}" ]; then do_resync="true" cat /dev/null > /etc/ntp/step-tickers for server in \\\$(echo "\\\${time_reference_servers}" | sed -e 's/,/ /g'); do echo "\\\${server}" >> /etc/ntp/step-tickers done fi if [ "\\\${current_ntp_servers}" != "\\\${time_reference_servers}" ]; then do_resync="true" sed -i -e '/^server\\s/s/^/#/g' -e '/^server 127[.]127[.]1[.]0/s/^#//g' /etc/ntp.conf for server in \\\$(echo "\\\${time_reference_servers}" | sed -e 's/,/ /g'); do echo "server \\\${server} iburst" >> /etc/ntp.conf done fi # Resync immediately if [ "\\\${do_resync}" = "true" ]; then # Stop NTPd systemctl stop ntpd # Resync time with PDC emulator DC systemctl restart ntpdate # Restart NTPd systemctl start ntpd fi EOM chmod 755 /usr/local/sbin/update-time-reference chown root:root /usr/local/sbin/update-time-reference cat <<- EOM > /etc/cron.d/update-time-reference # Check and keep the PDC emulator DC as time reference once every 6 hours 00 */6 * * * root /usr/local/sbin/update-time-reference > /var/log/update-time-reference.log 2>&1 EOM chmod 644 /etc/cron.d/update-time-reference chown root:root /etc/cron.d/update-time-reference # Setup an rsync cron job for sysvol and DFS-root replication # TODO: add PDC-emulator OS detection and switch to an equivalent solution for a Windows-based PDC emulator - see https://wiki.samba.org/index.php/Robocopy_based_SysVol_replication_workaround cat <<- EOM > /usr/local/sbin/sysvol-dfsroot-replication #!/bin/bash # Script to perform an rsync-based sysvol and DFS-root replication from the DC holding the PDC emulator FSMO role # Define a lock-removing function function cleanup () { local owner_pid=\\\$(cat /run/samba/sysvol-dfsroot-replication.lock 2>/dev/null) local my_pid=\\\$\\\$ [ "\\\${owner_pid}" = "\\\${my_pid}" ] && rm -f /run/samba/sysvol-dfsroot-replication.lock } # Define a synchronization function function syncall () { export KRB5CCNAME="FILE:\\\$(mktemp)" if [ \\\$? -ne 0 ]; then exit 255 fi SSH_CONTROL=\\\$(mktemp -u /run/samba/rsync-sysvol-dfsroot-control-socket.XXXXXXXXX) if [ \\\$? -ne 0 ]; then exit 254 fi kinit -k \\\$(hostname -s| awk '{print toupper(\\\$0)}')'\\\$@\\\${netbios_domain_name}' ssh -l \\\$(hostname -s| awk '{print toupper(\\\$0)}')'$' -K -x -a -fN -o "ExitOnForwardFailure yes" -M -S \\\${SSH_CONTROL} -T -L 873:127.0.0.1:873 \\\${domain_pdc_emulator} rsync -XAavz --delete-after --password-file=/etc/samba/rsync-sysvol-dfsroot.secret rsync://localhost:873/SysVol/ /var/lib/samba/sysvol/ rsync -XAavz --delete-after --password-file=/etc/samba/rsync-sysvol-dfsroot.secret rsync://localhost:873/DFSroot/ /var/lib/samba/dfsroot/ kdestroy ssh -S \\\${SSH_CONTROL} -O exit \\\${domain_pdc_emulator} } # Get the PID of the current owner of the lock owner_pid=\\\$(cat /run/samba/sysvol-dfsroot-replication.lock 2>/dev/null) # Get our own PID my_pid=\\\$\\\$ # Try to acquire lock # Note: a lock will be cleared out if held for more than four hours lockfile -l 14400 /run/samba/sysvol-dfsroot-replication.lock > /dev/null 2>&1 exitcode=\\\$? if [ "\\\${exitcode}" -ne "0" ]; then # Exit immediately if we did not get the lock exit 0 fi # Detect and terminate a stuck instance if [ -n "\\\${owner_pid}" ]; then # Note: there is the risk that the lock-holding instance simply died without removing the lock and then its PID is now held by a different innocent process - checking # TODO: this has a known TOCTOU problem - find an atomic equivalent and replace here if [ -f "/proc/\\\${owner_pid}/cmdline" -a "\\\$(cat /proc/\\\${owner_pid}/cmdline | xargs -0 | awk '{print \\\$1}')" = "\\\${0}" ]; then pkill -KILL -P "\\\${owner_pid}" sleep 15 else exit 0 fi fi # Declare ownership of the lock echo "\\\${my_pid}" > /run/samba/sysvol-dfsroot-replication.lock # Make sure to remove lock when terminating trap cleanup EXIT SIGHUP SIGTERM # Find the NetBIOS domain name netbios_domain_name=\\\$(samba-tool domain info \\\$(hostname) | awk 'BEGIN {IGNORECASE=1}; /^Netbios[[:space:]]*domain[[:space:]]*:/ {print \\\$4}') # Find the DC holding the PDC emulator FSMO role domain_pdc_emulator=\\\$(dig _ldap._tcp.pdc._msdcs.\\\$(dnsdomainname) SRV +short | awk '{print \\\$4}' | sed -e 's/[.]\\\$//') # Exit if NetBIOS domain name or PDC emulator role not found if [ -z "\\\${netbios_domain_name}" -o -z "\\\${domain_pdc_emulator}" ]; then exit 255 fi # Exit if PDC emulator role is residing on this DC if [ "\\\${domain_pdc_emulator}" = "\\\$(hostname)" ]; then # TODO: check whether we were not already PDC emulator and in that case perform one last sync from the previous PDC emulator before enabling rsync daemon if [ -s /var/lib/samba/synced-pdc-emulator ]; then previous_pdc_emulator=\\\$(cat /var/lib/samba/synced-pdc-emulator) # Note: enabling rsync daemon before exiting systemctl --now enable rsyncd.service exit 0 else # TODO: check whether we were PDC emulator previously and in that case wait to allow one last sync from the new PDC emulator before disabling rsync daemon # Note: disabling rsync daemon before exiting systemctl --now disable rsyncd.service exit 0 fi # Save the PDC emulator for later tracking echo "\\\${domain_pdc_emulator}" > /var/lib/samba/synced-pdc-emulator # Perform the synchronization syncall EOM chmod 755 /usr/local/sbin/sysvol-dfsroot-replication chown root:root /usr/local/sbin/sysvol-dfsroot-replication # Configure SSH to limit members of the group "Domain Controllers" to tunneling towards the rsync daemon # TODO: limitations involving AD groups do not seem to be effective on a DC - find out why and correct cat <<- EOM >> /etc/ssh/sshd_config Match Group Domain?Controllers PermitOpen 127.0.0.1:873 X11Forwarding no AllowAgentForwarding no PermitTTY no ForceCommand /bin/false EOM cat <<- EOM > /etc/cron.d/sysvol-dfsroot-replication # Run unidirectional sysvol and DFS-root replication from PDC emulator once every 5 minutes */5 * * * * root /usr/local/sbin/sysvol-dfsroot-replication > /var/log/samba/sysvol-dfsroot-replication.log 2>&1 EOM chmod 644 /etc/cron.d/sysvol-dfsroot-replication chown root:root /etc/cron.d/sysvol-dfsroot-replication # TODO: samba-tool backup fails on new DCs - forcing a RID allocation as a workaround - remove when fixed upstream samba-tool user create "\$(hostname -s)-init" --random-password samba-tool user delete "\$(hostname -s)-init" # Customize TLS key/cert/CA for LDAPS under /var/lib/samba/private/tls # TODO: use our own X.509 certificate (signed by our own CA) cat /etc/pki/tls/private/localhost.key > /var/lib/samba/private/tls/key.pem cat /etc/pki/tls/certs/localhost.crt > /var/lib/samba/private/tls/cert.pem cat /etc/pki/tls/certs/localhost.crt > /var/lib/samba/private/tls/ca.pem systemctl restart samba else logger -s -p "local7.err" -t "rc.samba-dc" "Error while \${action} Samba AD DC domain: \${res}" exit 255 fi # Configure PHP (set timezone, increase execution time and memory/request/filesize limits) sed -i -e 's/^\(.*max_execution_time\).*$/\1 = 3600/' -e 's/^\(.*memory_limit\).*$/\1 = 800M/' -e 's/^\(.*post_max_size\).*$/\1 = 400M/' -e 's/^\(.*upload_max_filesize\).*$/\1 = 500M/' -e "s>^.*date\\.timezone\\s*=.*\$>date.timezone = ${local_timezone}>" /etc/php.ini # Configure phpLDAPAdmin (allow only through HTTPS; allow from localhost and our networks only) sed -i -e 's/^\\(\\s*\\)\\(Order\\s*\\).*\\\$/\\1\\2allow,deny/' -e "/^\\\\s*Allow\\\\s*from\\\\s*127\\\\.0\\\\.0\\\\.1/s>127\\\\.0\\\\.0\\\\.1.*\$>${allowed_addr}>" -e "/^\\\\s*Require\\\\s*local/s>local.*\\$>ip ${allowed_addr}>" -e 's;^\\(\\s*\\)\\(.*\\)\$;\\1RewriteEngine On\\n\\1RewriteCond %{HTTPS} !=on\\n\\1RewriteRule ^.*\$ https://%{SERVER_NAME}%{REQUEST_URI} [R,L]\\n\\1\\2;' /etc/httpd/conf.d/phpldapadmin.conf # Add Apache alias for phpPgAdmin cat << EOM >> /etc/httpd/conf.d/phpldapadmin.conf Alias /ds /usr/share/phpldapadmin/htdocs RewriteEngine On RewriteCond %{HTTPS} !=on RewriteRule ^.*\$ https://%{SERVER_NAME}%{REQUEST_URI} [R,L] # Apache 2.4 Require ip ${allowed_addr} # Apache 2.2 Order allow,deny Deny from all Allow from ${allowed_addr} Allow from ::1 EOM # Restart Apache to apply configuration changes systemctl restart httpd EOF popd # 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="2020110101" # 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 multi_instance_max unset nicmacfix unset luks_passphrase unset luks_tangservers unset domain_join unset my_nameserver unset my_forwarders unset my_smtpserver unset use_smtps unset notification_receiver unset local_timezone 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" declare -a luks_tangservers domain_join="false" my_nameserver="8.8.8.8" my_forwarders="8.8.8.8" nicmacfix="false" multi_instance_max="9" local_timezone="UTC" 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_dc.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 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 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 nameserver address given_nameserver=$(sed -n -e "s/^.*hvp_nameserver=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_nameserver}" ]; then my_nameserver="${given_nameserver}" fi # Determine forwarders addresses given_forwarders=$(sed -n -e "s/^.*hvp_forwarders=\\(\\S*\\).*\$/\\1/p" /proc/cmdline) if [ -n "${given_forwarders}" ]; then my_forwarders="${given_forwarders}" fi # Determine multi-instance limit given_multi_instance_max=$(sed -n -e 's/^.*hvp_maxinstances=\(\S*\).*$/\1/p' /proc/cmdline) if echo "${given_multi_instance_max}" | grep -q '^[[:digit:]]\+$' ; then multi_instance_max="${given_multi_instance_max}" 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 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 # 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 # Enable HVP own DC-enabled Samba rebuild repo yum-config-manager --enable hvp-samba-dc > /dev/null # Make sure that we always prefer HVP own rebuild repo yum-config-manager --save --setopt='hvp-samba-dc.priority=50' > /dev/null # 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 Webmin repository definition # Define proper network source webmin_baseurl="http://download.webmin.com/download/yum/" webmin_gpgkey="http://www.webmin.com/jcameron-key.asc" # Prefer custom Webmin URLs, if any if [ -n "${hvp_repo_baseurl['webmin']}" ]; then webmin_baseurl="${hvp_repo_baseurl['webmin']}" fi if [ -n "${hvp_repo_gpgkey['webmin']}" ]; then webmin_gpgkey="${hvp_repo_gpgkey['webmin']}" fi cat << EOF > /etc/yum.repos.d/webmin.repo [webmin] name = Webmin Distribution Neutral baseurl = ${webmin_baseurl} gpgcheck = 1 enabled = 1 gpgkey = ${webmin_gpgkey} skip_if_unavailable = 1 EOF chmod 644 /etc/yum.repos.d/webmin.repo # 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{,-plugins} arj pwgen yum -y install yum-cron yum-plugin-ps gdisk # Install Nmon and Dstat yum -y install nmon dstat # Install Apache yum -y install httpd mod_ssl # Install Webalizer and MRTG yum -y install webalizer mrtg net-snmp net-snmp-utils # Install Logcheck yum -y install logcheck # Install Webmin yum -y install webmin # Note: immediately stop webmin started by postinst scriptlet /etc/init.d/webmin stop # Install custom Samba packages with AD DC support from HVP own repo and related utilities # Note: procmail package provides lockfile command needed to avoid overlapping runs of scheduled sync jobs yum -y install samba-dc samba-common-tools samba-client samba-winbind-clients oddjob-mkhomedir rsync krb5-workstation openldap-clients cyrus-sasl-gssapi procmail # Install custom Samba DC GPO support package yum -y install samba-dc-gpo-addons # Install phpLDAPAdmin yum -y install phpldapadmin # Install security-related tools yum -y install luksmeta clevis-{luks,udisks2,systemd} cryptsetup-reencrypt aide usbguard scap-security-guide openscap-{scanner,utils} # 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 elif dmidecode -s system-manufacturer | grep -q "oVirt" ; then yum -y install ovirt-guest-agent 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 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 # 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 yum-config-manager --enable hvp-samba-dc > /dev/null yum-config-manager --save --setopt='hvp-samba-dc.priority=50' > /dev/null # 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 (no splash screen, no Plymouth, show menu, wait 5 seconds for manual override) # Note: alternatively, Plymouth may be instructed to use detailed listing with: plymouth-set-default-theme -R details sed -i -e '/^GRUB_CMDLINE_LINUX/s/\s*rhgb//' -e '/^GRUB_TIMEOUT/s/=.*$/="5"/' /etc/default/grub grub2-mkconfig -o "${grub2_cfg_file}" # 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 systemd (no shutdown from keyboard) systemctl mask ctrl-alt-del.target # 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, add initial time adjusting from given server) # 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 NTPd # Note: configuration fragment to add NTP service for local clients generated in pre section above and appended in third post section below # Add safeguard for NTP on virtual machines if dmidecode -s system-manufacturer | egrep -q "(Microsoft|VMware|innotek|Parallels|Red.*Hat|oVirt|Xen)" ; then sed -i -e '1s/^/tinker panic 0\n/' /etc/ntp.conf fi # Create socket dir to support signed NTP replies # Note: signed NTP replies for Samba AD-DC interoperability configured through a custom configuration fragment created in pre section above and copied in third post section below # Note: samba is quite picky about permissions for the socket directory - change them and it will refuse to operate it mkdir -p /var/lib/samba/ntp_signd chgrp ntp /var/lib/samba/ntp_signd chmod 2750 /var/lib/samba/ntp_signd # Enable NTPd firewall-offline-cmd --add-service=ntp systemctl enable ntpd # Configure Samba AD DC # Note: initial domain provisioning performed by script created in pre section above and copied in third post section below # Note: current Samba AD DC package has a proper systemd unit - no need to create a custom one here # Add firewalld configuration for Samba AD DC cat << EOF > /etc/firewalld/services/samba-ad-dc.xml samba-ad-dc Samba AD DC is a Unix implementation of a full Active Directory Domain Controller. EOF chmod 644 /etc/firewalld/services/samba-ad-dc.xml # Enable Samba AD DC # Note: actually it will be enabled after domain provisioning # TODO: add output filtering rules (allow only NTP, DNS, HTTPS, SSH and the AD DS replica services) firewall-offline-cmd --add-service=dns firewall-offline-cmd --add-service=samba firewall-offline-cmd --add-service=samba-ad-dc systemctl disable samba # Customize SELinux configuration for phpLDAPAdmin setsebool -P httpd_can_connect_ldap on # TODO: import LDAP server X.509 certificate or use a common recognized CA then remove the following line echo -e 'TLS_REQCERT\tallow' >> /etc/openldap/ldap.conf # Configure phpLDAPAdmin # Note: login requires username specified as DN sed -i -e "/Local LDAP Server/s%^\\(.*\\)\$%\\1\\n\$servers->SetValue('server','host','ldaps://localhost');\\n\$servers->SetValue('server','port',636);\\n\$servers->SetValue('login','auth_type','session');\\n%" -e "s%^\\(\$servers->SetValue('login','attr','uid');\\).*\$%// \\1%" /etc/phpldapadmin/config.php # 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) # TODO: limit input SSH connections by means of firewalld (only from PAWs for administration and other DCs for rsync) 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} # 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.${domain_name['mgmt']}: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 # 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 # Configure Net-SNMP cp -a /etc/snmp/snmpd.conf /etc/snmp/snmpd.conf.orig cat << EOF > /etc/snmp/snmpd.conf # Simple setup of Net-SNMP for traffic monitoring rocommunity public dontLogTCPWrappersConnects yes EOF # Enable Net-SNMP systemctl enable snmpd # Configure MRTG # Configuration file customization through cfgmaker/indexmaker demanded to post-install rc.ks1stboot script # Configure MRTG-Apache integration (allow access from everywhere) sed -i -e 's/^\(\s*\)\(Require local.*\)$/\1Require all granted/' /etc/httpd/conf.d/mrtg.conf # Configure Apache # 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 Apache web service (disable certificate expiration warnings, do not advertise OS/Apache, disable default CGI directory and manual pages, create custom home page, disable TRACE/TRACK support, disable older/weakier protocols/crypto for SSL) cat << EOF >> /etc/sysconfig/httpd # # To avoid periodic checking (with warning email) of certificates validity, # set NOCERTWATCH here. # NOCERTWATCH="yes" EOF # Append custom DH parameters to our certificate file (needs httpd >= 2.2.15-32) # Note: newer Apache versions allow specifying custom DH parameters with: SSLOpenSSLConfCmd DHParameters "/etc/pki/tls/dhparams.pem" cat /etc/pki/tls/dhparams.pem >> /etc/pki/tls/certs/localhost.crt sed -i -e 's/^ServerTokens.*$/ServerTokens ProductOnly/' -e 's/^ServerSignature.*$/ServerSignature Off\n\n#\n# Disable TRACE for PCI compliance\nTraceEnable off/' -e 's/^\(ScriptAlias.*\)$/#\1/' /etc/httpd/conf/httpd.conf sed -i -e 's/^\(SSLProtocol.*\)$/#\1/' -e 's/^\(SSLCipherSuite.*\)$/#\1\n# Stricter settings for PCI compliance\nSSLProtocol all -SSLv2 -SSLv3\nSSLCipherSuite ALL:!EXP:!NULL:!ADH:!LOW:!RC4/' /etc/httpd/conf.d/ssl.conf # Prepare home page cat << EOF > /var/www/html/index.html AD DC Server

AD DC server

Avvertenza per gli utenti del servizio:

Questa macchina fornisce servizi di AD DC.

Se siete parte del personale tecnico:

Le funzionalità predisposte per l'amministrazione/controllo sono elencate di seguito.

  • Lo strumento web di amministrazione della macchina è disponibile qui.
  • Lo strumento web di amministrazione del servizio di directory è disponibile qui.
  • Lo strumento web di visualizzazione dell'utilizzo rete è disponibile qui.
  • Lo strumento web di visualizzazione dell'utilizzo http è disponibile qui.

End users notice:

This machine provides AD DC services.

If you are a technical staff member:

The maintenance/administrative resources are listed below.

  • The server administration web tool is available here.
  • The directory service administration web tool is available here.
  • The server network utilization web tool is available here.
  • The web server usage statistics are available here.

EOF chmod 644 /var/www/html/index.html # Enable Apache # TODO: restrict HTTP/HTTPS connections from PAWs only firewall-offline-cmd --add-service=http firewall-offline-cmd --add-service=https systemctl enable httpd # Configure Webmin # Add "/manage/" location with forced redirect to Webmin port in Apache configuration cat << EOF > /etc/httpd/conf.d/webmin.conf # # Apache-based redirection for Webmin # RewriteEngine On RewriteRule ^.*\$ https://%{HTTP_HOST}:10000 [R,L] # Apache 2.4 Require all granted # Apache 2.2 Order Deny,Allow Deny from all Allow from all EOF chmod 644 /etc/httpd/conf.d/webmin.conf # Configure Webmin to use a custom certificate # TODO: use our own X.509 certificate (signed by our own CA) cat /etc/pki/tls/private/localhost.key > /etc/webmin/miniserv.pem cat /etc/pki/tls/certs/localhost.crt >> /etc/webmin/miniserv.pem # Modify default setup cat << EOF >> /etc/webmin/config logfiles=1 logfullfiles=1 logtime=21900 logperms= logsyslog=0 logusers= logmodules= logclear=1 hostnamemode=0 help_width= dateformat=dd/mon/yyyy showhost=0 nofeedbackcc=0 hostnamedisplay= feedback_to= sysinfo=0 texttitles=1 showlogin=0 help_height= acceptlang=0 gotoone=1 gotomodule= deftab=webmin nohostname=0 notabs=0 realname= noremember=1 EOF sed -i -e 's/^logtime=.*$/logtime=21900/' /etc/webmin/miniserv.conf cat << EOF >> /etc/webmin/miniserv.conf no_resolv_myname=1 sockets= login_script=/etc/webmin/login.pl logout_script=/etc/webmin/logout.pl logclf=0 logclear=1 loghost=0 pam_conv= blockuser_time= blocklock= blockuser_failures= no_pam=0 logouttime=10 utmp= extracas= certfile= ssl_redirect=1 EOF # Add firewalld configuration for Webmin cat << EOF > /etc/firewalld/services/webmin.xml webmin webmin is a web-based interface for system administration for unix. EOF chmod 644 /etc/firewalld/services/webmin.xml # Enable Webmin # TODO: restrict Webmin connections from PAWs only firewall-offline-cmd --add-service=webmin systemctl enable webmin # Configure Webalizer (allow access from everywhere) # Note: webalizer initialization demanded to post-install rc.ks1stboot script sed -i -e 's/^\(\s*\)\(Require local.*\)$/\1Require all granted/' /etc/httpd/conf.d/webalizer.conf # Enable Webalizer sed -i -e '/WEBALIZER_CRON=/s/^#*\(WEBALIZER_CRON=\).*$/\1yes/' /etc/sysconfig/webalizer # 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 # 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: make sure that dracut points to our nameserver and/or forwarders dracut_nameservers="" if [ "${domain_join}" = "true" ]; then # Use give nameserver dracut_nameservers="${my_nameserver}" fi # Use given forwarders as nameservers for forwarder in $(echo "${my_forwarders}" | sed -e 's/,/ /g') ; do dracut_nameservers="${dracut_nameservers}:${forwarder}" done dracut_nameservers=$(echo "${dracut_nameservers}" | sed -e 's/^://g') main_ifcfg=$(grep -l '^DEFROUTE=.*yes' /etc/sysconfig/network-scripts/ifcfg-*) source "${main_ifcfg}" # Note: dracut would import its own and override NetworkManager config - applying workaround as per https://access.redhat.com/solutions/3017441#comment-1622491 cat << EOF > /etc/dracut.conf.d/clevis-nbde.conf # Static IP for a specific interface kernel_cmdline="ip=${IPADDR}::${GATEWAY}:$(cdr2mask ${PREFIX}):${HOSTNAME}:${DEVICE}:none:${dracut_nameservers}" # 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} # 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 # Dump Samba AD DC server and GPO state to be picked up by standard filesystem backup timestamp="\$(date -Ins | tr ':,' '-.')" content="domain-backup" mkdir -p /var/local/backup/ds samba-tool domain backup offline --targetdir=/var/local/backup/ds > /var/local/backup/ds/\${content}-\${timestamp}.log 2>&1 res1=\$? # In case of errors, do not remove anything and return error code upstream if [ \${res1} -eq 0 ]; then # Keep only the last two dumps and logs find /var/local/backup/ds -type f -printf '%T@\t%p\\0' | sort -z -nrk1 | sed -z -n -e '5,\$s/^\\S*\\s*//p' | xargs -0 rm -f -- fi content="gpo-backup" mkdir -p /var/local/backup/gpo gpo_backup_generalized -f /var/local/backup/gpo/\${content}-\${timestamp}.tar.gz > /var/local/backup/gpo/\${content}-\${timestamp}.log 2>&1 res2=\$? # In case of errors, do not remove anything and return error code upstream if [ \${res2} -eq 0 ]; then # Keep only the last two dumps and logs find /var/local/backup/gpo -type f -printf '%T@\t%p\\0' | sort -z -nrk1 | sed -z -n -e '5,\$s/^\\S*\\s*//p' | xargs -0 rm -f -- fi # Report errors if [ \${res1} -ne 0 -o \${res2} -ne 0 ]; then logger -s -p "local7.err" -t "dump2backup" "Error in dump procedures (res1: \${res1} - res2: \${res2})" exit 255 fi 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 # 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 # Initialize webalizer # Note: Apache logs must be not empty max_steps="30" for ((i=0;i<\${max_steps};i=i+1)); do if systemctl -q is-active httpd ; then wget -O /dev/null http://localhost/ /etc/cron.daily/00webalizer break fi sleep 5 done # Initialize MRTG configuration (needs Net-SNMP up) # TODO: add CPU/RAM/disk/etc. resource monitoring cfgmaker --output /etc/mrtg/mrtg.cfg --global "HtmlDir: /var/www/mrtg" --global "ImageDir: /var/www/mrtg" --global "LogDir: /var/lib/mrtg" --global "ThreshDir: /var/lib/mrtg" --no-down --zero-speed=1000000000 --if-filter='(\$default && \$if_is_ethernet)' public@localhost # Set execution mode parameters # Note: on CentOS7 MRTG is preferably configured as an always running service (for efficiency reasons) sed -i -e '/Global Config Options/s/^\\(.*\\)\$/\\1\\nRunAsDaemon: Yes\\nInterval: 5\\nNoDetach: Yes/' /etc/mrtg/mrtg.cfg # Setup MRTG index page indexmaker --output=/var/www/mrtg/index.html /etc/mrtg/mrtg.cfg # Enable MRTG # Note: MRTG is an always running service (for efficiency reasons) now systemctl --now enable mrtg 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="${multi_instance_max}" 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} # Modify already saved entries # Note: names on secondary zones are kept aligned sed -i -e "s/\\b\${current_name}\\b/\${tentative_name}/g" /etc/hosts # 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/webmin/miniserv.pem cat /etc/pki/tls/certs/localhost.crt >> /etc/webmin/miniserv.pem systemctl restart webmin httpd fi fi # Run Samba AD DC domain provisioning actions if [ -x /etc/rc.d/rc.samba-dc ]; then /etc/rc.d/rc.samba-dc 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. # Append hosts fragment (generated in pre section above) into installed system if [ -s /tmp/hvp-bind-zones/hosts ]; then cat /tmp/hvp-bind-zones/hosts >> ${ANA_INSTALL_PATH}/etc/hosts fi # 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 NTPd 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/ntp.conf ]; then sed -i -e '/^server\s/s/^/#/g' ${ANA_INSTALL_PATH}/etc/ntp.conf cat /tmp/hvp-ntpd-conf/ntp.conf >> ${ANA_INSTALL_PATH}/etc/ntp.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 chmod 755 ${ANA_INSTALL_PATH}/etc/rc.d/rc.users-setup chown root:root ${ANA_INSTALL_PATH}/etc/rc.d/rc.users-setup fi # Copy Samba configuration script (generated in pre section above) into installed system if [ -s /tmp/hvp-samba-conf/rc.samba-dc ]; then cp /tmp/hvp-samba-conf/rc.samba-dc ${ANA_INSTALL_PATH}/etc/rc.d/rc.samba-dc # Note: cleartext passwords contained - must restrict access chmod 700 ${ANA_INSTALL_PATH}/etc/rc.d/rc.samba-dc chown root:root ${ANA_INSTALL_PATH}/etc/rc.d/rc.samba-dc 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 # TODO: perform NetworkManager workaround configuration on interfaces as detected in pre section above - remove when fixed upstream for file in /tmp/hvp-networkmanager-conf/ifcfg-* ; do if [ -f "${file}" ]; then cfg_file_name=$(basename "${file}") sed -i -e '/^DEFROUTE=/d' -e '/^MTU=/d' "${ANA_INSTALL_PATH}/etc/sysconfig/network-scripts/${cfg_file_name}" cat "${file}" >> "${ANA_INSTALL_PATH}/etc/sysconfig/network-scripts/${cfg_file_name}" fi done # 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