-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathendpoint_agent_health.py
215 lines (207 loc) · 10 KB
/
endpoint_agent_health.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
from pprint import pprint
import requests
from getpass import getpass
from datetime import datetime, timedelta, timezone
from collections import defaultdict
## Set variable for a timeframe of the past 7 days
datecompare = datetime.now(timezone.utc) - timedelta(days=7)
datecompare = datecompare.strftime("%Y-%m-%d %H:%M:%S")
########################
### JIRA SERVER INFO ###
########################
jira_user = '[JIRA_Username]'
jira_password = '[JIRA_Password]'
jira_url = 'https://[JIRA_url]/rest/api/2/'
## In the call below we point to your inventory project, declare maximum results
## and specify a key. We used: project=INV, maxResults=5000, key=summary
inv_response = requests.get(jira_url + 'search?jql=project%3DINV&maxResults=5000&fields=key%2C%20summary',
auth=(jira_user, jira_password), headers={'Accept': 'application/json'})
jira_inventory = inv_response.json()
status = {}
###################
### CODE42 INFO ###
###################
username = '[Code42_API_User]'
c42passwd = getpass()
params = {'pgSize': '5000'}
c42response = requests.get('https://console.us.code42.com/api/Computer', auth=(username, c42passwd), params=params)
allinfo = c42response.json()
#################
### JAMF INFO ###
#################
user = '[JAMF_user]'
passwd = getpass()
jamfheaders = {
'Accept': 'application/json',
}
jamfurl = 'https://[JAMF_url]/JSSResource/'
response = requests.get(jamfurl + 'computers', headers=jamfheaders)
inventory = response.json()
########################
### CrowdStrike Info ###
########################
tokenheaders = {
'accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
}
tokendata = {
'client_id': '[CS_client_id]',
'client_secret': '[CS_client_secret]'
}
tokenresponse = requests.post('https://api.crowdstrike.com/oauth2/token', headers=tokenheaders, data=tokendata)
token = tokenresponse.json()
headers = {
'Accept': 'application/json',
'Authorization': 'Bearer ' + token['access_token'],
'cache-control': 'no-cache',
}
## That love letter I wrote? Here it is!
## Request a list of ALL unique CrowdStrike IDs registered to our account.
## Not currently used in our script, but very useful should you need it.
response = requests.get('https://api.crowdstrike.com/devices/queries/devices/v1?limit=5000', headers=headers)
csinfo = response.json()
correlation = {}
## Iterate through unique CrowdStrike IDs gathered in the step above
## Make an API call for each
for csids in csinfo['resources']:
compresponse = requests.get('https://api.crowdstrike.com/devices/entities/devices/v1?ids='
+ csids, headers=headers)
compinfo = compresponse.json()
try:
snumber = compinfo['resources'][0]['hostname']
except KeyError:
snumber = 'n/a'
correlation.update({snumber : compinfo['resources'][0]['device_id']})
###################################
### CrowdStrike Current Version ###
###################################
version_response = requests.get('https://api.crowdstrike.com/sensors/combined/installers/v1?limit=2&sort=release_date%7Cdesc&filter=platform%3A%22mac%22', headers=headers)
version_csinfo = version_response.json()
## Pull current CS agent version
current_version = (version_csinfo['resources'][0]['version'])
## Pull previous CS agent version.
current_version_minus = (version_csinfo['resources'][1]['version'])
#####################
### Umbrella Info ###
#####################
umbrellaurl = 'https://management.api.umbrella.com/v1/organizations/[Umbrella_org]/roamingcomputers'
umbrellaheaders = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': '[Basic_Umbrella_creds]'
}
umbrellaAll = defaultdict()
pagenum = 0
umbrellainventory = "true"
# Cisco updated their API so we iterate over each "page" of results and add them to a dictionary to use later
while umbrellainventory != []:
querystring = {'limit': '200', 'page': pagenum}
umbrellaresponse = requests.get(umbrellaurl, headers=umbrellaheaders, params=querystring)
umbrellainventory = umbrellaresponse.json()
# Gather potentially useful information and add it to a dictionary based on Computer Name
for entries in umbrellainventory:
computerName = entries['name']
deviceId = entries['deviceId']
lastSyncStatus = entries['lastSyncStatus']
lastSync = entries['lastSync']
osVersion = entries['osVersionName']
umbrellaAll[computerName] = {
'computerName': computerName,
'deviceId': deviceId,
'lastSyncStatus': lastSyncStatus,
'lastSync': lastSync,
'osVersion': osVersion
}
pagenum += 1
## Print CSV fields. Certainly room for doing this different ways
print("JAMF ID,User,SN,Deployment Status,JAMF last contact,"
"CS Agent ID,CrowdStrike last seen,CS Agent Status,Umbrella DeviceId,Umbrella last seen,"
"C42 UID,C42 last checkin,C42 Alert States")
## Iterate through results of our JIRA search from above.
for inv_count in jira_inventory['issues']:
comp_name = inv_count['fields']['summary']
ticket_num = inv_count['key']
## Pull custom "Computer Make" field within JIRA Inventory Project
comp_response = requests.get(jira_url + 'issue/' + ticket_num + '?fields=customfield_15402%2C%20customfield_15403',
auth=(jira_user, jira_password), headers={'Accept': 'application/json'})
comp_info = comp_response.json()
try:
comp_make = comp_info['fields']['customfield_15403']['value']
except TypeError:
comp_make = 'n/a'
## Gather computer deployment status
comp_status = comp_info['fields']['customfield_15402']['value']
status.update({comp_name : comp_status})
## Only care about Deployed Apple laptops
if comp_status == 'Deployed' and comp_make == 'Apple':
jamfstatus = requests.get(jamfurl + 'computers/name/' + comp_name, headers=jamfheaders)
jamfcompinfo = jamfstatus.json()
## Gather unique JAMF computer ID
compid = str(jamfcompinfo['computer']['general']['id'])
## Gather JAMF last checkin date and time
jamfcheckin = str(jamfcompinfo['computer']['general']['last_contact_time_utc'])
csuuid = "n/a"
user = "n/a"
cs_up_to_date = "n/a"
cslastseen = "n/a"
umbrellalastseen = "n/a"
umbrelladeviceid = "n/a"
## Gather User information from JAMF
if jamfcompinfo['computer']['location']['username']:
user = str(jamfcompinfo['computer']['location']['username'])
## Umbrella requires some special logic to match computers
## The Umbrella computer name depends on when during the computer standup
## process umbrella is installed.
try:
## Gather Umbrella last seen date and time using comp_name as the key for the Umbrella dictionary created above
umbrellalastseen = umbrellaAll[comp_name]['lastSync']
## Gather unique Umbrella DeviceID using comp_name as the key for the Umbrella dictionary created above
umbrelladeviceid = umbrellaAll[comp_name]['deviceId']
except:
continue
## We have a script in JAMF which has devices run a CS command and gather
## their unique CrowdStrike ID and store it in a custom attribute
## Here we iterate through thouse custom attributes to pull that CS ID
for extensions in jamfcompinfo['computer']['extension_attributes']:
if str(extensions['name']) == 'CrowdStrike Agent ID':
if str(extensions['value']) != '':
csuuid = str(extensions['value'])
csuuid = csuuid.lower()
csuuid = csuuid.replace('-', '')
try:
## API call to CrowdStrike with unique CS ID
csresponse = requests.get('https://api.crowdstrike.com/devices/entities/devices/v1?ids=' + csuuid,
headers=headers)
csinfo = csresponse.json()
if csinfo['resources'][0]['agent_version']:
##Set Agent Version
agent_version = csinfo['resources'][0]['agent_version']
## Check if agent update is needed
if agent_version[:-2] not in [current_version, current_version_minus]:
cs_up_to_date = "Needs Update - " + agent_version
## Check if CrowdStrike is up to date
elif agent_version[:-2] in [current_version, current_version_minus]:
cs_up_to_date = "OK - " + agent_version
## Gather CrowdStrike last checkin date and time
if csinfo['resources'][0]['last_seen']:
cslastseen = csinfo['resources'][0]['last_seen']
## Excemption for a device not being registered in CrowdStrike
except IndexError:
cslastseen = 'not in CrowdStrike'
c42alert = 'n/a'
c42checkin = 'n/a'
c42uid = 'n/a'
## Iterate through devices in Code42
for c42_count in allinfo['data']['computers']:
if comp_name == c42_count['osHostname']:
## Due to Legal Hold, Code42 can have more than one entry per
## device. To make sure we are reporting on an actively used
## device we look for devices which have checked in within 7 days
if datecompare <= str(c42_count['lastConnected']):
c42uid = str(c42_count['guid'])
c42checkin = str(c42_count['lastConnected'])
c42alert = str(c42_count['alertStates'])
## Print information gathered above
print(compid + ',' + user + ',' + comp_name + ',' + comp_status + ',' + jamfcheckin + ',' + csuuid + ','
+ cslastseen + ',' + cs_up_to_date + ',' + umbrelladeviceid + ',' + umbrellalastseen + ',' + c42uid
+ ',' + c42checkin + ',' + c42alert)