-
Notifications
You must be signed in to change notification settings - Fork 2
/
cef_installer.py
339 lines (295 loc) · 13.5 KB
/
cef_installer.py
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
#! /usr/local/bin/python3
# ----------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# ----------------------------------------------------------------------------
# This script is used to install CEF agent on a linux machine an configure the
# syslog daemon on the linux machine.
# Supported OS:
# 64-bit
# CentOS 6 and 7
# Amazon Linux 2017.09
# Oracle Linux 6 and 7
# Red Hat Enterprise Linux Server 6 and 7
# Debian GNU/Linux 8 and 9
# Ubuntu Linux 14.04 LTS, 16.04 LTS and 18.04 LTS
# SUSE Linux Enterprise Server 12
# 32-bit
# CentOS 6
# Oracle Linux 6
# Red Hat Enterprise Linux Server 6
# Debian GNU/Linux 8 and 9
# Ubuntu Linux 14.04 LTS and 16.04 LTS
# For more information please check the OMS-Agent-for-Linux documentation.
#
# Daemon versions:
# Syslog-ng: 2.1 - 3.22.1
# Rsyslog: v8
import subprocess
import time
import sys
rsyslog_daemon_name = "rsyslog"
syslog_ng_daemon_name = "syslog-ng"
omsagent_file_name = "onboard_agent.sh"
oms_agent_url = "https://raw.githubusercontent.com/Microsoft/OMS-Agent-for-Linux/master/installer/scripts/" + omsagent_file_name
help_text = "Optional arguments for the python script are:\n\t-T: for TCP\n\t-U: for UDP which is the default value.\n\t-F: for no facility restrictions.\n\t-p: for changing default port from 25226"
omsagent_default_incoming_port = "25226"
daemon_default_incoming_port = "514"
rsyslog_daemon_forwarding_configuration_path = "/etc/rsyslog.d/security-config-omsagent.conf"
rsyslog_conf_path = "/etc/rsyslog.conf"
syslog_ng_conf_path = "/etc/syslog-ng/syslog-ng.conf"
rsyslog_module_udp_content = "# provides UDP syslog reception\nmodule(load=\"imudp\")\ninput(type=\"imudp\" port=\"" + daemon_default_incoming_port + "\")\n"
rsyslog_module_tcp_content = "# provides TCP syslog reception\nmodule(load=\"imtcp\")\ninput(type=\"imtcp\" port=\"" + daemon_default_incoming_port + "\")\n"
rsyslog_old_config_udp_content = "# provides UDP syslog reception\n$ModLoad imudp\n$UDPServerRun " + daemon_default_incoming_port + "\n"
rsyslog_old_config_tcp_content = "# provides TCP syslog reception\n$ModLoad imtcp\n$InputTCPServerRun " + daemon_default_incoming_port + "\n"
oms_agent_configuration_url = "https://raw.githubusercontent.com/microsoft/OMS-Agent-for-Linux/master/installer/conf/omsagent.d/security_events.conf"
def print_error(input_str):
'''
Print given text in red color for Error text
:param input_str:
'''
print("\033[1;31;40m" + input_str + "\033[0m")
def print_ok(input_str):
'''
Print given text in green color for Ok text
:param input_str:
'''
print("\033[1;32;40m" + input_str + "\033[0m")
def print_warning(input_str):
'''
Print given text in yellow color for warning text
:param input_str:
'''
print("\033[1;33;40m" + input_str + "\033[0m")
def print_notice(input_str):
'''
Print given text in white background
:param input_str:
'''
print("\033[0;30;47m" + input_str + "\033[0m")
def print_command_response(input_str):
'''
Print given text in green color for Ok text
:param input_str:
'''
print("\033[1;34;40m" + input_str + "\033[0m")
def handle_error(e, error_response_str):
error_output = e.decode('ascii')
print_error(error_response_str)
print_error(error_output)
return False
def process_check(process_name):
'''
function who check using the ps -ef command if the 'process_name' is running
:param process_name:
:return: True if the process is running else False
'''
p1 = subprocess.Popen(["ps", "-ef"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["grep", "-i", process_name], stdin=p1.stdout, stdout=subprocess.PIPE)
o, e = p2.communicate()
tokens = o.decode('ascii').split('\n')
tokens.remove('')
return len(tokens)
def create_daemon_forwarding_configuration(omsagent_incoming_port, daemon_configuration_path, daemon_name):
'''
Create the daemon configuration to forward messages over TCP to the
oms agent
:param omsagent_incoming_port: port for communication between the omsagent the the daemon
:param daemon_configuration_path: path of the configuration file
:param daemon_name: name of the daemon
:return:
'''
print("Creating " + daemon_name + " daemon configuration.")
print("Configuration is changed to forward daemon incoming syslog messages into the omsagent.")
print("Every command containing \'CEF\' string will be forwarded.")
print("Path:")
print_notice(daemon_configuration_path)
file_content = get_daemon_configuration_content(daemon_name, omsagent_incoming_port)
append_content_to_file(file_content, daemon_configuration_path, overide=True)
print_ok("Configuration for " + daemon_name + " daemon was changed successfully.")
return True
def set_omsagent_configuration(workspace_id, omsagent_incoming_port):
'''
Download the omsagent configuration and then change the omsagent incoming port
if required and change the protocol if required
:param workspace_id:
:param omsagent_incoming_port:
:param tcp:
:param udp:
:return:
'''
configuration_path = "/etc/opt/microsoft/omsagent/" + workspace_id + "/conf/omsagent.d/security_events.conf"
print("Creating omsagent configuration to listen to syslog daemon forwarding port - " + omsagent_incoming_port)
print("Configuration location is - " + configuration_path)
command_tokens = ["sudo", "wget", "-O", configuration_path, oms_agent_configuration_url]
print("Download configuration into the correct directory")
print_notice(" ".join(command_tokens))
time.sleep(3)
set_omsagent_configuration_command = subprocess.Popen(command_tokens, stdout=subprocess.PIPE)
o, e = set_omsagent_configuration_command.communicate()
if e is not None:
handle_error(e, error_response_str="Error: could not download omsagent configuration.")
return False
print_ok("Configuration for omsagent downloaded successfully.")
print("Trying to changed omsagent configuration")
if omsagent_incoming_port is not omsagent_default_incoming_port:
if change_omsagent_configuration_port(omsagent_incoming_port=omsagent_incoming_port, configuration_path=configuration_path):
print_ok("Incoming port for omsagent was changed to " + omsagent_incoming_port)
else:
print_error("Could not change omsagent incoming port")
if change_omsagent_protocol(configuration_path=configuration_path):
print_ok("Finished changing omsagent configuration")
return True
else:
print_error("Could not change the omsagent configuration")
return False
def is_rsyslog_new_configuration():
with open(rsyslog_conf_path, "rt") as fin:
for line in fin:
if "module" in line and "load" in line:
return True
fin.close()
return False
def set_rsyslog_new_configuration():
with open(rsyslog_conf_path, "rt") as fin:
with open("tmp.txt", "wt") as fout:
for line in fin:
if "imudp" in line or "imtcp" in line:
fout.write(line.replace("#", "")) if "#" in line else fout.write(line)
else:
fout.write(line)
command_tokens = ["sudo", "mv", "tmp.txt", rsyslog_conf_path]
write_new_content = subprocess.Popen(command_tokens, stdout=subprocess.PIPE)
time.sleep(3)
o, e = write_new_content.communicate()
if e is not None:
handle_error(e, error_response_str="Error: could not change Rsyslog.conf configuration in -" + rsyslog_conf_path)
return False
print_ok("Rsyslog.conf configuration was changed to fit required protocol - " + rsyslog_conf_path)
return True
def append_content_to_file(line, file_path, overide = False):
command_tokens = ["sudo", "bash", "-c", "printf '" + "\n" + line + "' >> " + file_path] if not overide else ["sudo", "bash", "-c", "printf '" + "\n" + line + "' > " + file_path]
write_new_content = subprocess.Popen(command_tokens, stdout=subprocess.PIPE)
time.sleep(3)
o, e = write_new_content.communicate()
if e is not None:
handle_error(e, error_response_str="Error: could not change Rsyslog.conf configuration add line \"" + line + "\" to file -" + rsyslog_conf_path)
return False
return True
def set_rsyslog_old_configuration():
add_udp = False
add_tcp = False
with open(rsyslog_conf_path, "rt") as fin:
for line in fin:
if "imudp" in line or "UDPServerRun" in line:
add_udp = True if "#" in line else False
elif "imtcp" in line or "InputTCPServerRun" in line:
add_tcp = True if "#" in line else False
fin.close()
if add_udp is True:
append_content_to_file(rsyslog_old_config_udp_content, rsyslog_conf_path)
if add_tcp:
append_content_to_file(rsyslog_old_config_tcp_content, rsyslog_conf_path)
print_ok("Rsyslog.conf configuration was changed to fit required protocol - " + rsyslog_conf_path)
return True
def set_rsyslog_configuration():
'''
Set the configuration for rsyslog
we support from version 7 and above
:return:
'''
if is_rsyslog_new_configuration():
set_rsyslog_new_configuration()
else:
set_rsyslog_old_configuration()
def change_omsagent_protocol(configuration_path):
'''
Changing the omsagent protocol, since the protocol type is set on the omsagent
configuration file
:param configuration_path:
'''
try:
# if opening this file failed the installation of the oms-agent has failed
fin = open(configuration_path, "rt")
with open("tmp.txt", "wt") as fout:
for line in fin:
if "protocol_type" in line and "udp" in line:
fout.write(line.replace("udp", "tcp"))
print_notice("Changing protocol type from udp to tcp in "+configuration_path)
print("Line changed: " + line)
else:
fout.write(line)
except IOError:
print_error("Oms-agent installation has failed please remove oms-agent and try again.")
return False
command_tokens = ["sudo", "mv", "tmp.txt", configuration_path]
write_new_content = subprocess.Popen(command_tokens, stdout=subprocess.PIPE)
time.sleep(3)
o, e = write_new_content.communicate()
if e is not None:
handle_error(e, error_response_str="Error: could not change omsagent configuration port in ." + configuration_path)
return False
print_ok("Omsagent configuration was changed to fit required protocol - " + configuration_path)
return True
def change_omsagent_configuration_port(omsagent_incoming_port, configuration_path):
'''
Changing the omsagent configuration port if required
:param omsagent_incoming_port:
:param configuration_path:
'''
with open(configuration_path, "rt") as fin:
with open("tmp.txt", "wt") as fout:
for line in fin:
fout.write(line.replace(omsagent_default_incoming_port, omsagent_incoming_port))
command_tokens = ["sudo", "mv", "tmp.txt", configuration_path]
write_new_content = subprocess.Popen(command_tokens, stdout=subprocess.PIPE)
time.sleep(3)
o, e = write_new_content.communicate()
if e is not None:
handle_error(e, error_response_str="Error: could not change omsagent configuration port in ." + configuration_path)
return False
print_ok("Omsagent incoming port was changed in configuration - " + configuration_path)
return True
def restart_rsyslog():
'''
Restart the Rsyslog daemon
'''
print("Restarting rsyslog daemon.")
command_tokens = ["sudo", "service", "rsyslog", "restart"]
print_notice(" ".join(command_tokens))
restart_rsyslog_command = subprocess.Popen(command_tokens, stdout=subprocess.PIPE)
time.sleep(3)
o, e = restart_rsyslog_command.communicate()
if e is not None:
handle_error(e, error_response_str="Could not restart rsyslog daemon")
return False
print_ok("Rsyslog daemon restarted successfully")
return True
def get_daemon_configuration_content(daemon_name, omsagent_incoming_port):
'''
Return the correct configuration according to the daemon name
:param daemon_name:
:param omsagent_incoming_port:
:return:
'''
if daemon_name is rsyslog_daemon_name:
return get_rsyslog_daemon_configuration_content(omsagent_incoming_port)
elif daemon_name is syslog_ng_daemon_name:
return get_syslog_ng_damon_configuration_content(omsagent_incoming_port)
else:
print_error("Could not create daemon configuration.")
return False
def get_rsyslog_daemon_configuration_content(omsagent_incoming_port):
'''Rsyslog accept every message containing CEF'''
rsyslog_daemon_configuration_content = ":rawmsg, regex, \"CEF\|ASA\" ~\n*.* @@127.0.0.1:"+ omsagent_incoming_port
print("Rsyslog daemon configuration content:")
content = rsyslog_daemon_configuration_content
print_command_response(content)
return content
def main():
omsagent_incoming_port = omsagent_default_incoming_port
port_argument = False
create_daemon_forwarding_configuration(omsagent_incoming_port=omsagent_incoming_port,
daemon_configuration_path=rsyslog_daemon_forwarding_configuration_path,
daemon_name=rsyslog_daemon_name)
set_rsyslog_configuration()
main()