-
Notifications
You must be signed in to change notification settings - Fork 69
/
elastic-container.sh
executable file
·289 lines (239 loc) · 9.42 KB
/
elastic-container.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
#!/bin/bash -eu
set -o pipefail
ipvar="0.0.0.0"
# These should be set in the .env file
declare LinuxDR
declare WindowsDR
declare MacOSDR
declare COMPOSE
# Ignore following warning
# shellcheck disable=SC1091
. .env
HEADERS=(
-H "kbn-version: ${STACK_VERSION}"
-H "kbn-xsrf: kibana"
-H 'Content-Type: application/json'
)
passphrase_reset() {
if grep -Fq "changeme" .env; then
echo "Sorry, looks like you haven't updated the passphrase from the default"
echo "Please update the changeme passphrases in the .env file."
exit 1
else
echo "Passphrase has been reset. Proceeding."
fi
}
# Create the script usage menu
usage() {
cat <<EOF | sed -e 's/^ //'
usage: ./elastic-container.sh [-v] (stage|start|stop|restart|status|help)
actions:
stage downloads all necessary images to local storage
start creates a container network and starts containers
stop stops running containers without removing them
destroy stops and removes the containers, the network, and volumes created
restart restarts all the stack containers
status check the status of the stack containers
clear clear all documents in logs and metrics indexes
help print this message
flags:
-v enable verbose output
EOF
}
# Create a function to enable the Detection Engine and load prebuilt rules in Kibana
configure_kbn() {
MAXTRIES=15
i=${MAXTRIES}
while [ $i -gt 0 ]; do
STATUS=$(curl -I -k --silent "${LOCAL_KBN_URL}" | head -n 1 | cut -d ' ' -f2)
echo
echo "Attempting to enable the Detection Engine and install prebuilt Detection Rules."
if [ "${STATUS}" == "302" ]; then
echo
echo "Kibana is up. Proceeding."
echo
output=$(curl -k --silent "${HEADERS[@]}" --user "${ELASTIC_USERNAME}:${ELASTIC_PASSWORD}" -XPOST "${LOCAL_KBN_URL}/api/detection_engine/index")
[[ ${output} =~ '"acknowledged":true' ]] || (
echo
echo "Detection Engine setup failed :-("
exit 1
)
echo "Detection engine enabled. Installing prepackaged rules."
curl -k --silent "${HEADERS[@]}" --user "${ELASTIC_USERNAME}:${ELASTIC_PASSWORD}" -XPUT "${LOCAL_KBN_URL}/api/detection_engine/rules/prepackaged" 1>&2
echo
echo "Prepackaged rules installed!"
echo
if [[ "${LinuxDR}" -eq 0 && "${WindowsDR}" -eq 0 && "${MacOSDR}" -eq 0 ]]; then
echo "No detection rules enabled in the .env file, skipping detection rules enablement."
echo
break
else
echo "Enabling detection rules"
if [ "${LinuxDR}" -eq 1 ]; then
curl -k --silent "${HEADERS[@]}" --user "${ELASTIC_USERNAME}:${ELASTIC_PASSWORD}" -X POST "${LOCAL_KBN_URL}/api/detection_engine/rules/_bulk_action" -d'
{
"query": "alert.attributes.tags: (\"Linux\" OR \"OS: Linux\")",
"action": "enable"
}
' 1>&2
echo
echo "Successfully enabled Linux detection rules"
fi
if [ "${WindowsDR}" -eq 1 ]; then
curl -k --silent "${HEADERS[@]}" --user "${ELASTIC_USERNAME}:${ELASTIC_PASSWORD}" -X POST "${LOCAL_KBN_URL}/api/detection_engine/rules/_bulk_action" -d'
{
"query": "alert.attributes.tags: (\"Windows\" OR \"OS: Windows\")",
"action": "enable"
}
' 1>&2
echo
echo "Successfully enabled Windows detection rules"
fi
if [ "${MacOSDR}" -eq 1 ]; then
curl -k --silent "${HEADERS[@]}" --user "${ELASTIC_USERNAME}:${ELASTIC_PASSWORD}" -X POST "${LOCAL_KBN_URL}/api/detection_engine/rules/_bulk_action" -d'
{
"query": "alert.attributes.tags: (\"macOS\" OR \"OS: macOS\")",
"action": "enable"
}
' 1>&2
echo
echo "Successfully enabled MacOS detection rules"
fi
fi
echo
break
else
echo
echo "Kibana still loading. Trying again in 40 seconds"
fi
sleep 40
i=$((i - 1))
done
[ $i -eq 0 ] && echo "Exceeded MAXTRIES (${MAXTRIES}) to setup detection engine." && exit 1
return 0
}
get_host_ip() {
os=$(uname -s)
if [ "${os}" == "Linux" ]; then
ipvar=$(hostname -I | awk '{ print $1}')
elif [ "${os}" == "Darwin" ]; then
ipvar=$(ifconfig en0 | awk '$1 == "inet" {print $2}')
fi
}
set_fleet_values() {
# Get the current Fleet settings
CURRENT_SETTINGS=$(curl -k -s -u "${ELASTIC_USERNAME}:${ELASTIC_PASSWORD}" -X GET "${LOCAL_KBN_URL}/api/fleet/agents/setup" -H "Content-Type: application/json")
# Check if Fleet is already set up
if echo "$CURRENT_SETTINGS" | grep -q '"isInitialized": true'; then
echo "Fleet settings are already configured."
return
fi
echo "Fleet is not initialized, setting up Fleet..."
fingerprint=$(${COMPOSE} exec -w /usr/share/elasticsearch/config/certs/ca elasticsearch cat ca.crt | openssl x509 -noout -fingerprint -sha256 | cut -d "=" -f 2 | tr -d :)
printf '{"fleet_server_hosts": ["%s"]}' "https://${ipvar}:${FLEET_PORT}" | curl -k --silent --user "${ELASTIC_USERNAME}:${ELASTIC_PASSWORD}" -XPUT "${HEADERS[@]}" "${LOCAL_KBN_URL}/api/fleet/settings" -d @- | jq
printf '{"hosts": ["%s"]}' "https://${ipvar}:9200" | curl -k --silent --user "${ELASTIC_USERNAME}:${ELASTIC_PASSWORD}" -XPUT "${HEADERS[@]}" "${LOCAL_KBN_URL}/api/fleet/outputs/fleet-default-output" -d @- | jq
printf '{"ca_trusted_fingerprint": "%s"}' "${fingerprint}" | curl -k --silent --user "${ELASTIC_USERNAME}:${ELASTIC_PASSWORD}" -XPUT "${HEADERS[@]}" "${LOCAL_KBN_URL}/api/fleet/outputs/fleet-default-output" -d @- | jq
printf '{"config_yaml": "%s"}' "ssl.verification_mode: certificate" | curl -k --silent --user "${ELASTIC_USERNAME}:${ELASTIC_PASSWORD}" -XPUT "${HEADERS[@]}" "${LOCAL_KBN_URL}/api/fleet/outputs/fleet-default-output" -d @- | jq
policy_id=$(printf '{"name": "%s", "description": "%s", "namespace": "%s", "monitoring_enabled": ["logs","metrics"], "inactivity_timeout": 1209600}' "Endpoint Policy" "" "default" | curl -k --silent --user "${ELASTIC_USERNAME}:${ELASTIC_PASSWORD}" -XPOST "${HEADERS[@]}" "${LOCAL_KBN_URL}/api/fleet/agent_policies?sys_monitoring=true" -d @- | jq -r '.item.id')
pkg_version=$(curl -k --user "${ELASTIC_USERNAME}:${ELASTIC_PASSWORD}" -XGET "${HEADERS[@]}" "${LOCAL_KBN_URL}/api/fleet/epm/packages/endpoint" -d : | jq -r '.item.version')
printf "{\"name\": \"%s\", \"description\": \"%s\", \"namespace\": \"%s\", \"policy_id\": \"%s\", \"enabled\": %s, \"inputs\": [{\"enabled\": true, \"streams\": [], \"type\": \"ENDPOINT_INTEGRATION_CONFIG\", \"config\": {\"_config\": {\"value\": {\"type\": \"endpoint\", \"endpointConfig\": {\"preset\": \"EDRComplete\"}}}}}], \"package\": {\"name\": \"endpoint\", \"title\": \"Elastic Defend\", \"version\": \"${pkg_version}\"}}" "Elastic Defend" "" "default" "${policy_id}" "true" | curl -k --silent --user "${ELASTIC_USERNAME}:${ELASTIC_PASSWORD}" -XPOST "${HEADERS[@]}" "${LOCAL_KBN_URL}/api/fleet/package_policies" -d @- | jq
}
clear_documents() {
if (($(curl -k --silent "${HEADERS[@]}" --user "${ELASTIC_USERNAME}:${ELASTIC_PASSWORD}" -X DELETE "https://${ipvar}:9200/_data_stream/logs-*" | grep -c "true") > 0)); then
printf "Successfully cleared logs data stream"
else
printf "Failed to clear logs data stream"
fi
echo
if (($(curl -k --silent "${HEADERS[@]}" --user "${ELASTIC_USERNAME}:${ELASTIC_PASSWORD}" -X DELETE "https://${ipvar}:9200/_data_stream/metrics-*" | grep -c "true") > 0)); then
printf "Successfully cleared metrics data stream"
else
printf "Failed to clear metrics data stream"
fi
echo
}
# Logic to enable the verbose output if needed
OPTIND=1 # Reset in case getopts has been used previously in the shell.
verbose=0
while getopts "v" opt; do
case "$opt" in
v)
verbose=1
;;
*) ;;
esac
done
shift $((OPTIND - 1))
[ "${1:-}" = "--" ] && shift
ACTION="${*:-help}"
if [ $verbose -eq 1 ]; then
exec 3<>/dev/stderr
else
exec 3<>/dev/null
fi
if docker compose >/dev/null; then
COMPOSE="docker compose"
elif command -v docker-compose >/dev/null; then
COMPOSE="docker-compose"
else
echo "elastic-container requires docker compose!"
exit 2
fi
case "${ACTION}" in
"stage")
# Collect the Elastic, Kibana, and Elastic-Agent Docker images
docker pull "docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}"
docker pull "docker.elastic.co/kibana/kibana:${STACK_VERSION}"
docker pull "docker.elastic.co/beats/elastic-agent:${STACK_VERSION}"
;;
"start")
passphrase_reset
get_host_ip
echo "Starting Elastic Stack network and containers."
${COMPOSE} up -d --no-deps
configure_kbn 1>&2 2>&3
echo "Waiting 40 seconds for Fleet Server setup."
echo
sleep 40
echo "Populating Fleet Settings."
set_fleet_values > /dev/null 2>&1
echo
echo "READY SET GO!"
echo
echo "Browse to https://localhost:${KIBANA_PORT}"
echo "Username: ${ELASTIC_USERNAME}"
echo "Passphrase: ${ELASTIC_PASSWORD}"
echo
;;
"stop")
echo "Stopping running containers."
${COMPOSE} stop
;;
"destroy")
echo "#####"
echo "Stopping and removing the containers, network, and volumes created."
echo "#####"
${COMPOSE} down -v
;;
"restart")
echo "#####"
echo "Restarting all Elastic Stack components."
echo "#####"
${COMPOSE} restart elasticsearch kibana fleet-server
;;
"status")
${COMPOSE} ps | grep -v setup
;;
"clear")
clear_documents
;;
"help")
usage
;;
*)
echo -e "Proper syntax not used. See the usage\n"
usage
;;
esac
# Close FD 3
exec 3>&-