Compare commits

..

11 Commits

Author SHA1 Message Date
m0duspwnens
62c702e269 Merge remote-tracking branch 'remotes/origin/dev' into feature/users 2021-11-19 09:58:01 -05:00
m0duspwnens
f10290246f Merge remote-tracking branch 'remotes/origin/master' into feature/users 2021-07-02 08:13:56 -04:00
m0duspwnens
c919f6bca0 remove requirement on groups 2021-06-23 18:28:19 -04:00
m0duspwnens
51b421a165 add usergroup, dont create additional groupos 2021-06-23 18:17:18 -04:00
m0duspwnens
86ff54e844 update pillar examples 2021-06-23 17:49:06 -04:00
m0duspwnens
b8cb3f5815 update comment 2021-06-23 17:02:53 -04:00
m0duspwnens
381a51271f add users to pillar and salt top 2021-06-23 15:53:20 -04:00
m0duspwnens
10500178d5 remove users: from users pillar 2021-06-23 15:51:40 -04:00
m0duspwnens
e81e66f40d add additional reserved usernames 2021-06-23 15:33:49 -04:00
m0duspwnens
f6bd74aadf add a list of reserved usernames for centos 2021-06-23 15:21:19 -04:00
m0duspwnens
322c2804fc add support for managing users that can ssh to a node via key 2021-06-23 12:39:48 -04:00
18 changed files with 261 additions and 74 deletions

1
HOTFIX
View File

@@ -1 +0,0 @@
WAZUH AIRGAPFIX

View File

@@ -1,6 +1,6 @@
## Security Onion 2.3.90-WAZUH ## Security Onion 2.3.80
Security Onion 2.3.90-AIRGAPFIX is here! Security Onion 2.3.80 is here!
## Screenshots ## Screenshots

View File

@@ -1,18 +1,18 @@
### 2.3.90-AIRGAPFIX ISO image built on 2021/12/01 ### 2.3.80 ISO image built on 2021/09/27
### Download and Verify ### Download and Verify
2.3.90-AIRGAPFIX ISO image: 2.3.80 ISO image:
https://download.securityonion.net/file/securityonion/securityonion-2.3.90-AIRGAPFIX.iso https://download.securityonion.net/file/securityonion/securityonion-2.3.80.iso
MD5: A87EEF66FEB2ED6E20ABD4ADDA4899C6 MD5: 24F38563860416F4A8ABE18746913E14
SHA1: D1AD74D1481E9FF6F1A79D27DC569DA6749EC54B SHA1: F923C005F54EA2A17AB225ADA0DA46042707AAD9
SHA256: E4FC40340357B098E881F13BC4960AA8CB5F5AC73C05E077C993078ED7F46D59 SHA256: 8E95D10AF664D9A406C168EC421D943CB23F0D0C1813C6C2DBA9B4E131984018
Signature for ISO image: Signature for ISO image:
https://github.com/Security-Onion-Solutions/securityonion/raw/master/sigs/securityonion-2.3.90-AIRGAPFIX.iso.sig https://github.com/Security-Onion-Solutions/securityonion/raw/master/sigs/securityonion-2.3.80.iso.sig
Signing key: Signing key:
https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/master/KEYS https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/master/KEYS
@@ -26,22 +26,22 @@ wget https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/ma
Download the signature file for the ISO: Download the signature file for the ISO:
``` ```
wget https://github.com/Security-Onion-Solutions/securityonion/raw/master/sigs/securityonion-2.3.90-AIRGAPFIX.iso.sig wget https://github.com/Security-Onion-Solutions/securityonion/raw/master/sigs/securityonion-2.3.80.iso.sig
``` ```
Download the ISO image: Download the ISO image:
``` ```
wget https://download.securityonion.net/file/securityonion/securityonion-2.3.90-AIRGAPFIX.iso wget https://download.securityonion.net/file/securityonion/securityonion-2.3.80.iso
``` ```
Verify the downloaded ISO image using the signature file: Verify the downloaded ISO image using the signature file:
``` ```
gpg --verify securityonion-2.3.90-AIRGAPFIX.iso.sig securityonion-2.3.90-AIRGAPFIX.iso gpg --verify securityonion-2.3.80.iso.sig securityonion-2.3.80.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 Wed 01 Dec 2021 11:07:16 AM EST using RSA key ID FE507013 gpg: Signature made Mon 27 Sep 2021 08:55:01 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.

