diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..c7f4227 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,32 @@ +name: Build + Release + +on: + push: + +jobs: + build-release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Generate DEV image + run: ./generate.sh + + - name: Generate PROD image + run: ./generate.sh --prod + + - name: Get Version + id: version + run: echo "version=$(cat VERSION)" >> "$GITHUB_OUTPUT" + + # Create a new draft release if we're pushing to a tag + - name: Create Release + uses: softprops/action-gh-release@v2 + # Only run this when we push to a tag + if: startsWith(github.ref, 'refs/tags/') + with: + files: | + output/*.gz + output/vmlinuz* + draft: true + diff --git a/README.md b/README.md index 7b72f12..1e96831 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # CentOS 7 Lite for diskless systems +[DOE Code](https://www.osti.gov/doecode/biblio/75992) + ## Description This repository contains the code used to generate CentOS 7 diskless images, which can be boot using IPXE. @@ -12,7 +14,7 @@ You need to run this script in a host with the docker engine installed in it. In order to generate the CentOS 7 diskless images, you just need to run the [generate.sh](generate.sh) script. The resulting files will be located in the [output](output) directory. generate.sh can be run using optional parameters: -If --prod is not passed as argument, the image will be built for production environment. Otherwise, it will build for dev environment. +If --prod is passed as argument, the image will be built for production environment. Otherwise, it will build for dev environment. Optional arguments: -h, --help Show this help message and exit @@ -30,3 +32,21 @@ cat /centos7-builder/diskless-root/etc/group ``` Each directory in this repository has a README.md file that you can check to learn more about its contents. + +## Testing with QEMU + +A simple run-qemu.sh script is provided to test the image locally in QEMU. + +`qemu-system-x86_64` must be available in your PATH for this to work. On Debian or Ubuntu, `qemu-system-x86_64` can be installed with `sudo apt install qemu-system`. + + +To boot the image in QEMU: +```sh +./run-qemu.sh +``` + +The script bridges host port 8022 to guest port 22, so you can SSH in with the following command: +``` +ssh -p 8022 laci@localhost +``` + diff --git a/VERSION b/VERSION index 5df58d4..c7e9775 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -R1.5.0 +R1.6.0 diff --git a/custom_files/SLAC_properties b/custom_files/SLAC_properties index e694a79..3d1b820 100644 --- a/custom_files/SLAC_properties +++ b/custom_files/SLAC_properties @@ -1 +1,2 @@ HAVE_ROOT_PASSWORD=1 +HAVE_NEW_ULIMITS=1 diff --git a/custom_files/disable_disconnected_nics.service b/custom_files/disable_disconnected_nics.service new file mode 100644 index 0000000..f7ffeb4 --- /dev/null +++ b/custom_files/disable_disconnected_nics.service @@ -0,0 +1,10 @@ +[Unit] +Description=Disable disconnected network interfaces on boot +After=network.target + +[Service] +Type=oneshot +ExecStart=/root/scripts/disable_disconnected_nics.sh + +[Install] +WantedBy=multi-user.target diff --git a/custom_files/disable_disconnected_nics.sh b/custom_files/disable_disconnected_nics.sh new file mode 100755 index 0000000..745df23 --- /dev/null +++ b/custom_files/disable_disconnected_nics.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# Get a list of all network interfaces (excluding loopback) +interfaces=$(ls /sys/class/net | grep -v lo) + +for iface in $interfaces; do + # Check if the interface is disconnected (carrier detected) + if [[ -f "/sys/class/net/$iface/carrier" ]] && [[ "$(cat /sys/class/net/$iface/carrier)" == "0" ]]; then + ip link set dev $iface down + fi +done diff --git a/custom_files/limits.conf b/custom_files/limits.conf new file mode 100644 index 0000000..7494fd6 --- /dev/null +++ b/custom_files/limits.conf @@ -0,0 +1,59 @@ +# /etc/security/limits.conf +# +#This file sets the resource limits for the users logged in via PAM. +#It does not affect resource limits of the system services. +# +#Also note that configuration files in /etc/security/limits.d directory, +#which are read in alphabetical order, override the settings in this +#file in case the domain is the same or more specific. +#That means for example that setting a limit for wildcard domain here +#can be overriden with a wildcard setting in a config file in the +#subdirectory, but a user specific setting here can be overriden only +#with a user specific setting in the subdirectory. +# +#Each line describes a limit for a user in the form: +# +# +# +#Where: +# can be: +# - a user name +# - a group name, with @group syntax +# - the wildcard *, for default entry +# - the wildcard %, can be also used with %group syntax, +# for maxlogin limit +# +# can have the two values: +# - "soft" for enforcing the soft limits +# - "hard" for enforcing hard limits +# +# can be one of the following: +# - core - limits the core file size (KB) +# - data - max data size (KB) +# - fsize - maximum filesize (KB) +# - memlock - max locked-in-memory address space (KB) +# - nofile - max number of open file descriptors +# - rss - max resident set size (KB) +# - stack - max stack size (KB) +# - cpu - max CPU time (MIN) +# - nproc - max number of processes +# - as - address space limit (KB) +# - maxlogins - max number of logins for this user +# - maxsyslogins - max number of logins on the system +# - priority - the priority to run user process with +# - locks - max number of file locks the user can hold +# - sigpending - max number of pending signals +# - msgqueue - max memory used by POSIX message queues (bytes) +# - nice - max nice priority allowed to raise to values: [-20, 19] +# - rtprio - max realtime priority +# +# +# + +* soft core 0 +* hard core unlimited +* hard memlock unlimited +* soft rtprio 0 +* hard rtprio unlimited + +# End of file diff --git a/custom_files/sshd_config b/custom_files/sshd_config new file mode 100644 index 0000000..be929ac --- /dev/null +++ b/custom_files/sshd_config @@ -0,0 +1,139 @@ +# $OpenBSD: sshd_config,v 1.100 2016/08/15 12:32:04 naddy Exp $ + +# This is the sshd server system-wide configuration file. See +# sshd_config(5) for more information. + +# This sshd was compiled with PATH=/usr/local/bin:/usr/bin + +# The strategy used for options in the default sshd_config shipped with +# OpenSSH is to specify options with their default value where +# possible, but leave them commented. Uncommented options override the +# default value. + +# If you want to change the port on a SELinux system, you have to tell +# SELinux about this change. +# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER +# +#Port 22 +#AddressFamily any +#ListenAddress 0.0.0.0 +#ListenAddress :: + +HostKey /etc/ssh/ssh_host_rsa_key +#HostKey /etc/ssh/ssh_host_dsa_key +HostKey /etc/ssh/ssh_host_ecdsa_key +HostKey /etc/ssh/ssh_host_ed25519_key + +# Ciphers and keying +#RekeyLimit default none + +# Logging +#SyslogFacility AUTH +SyslogFacility AUTHPRIV +#LogLevel INFO + +# Authentication: + +#LoginGraceTime 2m +PermitRootLogin no +#StrictModes yes +#MaxAuthTries 6 +#MaxSessions 10 + +#PubkeyAuthentication yes + +# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 +# but this is overridden so installations will only check .ssh/authorized_keys +AuthorizedKeysFile .ssh/authorized_keys + +#AuthorizedPrincipalsFile none + +#AuthorizedKeysCommand none +#AuthorizedKeysCommandUser nobody + +# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts +#HostbasedAuthentication no +# Change to yes if you don't trust ~/.ssh/known_hosts for +# HostbasedAuthentication +#IgnoreUserKnownHosts no +# Don't read the user's ~/.rhosts and ~/.shosts files +#IgnoreRhosts yes + +# To disable tunneled clear text passwords, change to no here! +#PasswordAuthentication yes +PermitEmptyPasswords yes +PasswordAuthentication yes + +# Change to no to disable s/key passwords +#ChallengeResponseAuthentication yes +ChallengeResponseAuthentication no + +# Kerberos options +#KerberosAuthentication no +#KerberosOrLocalPasswd yes +#KerberosTicketCleanup yes +#KerberosGetAFSToken no +#KerberosUseKuserok yes + +# GSSAPI options +GSSAPIAuthentication yes +GSSAPICleanupCredentials no +#GSSAPIStrictAcceptorCheck yes +#GSSAPIKeyExchange no +#GSSAPIEnablek5users no + +# Set this to 'yes' to enable PAM authentication, account processing, +# and session processing. If this is enabled, PAM authentication will +# be allowed through the ChallengeResponseAuthentication and +# PasswordAuthentication. Depending on your PAM configuration, +# PAM authentication via ChallengeResponseAuthentication may bypass +# the setting of "PermitRootLogin without-password". +# If you just want the PAM account and session checks to run without +# PAM authentication, then enable this but set PasswordAuthentication +# and ChallengeResponseAuthentication to 'no'. +# WARNING: 'UsePAM no' is not supported in Red Hat Enterprise Linux and may cause several +# problems. +UsePAM yes + +#AllowAgentForwarding yes +#AllowTcpForwarding yes +#GatewayPorts no +X11Forwarding yes +#X11DisplayOffset 10 +#X11UseLocalhost yes +#PermitTTY yes +#PrintMotd yes +#PrintLastLog yes +#TCPKeepAlive yes +#UseLogin no +#UsePrivilegeSeparation sandbox +#PermitUserEnvironment no +#Compression delayed +#ClientAliveInterval 0 +#ClientAliveCountMax 3 +#ShowPatchLevel no +#UseDNS yes +#PidFile /var/run/sshd.pid +#MaxStartups 10:30:100 +#PermitTunnel no +#ChrootDirectory none +#VersionAddendum none + +# no default banner path +#Banner none + +# SLAC: Do not accept locale-related environment variables +#AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES +#AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT +#AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE +AcceptEnv XMODIFIERS + +# override default of no subsystems +Subsystem sftp /usr/libexec/openssh/sftp-server + +# Example of overriding settings on a per-user basis +#Match User anoncvs +# X11Forwarding no +# AllowTcpForwarding no +# PermitTTY no +# ForceCommand cvs server diff --git a/custom_files/sudoers b/custom_files/sudoers index a5abe50..e798b0c 100644 --- a/custom_files/sudoers +++ b/custom_files/sudoers @@ -1,3 +1 @@ -laci ALL= NOPASSWD: /usr/bin/chrt -flaci ALL= NOPASSWD: /usr/bin/chrt -acctf ALL= NOPASSWD: /usr/bin/chrt +laci, flaci, acctf ALL= NOPASSWD: /usr/bin/chrt, /sbin/reboot, /sbin/poweroff, /sbin/shutdown diff --git a/docker/Dockerfile b/docker/Dockerfile index ecb99a4..d1f47d6 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,7 +1,14 @@ FROM centos:7 -# Install packages we will need in our 'builder' OS -RUN yum -y update && \ +# As of July 1st, 2024, mirrorlist.centos.org is gone and we need to switch to vault.centos.org +RUN sed -i s,mirror.centos.org,vault.centos.org,g /etc/yum.repos.d/CentOS-*.repo; \ + sed -i s,^#.*baseurl=http,baseurl=http,g /etc/yum.repos.d/CentOS-*.repo; \ + sed -i s,^mirrorlist=http,#mirrorlist=http,g /etc/yum.repos.d/CentOS-*.repo + +# Install packages we will need in our 'builder' OS. +# NOTE: Default ulimit is insanely high and causes yum to slow to a crawl +RUN ulimit -n 1024 && \ + yum -y update && \ yum install -y \ wget \ yumdownloader \ diff --git a/generate.sh b/generate.sh index 447cae8..0e6d7a7 100755 --- a/generate.sh +++ b/generate.sh @@ -4,7 +4,8 @@ cd docker && ./build.sh && cd - # Use the docker image to build the CentOS7 diskless images -docker container run -ti --rm \ +docker container run -i --rm \ + --ulimit "nofile=1024:1024" \ --mount src=${PWD}/output,target=/output,type=bind \ --mount src=centos7-builder,target=/centos7-builder,type=volume \ --mount src=${PWD}/scripts,target=/scripts,type=bind \ diff --git a/run-qemu.sh b/run-qemu.sh index 130d6c7..1bd6eb6 100755 --- a/run-qemu.sh +++ b/run-qemu.sh @@ -2,10 +2,25 @@ cd "$(dirname "${BASH_SOURCE[0]}")" +IMAGE=./output/CentOs7_Lite_dev_$(cat VERSION)_fs.cpio.gz +while test $# -gt 0; do + case $1 in + --prod) + IMAGE=./output/CentOs7_Lite_prod_$(cat VERSION)_fs.cpio.gz + shift + ;; + *) + echo "Unknown arg $1" + exit 1 + ;; + esac +done + qemu-system-x86_64 \ -m size=2048 \ -nographic -no-reboot \ -kernel ./$(find output -iname "vmlinuz-*" | head -n 1) \ - -initrd ./output/CentOs7_Lite_dev_$(cat VERSION)_fs.cpio.gz \ - -append "console=ttyS0 init=/init root=/dev/ram0" + -initrd $IMAGE \ + -append "console=ttyS0 init=/init root=/dev/ram0" \ + -nic user,hostfwd=tcp::8022-:22 diff --git a/scripts/generate-image.sh b/scripts/generate-image.sh index f7c379e..52a6a10 100755 --- a/scripts/generate-image.sh +++ b/scripts/generate-image.sh @@ -62,13 +62,19 @@ fi cd /centos7-builder # Download centos-release, if needed -if [ ! -f "centos-release-7-9.2009.1.el7.centos.x86_64.rpm" ]; then +if [ ! -f "centos-release-7-9.2009.0.el7.centos.x86_64.rpm" ]; then # Get the centos-release RPM - yumdownloader centos-release + #yumdownloader centos-release-7-9.2009.1.el7.centos + wget ftp.cs.stanford.edu/centos/centos/7/os/x86_64/Packages/centos-release-7-9.2009.0.el7.centos.x86_64.rpm fi # centos-release contains things like the yum configs, and is necessary to bootstrap the system -rpm --root=/centos7-builder/diskless-root -ivh --nodeps centos-release-7-9.2009.1.el7.centos.x86_64.rpm +rpm --root=/centos7-builder/diskless-root -ivh --nodeps centos-release-7-9.2009.0.el7.centos.x86_64.rpm +ls /centos7-builder/diskless-root #/etc/yum.repos.d/ +# Switch to Stanford mirrors now that mirror.centos.org is offline +sed -i s,mirror.centos.org,mirror.stanford.edu,g /centos7-builder/diskless-root/etc/yum.repos.d/CentOS-*.repo +sed -i s,^#.*baseurl=http,baseurl=http,g /centos7-builder/diskless-root/etc/yum.repos.d/CentOS-*.repo +sed -i s,^mirrorlist=http,#mirrorlist=http,g /centos7-builder/diskless-root/etc/yum.repos.d/CentOS-*.repo # Add Intel network card drivers for Dell R750 servers RPMs="./Intel_LAN_drivers_Dell_R750/*.rpm" @@ -117,6 +123,8 @@ fi cp -r /custom_files/run_bootfile_dev.sh root/scripts cp -r /custom_files/run_bootfile_prod.sh root/scripts cp -r /custom_files/create-users.sh root/scripts +cp -r /custom_files/disable_disconnected_nics.sh root/scripts +cp -r /custom_files/disable_disconnected_nics.service usr/lib/systemd/system/ if [ -n "$prod_flag" ]; then cp -r /custom_files/run_bootfile_prod.service usr/lib/systemd/system/run_bootfile.service else @@ -126,6 +134,8 @@ cp -r /custom_files/epics.conf etc/security/limits.d cp -r /custom_files/90-nproc.conf etc/security/limits.d cp -r /custom_files/SLAC_properties etc/SLAC_properties cp -r /custom_files/sudoers etc/sudoers +cp -f /custom_files/sshd_config etc/ssh/sshd_config +cp -f /custom_files/limits.conf etc/security/limits.conf # Set some important configuration if [ ! -e "init" ]; then @@ -147,7 +157,7 @@ else mkdir -p afs/slac.stanford.edu fi if [ -d "afs/slac.stanford.edu" ]; then - echo "172.23.66.102:/afs/slac.stanford.edu /afs/slac.stanford.edu nfs _netdev,auto,x-systemd.automount,x-systemd.mount-timeout=5min,x-systemd.after=sys-subsystem-net-devices-enp7s0.device,retry=10,timeo=14 0 0" > etc/fstab + echo "s3dflclsdevnfs001:/sdf/group/ad/transition/afs/slac.stanford.edu /afs/slac.stanford.edu nfs _netdev,auto,x-systemd.automount,x-systemd.mount-timeout=5min,x-systemd.after=sys-subsystem-net-devices-enp7s0.device,retry=10,timeo=14 0 0" > etc/fstab fi fi @@ -164,15 +174,22 @@ sed -i "s/#DefaultLimitRTPRIO=/DefaultLimitRTPRIO=infinity/g" etc/systemd/user.c # chroot, set a blank password to root, and create the laci account. laci # account must have UID 8412 and be part of an lcls group with GID 2211. # The IDs are important for accessing NFS directories. -# Activate NTP. +# Deactivate all NICs that are disconnected from a network. +# Activate NTP, generate required locales chroot . \ bash -c '\ /root/scripts/create-users.sh && \ systemctl enable /usr/lib/systemd/system/run_bootfile.service && \ - systemctl enable ntpd && \ + systemctl enable ntpd && \ + systemctl enable disable_disconnected_nics.service && \ + localedef -i en_US -f UTF-8 en_US.utf8 && \ exit \ ' +# Set the default locale. This matches the default on our DEV machines. +echo "LANG=en_US.utf8" > etc/locale.conf + + # Generate ssh keys to avoid generating new ones every time the diskless # system boots, creating annoying RSA key mismatch error messages when # an user wants to connect.