prep for next ai session

This commit is contained in:
2026-08-01 15:45:23 -05:00
parent 46c35106fb
commit 6244c1cc25
139 changed files with 16712 additions and 0 deletions
@@ -0,0 +1,426 @@
#!/bin/bash
# TSYS Security Hardening - Two-Factor Authentication
# Implements 2FA for SSH, Cockpit, and Webmin services
# Uses Google Authenticator (TOTP) for time-based tokens
#####
#Core framework functions...
#####
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
export PROJECT_ROOT_PATH
PROJECT_ROOT_PATH="$(cd "$SCRIPT_DIR/../../.." && pwd)"
export GIT_VENDOR_PATH_ROOT
GIT_VENDOR_PATH_ROOT="$PROJECT_ROOT_PATH/vendor/git@git.knownelement.com/29418/"
export KNELShellFrameworkRoot
KNELShellFrameworkRoot="$GIT_VENDOR_PATH_ROOT/KNEL/KNELShellFramework"
source "$KNELShellFrameworkRoot/Framework-ConfigFiles/FrameworkVars"
for framework_include_file in "$KNELShellFrameworkRoot"/Framework-Includes/*; do
source "$framework_include_file"
done
for project_include_file in "$PROJECT_ROOT_PATH"/Project-Includes/*; do
source "$project_include_file"
done
# 2FA Configuration
BACKUP_DIR="/root/backup/2fa"
PAM_CONFIG_DIR="/etc/pam.d"
SSH_CONFIG="/etc/ssh/sshd_config"
COCKPIT_CONFIG="/etc/cockpit/cockpit.conf"
# Create backup directory
mkdir -p "$BACKUP_DIR"
print_info "TSYS Two-Factor Authentication Setup"
# Backup existing configurations
function backup_configs() {
print_info "Creating backup of existing configurations..."
# Backup SSH configuration
if [[ -f "$SSH_CONFIG" ]]; then
cp "$SSH_CONFIG" "$BACKUP_DIR/sshd_config.bak"
print_info "SSH config backed up"
fi
# Backup PAM configurations
if [[ -d "$PAM_CONFIG_DIR" ]]; then
cp -r "$PAM_CONFIG_DIR" "$BACKUP_DIR/pam.d.bak"
print_info "PAM configs backed up"
fi
# Backup Cockpit configuration if exists
if [[ -f "$COCKPIT_CONFIG" ]]; then
cp "$COCKPIT_CONFIG" "$BACKUP_DIR/cockpit.conf.bak"
print_info "Cockpit config backed up"
fi
print_info "Backup completed: $BACKUP_DIR"
}
# Install required packages
function install_2fa_packages() {
print_info "Installing 2FA packages..."
# Update package cache
apt-get update
# Install Google Authenticator PAM module
# Install QR code generator for terminal display
apt-get install -y libpam-google-authenticator qrencode
print_info "2FA packages installed successfully"
}
# Configure SSH for 2FA
function configure_ssh_2fa() {
print_info "Configuring SSH for 2FA..."
# Configure SSH daemon
print_info "Updating SSH configuration..."
# Enable challenge-response authentication
if ! grep -q "^ChallengeResponseAuthentication yes" "$SSH_CONFIG"; then
sed -i 's/^ChallengeResponseAuthentication.*/ChallengeResponseAuthentication yes/' "$SSH_CONFIG" || \
echo "ChallengeResponseAuthentication yes" >> "$SSH_CONFIG"
fi
if ! grep -q "^KbdInteractiveAuthentication yes" "$SSH_CONFIG"; then
sed -i 's/^KbdInteractiveAuthentication.*/KbdInteractiveAuthentication yes/' "$SSH_CONFIG" || \
echo "KbdInteractiveAuthentication yes" >> "$SSH_CONFIG"
fi
# Enable PAM authentication
if ! grep -q "^UsePAM yes" "$SSH_CONFIG"; then
sed -i 's/^UsePAM.*/UsePAM yes/' "$SSH_CONFIG" || \
echo "UsePAM yes" >> "$SSH_CONFIG"
fi
# Configure authentication methods (key + 2FA)
if ! grep -q "^AuthenticationMethods" "$SSH_CONFIG"; then
echo "AuthenticationMethods publickey,keyboard-interactive" >> "$SSH_CONFIG"
else
sed -i 's/^AuthenticationMethods.*/AuthenticationMethods publickey,keyboard-interactive/' "$SSH_CONFIG"
fi
print_info "SSH configuration updated"
}
# Configure PAM for 2FA
function configure_pam_2fa() {
print_info "Configuring PAM for 2FA..."
# Create backup of original PAM SSH config
cp "$PAM_CONFIG_DIR/sshd" "$PAM_CONFIG_DIR/sshd.bak.$(date +%Y%m%d)"
# Configure PAM to use Google Authenticator
cat > "$PAM_CONFIG_DIR/sshd" << 'EOF'
# PAM configuration for SSH with 2FA
# Standard Un*x authentication
@include common-auth
# Google Authenticator 2FA
auth required pam_google_authenticator.so nullok
# Standard Un*x authorization
@include common-account
# SELinux needs to be the first session rule
session required pam_selinux.so close
session required pam_loginuid.so
# Standard Un*x session setup and teardown
@include common-session
# Print the message of the day upon successful login
session optional pam_motd.so motd=/run/motd.dynamic
session optional pam_motd.so noupdate
# Print the status of the user's mailbox upon successful login
session optional pam_mail.so standard noenv
# Set up user limits from /etc/security/limits.conf
session required pam_limits.so
# SELinux needs to intervene at login time
session required pam_selinux.so open
# Standard Un*x password updating
@include common-password
EOF
print_info "PAM configuration updated for SSH 2FA"
}
# Configure Cockpit for 2FA
function configure_cockpit_2fa() {
print_info "Configuring Cockpit for 2FA..."
# Create Cockpit config directory if it doesn't exist
mkdir -p "$(dirname "$COCKPIT_CONFIG")"
# Configure Cockpit to use PAM with 2FA
cat > "$COCKPIT_CONFIG" << 'EOF'
[WebService]
# Enable 2FA for Cockpit web interface
LoginTitle = TSYS Server Management
LoginTo = 300
RequireHost = true
[Session]
# Use PAM for authentication (includes 2FA)
Banner = /etc/cockpit/issue.cockpit
IdleTimeout = 15
EOF
# Create PAM configuration for Cockpit
cat > "$PAM_CONFIG_DIR/cockpit" << 'EOF'
# PAM configuration for Cockpit with 2FA
auth requisite pam_nologin.so
auth required pam_env.so
auth required pam_faillock.so preauth
auth sufficient pam_unix.so try_first_pass
auth required pam_google_authenticator.so nullok
auth required pam_faillock.so authfail
auth required pam_deny.so
account required pam_nologin.so
account include system-auth
account required pam_faillock.so
session required pam_selinux.so close
session required pam_loginuid.so
session optional pam_keyinit.so force revoke
session include system-auth
session required pam_selinux.so open
session optional pam_motd.so
EOF
print_info "Cockpit 2FA configuration completed"
}
# Configure Webmin for 2FA (if installed)
function configure_webmin_2fa() {
print_info "Checking for Webmin installation..."
local webmin_config="/etc/webmin/miniserv.conf"
if [[ -f "$webmin_config" ]]; then
print_info "Webmin found, configuring 2FA..."
# Stop webmin service
systemctl stop webmin || true
# Enable 2FA in Webmin configuration. `sed -i ... || echo` would never
# append, because sed returns 0 even when it matches nothing; guard with
# grep so the directive is added when absent and updated when present.
if grep -q '^twofactor_provider=' "$webmin_config"; then
sed -i 's/^twofactor_provider=.*/twofactor_provider=totp/' "$webmin_config"
else
echo "twofactor_provider=totp" >> "$webmin_config"
fi
# Enable 2FA requirement
if grep -q '^twofactor=' "$webmin_config"; then
sed -i 's/^twofactor=.*/twofactor=1/' "$webmin_config"
else
echo "twofactor=1" >> "$webmin_config"
fi
# Start webmin service
systemctl start webmin || true
print_info "Webmin 2FA configuration completed"
else
print_info "Webmin not found, skipping configuration"
fi
}
# Setup 2FA for users
function setup_user_2fa() {
print_info "Setting up 2FA for system users..."
local users=("localuser" "root")
for user in "${users[@]}"; do
if id "$user" &>/dev/null; then
print_info "Setting up 2FA for user: $user"
local user_home
user_home="$(getent passwd "$user" | cut -d: -f6)"
if [[ -z "$user_home" ]]; then
print_info "No home directory for $user, skipping"
continue
fi
# Create 2FA setup script for user
cat > "/tmp/setup-2fa-$user.sh" << 'EOF'
#!/bin/bash
echo "Setting up Google Authenticator for user: $USER"
echo "Please follow the prompts to configure 2FA:"
echo "1. Answer 'y' to update your time-based token"
echo "2. Scan the QR code with your authenticator app"
echo "3. Save the backup codes in a secure location"
echo "4. Answer 'y' to the remaining questions for security"
echo ""
google-authenticator -t -d -f -r 3 -R 30 -W
EOF
chmod +x "/tmp/setup-2fa-$user.sh"
# Instructions for user setup
cat > "$user_home/2fa-setup-instructions.txt" << EOF
TSYS Two-Factor Authentication Setup Instructions
==============================================
Your system has been configured for 2FA. To complete setup:
1. Install an authenticator app on your phone:
- Google Authenticator
- Authy
- Microsoft Authenticator
2. Run the setup command:
sudo /tmp/setup-2fa-$user.sh
3. Follow the prompts:
- Scan the QR code with your app
- Save the backup codes securely
- Answer 'y' to security questions
4. Test your setup:
- SSH to the server
- Enter your 6-digit code when prompted
IMPORTANT: Save backup codes in a secure location!
Without them, you may be locked out if you lose your phone.
For support, contact your system administrator.
EOF
chown "$user:$user" "$user_home/2fa-setup-instructions.txt"
print_info "2FA setup prepared for user: $user"
else
print_info "User $user not found, skipping"
fi
done
}
# Restart services
function restart_services() {
print_info "Restarting services..."
# Test SSH configuration
if sshd -t; then
systemctl restart sshd
print_info "SSH service restarted"
else
print_error "SSH configuration test failed"
return 1
fi
# Restart Cockpit if installed
if systemctl is-enabled cockpit.socket &>/dev/null; then
systemctl restart cockpit.socket
print_info "Cockpit service restarted"
fi
# Restart Webmin if installed
if systemctl is-enabled webmin &>/dev/null; then
systemctl restart webmin
print_info "Webmin service restarted"
fi
}
# Validation and testing
function validate_2fa_setup() {
print_info "Validating 2FA setup..."
# Check if Google Authenticator is installed
if command -v google-authenticator &>/dev/null; then
print_info "Google Authenticator installed"
else
print_error "Google Authenticator not found"
return 1
fi
# Check SSH configuration
if grep -q "AuthenticationMethods publickey,keyboard-interactive" "$SSH_CONFIG"; then
print_info "SSH 2FA configuration valid"
else
print_error "SSH 2FA configuration invalid"
return 1
fi
# Check PAM configuration
if grep -q "pam_google_authenticator.so" "$PAM_CONFIG_DIR/sshd"; then
print_info "PAM 2FA configuration valid"
else
print_error "PAM 2FA configuration invalid"
return 1
fi
# Check service status
if systemctl is-active sshd &>/dev/null; then
print_info "SSH service is running"
else
print_error "SSH service is not running"
return 1
fi
print_info "2FA validation completed successfully"
}
# Display final instructions
function show_final_instructions() {
print_info "2FA Setup Completed"
print_info "Two-Factor Authentication has been configured for:"
print_info "- SSH (requires key + 2FA token)"
print_info "- Cockpit web interface"
if [[ -f "/etc/webmin/miniserv.conf" ]]; then
print_info "- Webmin administration panel"
fi
print_info "IMPORTANT: Complete user setup immediately!"
print_info "1. Check /home/*/2fa-setup-instructions.txt for user setup"
print_info "2. Run setup scripts for each user"
print_info "3. Test 2FA before logging out"
print_info "Backup location: $BACKUP_DIR"
print_info "To disable 2FA, restore configurations from backup"
print_info "2FA setup completed successfully!"
}
# Main execution
function main() {
# Check if running as root
if [[ $EUID -ne 0 ]]; then
print_error "This script must be run as root"
exit 1
fi
# Execute setup steps
backup_configs
install_2fa_packages
configure_ssh_2fa
configure_pam_2fa
configure_cockpit_2fa
configure_webmin_2fa
setup_user_2fa
restart_services
validate_2fa_setup
show_final_instructions
}
# Run main function
main "$@"
@@ -0,0 +1,50 @@
#!/bin/bash
#####
#Core framework functions...
#####
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
export PROJECT_ROOT_PATH
PROJECT_ROOT_PATH="$(cd "$SCRIPT_DIR/../../.." && pwd)"
export GIT_VENDOR_PATH_ROOT
GIT_VENDOR_PATH_ROOT="$PROJECT_ROOT_PATH/vendor/git@git.knownelement.com/29418/"
export KNELShellFrameworkRoot
KNELShellFrameworkRoot="$GIT_VENDOR_PATH_ROOT/KNEL/KNELShellFramework"
export CONFIGFILES_PATH
CONFIGFILES_PATH="$PROJECT_ROOT_PATH/provisioning/ConfigFiles"
source "$KNELShellFrameworkRoot/Framework-ConfigFiles/FrameworkVars"
for framework_include_file in "$KNELShellFrameworkRoot"/Framework-Includes/*; do
source "$framework_include_file"
done
for project_include_file in "$PROJECT_ROOT_PATH"/Project-Includes/*; do
source "$project_include_file"
done
# Material herein Sourced from
# https://cisofy.com/documentation/lynis/
# https://jbcsec.com/configure-linux-ssh/
# https://opensource.com/article/20/5/linux-security-lynis
# https://forum.greenbone.net/t/ssh-authentication/13536
# openvas
#lynis
#Auditd
cat "$CONFIGFILES_PATH/AuditD/auditd.conf" > /etc/audit/auditd.conf
# Systemd
cat "$CONFIGFILES_PATH/Systemd/journald.conf" > /etc/systemd/journald.conf
# logrotate
cat "$CONFIGFILES_PATH/Logrotate/logrotate.conf" > /etc/logrotate.conf
@@ -0,0 +1,3 @@
#!/bin/bash
# Sourced from https://wiki.debian.org/UnattendedUpgrades
@@ -0,0 +1,126 @@
#!/bin/bash
#########################################
#Core framework functions...
#########################################
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
export PROJECT_ROOT_PATH
PROJECT_ROOT_PATH="$(cd "$SCRIPT_DIR/../../.." && pwd)"
export GIT_VENDOR_PATH_ROOT
GIT_VENDOR_PATH_ROOT="$PROJECT_ROOT_PATH/vendor/git@git.knownelement.com/29418/"
export KNELShellFrameworkRoot
KNELShellFrameworkRoot="$GIT_VENDOR_PATH_ROOT/KNEL/KNELShellFramework"
export CONFIGFILES_PATH
CONFIGFILES_PATH="$PROJECT_ROOT_PATH/provisioning/ConfigFiles"
source "$KNELShellFrameworkRoot/Framework-ConfigFiles/FrameworkVars"
for framework_include_file in "$KNELShellFrameworkRoot"/Framework-Includes/*; do
source "$framework_include_file"
done
for project_include_file in "$PROJECT_ROOT_PATH"/Project-Includes/*; do
source "$project_include_file"
done
#########################################
# Core script code begins here
#########################################
# Sourced from
# https://complianceascode.readthedocs.io/en/latest/manual/developer/01_introduction.html
# https://github.com/ComplianceAsCode/content
# https://github.com/ComplianceAsCode
#apparmor
#enforcing
#enabled in bootloader config
#aide
#auditd
#disable auto mounting
#disable usb storage
#motd
#remote login warning banner
#Ensure time sync is working
#systemd-timesync
#ntp
#chrony
#password complexity
#password expiration warning
#password expiration time
#password hashing algo
#fix grub perms
if [ "$IS_RASPI" = 0 ] ; then
chown root:root /boot/grub/grub.cfg
chmod og-rwx /boot/grub/grub.cfg
chmod 0400 /boot/grub/grub.cfg
fi
#disable auto mounting
systemctl --now disable autofs || true
apt-get -y --purge remove autofs || true
#disable usb storage
cat "$CONFIGFILES_PATH/ModProbe/usb_storage.conf" > /etc/modprobe.d/usb_storage.conf
cat "$CONFIGFILES_PATH/ModProbe/dccp.conf" > /etc/modprobe.d/dccp.conf
cat "$CONFIGFILES_PATH/ModProbe/rds.conf" > /etc/modprobe.d/rds.conf
cat "$CONFIGFILES_PATH/ModProbe/sctp.conf" > /etc/modprobe.d/sctp.conf
cat "$CONFIGFILES_PATH/ModProbe/tipc.conf" > /etc/modprobe.d/tipc.conf
cat "$CONFIGFILES_PATH/ModProbe/cramfs.conf" > /etc/modprobe.d/cramfs.conf
cat "$CONFIGFILES_PATH/ModProbe/freevxfs.conf" > /etc/modprobe.d/freevxfs.conf
cat "$CONFIGFILES_PATH/ModProbe/hfs.conf" > /etc/modprobe.d/hfs.conf
cat "$CONFIGFILES_PATH/ModProbe/hfsplus.conf" > /etc/modprobe.d/hfsplus.conf
cat "$CONFIGFILES_PATH/ModProbe/jffs2.conf" > /etc/modprobe.d/jffs2.conf
cat "$CONFIGFILES_PATH/ModProbe/squashfs.conf" > /etc/modprobe.d/squashfs.conf
cat "$CONFIGFILES_PATH/ModProbe/udf.conf" > /etc/modprobe.d/udf.conf
#banners
cat "$CONFIGFILES_PATH/BANNERS/issue" > /etc/issue
cat "$CONFIGFILES_PATH/BANNERS/issue.net" > /etc/issue.net
cat "$CONFIGFILES_PATH/BANNERS/motd" > /etc/motd
#Cron perms
if [ -f /etc/cron.deny ]; then
rm /etc/cron.deny || true
fi
touch /etc/cron.allow
chmod g-wx,o-rwx /etc/cron.allow
chown root:root /etc/cron.allow
chmod og-rwx /etc/crontab
chmod og-rwx /etc/cron.hourly/
chmod og-rwx /etc/cron.daily/
chmod og-rwx /etc/cron.weekly/
chmod og-rwx /etc/cron.monthly/
chown root:root /etc/cron.d/
chmod og-rwx /etc/cron.d/
# At perms
rm -f /etc/at.deny || true
touch /etc/at.allow
chmod g-wx,o-rwx /etc/at.allow
chown root:root /etc/at.allow
@@ -0,0 +1,105 @@
#!/bin/bash
#########################################
#Core framework functions...
#########################################
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
export PROJECT_ROOT_PATH
PROJECT_ROOT_PATH="$(cd "$SCRIPT_DIR/../../.." && pwd)"
export GIT_VENDOR_PATH_ROOT
GIT_VENDOR_PATH_ROOT="$PROJECT_ROOT_PATH/vendor/git@git.knownelement.com/29418/"
export KNELShellFrameworkRoot
KNELShellFrameworkRoot="$GIT_VENDOR_PATH_ROOT/KNEL/KNELShellFramework"
export CONFIGFILES_PATH
CONFIGFILES_PATH="$PROJECT_ROOT_PATH/provisioning/ConfigFiles"
source "$KNELShellFrameworkRoot/Framework-ConfigFiles/FrameworkVars"
for framework_include_file in "$KNELShellFrameworkRoot"/Framework-Includes/*; do
source "$framework_include_file"
done
for project_include_file in "$PROJECT_ROOT_PATH"/Project-Includes/*; do
source "$project_include_file"
done
#########################################
# Core script code begins here
#########################################
export SUBODEV_CHECK
SUBODEV_CHECK="$(getent passwd | grep -c subodev || true)"
export LOCALUSER_CHECK
LOCALUSER_CHECK="$(getent passwd | grep -c localuser || true)"
export ROOT_SSH_DIR
ROOT_SSH_DIR="/root/.ssh"
export LOCALUSER_SSH_DIR
LOCALUSER_SSH_DIR="/home/localuser/.ssh"
export SUBODEV_SSH_DIR
SUBODEV_SSH_DIR="/home/subodev/.ssh"
if [ ! -d $ROOT_SSH_DIR ]; then
mkdir /root/.ssh/
fi
cat "$CONFIGFILES_PATH/SSH/AuthorizedKeys/root-ssh-authorized-keys" >/root/.ssh/authorized_keys
chmod 400 /root/.ssh/authorized_keys
chown root: /root/.ssh/authorized_keys
if [ "$LOCALUSER_CHECK" -gt 0 ]; then
if [ ! -d $LOCALUSER_SSH_DIR ]; then
mkdir -p /home/localuser/.ssh/
fi
cat "$CONFIGFILES_PATH/SSH/AuthorizedKeys/localuser-ssh-authorized-keys" >/home/localuser/.ssh/authorized_keys
chown localuser /home/localuser/.ssh/authorized_keys &&
chmod 400 /home/localuser/.ssh/authorized_keys
fi
if [ "$SUBODEV_CHECK" = 1 ]; then
if [ ! -d $SUBODEV_SSH_DIR ]; then
mkdir /home/subodev/.ssh/
fi
cat "$CONFIGFILES_PATH/SSH/AuthorizedKeys/localuser-ssh-authorized-keys" >/home/subodev/.ssh/authorized_keys
chmod 400 /home/subodev/.ssh/authorized_keys &&
chown subodev: /home/subodev/.ssh/authorized_keys
fi
export DEV_WORKSTATION_CHECK
DEV_WORKSTATION_CHECK="$(hostname | grep -Ec 'subopi-dev|CharlesDevServer' || true)"
if [ "$DEV_WORKSTATION_CHECK" -eq 0 ]; then
cat "$CONFIGFILES_PATH/SSH/Configs/tsys-sshd-config" >/etc/ssh/sshd_config
fi
#Don't deploy this config to a ubuntu server, it breaks openssh server. Works on kali/debian.
export UBUNTU_CHECK
UBUNTU_CHECK="$(distro | grep -c Ubuntu||true)"
if [ "$UBUNTU_CHECK" -ne 1 ]; then
cat "$CONFIGFILES_PATH/SSH/Configs/ssh-audit-hardening.conf" >/etc/ssh/sshd_config.d/ssh-audit_hardening.conf
chmod og-rwx /etc/ssh/sshd_config.d/*
fi
# Perms on sshd_config
chmod og-rwx /etc/ssh/sshd_config
#todo
# only strong MAC algos are used
@@ -0,0 +1,57 @@
#!/bin/bash
#########################################
#Core framework functions...
#########################################
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
export PROJECT_ROOT_PATH
PROJECT_ROOT_PATH="$(cd "$SCRIPT_DIR/../../.." && pwd)"
export GIT_VENDOR_PATH_ROOT
GIT_VENDOR_PATH_ROOT="$PROJECT_ROOT_PATH/vendor/git@git.knownelement.com/29418/"
export KNELShellFrameworkRoot
KNELShellFrameworkRoot="$GIT_VENDOR_PATH_ROOT/KNEL/KNELShellFramework"
source "$KNELShellFrameworkRoot/Framework-ConfigFiles/FrameworkVars"
for framework_include_file in "$KNELShellFrameworkRoot"/Framework-Includes/*; do
source "$framework_include_file"
done
for project_include_file in "$PROJECT_ROOT_PATH"/Project-Includes/*; do
source "$project_include_file"
done
#########################################
# Core script code begins here
#########################################
# We don't want to run this on the wazuh server, otherwise bad things happen...
export TSYS_NSM_CHECK
TSYS_NSM_CHECK="$(hostname |grep -c tsys-nsm ||true)"
if [ "$TSYS_NSM_CHECK" -eq 0 ]; then
if [ -f /usr/share/keyrings/wazuh.gpg ]; then
rm -f /usr/share/keyrings/wazuh.gpg
fi
curl -s https://packages.wazuh.com/key/GPG-KEY-WAZUH | gpg --no-default-keyring --keyring gnupg-ring:/usr/share/keyrings/wazuh.gpg --import
chmod 644 /usr/share/keyrings/wazuh.gpg
echo "deb [signed-by=/usr/share/keyrings/wazuh.gpg] https://packages.wazuh.com/4.x/apt/ stable main" > /etc/apt/sources.list.d/wazuh.list
apt-get update
WAZUH_MANAGER="tsys-nsm.knel.net" apt-get -y install wazuh-agent
systemctl daemon-reload
systemctl enable wazuh-agent
systemctl start wazuh-agent || true
echo "wazuh-agent hold" | dpkg --set-selections
fi