View File

@@ -2,6 +2,7 @@ base:
'*': '*':
- patch.needs_restarting - patch.needs_restarting
- logrotate - logrotate
- users
'*_eval or *_helixsensor or *_heavynode or *_sensor or *_standalone or *_import': '*_eval or *_helixsensor or *_heavynode or *_sensor or *_standalone or *_import':
- match: compound - match: compound

2
pillar/users/init.sls Normal file
View File

@@ -0,0 +1,2 @@
# users pillar goes in /opt/so/saltstack/local/pillar/users/init.sls
# the users directory may need to be created under /opt/so/saltstack/local/pillar

View File

@@ -0,0 +1,19 @@
users:
sclapton:
# required fields
status: present
# node_access determines which node types the user can access.
# this can either be by grains.role or by final part of the minion id after the _
node_access:
- standalone
- searchnode
# optional fields
fullname: Stevie Claptoon
uid: 1001
gid: 1001
homephone: does not have a phone
groups:
- mygroup1
- mygroup2
- wheel # give sudo access

20
pillar/users/pillar.usage Normal file
View File

@@ -0,0 +1,20 @@
users:
sclapton:
# required fields
status: <present | absent>
# node_access determines which node types the user can access.
# this can either be by grains.role or by final part of the minion id after the _
node_access:
- standalone
- searchnode
# optional fields
fullname: <string>
uid: <integer>
gid: <integer>
roomnumber: <string>
workphone: <string>
homephone: <string>
groups:
- <string>
- <string>
- wheel # give sudo access

View File

@@ -23,6 +23,7 @@ import sys
import argparse import argparse
import re import re
from lxml import etree as ET from lxml import etree as ET
from xml.dom import minidom
from datetime import datetime as dt from datetime import datetime as dt
from datetime import timezone as tz from datetime import timezone as tz
@@ -78,15 +79,20 @@ def ip_prompt() -> str:
def wazuh_enabled() -> bool: def wazuh_enabled() -> bool:
file = f'{LOCAL_SALT_DIR}/pillar/global.sls' for file in os.listdir(f'{LOCAL_SALT_DIR}/pillar'):
with open(file, 'r') as pillar: with open(file, 'r') as pillar:
if 'wazuh: 1' in pillar.read(): if 'wazuh: 1' in pillar.read():
return True return True
return False return False
def root_to_str(root: ET.ElementTree) -> str: def root_to_str(root: ET.ElementTree) -> str:
return ET.tostring(root, encoding='unicode', method='xml', xml_declaration=False, pretty_print=True) xml_str = ET.tostring(root, encoding='unicode', method='xml').replace('\n', '')
xml_str = re.sub(r'(?:(?<=>) *)', '', xml_str)
xml_str = re.sub(r' -', '', xml_str)
xml_str = re.sub(r' -->', ' -->', xml_str)
dom = minidom.parseString(xml_str)
return dom.toprettyxml(indent=" ")
def add_wl(ip): def add_wl(ip):
@@ -118,7 +124,7 @@ def apply(role: str, ip: str) -> int:
else: else:
return cmd.returncode return cmd.returncode
if cmd.returncode == 0: if cmd.returncode == 0:
if wazuh_enabled() and role=='analyst': if wazuh_enabled and role=='analyst':
try: try:
add_wl(ip) add_wl(ip)
print(f'Added whitelist entry for {ip} from {WAZUH_CONF}', file=sys.stderr) print(f'Added whitelist entry for {ip} from {WAZUH_CONF}', file=sys.stderr)

View File

