Skip to content

Commit f9a5abf

Browse files
flaviomutti-sysdigDavide Schiera
authored andcommitted
Get image profiles from secure (#96)
1 parent e637886 commit f9a5abf

File tree

2 files changed

+225
-0
lines changed

2 files changed

+225
-0
lines changed

examples/list_profiles.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/usr/bin/env python
2+
#
3+
# List the current set of image profiles.
4+
#
5+
6+
import os
7+
import sys
8+
import json
9+
sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..'))
10+
from sdcclient import SdSecureClient
11+
12+
13+
def usage():
14+
print('usage: %s <secure-endpoint> <sysdig-token>' % sys.argv[0])
15+
sys.exit(1)
16+
17+
18+
#
19+
# Check number of parameters
20+
#
21+
if len(sys.argv) < 2:
22+
usage()
23+
24+
sdc_endpoint = sys.argv[1]
25+
sdc_token = sys.argv[2]
26+
27+
#
28+
# Instantiate the SDC client
29+
#
30+
sdclient = SdSecureClient(sdc_token, sdc_endpoint)
31+
32+
#
33+
# Retrieve all the image profiles
34+
#
35+
ok, res = sdclient.list_image_profiles()
36+
37+
38+
if not ok:
39+
print(res)
40+
sys.exit(1)
41+
42+
43+
# Strip the surrounding json to only keep the list of profiles
44+
res = res['profiles']
45+
46+
for profile in res:
47+
print("ID: {}, Name: {}".format(profile["profileId"], profile["imageName"]))

sdcclient/_secure.py

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,3 +974,181 @@ def get_command_audit(self, id, metrics=[]):
974974
metrics="&metrics=" + json.dumps(metrics) if metrics else "")
975975
res = requests.get(url, headers=self.hdrs, verify=self.ssl_verify)
976976
return self._request_result(res)
977+
978+
def list_image_profiles(self):
979+
'''**Description**
980+
List the current set of image profiles.
981+
982+
**Arguments**
983+
- None
984+
985+
**Success Return Value**
986+
A JSON object containing the details of each profile.
987+
988+
'''
989+
url = "{url}/api/profiling/v1/secure/profileGroups/0/profiles".format(
990+
url = self.url
991+
)
992+
993+
res = requests.get(url, headers=self.hdrs, verify=self.ssl_verify)
994+
return self._request_result(res)
995+
996+
997+
def get_image_profile(self, profileId):
998+
'''**Description**
999+
Find the image profile with a (partial) profile ID <profileId> and return its json description.
1000+
1001+
**Arguments**
1002+
- name: the name of the image profile to fetch
1003+
1004+
**Success Return Value**
1005+
A JSON object containing the description of the image profile. If there is no image profile with
1006+
the given name, returns False. Moreover, it could happen that more than one profile IDs have a collision.
1007+
It is due to the fact that a partial profile ID can be passed and interpreted; in this case a set of
1008+
collision profiles is returned, and the full complete ID string is printed. In this case, it returns
1009+
false.
1010+
1011+
'''
1012+
1013+
# RETRIEVE ALL THE IMAGE PROFILES
1014+
ok, image_profiles = self.list_image_profiles()
1015+
1016+
if not ok:
1017+
return [False, self.lasterr]
1018+
1019+
1020+
'''
1021+
The content of the json stored in the image_profiles dictionary:
1022+
1023+
{
1024+
"offset": 0,
1025+
"limit": 99,
1026+
"canLoadMore": false,
1027+
"profiles": [
1028+
...
1029+
]
1030+
}
1031+
'''
1032+
1033+
matched_profiles = self.__get_matched_profileIDs(profileId, image_profiles['profiles'])
1034+
1035+
# Profile ID not found
1036+
if len(matched_profiles) == 0:
1037+
return [False, "No profile with ID {}".format(profileId)]
1038+
1039+
# Principal workflow. Profile ID found
1040+
elif len(matched_profiles) == 1:
1041+
# Matched id. Return information
1042+
url = "{url}/api/profiling/v1/secure/profiles/{profileId}".format(
1043+
url = self.url,
1044+
profileId = matched_profiles[0]['profileId']
1045+
)
1046+
1047+
res = requests.get(url, headers=self.hdrs, verify=self.ssl_verify)
1048+
return self._request_result(res)
1049+
1050+
# Collision detected. The full profile IDs are returned
1051+
elif len(matched_profiles) >= 2:
1052+
return [False, matched_profiles]
1053+
1054+
1055+
def __get_matched_profileIDs(self, requested_profile, profile_list):
1056+
'''
1057+
**Description**
1058+
Helper function for retrieving the list of matching profile
1059+
1060+
**Arguments**
1061+
- the requested profile Id (string)
1062+
- List of dictionary, where each dictionary contains the profile information
1063+
1064+
**Success Return Value**
1065+
List of dictionary, where each dictionary represents a profile with the ID prefix substring
1066+
matching the requested one
1067+
1068+
**Content structure of the profile_list parameter**
1069+
This array of profiles contains all the relevant information. For the purposes of this function, only
1070+
the profileId field is relevant.
1071+
1072+
[
1073+
{
1074+
"profileGroupId": 0,
1075+
"profileId": "00000000000000000000000000000000000000000000",
1076+
"profileVersion": 0,
1077+
"profileName": "AAA/BBB:XYZ@0000000000000000000000",
1078+
"imageId": "00000000000000000000000000000000000000000000",
1079+
"imageName": "AAA/BBB:XYZ",
1080+
"processesProposal": {
1081+
"subcategories": [
1082+
{
1083+
"name": "process",
1084+
"ruleName": "process - 00000000000000000000000000000000000000000000",
1085+
"ruleType": "PROCESS",
1086+
"score": 000
1087+
}
1088+
],
1089+
"score": 000
1090+
},
1091+
"fileSystemProposal": {
1092+
"subcategories": [
1093+
{
1094+
"name": "filesystem",
1095+
"ruleName": "filesystem - 00000000000000000000000000000000000000000000",
1096+
"ruleType": "FILESYSTEM",
1097+
"score": 000
1098+
}
1099+
],
1100+
"score": 000
1101+
},
1102+
"syscallProposal": {
1103+
"subcategories": [
1104+
{
1105+
"name": "syscalls",
1106+
"ruleName": "syscalls - 00000000000000000000000000000000000000000000",
1107+
"ruleType": "SYSCALL",
1108+
"score": 000
1109+
}
1110+
],
1111+
"score": 000
1112+
},
1113+
"networkProposal": {
1114+
"subcategories": [
1115+
{
1116+
"name": "network",
1117+
"ruleName": "network - 00000000000000000000000000000000000000000000",
1118+
"ruleType": "NETWORK",
1119+
"score": 000
1120+
}
1121+
],
1122+
"score": 000
1123+
},
1124+
"containerImagesProposal": {
1125+
"subcategories": [
1126+
{
1127+
"name": "container image",
1128+
"ruleName": "container image - 00000000000000000000000000000000000000000000",
1129+
"ruleType": "CONTAINER",
1130+
"score": 0
1131+
}
1132+
],
1133+
"score": 0
1134+
},
1135+
"status": "STATUS_VALUE",
1136+
"score": 000
1137+
},
1138+
...
1139+
]
1140+
'''
1141+
1142+
matched_profiles = []
1143+
1144+
request_len = len(requested_profile)
1145+
for profile in profile_list:
1146+
1147+
# get the length of the substring to match
1148+
str_len_match = min(len(profile), request_len)
1149+
1150+
if profile['profileId'][0:str_len_match] == requested_profile[0:str_len_match]:
1151+
matched_profiles.append(profile)
1152+
1153+
return matched_profiles
1154+

0 commit comments

Comments
 (0)