Merge pull request #14650 from Security-Onion-Solutions/hotfix/2.4.150

Hotfix 2.4.150
This commit is contained in:
Mike Reeves
2025-05-22 13:35:33 -04:00
committed by GitHub
4 changed files with 77 additions and 63 deletions

View File

@@ -1,17 +1,17 @@
### 2.4.150-20250512 ISO image released on 2025/05/12 ### 2.4.150-20250522 ISO image released on 2025/05/22
### Download and Verify ### Download and Verify
2.4.150-20250512 ISO image: 2.4.150-20250522 ISO image:
https://download.securityonion.net/file/securityonion/securityonion-2.4.150-20250512.iso https://download.securityonion.net/file/securityonion/securityonion-2.4.150-20250522.iso
MD5: 7A7469A7A38EA9A2DB770C36AE36A0CA MD5: 239E69B83072BBF2602D4043FE53A160
SHA1: 7E768D515353F339DC536DED6207B786DAFF7D27 SHA1: C62893D3C7F5592665BFDCBC9A45BB20A926F9A8
SHA256: F8B2EB6B332F2367F0C097D211577565C8FB5CC7809E97D63687C634035B3699 SHA256: 2ADE037C7FD34591030B1FAC10392C4E6613F152DD24BFBD897E57EE300895B9
Signature for ISO image: Signature for ISO image:
https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.150-20250512.iso.sig https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.150-20250522.iso.sig
Signing key: Signing key:
https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2.4/main/KEYS https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2.4/main/KEYS
@@ -25,22 +25,22 @@ wget https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2.
Download the signature file for the ISO: Download the signature file for the ISO:
``` ```
wget https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.150-20250512.iso.sig wget https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.150-20250522.iso.sig
``` ```
Download the ISO image: Download the ISO image:
``` ```
wget https://download.securityonion.net/file/securityonion/securityonion-2.4.150-20250512.iso wget https://download.securityonion.net/file/securityonion/securityonion-2.4.150-20250522.iso
``` ```
Verify the downloaded ISO image using the signature file: Verify the downloaded ISO image using the signature file:
``` ```
gpg --verify securityonion-2.4.150-20250512.iso.sig securityonion-2.4.150-20250512.iso gpg --verify securityonion-2.4.150-20250522.iso.sig securityonion-2.4.150-20250522.iso
``` ```
The output should show "Good signature" and the Primary key fingerprint should match what's shown below: The output should show "Good signature" and the Primary key fingerprint should match what's shown below:
``` ```
gpg: Signature made Fri 09 May 2025 06:27:29 PM EDT using RSA key ID FE507013 gpg: Signature made Thu 22 May 2025 11:15:06 AM EDT using RSA key ID FE507013
gpg: Good signature from "Security Onion Solutions, LLC <info@securityonionsolutions.com>" gpg: Good signature from "Security Onion Solutions, LLC <info@securityonionsolutions.com>"
gpg: WARNING: This key is not certified with a trusted signature! gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner. gpg: There is no indication that the signature belongs to the owner.

1
HOTFIX
View File

@@ -0,0 +1 @@
20250522

View File