@@ -599,7 +599,7 @@ up_to_2.3.80() {
up_to_2.3.90() { up_to_2.3.90() {
for i in manager managersearch eval standalone; do for i in manager managersearch eval standalone; do
if compgen -G "/opt/so/saltstack/local/pillar/minions/*_$i.sls"; then if compgen -G "/opt/so/saltstack/local/pillar/minions/*_$i.sls" > /dev/null; then
echo "soc:" >> /opt/so/saltstack/local/pillar/minions/*_$i.sls echo "soc:" >> /opt/so/saltstack/local/pillar/minions/*_$i.sls
sed -i "/^soc:/a \\ es_index_patterns: '*:so-*,*:endgame-*'" /opt/so/saltstack/local/pillar/minions/*_$i.sls sed -i "/^soc:/a \\ es_index_patterns: '*:so-*,*:endgame-*'" /opt/so/saltstack/local/pillar/minions/*_$i.sls
fi fi
@@ -636,8 +636,6 @@ up_to_2.3.90() {
fi fi
sed -i -re 's/^(playbook_admin.*|playbook_automation.*)/ \1/g' /opt/so/saltstack/local/pillar/secrets.sls
INSTALLEDVERSION=2.3.90 INSTALLEDVERSION=2.3.90
} }
@@ -809,22 +807,16 @@ upgrade_to_2.3.50_repo() {
} }
verify_latest_update_script() { verify_latest_update_script() {
#we need to render soup and so-common first since they contain jinja
salt-call slsutil.renderer $UPDATE_DIR/salt/common/tools/sbin/soup default_renderer='jinja' --local --out=newline_values_only --out-indent=-4 --out-file=/tmp/soup
sed -i -e '$a\' /tmp/soup
salt-call slsutil.renderer $UPDATE_DIR/salt/common/tools/sbin/so-common default_renderer='jinja' --local --out=newline_values_only --out-indent=-4 --out-file=/tmp/so-common
sed -i -e '$a\' /tmp/so-common
# Check to see if the update scripts match. If not run the new one. # Check to see if the update scripts match. If not run the new one.
CURRENTSOUP=$(md5sum /usr/sbin/soup | awk '{print $1}') CURRENTSOUP=$(md5sum /opt/so/saltstack/default/salt/common/tools/sbin/soup | awk '{print $1}')
GITSOUP=$(md5sum /tmp/soup | awk '{print $1}') GITSOUP=$(md5sum $UPDATE_DIR/salt/common/tools/sbin/soup | awk '{print $1}')
CURRENTCMN=$(md5sum /usr/sbin/so-common | awk '{print $1}') CURRENTCMN=$(md5sum /opt/so/saltstack/default/salt/common/tools/sbin/so-common | awk '{print $1}')
GITCMN=$(md5sum /tmp/so-common | awk '{print $1}') GITCMN=$(md5sum $UPDATE_DIR/salt/common/tools/sbin/so-common | awk '{print $1}')
CURRENTIMGCMN=$(md5sum /usr/sbin/so-image-common | awk '{print $1}') CURRENTIMGCMN=$(md5sum /opt/so/saltstack/default/salt/common/tools/sbin/so-image-common | awk '{print $1}')
GITIMGCMN=$(md5sum $UPDATE_DIR/salt/common/tools/sbin/so-image-common | awk '{print $1}') GITIMGCMN=$(md5sum $UPDATE_DIR/salt/common/tools/sbin/so-image-common | awk '{print $1}')
if [[ "$CURRENTSOUP" == "$GITSOUP" && "$CURRENTCMN" == "$GITCMN" && "$CURRENTIMGCMN" == "$GITIMGCMN" ]]; then if [[ "$CURRENTSOUP" == "$GITSOUP" && "$CURRENTCMN" == "$GITCMN" && "$CURRENTIMGCMN" == "$GITIMGCMN" ]]; then
echo "This version of the soup script is up to date. Proceeding." echo "This version of the soup script is up to date. Proceeding."
rm -f /tmp/soup /tmp/so-common
else else
echo "You are not running the latest soup version. Updating soup and its components. Might take multiple runs to complete" echo "You are not running the latest soup version. Updating soup and its components. Might take multiple runs to complete"
cp $UPDATE_DIR/salt/common/tools/sbin/soup $DEFAULT_SALT_DIR/salt/common/tools/sbin/ cp $UPDATE_DIR/salt/common/tools/sbin/soup $DEFAULT_SALT_DIR/salt/common/tools/sbin/
@@ -837,23 +829,6 @@ verify_latest_update_script() {
fi fi
} }
apply_hotfix() {
if [[ "$INSTALLEDVERSION" == "2.3.90" && "$HOTFIXVERSION" == "WAZUH" ]] ; then
FILE="/nsm/wazuh/etc/ossec.conf"
echo "Detecting if ossec.conf needs corrected..."
if head -1 $FILE | grep -q "xml version"; then
echo "$FILE has an XML header; removing"
sed -i 1d $FILE
so-wazuh-restart
else
echo "$FILE does not have an XML header, so no changes are necessary."
fi
else
echo "Skipping ossec.conf check ($INSTALLEDVERSION/$HOTFIXVERSION)"
fi
}
main() { main() {
trap 'check_err $?' EXIT trap 'check_err $?' EXIT
@@ -908,10 +883,9 @@ main() {
set -e set -e
if [ "$is_hotfix" == "true" ]; then if [ "$is_hotfix" == "true" ]; then
echo "Applying $HOTFIXVERSION hotfix" echo "Applying $HOTFIXVERSION"
copy_new_files copy_new_files
apply_hotfix echo ""
echo "Hotfix applied"
update_version update_version
salt-call state.highstate -l info queue=True salt-call state.highstate -l info queue=True
else else
@@ -951,21 +925,21 @@ main() {
echo "Upgrading Salt" echo "Upgrading Salt"
# Update the repo files so it can actually upgrade # Update the repo files so it can actually upgrade
upgrade_salt upgrade_salt
fi
echo "Checking if Salt was upgraded." echo "Checking if Salt was upgraded."
echo ""
# Check that Salt was upgraded
SALTVERSIONPOSTUPGRADE=$(salt --versions-report | grep Salt: | awk '{print $2}')
if [[ "$SALTVERSIONPOSTUPGRADE" != "$NEWSALTVERSION" ]]; then
echo "Salt upgrade failed. Check of indicators of failure in $SOUP_LOG."
echo "Once the issue is resolved, run soup again."
echo "Exiting."
echo ""
exit 0
else
echo "Salt upgrade success."
echo "" echo ""
# Check that Salt was upgraded
SALTVERSIONPOSTUPGRADE=$(salt --versions-report | grep Salt: | awk '{print $2}')
if [[ "$SALTVERSIONPOSTUPGRADE" != "$NEWSALTVERSION" ]]; then
echo "Salt upgrade failed. Check of indicators of failure in $SOUP_LOG."
echo "Once the issue is resolved, run soup again."
echo "Exiting."
echo ""
exit 0
else
echo "Salt upgrade success."
echo ""
fi
fi fi
preupgrade_changes preupgrade_changes
@@ -1170,3 +1144,4 @@ fi
echo "### Preparing soup at $(date) ###" echo "### Preparing soup at $(date) ###"
main "$@" | tee -a $SOUP_LOG main "$@" | tee -a $SOUP_LOG

View File

@@ -65,10 +65,6 @@ yumconf:
- mode: 644 - mode: 644
- template: jinja - template: jinja
- show_changes: False - show_changes: False
cleanairgap:
file.absent:
- name: /etc/yum.repos.d/airgap_repo.repo
{% endif %} {% endif %}
cleanyum: cleanyum:

View File

@@ -34,6 +34,7 @@ base:
- match: compound - match: compound
- salt.minion - salt.minion
- common - common
- users
- patch.os.schedule - patch.os.schedule
- motd - motd
- salt.minion-check - salt.minion-check

110
salt/users/init.sls Normal file
View File

@@ -0,0 +1,110 @@
# The creation of a user will require a pub key placed in /opt/so/saltstack/local/salt/users/authorized_keys/<username>
# If a user is changed from present to absent, their usergroup will be removed, but any additional usergroups that were created
# for that user will remain.
{% from 'users/map.jinja' import reserved_usernames with context %}
{% for username, userdeets in pillar.get('users', {}).items() if username not in reserved_usernames %}
{% if 'status' in userdeets %}
{% if userdeets.status == 'absent' %}
remove_user_{{username}}:
user.absent:
- name: {{ username }}
{% if 'purge' in userdeets %}
- purge: {{ userdeets.purge }}
{% endif %}
- force: True
{% elif userdeets.status == 'present' %}
{% if 'node_access' in userdeets %}
{% if grains.role in userdeets.node_access or grains.id.split('_')|last in userdeets.node_access %}
add_user_group_{{username}}:
group.present:
- name: {{ username }}
{% if 'uid' in userdeets %}
- gid: {{ userdeets.uid }}
{% endif %}
add_user_{{username}}:
user.present:
- name: {{ username }}
- home: {{ userdeets.get('home', "/home/%s" % username) }}
- shell: {{ userdeets.get('shell', '/bin/bash') }}
- usergroup: True
{% if 'fullname' in userdeets %}
- fullname: {{ userdeets.fullname }}
{% endif %}
{% if 'uid' in userdeets %}
- uid: {{ userdeets.uid }}
{% endif %}
{% if 'gid' in userdeets %}
- gid: {{ userdeets.gid }}
{% endif %}
{% if 'roomnumber' in userdeets %}
- roomnumber: {{ userdeets.roomnumber }}
{% endif %}
{% if 'workphone' in userdeets %}
- workphone: {{ userdeets.workphone }}
{% endif %}
{% if 'homephone' in userdeets %}
- homephone: {{ userdeets.homephone }}
{% endif %}
{% if 'groups' in userdeets %}
- groups:
{% for group in userdeets.groups %}
- {{ group }}
{% endfor %}
{% endif %}
{{username}}_authorized_keys:
file.managed:
- name: /home/{{username}}/.ssh/authorized_keys
- source: salt://users/authorized_keys/{{username}}
- user: {{username}}
- group: {{username}}
- mode: 644
- show_diff: False
- makedirs: True
- require:
- user: add_user_{{username}}
{% endif %}
{% endif %}
{% else %}
unknown_status_or_password_not_provided_for_user_{{username}}:
test.fail_without_changes:
- comment: "Verify status is 'present' or 'absent' and a password is provided for {{username}} in the users pillar."
{% endif %}
{% else %}
status_not_provided_for_user_{{username}}:
test.fail_without_changes:
- comment: "Status should be 'present' or 'absent'."
{% endif %}
{% endfor %}
disable_wheel_pwd_required:
file.comment:
- name: /etc/sudoers
- regex: "%wheel\\s+ALL=\\(ALL\\)\\s+ALL"
allow_wheel_no_pwd:
file.uncomment:
- name: /etc/sudoers
- regex: "%wheel\\s+ALL=\\(ALL\\)\\s+NOPASSWD: ALL"

58
salt/users/map.jinja Normal file
View File

@@ -0,0 +1,58 @@
{% set reserved_usernames = [
'root',
'bin',
'daemon',
'adm',
'lp',
'sync',
'shutdown',
'halt',
'mail',
'operator',
'games',
'ftp',
'nobody',
'systemd-network',
'dbus',
'polkitd',
'tss',
'sshd',
'ossec',
'postfix',
'chrony',
'ntp',
'tcpdump',
'socore',
'soremote',
'elasticsearch',
'stenographer',
'suricata',
'zeek',
'curator',
'kratos',
'kibana',
'elastalert',
'ossecm',
'ossecr',
'logstash',
'sys',
'man',
'news',
'uucp',
'proxy',
'www-data',
'backup',
'list',
'irc',
'gnats',
'systemd-resolve',
'syslog',
'messagebus',
'_apt',
'lxd',
'uuidd',
'dnsmasq',
'landscape',
'pollinate',
'ossec'
] %}

View File

@@ -318,7 +318,7 @@ if ! [[ -f $install_opt_file ]]; then
elif [[ $is_minion && $is_iso ]]; then elif [[ $is_minion && $is_iso ]]; then
$sshcmd -i /root/.ssh/so.key soremote@"$MSRV" [[ -f /etc/yum.repos.d/airgap_repo.repo ]] >> $setup_log 2>&1 $sshcmd -i /root/.ssh/so.key soremote@"$MSRV" [[ -f /etc/yum.repos.d/airgap_repo.repo ]] >> $setup_log 2>&1
airgap_check=$? airgap_check=$?
[[ $airgap_check == 0 ]] && is_airgap=true >> $setup_log 2>&1 [[ $airgap_check ]] && is_airgap=true >> $setup_log 2>&1
fi fi
reset_proxy reset_proxy

View File

@@ -753,7 +753,7 @@ whiptail_install_type_dist() {
dist_option=$(whiptail --title "$whiptail_title" --menu "Do you want to start a new deployment or join this box to \nan existing deployment?" 11 75 2 \ dist_option=$(whiptail --title "$whiptail_title" --menu "Do you want to start a new deployment or join this box to \nan existing deployment?" 11 75 2 \
"New Deployment " "Create a new Security Onion deployment" \ "New Deployment " "Create a new Security Onion deployment" \
"Existing Deployment " "Join to an existing Security Onion deployment " \ "Existing Deployment " "Join to an exisiting Security Onion deployment " \
3>&1 1>&2 2>&3 3>&1 1>&2 2>&3
) )
local exitstatus=$? local exitstatus=$?

Binary file not shown.