From cfc33b1a34acf93f1ee6d93c3bbda4c98ee0777c Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Sun, 28 Jan 2024 10:12:25 -0500 Subject: [PATCH 01/12] Sync Elastic Agent Artifacts --- files/salt/master/master | 3 ++- salt/elasticfleet/enabled.sls | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/files/salt/master/master b/files/salt/master/master index b93fa93de..e9b36868c 100644 --- a/files/salt/master/master +++ b/files/salt/master/master @@ -41,7 +41,8 @@ file_roots: base: - /opt/so/saltstack/local/salt - /opt/so/saltstack/default/salt - + elasticartifacts: + - /nsm/elastic-fleet/artifacts # The master_roots setting configures a master-only copy of the file_roots dictionary, # used by the state compiler. diff --git a/salt/elasticfleet/enabled.sls b/salt/elasticfleet/enabled.sls index fef85d24c..bd8ab51c0 100644 --- a/salt/elasticfleet/enabled.sls +++ b/salt/elasticfleet/enabled.sls @@ -41,6 +41,15 @@ so-elastic-fleet-auto-configure-elasticsearch-urls: - retry: True {% endif %} +# Sync Elastic Agent artifacts to Fleet Node +{% if grains.role in ['so-fleet'] %} +elasticagent_syncartifacts: + file.recurse: + - name: /nsm/elastic-fleet/artifacts/beats + - source: salt://beats?saltenv=elasticartifacts + +{% endif %} + {% if SERVICETOKEN != '' %} so-elastic-fleet: docker_container.running: From 1847e5c3c0093751c6826df33c2b88a70933ea3c Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Sun, 28 Jan 2024 11:37:18 -0500 Subject: [PATCH 02/12] Enable nginx on Fleet Node --- salt/allowed_states.map.jinja | 1 + salt/nginx/etc/nginx.conf | 20 ++++++++++++++++++++ salt/top.sls | 1 + 3 files changed, 22 insertions(+) diff --git a/salt/allowed_states.map.jinja b/salt/allowed_states.map.jinja index d27f51ede..3ead8b26e 100644 --- a/salt/allowed_states.map.jinja +++ b/salt/allowed_states.map.jinja @@ -180,6 +180,7 @@ 'telegraf', 'firewall', 'logstash', + 'nginx', 'healthcheck', 'schedule', 'elasticfleet', diff --git a/salt/nginx/etc/nginx.conf b/salt/nginx/etc/nginx.conf index d5981be77..236f8da7f 100644 --- a/salt/nginx/etc/nginx.conf +++ b/salt/nginx/etc/nginx.conf @@ -39,6 +39,26 @@ http { include /etc/nginx/conf.d/*.conf; + {%- if role in ['fleet'] %} + + server { + listen 8443; + server_name {{ GLOBALS.hostname }}; + root /opt/socore/html; + location /artifacts/ { + try_files $uri =206; + proxy_read_timeout 90; + proxy_connect_timeout 90; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Proxy ""; + proxy_set_header X-Forwarded-Proto $scheme; + } + } + + {%- endif %} + {%- if role in ['eval', 'managersearch', 'manager', 'standalone', 'import'] %} server { diff --git a/salt/top.sls b/salt/top.sls index f8979956e..16b355476 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -264,6 +264,7 @@ base: - telegraf - firewall - logstash + - nginx - elasticfleet - elasticfleet.install_agent_grid - schedule From afa98fa147f9b66a97692a35917f6dc766b3b93f Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Sun, 28 Jan 2024 14:20:52 -0500 Subject: [PATCH 03/12] update artifacts URL automatically --- salt/elasticfleet/enabled.sls | 7 +- .../so-elastic-fleet-artifacts-url-update | 102 ++++++++++++++++++ salt/firewall/containers.map.jinja | 1 + salt/nginx/enabled.sls | 5 + 4 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-artifacts-url-update diff --git a/salt/elasticfleet/enabled.sls b/salt/elasticfleet/enabled.sls index bd8ab51c0..dca7f479f 100644 --- a/salt/elasticfleet/enabled.sls +++ b/salt/elasticfleet/enabled.sls @@ -33,12 +33,17 @@ so-elastic-fleet-auto-configure-server-urls: - retry: True {% endif %} -# Automatically update Fleet Server Elasticsearch URLs +# Automatically update Fleet Server Elasticsearch URLs & Agent Artifact URLs {% if grains.role not in ['so-fleet'] %} so-elastic-fleet-auto-configure-elasticsearch-urls: cmd.run: - name: /usr/sbin/so-elastic-fleet-es-url-update - retry: True + +so-elastic-fleet-auto-configure-elasticsearch-urls: + cmd.run: + - name: /usr/sbin/so-elastic-fleet-artifacts-url-update + - retry: True {% endif %} # Sync Elastic Agent artifacts to Fleet Node diff --git a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-artifacts-url-update b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-artifacts-url-update new file mode 100644 index 000000000..685db392f --- /dev/null +++ b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-artifacts-url-update @@ -0,0 +1,102 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0; you may not use +# this file except in compliance with the Elastic License 2.0. +{% from 'vars/globals.map.jinja' import GLOBALS %} + +. /usr/sbin/so-common + +# Only run on Managers +if ! is_manager_node; then + printf "Not a Manager Node... Exiting" + exit 0 +fi + +########## +# Set Elastic Agent Artifact Registry URL + + + + +function update_es_urls() { + +# For each element in NEWLIST, create a new entry + +JSON_STRING=$( jq -n \ + --arg NAME "FleetServer_{{ GLOBALS.hostname }}" \ + --arg URL "http://{{ GLOBALS.url_base }}:8443/artifacts/" \ + '{"name":$NAME,"host":$URL,"is_default":true}' + ) + +curl -K /opt/so/conf/elasticsearch/curl.config -L -X POST "localhost:5601/api/fleet/agent_download_sources" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" + +######### + + # Generate updated JSON payload +{% if grains.role not in ['so-import', 'so-eval'] %} + JSON_STRING=$(jq -n --arg UPDATEDLIST $NEW_LIST_JSON '{"name":"so-manager_elasticsearch","type":"elasticsearch","hosts": $UPDATEDLIST,"config_yaml":""}') +{%- else %} + JSON_STRING=$(jq -n --arg UPDATEDLIST $NEW_LIST_JSON '{"name":"so-manager_elasticsearch","type":"elasticsearch","hosts": $UPDATEDLIST,"is_default":true,"is_default_monitoring":true,"config_yaml":""}') +{%- endif %} + # Update Fleet Elasticsearch URLs + curl -K /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/outputs/so-manager_elasticsearch" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" +} + +#START HERE + +# Get current list of Artifact URLs +#RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/outputs/so-manager_elasticsearch') +RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/agent_download_sources') + + +# Check to make sure that the server responded with good data - else, bail from script +CHECKSUM=$(jq -r '.page' <<< "$RAW_JSON") +if [ "$CHECKSUM" != "1" ]; then + printf "Failed to query for current Elastic Agent Artifact URLs..." + exit 1 +fi + +# Get the current list of Elastic Agent Artifact URLs & hash them +CURRENT_LIST=$(jq -c -r '.items[].host' <<< "$RAW_JSON") +CURRENT_HASH=$(sha1sum <<< "$CURRENT_LIST" | awk '{print $1}') + + +# Create array & add initial elements +if [ "{{ GLOBALS.hostname }}" = "{{ GLOBALS.url_base }}" ]; then + NEW_LIST=("http://{{ GLOBALS.url_base }}:8443/artifacts/") +else + NEW_LIST=("http://{{ GLOBALS.url_base }}:8443/artifacts/" "http://{{ GLOBALS.hostname }}:8443/artifacts/") +fi + +# Query for the current Grid Nodes that are running Logstash (which includes Fleet Nodes) +LOGSTASHNODES=$(salt-call --out=json pillar.get logstash:nodes | jq '.local') + +# Query for Fleet Nodes & add them to the list (Hostname) +if grep -q "fleet" <<< $LOGSTASHNODES; then + readarray -t FLEETNODES < <(jq -r ' .fleet | keys_unsorted[]' <<< $LOGSTASHNODES) + for NODE in "${FLEETNODES[@]}" + do + NEW_LIST+=("http://$NODE:8443/artifacts/") + done +fi + +# Sort & hash the new list of Fleet Elasticsearch URLs +NEW_LIST_JSON=$(jq --compact-output --null-input '$ARGS.positional' --args -- "${NEW_LIST[@]}") +NEW_HASH=$(sha1sum <<< "$NEW_LIST_JSON" | awk '{print $1}') + +# Compare the current & new list of URLs - if different, update the Fleet Elasticsearch URLs +if [ "$1" = "--force" ]; then + printf "\nUpdating List, since --force was specified.\n" + printf "Current List: $CURRENT_LIST\nNew List: $NEW_LIST_JSON\n" + update_es_urls + exit 0 +fi + +if [ "$NEW_HASH" = "$CURRENT_HASH" ]; then + printf "\nHashes match - no update needed.\n" + printf "Current List: $CURRENT_LIST\nNew List: $NEW_LIST_JSON\n" + exit 0 +else + printf "\nHashes don't match - update needed.\n" + printf "Current List: $CURRENT_LIST\nNew List: $NEW_LIST_JSON\n" + #update_es_urls +fi diff --git a/salt/firewall/containers.map.jinja b/salt/firewall/containers.map.jinja index 0ba2389e9..99a3bd5d0 100644 --- a/salt/firewall/containers.map.jinja +++ b/salt/firewall/containers.map.jinja @@ -95,6 +95,7 @@ {% set NODE_CONTAINERS = [ 'so-elastic-fleet', 'so-logstash', + 'so-nginx' ] %} {% elif GLOBALS.role == 'so-sensor' %} diff --git a/salt/nginx/enabled.sls b/salt/nginx/enabled.sls index dda475655..eca9c237a 100644 --- a/salt/nginx/enabled.sls +++ b/salt/nginx/enabled.sls @@ -14,6 +14,9 @@ include: - nginx.config - nginx.sostatus + +{% if grains.role not in ['so-fleet'] %} + {# if the user has selected to replace the crt and key in the ui #} {% if NGINXMERGED.ssl.replace_cert %} @@ -88,6 +91,8 @@ make-rule-dir-nginx: - recurse: - user - group + +{% endif %} so-nginx: docker_container.running: From 0d08bb0a91f817efd7d66a8f818706c9b8afe65d Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Mon, 29 Jan 2024 11:37:28 -0500 Subject: [PATCH 04/12] Finalize script --- salt/elasticfleet/enabled.sls | 2 +- .../so-elastic-fleet-artifacts-url-update | 129 +++++++----------- 2 files changed, 51 insertions(+), 80 deletions(-) diff --git a/salt/elasticfleet/enabled.sls b/salt/elasticfleet/enabled.sls index dca7f479f..f5f53c2a5 100644 --- a/salt/elasticfleet/enabled.sls +++ b/salt/elasticfleet/enabled.sls @@ -40,7 +40,7 @@ so-elastic-fleet-auto-configure-elasticsearch-urls: - name: /usr/sbin/so-elastic-fleet-es-url-update - retry: True -so-elastic-fleet-auto-configure-elasticsearch-urls: +so-elastic-fleet-auto-configure-artifact-urls: cmd.run: - name: /usr/sbin/so-elastic-fleet-artifacts-url-update - retry: True diff --git a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-artifacts-url-update b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-artifacts-url-update index 685db392f..bcd3ef7f7 100644 --- a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-artifacts-url-update +++ b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-artifacts-url-update @@ -11,92 +11,63 @@ if ! is_manager_node; then exit 0 fi -########## -# Set Elastic Agent Artifact Registry URL - - - - -function update_es_urls() { - -# For each element in NEWLIST, create a new entry - -JSON_STRING=$( jq -n \ - --arg NAME "FleetServer_{{ GLOBALS.hostname }}" \ - --arg URL "http://{{ GLOBALS.url_base }}:8443/artifacts/" \ - '{"name":$NAME,"host":$URL,"is_default":true}' - ) - -curl -K /opt/so/conf/elasticsearch/curl.config -L -X POST "localhost:5601/api/fleet/agent_download_sources" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" - -######### - - # Generate updated JSON payload -{% if grains.role not in ['so-import', 'so-eval'] %} - JSON_STRING=$(jq -n --arg UPDATEDLIST $NEW_LIST_JSON '{"name":"so-manager_elasticsearch","type":"elasticsearch","hosts": $UPDATEDLIST,"config_yaml":""}') -{%- else %} - JSON_STRING=$(jq -n --arg UPDATEDLIST $NEW_LIST_JSON '{"name":"so-manager_elasticsearch","type":"elasticsearch","hosts": $UPDATEDLIST,"is_default":true,"is_default_monitoring":true,"config_yaml":""}') -{%- endif %} - # Update Fleet Elasticsearch URLs - curl -K /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/outputs/so-manager_elasticsearch" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" +# Function to check if an array contains a value +array_contains () { + local array="$1[@]" + local seeking=$2 + local in=1 + for element in "${!array}"; do + if [[ $element == "$seeking" ]]; then + in=0 + break + fi + done + return $in } -#START HERE - -# Get current list of Artifact URLs -#RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/outputs/so-manager_elasticsearch') -RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/agent_download_sources') - - -# Check to make sure that the server responded with good data - else, bail from script -CHECKSUM=$(jq -r '.page' <<< "$RAW_JSON") -if [ "$CHECKSUM" != "1" ]; then - printf "Failed to query for current Elastic Agent Artifact URLs..." - exit 1 -fi - -# Get the current list of Elastic Agent Artifact URLs & hash them -CURRENT_LIST=$(jq -c -r '.items[].host' <<< "$RAW_JSON") -CURRENT_HASH=$(sha1sum <<< "$CURRENT_LIST" | awk '{print $1}') - - -# Create array & add initial elements -if [ "{{ GLOBALS.hostname }}" = "{{ GLOBALS.url_base }}" ]; then - NEW_LIST=("http://{{ GLOBALS.url_base }}:8443/artifacts/") -else - NEW_LIST=("http://{{ GLOBALS.url_base }}:8443/artifacts/" "http://{{ GLOBALS.hostname }}:8443/artifacts/") -fi - # Query for the current Grid Nodes that are running Logstash (which includes Fleet Nodes) LOGSTASHNODES=$(salt-call --out=json pillar.get logstash:nodes | jq '.local') +# Initialize an array for new hosts from Fleet Nodes +declare -a NEW_LIST=() + # Query for Fleet Nodes & add them to the list (Hostname) -if grep -q "fleet" <<< $LOGSTASHNODES; then - readarray -t FLEETNODES < <(jq -r ' .fleet | keys_unsorted[]' <<< $LOGSTASHNODES) - for NODE in "${FLEETNODES[@]}" - do - NEW_LIST+=("http://$NODE:8443/artifacts/") - done +if grep -q "fleet" <<< "$LOGSTASHNODES"; then + readarray -t FLEETNODES < <(jq -r '.fleet | keys_unsorted[]' <<< "$LOGSTASHNODES") + for NODE in "${FLEETNODES[@]}"; do + NEW_LIST+=("http://$NODE:8443/artifacts/") + done fi -# Sort & hash the new list of Fleet Elasticsearch URLs -NEW_LIST_JSON=$(jq --compact-output --null-input '$ARGS.positional' --args -- "${NEW_LIST[@]}") -NEW_HASH=$(sha1sum <<< "$NEW_LIST_JSON" | awk '{print $1}') +# Create an array for expected hosts and their names +declare -A expected_hosts=( + ["http://{{ GLOBALS.url_base }}:8443/artifacts/"]="FleetServer_{{ GLOBALS.hostname }}" + ["https://artifacts.elastic.co/downloads/"]="Elastic Artifacts" +) -# Compare the current & new list of URLs - if different, update the Fleet Elasticsearch URLs -if [ "$1" = "--force" ]; then - printf "\nUpdating List, since --force was specified.\n" - printf "Current List: $CURRENT_LIST\nNew List: $NEW_LIST_JSON\n" - update_es_urls - exit 0 -fi +# Merge NEW_LIST into expected_hosts +for host in "${NEW_LIST[@]}"; do + expected_hosts[$host]="FleetServer" +done -if [ "$NEW_HASH" = "$CURRENT_HASH" ]; then - printf "\nHashes match - no update needed.\n" - printf "Current List: $CURRENT_LIST\nNew List: $NEW_LIST_JSON\n" - exit 0 -else - printf "\nHashes don't match - update needed.\n" - printf "Current List: $CURRENT_LIST\nNew List: $NEW_LIST_JSON\n" - #update_es_urls -fi +# Fetch the current hosts from the API +current_hosts=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/agent_download_sources' | jq -r .items[].host) + +# Convert current hosts to an array +IFS=$'\n' read -rd '' -a current_hosts_array <<<"$current_hosts" + +# Check each expected host +for host in "${!expected_hosts[@]}"; do + array_contains current_hosts_array "$host" || { + echo "$host (${expected_hosts[$host]}) is missing. Adding it..." + + # Prepare the JSON payload + JSON_STRING=$( jq -n \ + --arg NAME "${expected_hosts[$host]}" \ + --arg URL "$host" \ + '{"name":$NAME,"host":$URL}' ) + + # Create the missing host + curl -K /opt/so/conf/elasticsearch/curl.config -L -X POST "localhost:5601/api/fleet/agent_download_sources" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" + } +done From 0fe96bfc2d66223f2d3ffa1ad4ee30ed5b1144fc Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Wed, 31 Jan 2024 16:17:40 -0500 Subject: [PATCH 05/12] switch to symlink --- salt/elasticfleet/enabled.sls | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/salt/elasticfleet/enabled.sls b/salt/elasticfleet/enabled.sls index f5f53c2a5..a84d51cfc 100644 --- a/salt/elasticfleet/enabled.sls +++ b/salt/elasticfleet/enabled.sls @@ -44,6 +44,13 @@ so-elastic-fleet-auto-configure-artifact-urls: cmd.run: - name: /usr/sbin/so-elastic-fleet-artifacts-url-update - retry: True + +elasticagentartifactssymlink: + file.symlink: + - name: /opt/so/saltstack/local/salt/beats + - target: /nsm/elastic-fleet/artifacts/beats + - user: socore + - group: socore {% endif %} # Sync Elastic Agent artifacts to Fleet Node @@ -51,8 +58,7 @@ so-elastic-fleet-auto-configure-artifact-urls: elasticagent_syncartifacts: file.recurse: - name: /nsm/elastic-fleet/artifacts/beats - - source: salt://beats?saltenv=elasticartifacts - + - source: salt://beats {% endif %} {% if SERVICETOKEN != '' %} From 2f03248612bc7e881733d1eec9201d8e70f3fd7c Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 31 Jan 2024 16:22:44 -0500 Subject: [PATCH 06/12] use different nginx defaults for so-fleet node hosting artifacts --- salt/docker/defaults.yaml | 7 +++++++ salt/firewall/containers.map.jinja | 2 +- salt/nginx/enabled.sls | 23 +++++++++++++++-------- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/salt/docker/defaults.yaml b/salt/docker/defaults.yaml index 9a27843ae..4bc212fbe 100644 --- a/salt/docker/defaults.yaml +++ b/salt/docker/defaults.yaml @@ -84,6 +84,13 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + 'so-nginx-fleet-node': + final_octet: 31 + port_bindings: + - 8443:8443 + custom_bind_mounts: [] + extra_hosts: [] + extra_env: [] 'so-playbook': final_octet: 32 port_bindings: diff --git a/salt/firewall/containers.map.jinja b/salt/firewall/containers.map.jinja index 99a3bd5d0..b3ead0f4c 100644 --- a/salt/firewall/containers.map.jinja +++ b/salt/firewall/containers.map.jinja @@ -95,7 +95,7 @@ {% set NODE_CONTAINERS = [ 'so-elastic-fleet', 'so-logstash', - 'so-nginx' + 'so-nginx-fleet-node' ] %} {% elif GLOBALS.role == 'so-sensor' %} diff --git a/salt/nginx/enabled.sls b/salt/nginx/enabled.sls index eca9c237a..273fb65be 100644 --- a/salt/nginx/enabled.sls +++ b/salt/nginx/enabled.sls @@ -94,17 +94,24 @@ make-rule-dir-nginx: {% endif %} +{# if this is an so-fleet node then we want to use the port bindings, custom bind mounts defined for fleet #} +{% if GLOBALS.role == 'so-fleet' %} +{% set container_config = 'so-nginx-fleet-node' %} +{% else %} +{% set container_config = 'so-nginx' %} +{% endif %} + so-nginx: docker_container.running: - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-nginx:{{ GLOBALS.so_version }} - hostname: so-nginx - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-nginx'].ip }} + - ipv4_address: {{ DOCKER.containers[container_config].ip }} - extra_hosts: - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} - {% if DOCKER.containers['so-nginx'].extra_hosts %} - {% for XTRAHOST in DOCKER.containers['so-nginx'].extra_hosts %} + {% if DOCKER.containers[container_config].extra_hosts %} + {% for XTRAHOST in DOCKER.containers[container_config].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} @@ -124,20 +131,20 @@ so-nginx: - /nsm/repo:/opt/socore/html/repo:ro - /nsm/rules:/nsm/rules:ro {% endif %} - {% if DOCKER.containers['so-nginx'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-nginx'].custom_bind_mounts %} + {% if DOCKER.containers[container_config].custom_bind_mounts %} + {% for BIND in DOCKER.containers[container_config].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - {% if DOCKER.containers['so-nginx'].extra_env %} + {% if DOCKER.containers[container_config].extra_env %} - environment: - {% for XTRAENV in DOCKER.containers['so-nginx'].extra_env %} + {% for XTRAENV in DOCKER.containers[container_config].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} - cap_add: NET_BIND_SERVICE - port_bindings: - {% for BINDING in DOCKER.containers['so-nginx'].port_bindings %} + {% for BINDING in DOCKER.containers[container_config].port_bindings %} - {{ BINDING }} {% endfor %} - watch: From ae32ac40c2dde62a0c26319c78a667700406f94e Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 31 Jan 2024 16:28:45 -0500 Subject: [PATCH 07/12] add fleet node nginx to docker annotations --- salt/docker/soc_docker.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/docker/soc_docker.yaml b/salt/docker/soc_docker.yaml index 850324a9e..6e0efeb20 100644 --- a/salt/docker/soc_docker.yaml +++ b/salt/docker/soc_docker.yaml @@ -48,6 +48,7 @@ docker: so-logstash: *dockerOptions so-mysql: *dockerOptions so-nginx: *dockerOptions + so-nginx-fleet-node: *dockerOptions so-playbook: *dockerOptions so-redis: *dockerOptions so-sensoroni: *dockerOptions From e090518b5920ef593e9bbb336a938edb6afe3a0e Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Thu, 1 Feb 2024 09:46:53 -0500 Subject: [PATCH 08/12] Refactor script --- .../so-elastic-fleet-artifacts-url-update | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-artifacts-url-update b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-artifacts-url-update index bcd3ef7f7..ffbeaf6e1 100644 --- a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-artifacts-url-update +++ b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-artifacts-url-update @@ -26,7 +26,7 @@ array_contains () { } # Query for the current Grid Nodes that are running Logstash (which includes Fleet Nodes) -LOGSTASHNODES=$(salt-call --out=json pillar.get logstash:nodes | jq '.local') +LOGSTASHNODES='{{ salt['pillar.get']('logstash:nodes', {}) | tojson }}' # Initialize an array for new hosts from Fleet Nodes declare -a NEW_LIST=() @@ -40,34 +40,46 @@ if grep -q "fleet" <<< "$LOGSTASHNODES"; then fi # Create an array for expected hosts and their names -declare -A expected_hosts=( +declare -A expected_urls=( ["http://{{ GLOBALS.url_base }}:8443/artifacts/"]="FleetServer_{{ GLOBALS.hostname }}" ["https://artifacts.elastic.co/downloads/"]="Elastic Artifacts" ) -# Merge NEW_LIST into expected_hosts +# Merge NEW_LIST into expected_urls for host in "${NEW_LIST[@]}"; do - expected_hosts[$host]="FleetServer" + expected_urls[$host]="FleetServer" done # Fetch the current hosts from the API -current_hosts=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/agent_download_sources' | jq -r .items[].host) +current_urls=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/agent_download_sources' | jq -r .items[].host) # Convert current hosts to an array -IFS=$'\n' read -rd '' -a current_hosts_array <<<"$current_hosts" +IFS=$'\n' read -rd '' -a current_urls_array <<<"$current_urls" + +# Flag to track if any host was added +any_url_added=0 # Check each expected host -for host in "${!expected_hosts[@]}"; do - array_contains current_hosts_array "$host" || { - echo "$host (${expected_hosts[$host]}) is missing. Adding it..." +for host in "${!expected_urls[@]}"; do + array_contains current_urls_array "$host" || { + echo "$host (${expected_urls[$host]}) is missing. Adding it..." # Prepare the JSON payload JSON_STRING=$( jq -n \ - --arg NAME "${expected_hosts[$host]}" \ + --arg NAME "${expected_urls[$host]}" \ --arg URL "$host" \ '{"name":$NAME,"host":$URL}' ) # Create the missing host curl -K /opt/so/conf/elasticsearch/curl.config -L -X POST "localhost:5601/api/fleet/agent_download_sources" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" + + # Flag that an artifact URL was added + any_url_added=1 } + done + + +if [[ $any_url_added -eq 0 ]]; then + echo "All expected artifact URLs are present. No updates needed." +fi From 8d0e8789bd949932df12397e3edafd4bfb4dd9e2 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Thu, 8 Feb 2024 09:54:51 -0500 Subject: [PATCH 09/12] Use salt file roots --- salt/elasticfleet/enabled.sls | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/salt/elasticfleet/enabled.sls b/salt/elasticfleet/enabled.sls index a84d51cfc..53ec6c1ef 100644 --- a/salt/elasticfleet/enabled.sls +++ b/salt/elasticfleet/enabled.sls @@ -45,12 +45,6 @@ so-elastic-fleet-auto-configure-artifact-urls: - name: /usr/sbin/so-elastic-fleet-artifacts-url-update - retry: True -elasticagentartifactssymlink: - file.symlink: - - name: /opt/so/saltstack/local/salt/beats - - target: /nsm/elastic-fleet/artifacts/beats - - user: socore - - group: socore {% endif %} # Sync Elastic Agent artifacts to Fleet Node @@ -58,7 +52,7 @@ elasticagentartifactssymlink: elasticagent_syncartifacts: file.recurse: - name: /nsm/elastic-fleet/artifacts/beats - - source: salt://beats + - source: salt://beats?saltenv=elasticartifacts {% endif %} {% if SERVICETOKEN != '' %} From 683abf0179701d7abfedbfd6d6d08d9227f8b949 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Thu, 8 Feb 2024 13:24:25 -0500 Subject: [PATCH 10/12] Rework naming --- .../sbin_jinja/so-elastic-fleet-artifacts-url-update | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-artifacts-url-update b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-artifacts-url-update index ffbeaf6e1..721525668 100644 --- a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-artifacts-url-update +++ b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-artifacts-url-update @@ -35,7 +35,9 @@ declare -a NEW_LIST=() if grep -q "fleet" <<< "$LOGSTASHNODES"; then readarray -t FLEETNODES < <(jq -r '.fleet | keys_unsorted[]' <<< "$LOGSTASHNODES") for NODE in "${FLEETNODES[@]}"; do - NEW_LIST+=("http://$NODE:8443/artifacts/") + URL="http://$NODE:8443/artifacts/" + NAME="FleetServer_$NODE" + NEW_LIST+=("$URL=$NAME") done fi @@ -46,8 +48,11 @@ declare -A expected_urls=( ) # Merge NEW_LIST into expected_urls -for host in "${NEW_LIST[@]}"; do - expected_urls[$host]="FleetServer" +for entry in "${NEW_LIST[@]}"; do + # Extract URL and Name from each entry + IFS='=' read -r URL NAME <<< "$entry" + # Add to expected_urls, automatically handling URL as key and NAME as value + expected_urls["$URL"]="$NAME" done # Fetch the current hosts from the API From 66ac36a9440682efdea72d4018675b6252238f9c Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Sat, 10 Feb 2024 11:07:26 -0500 Subject: [PATCH 11/12] Update soup --- salt/manager/tools/sbin/soup | 3 +++ 1 file changed, 3 insertions(+) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index d93218db4..600cb5d4e 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -610,6 +610,9 @@ up_to_2.4.50() { mkdir /opt/so/rules/nids/suri chown socore:socore /opt/so/rules/nids/suri mv -v /opt/so/rules/nids/*.rules /opt/so/rules/nids/suri/. + + echo "Adding /nsm/elastic-fleet/artifacts to file_roots in /etc/salt/master using so-yaml" + so-yaml.py append /etc/salt/master file_roots.base /nsm/elastic-fleet/artifacts INSTALLEDVERSION=2.4.50 } From eafb5cf15eed65c0ff2050b431ccceb0e0761f46 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Sun, 11 Feb 2024 13:18:20 -0500 Subject: [PATCH 12/12] Change to file_root --- salt/elasticfleet/enabled.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/elasticfleet/enabled.sls b/salt/elasticfleet/enabled.sls index 53ec6c1ef..5b0cff5df 100644 --- a/salt/elasticfleet/enabled.sls +++ b/salt/elasticfleet/enabled.sls @@ -52,7 +52,7 @@ so-elastic-fleet-auto-configure-artifact-urls: elasticagent_syncartifacts: file.recurse: - name: /nsm/elastic-fleet/artifacts/beats - - source: salt://beats?saltenv=elasticartifacts + - source: salt://beats {% endif %} {% if SERVICETOKEN != '' %}