Skip to content

Commit 4fad268

Browse files
committed
connect all domains script
1 parent e04bc12 commit 4fad268

File tree

2 files changed

+357
-0
lines changed

2 files changed

+357
-0
lines changed

connect/README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# connect_all_domains
2+
3+
The following script connects all domains of a tenant's MDS to the cloud-services portal.
4+
5+
## Instructions
6+
Clone the repository with this command:
7+
```git
8+
git clone https://github.com/CheckPointSW/UsefulManagementApiTools
9+
```
10+
or by clicking the Download ZIP button.
11+
12+
Download and install the [Check Point API Python SDK](https://github.com/CheckPointSW/cp_mgmt_api_python_sdk)
13+
repository, follow the instructions in the SDK repository.
14+
15+
To create the required keys, you must go to [Check Point Infinity Portal](https://portal.checkpoint.com) -> Settings -> API Keys -> New -> New Account API Key.
16+
Then choose "Security Management" as the service.
17+
18+
## Usage Syntax
19+
20+
• --client_id: Required. The Client ID.
21+
22+
• --access_key: Required. The Access Key.
23+
24+
• --region: Required. The region. Choices are [ap, us, eu, uae, in].
25+
26+
• --server: The server IP address or hostname, required when running from remote.
27+
28+
• --api_key: The API Key, required when running from remote.
29+
30+
• --api_port: The API Port, required if running from remote, and it isn't the default value (443).
31+
32+
• --debug_file: API calls debug file name.
33+
34+
##Examples
35+
36+
• Running the script on the Multi-Domain Server:
37+
`python connect_all_domains.py --client_id <tenant_client_id> --access_key <tenant_access_key> --region eu --debug_file api_calls.json`
38+
39+
• Running the script from remote:
40+
`python connect_all_domains.py --client_id <tenant_client_id> --access_key <tenant_access_key> --region eu --server 192.168.1.1 --api_key <your_api_key> --api_port 8080`
41+
42+
## Development Environment
43+
44+
The tool is developed using Python language version 3.7 and [Check Point API Python SDK.](https://github.com/CheckPoint-APIs-Team/cpapi-python-sdk)
45+
46+
##Note
47+
48+
In order to run the script, explicit consent must be given.
49+
The connect_all_domains.log and api debug files will be created in project location.

connect/connect_all_domains.py

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
import argparse
2+
import os
3+
import ssl
4+
import subprocess
5+
import time
6+
7+
from cpapi import APIClient, APIClientArgs
8+
import http.client
9+
import json
10+
import logging
11+
import sys
12+
from logging.handlers import RotatingFileHandler
13+
14+
CURL_CLI = '$MDS_FWDIR/bin/curl_cli'
15+
16+
CONSENT_MESSAGE = "I wish to connect my Self-Hosted Security Management environment and Security Gateways to the" \
17+
" Infinity Portal. These will share with Check Point information which may include personal data and" \
18+
" which will be processed per Check Point’s Privacy Policy.\n" \
19+
"I understand that when connecting multiple Security Managements, data may be shared between them."
20+
21+
DEFAULT_API_PORT = 443
22+
LOCAL_HOST_IP = "127.0.0.1"
23+
LOCAL_HOST = "localhost"
24+
SYSTEM_DATA = "System Data"
25+
26+
27+
CI_URL_MAP = {
28+
"ap": "cloudinfra-gw.ap.portal.checkpoint.com",
29+
"us": "cloudinfra-gw-us.portal.checkpoint.com",
30+
"eu": "cloudinfra-gw.portal.checkpoint.com",
31+
"uae": "cloudinfra-gw.ae.portal.checkpoint.com",
32+
"in": "cloudinfra-gw.in.portal.checkpoint.com"
33+
}
34+
35+
36+
def make_http_request(method, endpoint, headers, data=None):
37+
if server == LOCAL_HOST_IP or server == LOCAL_HOST:
38+
return make_http_request_from_server(method, endpoint, headers, data)
39+
return make_http_request_from_remote(method, endpoint, headers, data)
40+
41+
42+
def make_http_request_from_remote(method, endpoint, headers, data=None):
43+
conn = http.client.HTTPSConnection(ci_url)
44+
conn.request(method, endpoint, body=data, headers=headers)
45+
response = conn.getresponse()
46+
status_code = response.status
47+
content = response.read().decode()
48+
conn.close()
49+
50+
return status_code, content
51+
52+
53+
def make_http_request_from_server(method, endpoint, headers, data=None):
54+
command = CURL_CLI + " --cacert $CPDIR/conf/ca-bundle-public-cloud.crt -w \"\\nCODE:%{http_code}\\n\""
55+
command += f" -X {method} https://{ci_url}{endpoint}"
56+
for key, value in headers.items():
57+
command += f" -H '{key}: {value}'"
58+
command += f" -d '{data}'"
59+
if proxy and proxy_port:
60+
command += f" -x http://{proxy}:{proxy_port}"
61+
62+
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
63+
output, err = p.communicate()
64+
p.wait()
65+
if p.returncode != 0:
66+
logger.error("Failed to run command {}, failure reason is {} ".format(command, err))
67+
logger.debug("json_string is {} ".format(output))
68+
try:
69+
json_temp = output.decode("utf-8")
70+
code = json_temp.split("CODE:")[1]
71+
logger.info("Status code: " + code)
72+
json_temp = json_temp.strip("\\nCODE:"+code+"\\n")
73+
return int(code.strip()), json_temp
74+
75+
except ValueError as ex:
76+
logger.error(output)
77+
78+
79+
def add_om_prem(jwt, domain):
80+
headers = {
81+
'Content-Type': 'application/json',
82+
'Authorization': 'Bearer {}'.format(jwt),
83+
'User-Agent': 'connect-all-domains'
84+
}
85+
86+
data = json.dumps({
87+
"name": domain,
88+
"isCloudMgmtService": False,
89+
"consent": True
90+
})
91+
92+
code, content = make_http_request("POST", "/app/maas/api/v2/environments/", headers, data)
93+
94+
if code == 200:
95+
logger.info(f'Successfully added MGMT instance of domain: {domain}')
96+
content = json.loads(content)
97+
return content['data']['authToken']['token']
98+
else:
99+
logger.error(f'Failed to add MGMT instance for domain {domain}')
100+
return None
101+
102+
103+
def get_jwt():
104+
headers = {
105+
'Content-Type': 'application/json',
106+
'User-Agent': 'connect-all-domains'
107+
}
108+
109+
data = json.dumps({
110+
"clientId": client_id,
111+
"accessKey": access_key
112+
})
113+
114+
code, content = make_http_request("POST", "/auth/external", headers, data)
115+
if code == 200 or (code == 302 and proxy and proxy_port):
116+
logger.info("Successfully created external jwt from given keys")
117+
content = json.loads(content)
118+
return content['data']['token']
119+
else:
120+
logger.error("Failed to create external jwt from given keys with the following error: {}".format(content))
121+
exit(1)
122+
123+
124+
def logger_configuration():
125+
log_backup_count = 3
126+
script_dir = os.path.dirname(os.path.abspath(__file__))
127+
log_file = os.path.join(script_dir, 'connect_all_domains.log')
128+
log_max_bytes = 10_000_000_000
129+
log_formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s")
130+
logging_handler = RotatingFileHandler(log_file, maxBytes=log_max_bytes, backupCount=log_backup_count)
131+
logging_handler.setFormatter(log_formatter)
132+
logging_handler.setLevel(logging.DEBUG)
133+
logger = logging.getLogger('root')
134+
logger.setLevel(logging.INFO)
135+
logger.addHandler(logging_handler)
136+
137+
return logger
138+
139+
140+
def user_consent():
141+
print("Connect my Self-hosted Security Management environment and Security Gateways to Infinity")
142+
print(CONSENT_MESSAGE)
143+
consent = input("Do you agree? y/n: ")
144+
logger.info("User must agree to the following message:\n {}".format(CONSENT_MESSAGE))
145+
logger.info("User's response: {}".format(consent))
146+
if consent.lower() != "y":
147+
raise Exception("Consent must be given in order to run this script")
148+
149+
150+
def get_args(args):
151+
if args:
152+
parser = argparse.ArgumentParser()
153+
parser.add_argument("--client_id", type=str, action="store", help="Client Id", dest="client_id", required=True)
154+
parser.add_argument("--access_key", type=str, action="store", help="Access Key", dest="access_key",
155+
required=True)
156+
parser.add_argument("--region", type=str, action="store", help="Region", dest="region",
157+
choices=['ap', 'us', 'eu', 'uae', 'in'], required=True)
158+
parser.add_argument("--server", type=str, action="store", help="Server IP address or hostname, must be given "
159+
"when running from remote", dest="server")
160+
parser.add_argument("--api_key", type=str, action="store",
161+
help="Api-Key must be given when running from remote", dest="api_key")
162+
parser.add_argument("--api_port", type=str, action="store",
163+
help="Api Port must be given if running from remote and it isn't the default value",
164+
dest="api_port")
165+
parser.add_argument("--debug_file", type=str, action="store", help="Api calls debug file name", dest="debug_file")
166+
167+
args = parser.parse_args()
168+
client_id = args.client_id
169+
access_key = args.access_key
170+
region = args.region
171+
server = args.server if args.server else LOCAL_HOST_IP
172+
api_key = args.api_key
173+
api_port = args.api_port
174+
debug_file = args.debug_file if args.debug_file else ""
175+
176+
return client_id, access_key, region, server, api_key, api_port, debug_file
177+
178+
else:
179+
logger.error("No arguments given")
180+
exit(1)
181+
182+
183+
def login(domain):
184+
logger.info("Logging in to domain {} of server {}...".format(domain, server))
185+
payload = {"session-name": "connect all domains to infinity portal",
186+
"session-description": "connect all domains to infinity portal"}
187+
if api_key:
188+
login_res = api_client.login_with_api_key(api_key=api_key, domain=domain, payload=payload)
189+
else:
190+
login_res = api_client.login_as_root(domain=domain, payload=payload)
191+
if login_res.success is False:
192+
logger.error("Login failed:\n{}".format(login_res.error_message))
193+
if domain == SYSTEM_DATA:
194+
exit(1)
195+
return login_res.success
196+
197+
198+
def get_proxy():
199+
proxy_reply = api_client.api_call("show-proxy")
200+
if proxy_reply.success is False:
201+
logger.error("Failed to get proxy data:\n{}".format(proxy_reply.error_message))
202+
api_client.api_call("logout", {})
203+
exit(1)
204+
if proxy_reply.data["enabled"]:
205+
return proxy_reply.data["address"], proxy_reply.data["port"]
206+
else:
207+
return None, None
208+
209+
210+
def get_port():
211+
script_path = os.path.expandvars("$MDS_FWDIR/scripts/api_get_port.py")
212+
try:
213+
result = subprocess.run(['python3', script_path, '-f', 'json'], capture_output=True, text=True, check=True)
214+
json_data = json.loads(result.stdout)
215+
return int(json_data["external_port"])
216+
except subprocess.CalledProcessError as e:
217+
print(f"Error running script: {e}")
218+
except json.JSONDecodeError as e:
219+
print(f"Error parsing JSON: {e}")
220+
return DEFAULT_API_PORT
221+
222+
223+
def get_domains():
224+
domains = api_client.api_query("show-domains")
225+
if domains.success is False:
226+
logger.error("Failed to get the domains data:\n{}".format(domains.error_message))
227+
api_client.api_call("logout", {})
228+
exit(1)
229+
return domains.data
230+
231+
232+
def connect_cloud_services(domain, auth_token):
233+
res = login(domain)
234+
if res is False:
235+
return res
236+
connect_reply = api_client.api_call("connect-cloud-services", {"auth-token": auth_token})
237+
connected = False
238+
if connect_reply.success is False:
239+
logger.error(
240+
"Failed to run connect-cloud-services on domain {}:\n{}".format(domain, connect_reply.error_message))
241+
print("Failed to connect domain: {}".format(domain))
242+
else:
243+
logger.info("Successfully connected cloud services on domain {}".format(domain))
244+
print("Successfully connected domain: {}".format(domain))
245+
connected = True
246+
api_client.api_call("logout", {})
247+
return connected
248+
249+
250+
if __name__ == "__main__":
251+
logger = logger_configuration()
252+
logger.info("=====================================================================================================")
253+
print("=====================================================================================================")
254+
user_consent()
255+
client_id, access_key, region, server, api_key, api_port, debug_file = get_args(sys.argv[1:])
256+
ci_url = CI_URL_MAP.get(region)
257+
api_client = APIClient(APIClientArgs(server=server, debug_file=debug_file))
258+
if server != LOCAL_HOST and server != LOCAL_HOST_IP: # if running from remote
259+
api_port = int(api_port) if api_port else DEFAULT_API_PORT
260+
else:
261+
api_port = int(api_port) if api_port else get_port()
262+
api_client.set_port(api_port)
263+
api_client.user_agent = "connect-all-domains"
264+
logger.info("=====================================================================================================")
265+
266+
login(SYSTEM_DATA)
267+
if server == LOCAL_HOST_IP or server == LOCAL_HOST:
268+
proxy, proxy_port = get_proxy()
269+
else:
270+
proxy = None
271+
proxy_port = None
272+
domains = get_domains()
273+
api_client.api_call("logout", {})
274+
275+
jwt = get_jwt()
276+
277+
successful_connections = []
278+
failed_connections = []
279+
280+
for domain in domains:
281+
domain_name = domain["name"]
282+
logger.info("==========================================================")
283+
logger.info("Starting to connect-cloud-services on domain {}".format(domain_name))
284+
auth_token = add_om_prem(jwt, domain_name)
285+
if auth_token is None:
286+
failed_connections.append(domain_name)
287+
continue
288+
connect_success = connect_cloud_services(domain_name, auth_token)
289+
if connect_success:
290+
successful_connections.append(domain_name)
291+
else:
292+
failed_connections.append(domain_name)
293+
time.sleep(3)
294+
api_client.save_debug_data()
295+
logger.info("==========================================================\nScript finished")
296+
print("=====================================================================================================")
297+
if len(successful_connections) == len(domains):
298+
print("Successfully connected all domains")
299+
exit(0)
300+
if len(successful_connections) > 0:
301+
print("Successfully connected the following domains:")
302+
for name in successful_connections:
303+
print(name)
304+
if len(failed_connections) > 0:
305+
print("Failed to connect the following domains:")
306+
for name in failed_connections:
307+
print(name)
308+
exit(1)

0 commit comments

Comments
 (0)