def run(): '''Run Ironhouse example''' # These direcotries are generated by the generate_certificates script base_dir = os.path.dirname(__file__) keys_dir = os.path.join(base_dir, 'certificates') public_keys_dir = os.path.join(base_dir, 'public_keys') secret_keys_dir = os.path.join(base_dir, 'private_keys') if not (os.path.exists(keys_dir) and os.path.exists(public_keys_dir) and os.path.exists(secret_keys_dir)): logging.critical( "Certificates are missing - run generate_certificates script first" ) sys.exit(1) # Start an authenticator for this context. auth = IOLoopAuthenticator() auth.allow('127.0.0.1') # Tell authenticator to use the certificate in a directory auth.configure_curve(domain='*', location=public_keys_dir) server_secret_file = os.path.join(secret_keys_dir, "server.key_secret") server = setup_server(server_secret_file) server_public_file = os.path.join(public_keys_dir, "server.key") client_secret_file = os.path.join(secret_keys_dir, "client.key_secret") client = setup_client(client_secret_file, server_public_file) client.send(b'Hello') auth.start() ioloop.IOLoop.instance().start()
def __init__(self, app=None, keyname="server", bind_addr="tcp://127.0.0.1:5556", crypto=True, zap_auth=True): self.app = app self.keyname = keyname self.bind_addr = bind_addr self.crypto = crypto self.zap_auth = zap_auth self.ctx = zmq.Context() self.loop = IOLoop.instance() self.identities = {} self.server = self.ctx.socket(zmq.ROUTER) if self.crypto: self.keymonkey = KeyMonkey(self.keyname) self.server = self.keymonkey.setupServer(self.server, self.bind_addr) self.server.bind(self.bind_addr) logging.debug("%s listening for new client connections at %s" % ( self.keyname, self.bind_addr)) self.server = ZMQStream(self.server) # Setup ZAP: if self.zap_auth: if not self.crypto: logging.fatal("ZAP requires CurveZMQ (crypto) to be enabled. Exiting.") sys.exit(1) self.auth = IOLoopAuthenticator(self.ctx) logging.info("ZAP enabled. Authorizing clients in %s." % self.keymonkey.authorized_clients_dir) if not os.path.isdir(self.keymonkey.authorized_clients_dir): logging.fatal("Directory not found: %s. Exiting." % self.keymonkey.authorized_clients_dir) sys.exit(1) self.auth.configure_curve(domain='*', location=self.keymonkey.authorized_clients_dir) self.setup() self.start()
def stream(self, sock_type, address: str, callback: Callable = None, use_encryption: bool = False, server_curve_id: str = None, curve_dir: str = None, use_zap: bool = False): """ Method used to setup a ZMQ stream which will be bound to a ZMQ.REP socket. On this REP stream we register a callback to execute client queries as they arrive. The stream is used in conjunction with `tornado` eventloop Args: sock_type: ZMQ Socket type. For e.g. zmq.REP address: Address to bind to callback: A callback to invoke as messages arrive on the ZMQ stream use_encryption: True if you want CurveZMQ encryption to be enabled server_curve_id: Server curve id. Defaults to "id_server_{}_curve".format(socket.gethostname()) curve_dir: Curve key files directory. Defaults to `~/.curve` use_zap: True if you want ZAP authentication to be enabled. Raises: sqlite_rx.exception.SQLiteRxZAPSetupError: If ZAP is enabled without CurveZMQ """ self.socket = self.context.socket(sock_type) if use_encryption or use_zap: server_curve_id = server_curve_id if server_curve_id else "id_server_{}_curve".format( socket.gethostname()) keymonkey = KeyMonkey(key_id=server_curve_id, destination_dir=curve_dir) if use_encryption: LOG.info("Setting up encryption using CurveCP") self.socket = keymonkey.setup_secure_server( self.socket, address) if use_zap: if not use_encryption: raise SQLiteRxZAPSetupError( "ZAP requires CurveZMQ(use_encryption = True) to be enabled. Exiting" ) self.auth = IOLoopAuthenticator(self.context) LOG.info("ZAP enabled. \n Authorizing clients in %s.", keymonkey.authorized_clients_dir) self.auth.configure_curve( domain="*", location=keymonkey.authorized_clients_dir) self.auth.start() self.socket.bind(address) stream = zmqstream.ZMQStream(self.socket, self.loop) if callback: stream.on_recv(callback) return stream
def run(self): if self._server: log.warning('Tried to run an already running server again.') return if not os.path.isfile(self._server_private_key): log.critical( 'No private key is installed for Lighthouse. Can not create an encrypted connection.' ) sys.exit(2) if not os.path.isdir(self._trusted_keys_dir): log.warning( 'Trusted keys directory does not exist. No clients will be able to make connections to this Lighthouse server.' ) # Start an authenticator for this context. auth = IOLoopAuthenticator(self._ctx) # NOTE: auth.allow('127.0.0.1') can be used to allow access only from specific IPs (whitelisting) # Tell authenticator to use the certificate in a directory auth.configure_curve(domain='*', location=self._trusted_keys_dir) self._setup_server() auth.start() ioloop.IOLoop.instance().start()
def __authenticate(self): if not os.path.exists(self.config.get_server_public_key_file()): self.logger.fatal('server public key missing: %s' % self.config.get_server_public_key_file()) exit(1) if not os.path.exists(self.config.get_client_secret_key_file()): self.fatal('client secret key missing: %s' % self.config.get_client_secret_key_file()) exit(1) auth = IOLoopAuthenticator() # Tell authenticator to use the certificate in a directory auth.configure_curve(domain='*', location=self.config.get_default_keys_dir())
def _setup_auth(self, auth_whitelist: list, loop): if loop is None: self.auth = ThreadAuthenticator(self.context) else: self.auth = IOLoopAuthenticator(self.context, io_loop=loop) # allow all local host self.logger.debug('Auth whitelist %s', auth_whitelist) if auth_whitelist is not None: self.auth.allow(auth_whitelist) self._base_filepath = get_certificate_filepath() public_key_location = path.join(self._base_filepath, 'public_keys') self.auth.configure_curve(domain='*', location=public_key_location) self.auth.start()
def __authenticate(self): public_keys_dir = self.config.get_public_keys_dir() private_keys_dir = self.config.get_private_keys_dir() if not (os.path.exists(public_keys_dir) and os.path.exists(private_keys_dir)): msg = ("Certificates are missing: %s and %s - " "run generate_certificates script first" % (public_keys_dir, private_keys_dir)) self.config.get_logger(__name__).critical(msg) raise Exception(msg) auth = IOLoopAuthenticator() auth.configure_curve(domain='*', location=public_keys_dir) return os.path.join(private_keys_dir, "server.key_secret")
def start(self): # Setup ZAP: if self.zap_auth: if not self.crypto: print("ZAP requires CurveZMQ (crypto) to be enabled. Exiting.") sys.exit(1) self.auth = IOLoopAuthenticator(self.ctx) self.auth.deny(None) print("ZAP enabled.\nAuthorizing clients in %s." % self.keymonkey.authorized_clients_dir) self.auth.configure_curve( domain='*', location=self.keymonkey.authorized_clients_dir) self.auth.start() self.periodic.start() try: self.loop.start() except KeyboardInterrupt: pass
def make_auth(self): from zmq.auth.ioloop import IOLoopAuthenticator return IOLoopAuthenticator(self.context, io_loop=self.io_loop)
def make_auth(self): return IOLoopAuthenticator(self.context, io_loop=self.io_loop)
(r"/add/([^/]+)", FunctionHandler), (r"/commands", CommandsHandler), (r"/iptables", IptablesHandler), (r"/key", KeyHandler), ]) #start unsecure zmq server base_dir = os.path.dirname(__file__) public_keys_dir = os.path.join(base_dir, 'public_keys') secret_keys_dir = os.path.join(base_dir, 'private_keys') # Start an authenticator for this context. ctx_server_unsec = zmq.Context() server_unsec = ctx_server_unsec.socket(zmq.REP) auth_unsec = IOLoopAuthenticator() auth_unsec.configure_curve(domain='*', location='*') server_secret_file = os.path.join(secret_keys_dir, "server.key_secret") server_unsec = setup_server_unsec(server_unsec, server_secret_file) server_public_file = os.path.join(public_keys_dir, "server.key") auth_unsec.start() ### Start if __name__ == "__main__": application.listen(8888) io_loop = ioloop.IOLoop.instance() conn = sqlite3.connect('clients.db') c = conn.cursor() sql = 'create table if not exists' \
def message_proxy(self, work_dir): """ drone_data_inboud is for data comming from drones drone_data_outbound is for commands to the drones, topic must either be a drone ID or all for sending a broadcast message to all drones """ public_keys_dir = os.path.join(work_dir, 'certificates', 'public_keys') secret_keys_dir = os.path.join(work_dir, 'certificates', 'private_keys') # start and configure auth worker auth = IOLoopAuthenticator() auth.start() auth.allow('127.0.0.1') auth.configure_curve(domain='*', location=public_keys_dir) # external interfaces for communicating with drones server_secret_file = os.path.join(secret_keys_dir, 'beeswarm_server.pri') server_public, server_secret = load_certificate(server_secret_file) drone_data_inbound = beeswarm.shared.zmq_context.socket(zmq.PULL) drone_data_inbound.curve_secretkey = server_secret drone_data_inbound.curve_publickey = server_public drone_data_inbound.curve_server = True drone_data_inbound.bind('tcp://*:{0}'.format( self.config['network']['zmq_port'])) drone_data_outbound = beeswarm.shared.zmq_context.socket(zmq.PUB) drone_data_outbound.curve_secretkey = server_secret drone_data_outbound.curve_publickey = server_public drone_data_outbound.curve_server = True drone_data_outbound.bind('tcp://*:{0}'.format( self.config['network']['zmq_command_port'])) # internal interfaces # all inbound session data from drones will be replayed on this socket drone_data_socket = beeswarm.shared.zmq_context.socket(zmq.PUB) drone_data_socket.bind(SocketNames.DRONE_DATA.value) # all commands received on this will be published on the external interface drone_command_socket = beeswarm.shared.zmq_context.socket(zmq.PULL) drone_command_socket.bind(SocketNames.DRONE_COMMANDS.value) poller = zmq.Poller() poller.register(drone_data_inbound, zmq.POLLIN) poller.register(drone_command_socket, zmq.POLLIN) while True: # .recv() gives no context switch - why not? using poller with timeout instead socks = dict(poller.poll(100)) gevent.sleep() if drone_command_socket in socks and socks[ drone_command_socket] == zmq.POLLIN: data = drone_command_socket.recv() drone_id, _ = data.split(' ', 1) logger.debug("Sending drone command to: {0}".format(drone_id)) # pub socket takes care of filtering drone_data_outbound.send(data) elif drone_data_inbound in socks and socks[ drone_data_inbound] == zmq.POLLIN: raw_msg = drone_data_inbound.recv() split_data = raw_msg.split(' ', 2) if len(split_data) == 3: topic, drone_id, data = split_data else: data = None topic, drone_id, = split_data logger.debug("Received {0} message from {1}.".format( topic, drone_id)) # relay message on internal socket drone_data_socket.send(raw_msg)
def message_proxy(self, work_dir): """ drone_data_inboud is for data comming from drones drone_data_outbound is for commands to the drones, topic must either be a drone ID or all for sending a broadcast message to all drones """ public_keys_dir = os.path.join(work_dir, 'certificates', 'public_keys') secret_keys_dir = os.path.join(work_dir, 'certificates', 'private_keys') # start and configure auth worker auth = IOLoopAuthenticator() auth.start() auth.allow('127.0.0.1') auth.configure_curve(domain='*', location=public_keys_dir) # external interfaces for communicating with drones server_secret_file = os.path.join(secret_keys_dir, 'beeswarm_server.pri') server_public, server_secret = load_certificate(server_secret_file) drone_data_inbound = beeswarm.shared.zmq_context.socket(zmq.PULL) drone_data_inbound.curve_secretkey = server_secret drone_data_inbound.curve_publickey = server_public drone_data_inbound.curve_server = True drone_data_inbound.bind('tcp://*:{0}'.format( self.config['network']['zmq_port'])) drone_data_outbound = beeswarm.shared.zmq_context.socket(zmq.PUB) drone_data_outbound.curve_secretkey = server_secret drone_data_outbound.curve_publickey = server_public drone_data_outbound.curve_server = True drone_data_outbound.bind('tcp://*:{0}'.format( self.config['network']['zmq_command_port'])) # internal interfaces # all inbound session data from drones will be replayed in this socket sessionPublisher = beeswarm.shared.zmq_context.socket(zmq.PUB) sessionPublisher.bind('inproc://sessionPublisher') # all commands received on this will be published on the external interface drone_command_receiver = beeswarm.shared.zmq_context.socket(zmq.PULL) drone_command_receiver.bind('inproc://droneCommandReceiver') poller = zmq.Poller() poller.register(drone_data_inbound, zmq.POLLIN) poller.register(drone_command_receiver, zmq.POLLIN) while True: # .recv() gives no context switch - why not? using poller with timeout instead socks = dict(poller.poll(100)) gevent.sleep() if drone_command_receiver in socks and socks[ drone_command_receiver] == zmq.POLLIN: data = drone_command_receiver.recv() drone_id, _ = data.split(' ', 1) logger.debug("Sending drone command to: {0}".format(drone_id)) # pub socket takes care of filtering drone_data_outbound.send(data) elif drone_data_inbound in socks and socks[ drone_data_inbound] == zmq.POLLIN: split_data = drone_data_inbound.recv().split(' ', 2) if len(split_data) == 3: topic, drone_id, data = split_data else: data = None topic, drone_id, = split_data logger.debug("Received {0} message from {1}.".format( topic, drone_id)) db_session = database_setup.get_session() drone = db_session.query(Drone).filter( Drone.id == drone_id).one() drone.last_activity = datetime.now() db_session.add(drone) db_session.commit() if topic == Messages.SESSION_HONEYPOT or topic == Messages.SESSION_CLIENT: sessionPublisher.send('{0} {1}'.format(topic, data)) elif topic == Messages.KEY or topic == Messages.CERT: # for now we just store the fingerprint # in the future it might be relevant to store the entire public key and private key # for forensic purposes if topic == Messages.CERT: cert = data.split(' ', 1)[1] digest = generate_cert_digest(cert) logging.debug( 'Storing public key digest: {0} for drone {1}.'. format(digest, drone_id)) db_session = database_setup.get_session() drone = db_session.query(Drone).filter( Drone.id == drone_id).one() drone.cert_digest = digest db_session.add(drone) db_session.commit() elif topic == Messages.PING: pass elif topic == Messages.IP: ip_address = data logging.debug('Drone {0} reported ip: {1}'.format( drone_id, ip_address)) db_session = database_setup.get_session() drone = db_session.query(Drone).filter( Drone.id == drone_id).one() if drone.ip_address != ip_address: drone.ip_address = ip_address db_session.add(drone) db_session.commit() send_zmq_request( 'inproc://configCommands', '{0} {1}'.format(Messages.DRONE_CONFIG_CHANGED, drone_id)) # drone want it's config transmitted elif topic == Messages.DRONE_CONFIG: config_dict = send_zmq_request( 'inproc://configCommands', '{0} {1}'.format(Messages.DRONE_CONFIG, drone_id)) drone_data_outbound.send('{0} {1} {2}'.format( drone_id, Messages.CONFIG, json.dumps(config_dict))) else: logger.warn( 'Message with unknown topic received: {0}'.format( topic))