@@ -4,22 +4,16 @@
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
# https://securityonion.net/license; you may not use this file except in compliance with the # https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0. # Elastic License 2.0.
import sys, argparse, re, subprocess, json
import sys, argparse, re, docker
from packaging.version import Version, InvalidVersion from packaging.version import Version, InvalidVersion
from itertools import groupby, chain from itertools import groupby, chain
def get_image_name(string) -> str: def get_image_name(string) -> str:
return ':'.join(string.split(':')[:-1]) return ':'.join(string.split(':')[:-1])
def get_so_image_basename(string) -> str: def get_so_image_basename(string) -> str:
return get_image_name(string).split('/so-')[-1] return get_image_name(string).split('/so-')[-1]
def get_image_version(string) -> str: def get_image_version(string) -> str:
ver = string.split(':')[-1] ver = string.split(':')[-1]
if ver == 'latest': if ver == 'latest':
@@ -35,33 +29,49 @@ def get_image_version(string) -> str:
return '999999.9.9' return '999999.9.9'
return ver return ver
def run_command(command):
process = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
if process.returncode != 0:
print(f"Error executing command: {command}", file=sys.stderr)
print(f"Error message: {process.stderr}", file=sys.stderr)
exit(1)
return process.stdout
def main(quiet): def main(quiet):
client = docker.from_env() try:
# Prune old/stopped containers using docker CLI
# Prune old/stopped containers
if not quiet: print('Pruning old containers') if not quiet: print('Pruning old containers')
client.containers.prune() run_command('docker container prune -f')
image_list = client.images.list(filters={ 'dangling': False }) # Get list of images using docker CLI
images_json = run_command('docker images --format "{{json .}}"')
# Map list of image objects to flattened list of tags (format: "name:version") # Parse the JSON output
tag_list = list(chain.from_iterable(list(map(lambda x: x.attrs.get('RepoTags'), image_list)))) image_list = []
for line in images_json.strip().split('\n'):
if line: # Skip empty lines
image_list.append(json.loads(line))
# Extract tags in the format "name:version"
tag_list = []
for img in image_list:
# Skip dangling images
if img.get('Repository') != "<none>" and img.get('Tag') != "<none>":
tag = f"{img.get('Repository')}:{img.get('Tag')}"
# Filter to only SO images (base name begins with "so-") # Filter to only SO images (base name begins with "so-")
tag_list = list(filter(lambda x: re.match(r'^.*\/so-[^\/]*$', get_image_name(x)), tag_list)) if re.match(r'^.*\/so-[^\/]*$', get_image_name(tag)):
tag_list.append(tag)
# Group tags into lists by base name (sort by same projection first) # Group tags into lists by base name (sort by same projection first)
tag_list.sort(key=lambda x: get_so_image_basename(x)) tag_list.sort(key=lambda x: get_so_image_basename(x))
grouped_tag_lists = [ list(it) for _, it in groupby(tag_list, lambda x: get_so_image_basename(x)) ] grouped_tag_lists = [list(it) for k, it in groupby(tag_list, lambda x: get_so_image_basename(x))]
no_prunable = True no_prunable = True
for t_list in grouped_tag_lists: for t_list in grouped_tag_lists:
try: try:
# Group tags by version, in case multiple images exist with the same version string # Group tags by version, in case multiple images exist with the same version string
t_list.sort(key=lambda x: Version(get_image_version(x)), reverse=True) t_list.sort(key=lambda x: Version(get_image_version(x)), reverse=True)
grouped_t_list = [ list(it) for _,it in groupby(t_list, lambda x: get_image_version(x)) ] grouped_t_list = [list(it) for k, it in groupby(t_list, lambda x: get_image_version(x))]
# Keep the 2 most current version groups # Keep the 2 most current version groups
if len(grouped_t_list) <= 2: if len(grouped_t_list) <= 2:
continue continue
@@ -71,10 +81,10 @@ def main(quiet):
for tag in group: for tag in group:
if not quiet: print(f'Removing image {tag}') if not quiet: print(f'Removing image {tag}')
try: try:
client.images.remove(tag, force=True) run_command(f'docker rmi -f {tag}')
except docker.errors.ClientError as e: except Exception as e:
print(f'Could not remove image {tag}, continuing...') print(f'Could not remove image {tag}, continuing...')
except (docker.errors.APIError, InvalidVersion) as e: except (InvalidVersion) as e:
print(f'so-{get_so_image_basename(t_list[0])}: {e}', file=sys.stderr) print(f'so-{get_so_image_basename(t_list[0])}: {e}', file=sys.stderr)
exit(1) exit(1)
except Exception as e: except Exception as e:
@@ -85,6 +95,9 @@ def main(quiet):
if no_prunable and not quiet: if no_prunable and not quiet:
print('No Security Onion images to prune') print('No Security Onion images to prune')
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
exit(1)
if __name__ == "__main__": if __name__ == "__main__":
main_parser = argparse.ArgumentParser(add_help=False) main_parser = argparse.ArgumentParser(add_help=False)

Binary file not shown.