def device_cert_required() -> bool: apidata = get_apidata() if 'verify_tls_device' in apidata and type(apidata['verify_tls_device']) == bool and \ not apidata['verify_tls_device']: return False else: return True
def generate_device_cert(hostname: str, ipv4_address: IPv4Address): apidata = get_apidata() try: if not os.path.isfile(apidata['cafile']): raise Exception("Specified cafile is not a file: {}".format( apidata['cafile'])) except KeyError: raise Exception("No cafile specified in api.yml") try: if not os.path.isfile(apidata['cakeyfile']): raise Exception("Specified cakeyfile is not a file: {}".format( apidata['cakeyfile'])) except KeyError: raise Exception("No cakeyfile specified in api.yml") try: if not os.path.isdir(apidata['certpath']): raise Exception("Specified certpath is not a directory") except KeyError: raise Exception("No certpath found in api.yml settings") with open(apidata['cakeyfile'], "rb") as cakeyfile: root_key = serialization.load_pem_private_key( cakeyfile.read(), password=None, ) with open(apidata['cafile'], "rb") as cafile: root_cert = x509.load_pem_x509_certificate(cafile.read()) cert_key = rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()) new_subject = x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, hostname), ]) cert = (x509.CertificateBuilder().subject_name(new_subject).issuer_name( root_cert.issuer).public_key(cert_key.public_key()).serial_number( x509.random_serial_number()).not_valid_before( datetime.datetime.utcnow()).not_valid_after( datetime.datetime.utcnow() + datetime.timedelta(days=7300)).add_extension( x509.SubjectAlternativeName( [x509.IPAddress(ipv4_address)]), critical=False, ).sign(root_key, hashes.SHA256(), default_backend())) with open(os.path.join(apidata['certpath'], "{}.crt".format(hostname)), "wb") as f: f.write(cert.public_bytes(serialization.Encoding.PEM)) with open(os.path.join(apidata['certpath'], "{}.key".format(hostname)), "wb") as f: f.write( cert_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption(), ))
def firmware_url(self) -> str: apidata = get_apidata() httpd_url = '' if isinstance(apidata, dict) and 'firmware_url' in apidata: httpd_url = apidata['firmware_url'] elif 'FIRMWARE_URL' in os.environ: httpd_url = os.environ['FIRMWARE_URL'] return httpd_url
def get_ssl_context(): apidata = get_apidata() new_ssl_context = None if 'cafile' in apidata: if os.path.isfile(apidata['cafile']): new_ssl_context = ssl.create_default_context( cafile=apidata['cafile']) else: logger.error("Specified cafile is not a file: {}".format( apidata['cafile'])) if 'verify_tls_device' in apidata and type(apidata['verify_tls_device']) == bool and \ not apidata['verify_tls_device']: logger.warning("Accepting unverified TLS certificates") new_ssl_context = ssl._create_unverified_context() if not new_ssl_context: logger.debug("Using system default CAs") new_ssl_context = ssl.create_default_context() return new_ssl_context
def post(self, hostname: str): """Apply exact specified configuration to device without using templates""" json_data = request.get_json() apply_kwargs = {'hostname': hostname} allow_live_run = get_apidata()['allow_apply_config_liverun'] if not Device.valid_hostname(hostname): return empty_result( status='error', data=f"Invalid hostname specified" ), 400 if 'full_config' not in json_data: return empty_result('error', "full_config must be specified"), 400 if 'dry_run' in json_data and isinstance(json_data['dry_run'], bool) \ and not json_data['dry_run']: if allow_live_run: apply_kwargs['dry_run'] = False else: return empty_result('error', "Apply config live_run is not allowed"), 400 else: apply_kwargs['dry_run'] = True apply_kwargs['config'] = json_data['full_config'] scheduler = Scheduler() job_id = scheduler.add_onetime_job( 'cnaas_nms.confpush.sync_devices:apply_config', when=1, scheduled_by=get_jwt_identity(), kwargs=apply_kwargs, ) res = empty_result(data=f"Scheduled job to apply config {hostname}") res['job_id'] = job_id return res, 200
if stop_websocket_threads: break if __name__ == '__main__': # Starting via python run.py # gevent monkey patching required if you start flask with the auto-reloader (debug mode) monkey.patch_all() from cnaas_nms.api import app from cnaas_nms.db.session import redis_session import json t_websocket_events = threading.Thread(target=thread_websocket_events) t_websocket_events.start() apidata = get_apidata() if isinstance(apidata, dict) and 'host' in apidata: host = apidata['host'] else: host = None app.socketio.run(get_app(), debug=True, host=host) stop_websocket_threads = True t_websocket_events.join() if 'COVERAGE' in os.environ: save_coverage() else: # Starting via uwsgi from cnaas_nms.api import app from cnaas_nms.db.session import redis_session
def arista_copy_cert(task, job_id: Optional[str] = None) -> str: set_thread_data(job_id) logger = get_logger() apidata = get_apidata() try: key_path = os.path.join(apidata['certpath'], "{}.key".format(task.host.name)) crt_path = os.path.join(apidata['certpath'], "{}.crt".format(task.host.name)) except KeyError: raise Exception("No certpath found in api.yml settings") except Exception as e: raise Exception("Unable to find path to cert {} for device".format( e, task.host.name)) if not os.path.isfile(key_path): raise Exception("Key file {} not found".format(key_path)) if not os.path.isfile(crt_path): raise Exception("Cert file {} not found".format(crt_path)) net_connect = task.host.get_connection("netmiko", task.nornir.config) net_connect.fast_cli = False res_key = task.run(netmiko_file_transfer, source_file=key_path, dest_file="cnaasnms.key", file_system="/mnt/flash", overwrite_file=True) if res_key.failed: logger.exception(res_key.exception) res_crt = task.run(netmiko_file_transfer, source_file=crt_path, dest_file="cnaasnms.crt", file_system="/mnt/flash", overwrite_file=True) if res_crt.failed: logger.exception(res_crt.exception) if res_key.failed or res_crt.failed: raise CopyError("Unable to copy cert file to device: {}".format( task.host.name)) else: logger.debug("Certificate successfully copied to device: {}".format( task.host.name)) certstore_commands = [ "copy flash:cnaasnms.crt certificate:", "copy flash:cnaasnms.key sslkey:", "delete flash:cnaasnms.key", "delete flash:cnaasnms.crt" ] for cmd in certstore_commands: res_certstore = task.run(netmiko_send_command, command_string=cmd, enable=True) if res_certstore.failed: logger.error( "Unable to copy cert into certstore on device: {}, command '{}' failed" .format(task.host.name, cmd)) raise CopyError( "Unable to copy cert into certstore on device: {}".format( task.host.name)) logger.debug( "Certificate successfully copied to certstore on device: {}".format( task.host.name)) return "Cert copy successful"
def verify_tls() -> bool: verify_tls = True apidata = get_apidata() if isinstance(apidata, dict) and 'verify_tls' in apidata: verify_tls = apidata['verify_tls'] return verify_tls
def get_httpd_url() -> str: apidata = get_apidata() httpd_url = 'https://cnaas_httpd/api/v1.0/firmware' if isinstance(apidata, dict) and 'httpd_url' in apidata: httpd_url = apidata['httpd_url'] return httpd_url
data = {'status': 'error', 'data': 'Invalid token signature'} elif isinstance(e, IndexError): # We might catch IndexErrors which are not cuased by JWT, # but this is better than nothing. data = {'status': 'error', 'data': 'JWT token missing?'} elif isinstance(e, NoAuthorizationError): data = {'status': 'error', 'data': 'JWT token missing?'} elif isinstance(e, InvalidHeaderError): data = {'status': 'error', 'data': 'Invalid header, JWT token missing? {}'.format(e)} else: return super(CnaasApi, self).handle_error(e) return jsonify(data), 401 try: jwt_pubkey = open(get_apidata()['jwtcert']).read() except Exception as e: print("Could not load public JWT cert from api.yml config: {}".format(e)) sys.exit(1) app = Flask(__name__) # TODO: make origins configurable cors = CORS(app, resources={r"/api/*": {"origins": "*"}}, expose_headers=["Content-Type", "Authorization", "X-Total-Count"]) socketio = SocketIO(app, cors_allowed_origins='*') app.config['SECRET_KEY'] = os.urandom(128) app.config['JWT_PUBLIC_KEY'] = jwt_pubkey app.config['JWT_IDENTITY_CLAIM'] = 'sub' app.config['JWT_ALGORITHM'] = 'ES256' app.config['JWT_ACCESS_TOKEN_EXPIRES'] = False