Skip to content

Commit 8cc28cd

Browse files
content-botSergeBakharevAradCarmi
authored
Docker Engine API improvements (demisto#19747) (demisto#20009)
* Revised documentation added CA Cert parm * copy/paste error * more copy/paste * added registry auth capability and image commands * better context output * need image before can create container with it * added command examples and requirements * removed my name from docs * 1.1.0 release notes * revise version to 1.1.0 * type9 inputs * use the sshkey attribute of saved cred for private key * Update Packs/DevSecOps/Integrations/DockerEngine/DockerEngine.py Co-authored-by: Arad Carmi <[email protected]> * Update Packs/DevSecOps/ReleaseNotes/1_1_0.md Co-authored-by: Arad Carmi <[email protected]> * Update Packs/DevSecOps/Integrations/DockerEngine/DockerEngine.yml Co-authored-by: Arad Carmi <[email protected]> * python image bump to 3.10.5.31928 * bump docker image in release note Co-authored-by: Arad Carmi <[email protected]> Co-authored-by: aradcarmi <[email protected]> Co-authored-by: SergeBakharev <[email protected]> Co-authored-by: Arad Carmi <[email protected]> Co-authored-by: aradcarmi <[email protected]>
1 parent 924991c commit 8cc28cd

File tree

7 files changed

+659
-383
lines changed

7 files changed

+659
-383
lines changed

Packs/DevSecOps/Integrations/DockerEngine/DockerEngine.py

+57-20
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,40 @@
11
import urllib3
2+
from base64 import urlsafe_b64encode
23

34
from CommonServerPython import *
45

56

67
class Client:
7-
def __init__(self, server_url, verify, proxy, headers, client_cert, client_key):
8+
def __init__(self, server_url, verify, proxy, headers, client_cert, client_key, ca_cert):
9+
ca_cert_path = ''
10+
if ca_cert:
11+
ca_cert_path = 'ca.cert'
12+
with open(ca_cert_path, 'wb') as file:
13+
file.write(ca_cert.encode())
14+
self._verify = ca_cert_path
15+
else:
16+
self._verify = verify
817
self._base_url = server_url
9-
self._verify = verify
1018
self._proxy = proxy
11-
self._headers = headers
19+
self._headers = headers if headers else dict()
1220
self._client_cert = client_cert
1321
self._client_key = client_key
1422

23+
def reg_auth(self, identitytoken, registry_username, registry_password, registry_serveraddress):
24+
if identitytoken and any([registry_username, registry_password, registry_serveraddress]):
25+
raise ValueError(
26+
"Registry IdentityToken and Credential auth paramaters provided. \
27+
Can only use one authentication method not both.")
28+
if identitytoken:
29+
json_string = json.dumps({"identitytoken": identitytoken})
30+
self._headers['X-Registry-Auth'] = urlsafe_b64encode(json_string.encode('utf-8'))
31+
else:
32+
if not all([registry_username, registry_password, registry_serveraddress]):
33+
raise ValueError("Credential Auth method requires registry_username, registry_password, registry_serveraddress")
34+
json_string = json.dumps({"username": registry_username, "password": registry_password,
35+
"serveraddress": registry_serveraddress})
36+
self._headers['X-Registry-Auth'] = urlsafe_b64encode(json_string.encode('utf-8'))
37+
1538
def _http_request(self, method, url_suffix='', full_url=None, params=None, headers=None, data=None, json_data=None):
1639
address = full_url if full_url else urljoin(self._base_url, url_suffix)
1740
headers = headers if headers else self._headers
@@ -25,6 +48,7 @@ def _http_request(self, method, url_suffix='', full_url=None, params=None, heade
2548
client_key_path = 'client_key.key'
2649
with open(client_key_path, 'wb') as file:
2750
file.write(self._client_key.encode())
51+
2852
response = requests.session().request(
2953
method,
3054
address,
@@ -34,11 +58,16 @@ def _http_request(self, method, url_suffix='', full_url=None, params=None, heade
3458
json=json_data,
3559
headers=headers,
3660
cert=(client_cert_path, client_key_path),
37-
timeout=2,
38-
61+
timeout=None
3962
)
63+
64+
# Some docker commands return no data, just a status code.
65+
# Better pass the status code on as the result, rather than nothing
66+
if not response.content:
67+
return {'Status Code': response.status_code}
68+
4069
if response.headers.get('Content-Type') == 'application/json':
41-
return json.loads(response.content)
70+
return json.loads(response.content.splitlines()[-1]) # If content is jsonl, latest message is the most relevant
4271
else:
4372
return response.content
4473

@@ -212,7 +241,7 @@ def container_kill_request(self, id_, signal):
212241
return response
213242

214243
def container_list_request(self, list_all, limit, size, filters):
215-
params = assign_params(list_all=list_all, limit=limit, size=size, filters=filters)
244+
params = assign_params(all=list_all, limit=limit, size=size, filters=filters)
216245

217246
headers = self._headers
218247

@@ -457,15 +486,14 @@ def image_commit_request(self, containerconfig_hostname, containerconfig_domainn
457486

458487
return response
459488

460-
def image_create_request(self, from_image, from_src, repo, tag, message, input_image, platform):
461-
params = assign_params(from_image=from_image, from_src=from_src, repo=repo, tag=tag, message=message,
489+
def image_create_request(self, from_image, from_src, repo, tag, message, platform):
490+
params = assign_params(fromImage=from_image, fromSrc=from_src, repo=repo, tag=tag, message=message,
462491
platform=platform)
463-
data = assign_params(input_image=input_image)
464492

465493
headers = self._headers
466494
headers['Content-Type'] = 'text/plain'
467495

468-
response = self._http_request('post', 'images/create', params=params, json_data=data, headers=headers)
496+
response = self._http_request('post', 'images/create', params=params, headers=headers)
469497

470498
return response
471499

@@ -1230,7 +1258,7 @@ def container_delete_command(client, args):
12301258

12311259
response = client.container_delete_request(id_, v, force, link)
12321260
command_results = CommandResults(
1233-
outputs_prefix='Docker',
1261+
outputs_prefix='Docker.ContainerDelete',
12341262
outputs_key_field='',
12351263
outputs=response,
12361264
raw_response=response
@@ -1789,13 +1817,12 @@ def image_create_command(client, args):
17891817
repo = str(args.get('repo', ''))
17901818
tag = str(args.get('tag', ''))
17911819
message = str(args.get('message', ''))
1792-
input_image = str(args.get('input_image', ''))
17931820
platform = str(args.get('platform', ''))
17941821

1795-
response = client.image_create_request(from_image, from_src, repo, tag, message, input_image, platform)
1822+
response = client.image_create_request(from_image, from_src, repo, tag, message, platform)
17961823
command_results = CommandResults(
1797-
outputs_prefix='Docker',
1798-
outputs_key_field='',
1824+
outputs_prefix='Docker.ImageCreate',
1825+
outputs_key_field='Status',
17991826
outputs=response,
18001827
raw_response=response
18011828
)
@@ -1926,7 +1953,7 @@ def image_push_command(client, args):
19261953

19271954
response = client.image_push_request(name, tag)
19281955
command_results = CommandResults(
1929-
outputs_prefix='Docker',
1956+
outputs_prefix='Docker.ImagePush',
19301957
outputs_key_field='',
19311958
outputs=response,
19321959
raw_response=response
@@ -1958,7 +1985,7 @@ def image_tag_command(client, args):
19581985

19591986
response = client.image_tag_request(name, repo, tag)
19601987
command_results = CommandResults(
1961-
outputs_prefix='Docker',
1988+
outputs_prefix='Docker.ImageTag',
19621989
outputs_key_field='',
19631990
outputs=response,
19641991
raw_response=response
@@ -2866,17 +2893,27 @@ def main():
28662893
args = demisto.args()
28672894
url = params.get('url')
28682895
client_cert = params.get('client_certificate')
2869-
client_key = params.get('client_key')
2896+
client_key = params.get('client_key', {}).get('credentials', {}).get('sshkey')
2897+
ca_cert = params.get('ca_certificate')
28702898
verify_certificate = not params.get('insecure', False)
28712899
proxy = params.get('proxy', False)
2900+
identitytoken = params.get('identitytoken', False)
2901+
registry_username = params.get('Registry Username', {}).get('identifier', False)
2902+
registry_password = params.get('Registry Username', {}).get('password', False)
2903+
registry_serveraddress = params.get('registry_serveraddress', False)
28722904

28732905
command = demisto.command()
28742906
LOG(f'Command being called is {command}')
28752907

28762908
try:
28772909
urllib3.disable_warnings()
28782910
client = Client(urljoin(url, "/v1.41"), verify_certificate, proxy, headers=None,
2879-
client_cert=client_cert, client_key=client_key)
2911+
client_cert=client_cert, client_key=client_key, ca_cert=ca_cert)
2912+
2913+
if any([identitytoken, registry_username, registry_password, registry_serveraddress]):
2914+
client.reg_auth(identitytoken=identitytoken, registry_username=registry_username,
2915+
registry_password=registry_password, registry_serveraddress=registry_serveraddress)
2916+
28802917
commands = {
28812918
'docker-build-prune': build_prune_command,
28822919
'docker-config-create': config_create_command,

0 commit comments

Comments
 (0)