#!/bin/bash # 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 elastic_fleet_policy_create() { NAME=$1 DESC=$2 FLEETSERVER=$3 JSON_STRING=$( jq -n \ --arg NAME "$NAME" \ --arg DESC "$DESC" \ --arg FLEETSERVER "$FLEETSERVER" \ '{"name": $NAME,"id":$NAME,"description":$DESC,"namespace":"default","monitoring_enabled":["logs"],"inactivity_timeout":1209600,"has_fleet_server":$FLEETSERVER}' ) # Create Fleet Policy curl -K /opt/so/conf/elasticsearch/curl.config -L -X POST "localhost:5601/api/fleet/agent_policies" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" } elastic_fleet_policy_update() { POLICYID=$1 JSONBLOB=$2 curl -K /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/agent_policies/$POLICYID" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING_UPDATE" } elastic_fleet_integration_create() { JSONBLOB=$1 #curl -K /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/agent_policies/package_policies" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSONBLOB" curl -K /opt/so/conf/elasticsearch/curl.config -L -X POST "localhost:5601/api/fleet/package_policies" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSONBLOB" } mkdir -p /opt/so/conf/elastic-fleet/certs cp /etc/ssl/certs/intca.crt /opt/so/conf/elastic-fleet/certs cp /etc/pki/elasticfleet* /opt/so/conf/elastic-fleet/certs printf "\n### Create ES Token ###\n" ESTOKEN=$(curl -K /opt/so/conf/elasticsearch/curl.config -L -X POST "localhost:5601/api/fleet/service_tokens" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' | jq -r .value) ### Create Outputs & Fleet URLs ### printf "\nAdd Manager Elasticsearch Ouput...\n" ESCACRT=$(openssl x509 -in /opt/so/conf/elastic-fleet/certs/intca.crt) JSON_STRING=$( jq -n \ --arg ESCACRT "$ESCACRT" \ '{"name":"so-manager_elasticsearch","id":"so-manager_elasticsearch","type":"elasticsearch","hosts":["https://{{ GLOBALS.manager_ip }}:9200","https://{{ GLOBALS.manager }}:9200"],"is_default":true,"is_default_monitoring":true,"config_yaml":"","ssl":{"certificate_authorities": [$ESCACRT]}}' ) curl -K /opt/so/conf/elasticsearch/curl.config -L -X POST "localhost:5601/api/fleet/outputs" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" printf "\n\n" printf "\nCreate Logstash Output if node is not an Import or Eval install\n" {% if grains.role not in ['so-import', 'so-eval'] %} LOGSTASHCRT=$(openssl x509 -in /opt/so/conf/elastic-fleet/certs/elasticfleet.crt) LOGSTASHKEY=$(openssl rsa -in /opt/so/conf/elastic-fleet/certs/elasticfleet.key) LOGSTASHCA=$(openssl x509 -in /opt/so/conf/elastic-fleet/certs/intca.crt) JSON_STRING=$( jq -n \ --arg LOGSTASHCRT "$LOGSTASHCRT" \ --arg LOGSTASHKEY "$LOGSTASHKEY" \ --arg LOGSTASHCA "$LOGSTASHCA" \ '{"name":"grid-logstash","is_default":true,"is_default_monitoring":true,"id":"so-manager_logstash","type":"logstash","hosts":["{{ GLOBALS.manager_ip }}:5055", "{{ GLOBALS.manager }}:5055"],"config_yaml":"","ssl":{"certificate": $LOGSTASHCRT,"key": $LOGSTASHKEY,"certificate_authorities":[ $LOGSTASHCA ]},"proxy_id":null}' ) curl -K /opt/so/conf/elasticsearch/curl.config -L -X POST "localhost:5601/api/fleet/outputs" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" printf "\n\n" {%- endif %} printf "\nAdd SO-Manager Fleet URL\n" ## This array replaces whatever URLs are currently configured curl -K /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/settings" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d '{"fleet_server_hosts":["https://{{ GLOBALS.manager_ip }}:8220", "https://{{ GLOBALS.manager }}:8220"]}' printf "\n\n" ### Create Policies & Associated Integration Configuration ### # Manager Fleet Server Host elastic_fleet_policy_create "FleetServer_{{ GLOBALS.hostname }}" "Fleet Server - {{ GLOBALS.hostname }}" "true" | jq #elastic_fleet_policy_update "FleetServer_{{ GLOBALS.hostname }}" "@FleeServerHost_Fixup" # Initial Endpoints elastic_fleet_policy_create "endpoints-initial" "Initial Endpoint Policy" "false" | jq for INTEGRATION in opt/so/saltstack/default/salt/elasticfleet/files/integrations/endpoints-initial/*.json do elastic_fleet_integration_create "@$INTEGRATION" | jq done # Grid Nodes elastic_fleet_policy_create "so-grid-nodes" "SO Grid Node Policy" "false" for INTEGRATION in /opt/so/saltstack/default/salt/elasticfleet/files/integrations/grid-nodes/*.json do elastic_fleet_integration_create "@$INTEGRATION" | jq done ### Finalization ### # Query for Enrollment Tokens for default policies ENDPOINTSENROLLMENTOKEN=$(curl -K /opt/so/conf/elasticsearch/curl.config -L "localhost:5601/api/fleet/enrollment_api_keys" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' | jq .list | jq -r -c '.[] | select(.policy_id | contains("endpoints-default")) | .api_key') GRIDNODESENROLLMENTOKEN=$(curl -K /opt/so/conf/elasticsearch/curl.config -L "localhost:5601/api/fleet/enrollment_api_keys" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' | jq .list | jq -r -c '.[] | select(.policy_id | contains("so-grid-nodes")) | .api_key') # Store needed data in minion pillar pillar_file=/opt/so/saltstack/local/pillar/minions/{{ GLOBALS.minion_id }}.sls printf '%s\n'\ "elasticfleet:"\ " server:"\ " es_token: '$ESTOKEN'"\ " endpoints_enrollment: '$ENDPOINTSENROLLMENTOKEN'"\ " grid_enrollment: '$GRIDNODESENROLLMENTOKEN'"\ "" >> "$pillar_file" #Store Grid Nodes Enrollment token in Global pillar global_pillar_file=/opt/so/saltstack/local/pillar/soc_global.sls printf '%s\n'\ " fleet_grid_enrollment_token: '$GRIDNODESENROLLMENTOKEN'"\ "" >> "$global_pillar_file" # Call Elastic-Fleet Salt State salt-call state.apply elasticfleet queue=True