diff --git a/salt/manager/files/mirror-kernel.txt b/salt/manager/files/mirror-kernel.txt new file mode 100644 index 000000000..1d9ce75d2 --- /dev/null +++ b/salt/manager/files/mirror-kernel.txt @@ -0,0 +1,2 @@ +https://repo.securityonion.net/file/so-repo/prod/3/oracle/9-uek8 +https://repo-alt.securityonion.net/prod/3/oracle/9-uek8 diff --git a/salt/manager/files/repodownload.conf b/salt/manager/files/repodownload.conf index 3c156a9db..67ae4b121 100644 --- a/salt/manager/files/repodownload.conf +++ b/salt/manager/files/repodownload.conf @@ -10,4 +10,9 @@ keepcache=0 name=Security Onion Repo repo mirrorlist=file:///opt/so/conf/reposync/mirror.txt enabled=1 -gpgcheck=1 \ No newline at end of file +gpgcheck=1 +[securityonionkernel] +name=Security Onion Repo repo +mirrorlist=file:///opt/so/conf/reposync/mirror-kernel.txt +enabled=1 +gpgcheck=1 diff --git a/salt/manager/init.sls b/salt/manager/init.sls index 2353bb64b..e77b1a601 100644 --- a/salt/manager/init.sls +++ b/salt/manager/init.sls @@ -86,6 +86,28 @@ repo_dir: - group - show_changes: False +kernelrepo_dir: + file.directory: + - name: /nsm/kernelrepo + - user: socore + - group: socore + - recurse: + - user + - group + - show_changes: False + +# Ensure /nsm/kernelrepo is always a valid (if empty) repo before it is ever assigned to +# a client. Without repodata/repomd.xml an enabled file:///nsm/kernelrepo repo makes every +# dnf operation fail; so-repo-sync only populates it after the highstate, so seed an empty +# repo here. Only runs when repodata is missing, so it won't clobber a synced repo. +kernelrepo_init_empty: + cmd.run: + - name: createrepo /nsm/kernelrepo + - unless: 'test -e /nsm/kernelrepo/repodata/repomd.xml' + - require: + - file: kernelrepo_dir + - pkg: install_createrepo + manager_sbin: file.recurse: - name: /usr/sbin @@ -122,6 +144,13 @@ so-repo-mirrorlist: - user: socore - group: socore +so-repo-kernel-mirrorlist: + file.managed: + - name: /opt/so/conf/reposync/mirror-kernel.txt + - source: salt://manager/files/mirror-kernel.txt + - user: socore + - group: socore + so-repo-sync: {% if MANAGERMERGED.reposync.enabled %} cron.present: diff --git a/salt/manager/tools/sbin/so-repo-sync b/salt/manager/tools/sbin/so-repo-sync index a0393a36b..6c1b9d509 100755 --- a/salt/manager/tools/sbin/so-repo-sync +++ b/salt/manager/tools/sbin/so-repo-sync @@ -10,5 +10,16 @@ NOROOT=1 set -e curl --retry 5 --retry-delay 60 -A "reposync/$(sync_options)" https://sigs.securityonion.net/checkup --output /tmp/checkup + dnf reposync --norepopath -g --delete -m -c /opt/so/conf/reposync/repodownload.conf --repoid=securityonionsync --download-metadata -p /nsm/repo/ createrepo /nsm/repo + +# The kernel repo section is deployed to repodownload.conf by the manager highstate, which +# runs AFTER this script during soup. On the first upgrade to a kernel-aware version the +# on-disk config still predates the section, so guard on its presence to avoid dnf's +# "Unknown repo: 'securityonionkernel'" aborting the sync (set -e). The next sync after the +# highstate deploys the section will pick it up. +if grep -q '^\[securityonionkernel\]' /opt/so/conf/reposync/repodownload.conf; then + dnf reposync --norepopath -g --delete -m -c /opt/so/conf/reposync/repodownload.conf --repoid=securityonionkernel --download-metadata -p /nsm/kernelrepo/ + createrepo /nsm/kernelrepo +fi diff --git a/salt/nginx/enabled.sls b/salt/nginx/enabled.sls index 2e4c9631c..40fde5b0e 100644 --- a/salt/nginx/enabled.sls +++ b/salt/nginx/enabled.sls @@ -59,6 +59,7 @@ so-nginx: - /opt/so/conf/navigator/layers/:/opt/socore/html/navigator/assets/so:ro - /opt/so/conf/navigator/config.json:/opt/socore/html/navigator/assets/config.json:ro - /nsm/repo:/opt/socore/html/repo:ro + - /nsm/kernelrepo:/opt/socore/html/kernelrepo:ro - /nsm/rules:/nsm/rules:ro {% if NGINXMERGED.external_suricata %} - /opt/so/rules/nids/suri:/surirules:ro diff --git a/salt/repo/client/oracle.sls b/salt/repo/client/oracle.sls index 70f529830..2019a56d1 100644 --- a/salt/repo/client/oracle.sls +++ b/salt/repo/client/oracle.sls @@ -57,6 +57,26 @@ so_repo: - enabled: 1 - gpgcheck: 1 +so_kernel_repo: + pkgrepo.managed: + - name: securityonionkernel + - humanname: Security Onion Kernel Repo + {% if GLOBALS.is_manager %} + - baseurl: file:///nsm/kernelrepo/ + {% else %} + - baseurl: https://{{ GLOBALS.repo_host }}/kernelrepo + {% endif %} + - enabled: 1 + - gpgcheck: 1 + # Supplementary kernel repo: tolerate it being empty/unreachable (e.g. before the + # manager has populated /nsm/kernelrepo) so a missing repomd.xml can't make every + # dnf/pkg operation on the grid fail. + - skip_if_unavailable: 1 + # Only assign the kernel repo once physical NIC names are pinned by MAC, so the + # UEK8 kernel update can't renumber interfaces SO binds by name (see pin_nic_names + # in salt/common/init.sls, which drops this marker via /usr/sbin/so-nic-pin). + - onlyif: 'test -e /opt/so/state/nic_names_pinned' + {% endif %} # TODO: Add a pillar entry for custom repos diff --git a/setup/so-functions b/setup/so-functions index 2d5181dc1..b9a061168 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -886,6 +886,7 @@ create_repo() { title "Create the repo directory" logCmd "dnf -y install yum-utils createrepo_c" logCmd "createrepo /nsm/repo" + logCmd "createrepo /nsm/kernelrepo" } @@ -1812,6 +1813,16 @@ securityonion_repo() { echo "mirrorlist=file:///etc/yum/mirror.txt" >> /etc/yum.repos.d/securityonion.repo echo "enabled=1" >> /etc/yum.repos.d/securityonion.repo echo "gpgcheck=1" >> /etc/yum.repos.d/securityonion.repo + echo "https://repo.securityonion.net/file/so-repo/prod/3/oracle/9-uek8" > /etc/yum/mirror-kernel.txt + echo "https://so-repo-east.s3.us-east-005.backblazeb2.com/prod/3/oracle/9-uek8" >> /etc/yum/mirror-kernel.txt + echo "[securityonionkernel]" > /etc/yum.repos.d/securityonionkernel.repo + echo "name=Security Onion Kernel Repo repo" >> /etc/yum.repos.d/securityonionkernel.repo + echo "mirrorlist=file:///etc/yum/mirror-kernel.txt" >> /etc/yum.repos.d/securityonionkernel.repo + echo "enabled=1" >> /etc/yum.repos.d/securityonionkernel.repo + echo "gpgcheck=1" >> /etc/yum.repos.d/securityonionkernel.repo + # Supplementary kernel repo: tolerate it being empty/unreachable so a missing + # repomd.xml can't make every dnf operation fail before the repo is populated. + echo "skip_if_unavailable=1" >> /etc/yum.repos.d/securityonionkernel.repo logCmd "dnf repolist" else echo "[securityonion]" > /etc/yum.repos.d/securityonion.repo @@ -1820,6 +1831,13 @@ securityonion_repo() { echo "enabled=1" >> /etc/yum.repos.d/securityonion.repo echo "gpgcheck=1" >> /etc/yum.repos.d/securityonion.repo echo "sslverify=0" >> /etc/yum.repos.d/securityonion.repo + echo "[securityonionkernel]" > /etc/yum.repos.d/securityonionkernel.repo + echo "name=Security Onion Kernel Repo" >> /etc/yum.repos.d/securityonionkernel.repo + echo "baseurl=https://$MSRV/kernelrepo" >> /etc/yum.repos.d/securityonionkernel.repo + echo "enabled=1" >> /etc/yum.repos.d/securityonionkernel.repo + echo "gpgcheck=1" >> /etc/yum.repos.d/securityonionkernel.repo + echo "sslverify=0" >> /etc/yum.repos.d/securityonionkernel.repo + echo "skip_if_unavailable=1" >> /etc/yum.repos.d/securityonionkernel.repo logCmd "dnf repolist" fi elif [[ ! $waitforstate ]]; then @@ -1829,12 +1847,25 @@ securityonion_repo() { echo "enabled=1" >> /etc/yum.repos.d/securityonion.repo echo "gpgcheck=1" >> /etc/yum.repos.d/securityonion.repo echo "sslverify=0" >> /etc/yum.repos.d/securityonion.repo + echo "[securityonionkernel]" > /etc/yum.repos.d/securityonionkernel.repo + echo "name=Security Onion Kernel Repo" >> /etc/yum.repos.d/securityonionkernel.repo + echo "baseurl=https://$MSRV/kernelrepo" >> /etc/yum.repos.d/securityonionkernel.repo + echo "enabled=1" >> /etc/yum.repos.d/securityonionkernel.repo + echo "gpgcheck=1" >> /etc/yum.repos.d/securityonionkernel.repo + echo "sslverify=0" >> /etc/yum.repos.d/securityonionkernel.repo + echo "skip_if_unavailable=1" >> /etc/yum.repos.d/securityonionkernel.repo elif [[ $waitforstate ]]; then echo "[securityonion]" > /etc/yum.repos.d/securityonion.repo echo "name=Security Onion Repo" >> /etc/yum.repos.d/securityonion.repo echo "baseurl=file:///nsm/repo/" >> /etc/yum.repos.d/securityonion.repo echo "enabled=1" >> /etc/yum.repos.d/securityonion.repo echo "gpgcheck=1" >> /etc/yum.repos.d/securityonion.repo + echo "[securityonionkernel]" > /etc/yum.repos.d/securityonionkernel.repo + echo "name=Security Onion Kernel Repo" >> /etc/yum.repos.d/securityonionkernel.repo + echo "baseurl=file:///nsm/kernelrepo/" >> /etc/yum.repos.d/securityonionkernel.repo + echo "enabled=1" >> /etc/yum.repos.d/securityonionkernel.repo + echo "gpgcheck=1" >> /etc/yum.repos.d/securityonionkernel.repo + echo "skip_if_unavailable=1" >> /etc/yum.repos.d/securityonionkernel.repo fi logCmd "dnf repolist all" if [[ $waitforstate ]]; then @@ -1850,9 +1881,12 @@ repo_sync_local() { # Sync the repo from the SO repo locally. info "Adding Repo Download Configuration" mkdir -p /nsm/repo + mkdir -p /nsm/kernelrepo mkdir -p /opt/so/conf/reposync/cache echo "https://repo.securityonion.net/file/so-repo/prod/3/oracle/9" > /opt/so/conf/reposync/mirror.txt echo "https://repo-alt.securityonion.net/prod/3/oracle/9" >> /opt/so/conf/reposync/mirror.txt + echo "https://repo.securityonion.net/file/so-repo/prod/3/oracle/9-uek8" > /opt/so/conf/reposync/mirror-kernel.txt + echo "https://repo-alt.securityonion.net/prod/3/oracle/9-uek8" >> /opt/so/conf/reposync/mirror-kernel.txt echo "[main]" > /opt/so/conf/reposync/repodownload.conf echo "gpgcheck=1" >> /opt/so/conf/reposync/repodownload.conf echo "installonly_limit=3" >> /opt/so/conf/reposync/repodownload.conf @@ -1866,12 +1900,18 @@ repo_sync_local() { echo "mirrorlist=file:///opt/so/conf/reposync/mirror.txt" >> /opt/so/conf/reposync/repodownload.conf echo "enabled=1" >> /opt/so/conf/reposync/repodownload.conf echo "gpgcheck=1" >> /opt/so/conf/reposync/repodownload.conf + echo "[securityonionkernel]" >> /opt/so/conf/reposync/repodownload.conf + echo "name=Security Onion Kernel Repo repo" >> /opt/so/conf/reposync/repodownload.conf + echo "mirrorlist=file:///opt/so/conf/reposync/mirror-kernel.txt" >> /opt/so/conf/reposync/repodownload.conf + echo "enabled=1" >> /opt/so/conf/reposync/repodownload.conf + echo "gpgcheck=1" >> /opt/so/conf/reposync/repodownload.conf logCmd "dnf repolist" if [[ ! $is_airgap ]]; then curl --retry 5 --retry-delay 60 -A "netinstall/$SOVERSION/$OS/$(uname -r)/1" https://sigs.securityonion.net/checkup --output /tmp/install retry 5 60 "dnf reposync --norepopath -g --delete -m -c /opt/so/conf/reposync/repodownload.conf --repoid=securityonionsync --download-metadata -p /nsm/repo/" >> "$setup_log" 2>&1 || fail_setup + retry 5 60 "dnf reposync --norepopath -g --delete -m -c /opt/so/conf/reposync/repodownload.conf --repoid=securityonionkernel --download-metadata -p /nsm/kernelrepo/" >> "$setup_log" 2>&1 || fail_setup # After the download is complete run createrepo create_repo fi @@ -2228,6 +2268,13 @@ update_sudoers_for_testing() { } update_packages() { + # Pin physical NIC names by MAC BEFORE pulling packages, so the UEK8 kernel that + # the update below installs can't renumber the interfaces SO binds by name. Doing + # it here (instead of waiting for the common highstate) also drops the + # /opt/so/state/nic_names_pinned marker that gates the kernel repo, so the kernel + # repo is assigned on the very first highstate and the kernel isn't downgraded and + # then re-upgraded. Run-once: so-nic-pin no-ops if the marker already exists. + logCmd "bash ../salt/common/tools/sbin/so-nic-pin" logCmd "dnf repolist" logCmd "dnf -y update --allowerasing --exclude=salt*,docker*,containerd*" RMREPOFILES=("oracle-linux-ol9.repo" "uek-ol9.repo" "virt-ol9.repo")