def __init__(self, cb, config=None, address='', port=58337, backlog=100): self.cb = cb # Parse config <3 if config is not None: with open(config, 'r') as f: cfg = yaml.load(f) else: cfg = {} logfile = cfg.get('logfile', None) if logfile is not None: paramiko.util.log_to_file(logile) host_key_path = cfg.get('host_key', 'server.key') host_key_password = cfg.get('host_key_password', None) try: self.host_key = RSAKey.from_private_key_file( host_key_path, host_key_password) except paramiko.ssh_exception.PasswordRequiredException: print 'Invalid host_key_password' sys.exit(1) except IOError: print '*****************************************' print '** host_key does not exists! **' print '** In the name of security by default, **' print '** Sheet will generate one for you. **' print '*****************************************' RSAKey.generate(2048).write_private_key_file( host_key_path, host_key_password) self.handler = Broker.get(cfg.get('auth_handler', 'BaseAuth')) self.handler_conf = cfg.get('auth_handler_config', {}) try: self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.socket.bind((address, port)) except Exception as e: print 'Bind failed: ', str(e) traceback.print_exc() sys.exit(1) try: self.socket.listen(backlog) except Exception as e: print 'Listen/accept failed:', str(e) traceback.print_exc() sys.exit(1)
def generatekey(self): public_key = StringIO() private_key = StringIO() public_key_value = None private_key_value = None try: if self.keytype == 'rsa': key = RSAKey.generate(self.rsabits) elif self.keytype == 'ecdsa': key = ECDSAKey.generate(bits=self.ecdsabits) elif self.keytype == 'dss': key = DSSKey.generate(bits=self.dssbits) else: return None, "sshkey暂时不支持其它类型 %s" % self.keytype key.write_private_key(private_key) public_key.write("%s %s %s" % (key.get_name(), key.get_base64(), self.basename)) public_key_value = public_key.getvalue() private_key_value = private_key.getvalue() cache.set("user_%s_private_key" % self.username, private_key_value) cache.set("user_%s_public_key" % self.username, public_key_value) except Exception as e: logger.error(e.args) return None, e.args finally: public_key.close() private_key.close() return { "publickey": public_key_value, "privatekey": private_key_value }, None
def test_authorize_remote(fx_app, fx_authorized_servers, fx_master_key, fx_authorized_remote_set, fx_authorized_identity, fx_token_id, fx_key_store): public_key = RSAKey.generate(1024) fx_key_store.register(fx_authorized_identity, public_key) alias, remote = dict(fx_authorized_remote_set).popitem() with fx_app.test_client() as client: response = client.post( get_url('authorize_remote', token_id=fx_token_id, alias=alias)) assert response.status_code == 200 assert response.mimetype == 'application/json' result = json.loads(response.get_data()) assert result['success'] == 'authorized' assert result['remote'] == remote_dict(remote) expires_at = parse_date(result['expires_at']) thread, path, ev = fx_authorized_servers[remote.port] authorized_keys_path = path.join('.ssh', 'authorized_keys') with authorized_keys_path.open() as f: saved_keys = map(parse_openssh_pubkey, f) assert frozenset(saved_keys) == {fx_master_key, public_key} while datetime.datetime.now(datetime.timezone.utc) <= expires_at: time.sleep(1) time.sleep(1) with authorized_keys_path.open() as f: saved_keys = map(parse_openssh_pubkey, f) assert frozenset(saved_keys) == {fx_master_key}
def start_server(path: str, host: str, port: int, terminated: threading.Event): server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.settimeout(1) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind((host, port)) server_socket.listen(1) stub_cls = type('StubSFTPServer', (StubSFTPServer,), {'ROOT': path}) host_key = RSAKey.generate(1024) def accept(server_socket, mask): conn, addr = server_socket.accept() transport = Transport(conn) transport.add_server_key(host_key) transport.set_subsystem_handler('sftp', SFTPServer, stub_cls) server = StubServer(path) transport.start_server(server=server) while not terminated.is_set(): channel = transport.accept(1) if channel is not None and not terminated.is_set(): while transport.is_active() and not terminated.is_set(): terminated.wait(1) break sel = selectors.DefaultSelector() sel.register(server_socket, selectors.EVENT_READ, accept) last_used = time.time() while not terminated.is_set() and last_used + 10 > time.time(): events = sel.select(1) for key, mask in events: key.data(key.fileobj, mask) last_used = time.time()
def test_public_key(fx_app, fx_key_store, fx_authorized_identity, fx_token_id): key = RSAKey.generate(1024) fx_key_store.register(fx_authorized_identity, key) with fx_app.test_client() as client: response = client.get( get_url( 'public_key', token_id=fx_token_id, fingerprint=key.get_fingerprint() ) ) assert response.status_code == 200 assert response.mimetype == 'text/plain' assert parse_openssh_pubkey(response.data.decode()) == key with fx_app.test_client() as client: response = client.get( get_url( 'public_key', token_id=fx_token_id, fingerprint=os.urandom(16) ) ) assert response.status_code == 404 assert response.mimetype == 'application/json' error = json.loads(response.data.decode('utf-8')) assert error['error'] == 'not-found'
def gen_keys(key="", key_path_dir=""): """ 在KEY_DIR下创建一个 uuid命名的目录, 并且在该目录下 生产一对秘钥 :return: 返回目录名(uuid) """ key_basename = "key-" + uuid4().hex if not key_path_dir: key_path_dir = os.path.join(KEY_DIR, 'role_key', key_basename) private_key = os.path.join(key_path_dir, 'id_rsa') public_key = os.path.join(key_path_dir, 'id_rsa.pub') mkdir(key_path_dir, mode=0755) if not key: key = RSAKey.generate(2048) key.write_private_key_file(private_key) else: key_file = os.path.join(key_path_dir, 'id_rsa') with open(key_file, 'w') as f: f.write(key) f.close() with open(key_file) as f: try: key = RSAKey.from_private_key(f) except SSHException, e: shutil.rmtree(key_path_dir, ignore_errors=True) raise SSHException(e)
def main(): # pragma: no cover """The main function for :program:`geofront-server` CLI program.""" parser = main_parser() args = parser.parse_args() try: app.config.from_pyfile(os.path.abspath(args.config), silent=False) except FileNotFoundError: parser.error('unable to load configuration file: ' + args.config) logger = logging.getLogger('geofront') handler = logging.StreamHandler() level = logging.DEBUG if args.debug else logging.INFO handler.setLevel(level) logger.addHandler(handler) logger.setLevel(level) master_key_store = get_master_key_store() servers = frozenset(get_remote_set().values()) try: key = master_key_store.load() except EmptyStoreError: if args.create_master_key or args.renew_master_key: logger.warn('no master key; create one...') key = RSAKey.generate(1024) master_key_store.save(key) logger.info('created new master key: %s', get_key_fingerprint(key)) else: parser.error('no master key; try --create-master-key option ' 'if you want to create one') else: if args.renew_master_key and not os.environ.get('WERKZEUG_RUN_MAIN'): renew_master_key(servers, master_key_store) master_key_renewal_interval = app.config['MASTER_KEY_RENEWAL'] if not (master_key_renewal_interval is None or isinstance(master_key_renewal_interval, datetime.timedelta)): raise RuntimeError( 'MASTER_KEY_RENEWAL configuration must be an instance of ' 'datetime.timedelta, not {!r}'.format(master_key_renewal_interval)) if master_key_renewal_interval is not None: master_key_renewal = PeriodicalRenewal(servers, master_key_store, master_key_renewal_interval) waitress_options = {} if args.trusted_proxy: if hasattr(Adjustments, 'trusted_proxy'): # > 0.8.8 # https://github.com/Pylons/waitress/pull/42 waitress_options['trusted_proxy'] = True else: # <= 0.8.8 app.wsgi_app = ProxyFix(app.wsgi_app) try: if args.debug: app.run(args.host, args.port, debug=True) else: serve(app, host=args.host, port=args.port, asyncore_use_poll=True, **waitress_options) finally: if master_key_renewal_interval is not None: master_key_renewal.terminate()
def renew_master_key(servers: collections.abc.Set, key_store: MasterKeyStore) -> PKey: """Renew the master key. It creates a new master key, makes ``servers`` to authorize the new key, replaces the existing master key with the new key in the ``key_store``, and then makes ``servers`` to deauthorize the old key. All these operations are done in a two-phase renewal transaction. :param servers: servers to renew the master key. every element has to be an instance of :class:`~.remote.Remote` :type servers: :class:`collections.abc.Set` :param key_store: the master key store to update :type key_store: :class:`MasterKeyStore` :returns: the created new master key :rtype: :class:`paramiko.pkey.PKey` """ logger = logging.getLogger(__name__ + '.renew_master_key') logger.info('renew the master key...') old_key = key_store.load() logger.info('the existing master key: %s', get_key_fingerprint(old_key)) new_key = RSAKey.generate(1024) logger.info('created new master key: %s', get_key_fingerprint(new_key)) logger.info('authorize the new master key...') with TwoPhaseRenewal(servers, old_key, new_key): logger.info('the new master key is authorized; ' 'update the key store...') key_store.save(new_key) logger.info('master key store is successfully updated; ' 'deauthorize the existing master key...') logger.info('master key renewal has finished') return new_key
def renew_master_key(servers: collections.abc.Set, key_store: MasterKeyStore) -> PKey: """Renew the master key. It creates a new master key, makes ``servers`` to authorize the new key, replaces the existing master key with the new key in the ``key_store``, and then makes ``servers`` to deauthorize the old key. All these operations are done in a two-phase renewal transaction. :param servers: servers to renew the master key. every element has to be an instance of :class:`~.remote.Remote` :type servers: :class:`collections.abc.Set` :param key_store: the master key store to update :type key_store: :class:`MasterKeyStore` :returns: the created new master key :rtype: :class:`paramiko.pkey.PKey` """ logger = logging.getLogger(__name__ + ".renew_master_key") logger.info("renew the master key...") old_key = key_store.load() logger.info("the existing master key: %s", get_key_fingerprint(old_key)) new_key = RSAKey.generate(1024) logger.info("created new master key: %s", get_key_fingerprint(new_key)) logger.info("authorize the new master key...") with TwoPhaseRenewal(servers, old_key, new_key): logger.info("the new master key is authorized; " "update the key store...") key_store.save(new_key) logger.info("master key store is successfully updated; " "deauthorize the existing master key...") logger.info("master key renewal has finished") return new_key
def generate_ssh_key(path): """Create a new SSH private/public key pair.""" key = RSAKey.generate(2048) key.write_private_key_file(path) with open(path + ".pub", "wb") as f: s = "%s %s" % (key.get_name(), key.get_base64()) f.write(s.encode("ascii"))
def test_delete_public_key(fx_app, fx_key_store, fx_authorized_identity, fx_token_id): key = RSAKey.generate(1024) fx_key_store.register(fx_authorized_identity, key) with fx_app.test_client() as client: response = client.delete( get_url( 'delete_public_key', token_id=fx_token_id, fingerprint=key.get_fingerprint() ) ) assert response.status_code == 200 assert key not in fx_key_store.list_keys(fx_authorized_identity) with fx_app.test_client() as client: response = client.delete( get_url( 'delete_public_key', token_id=fx_token_id, fingerprint=key.get_fingerprint() ) ) assert response.status_code == 404 assert response.mimetype == 'application/json' error = json.loads(response.data.decode('utf-8')) assert error['error'] == 'not-found'
def test_authorize_remote(fx_app, fx_authorized_servers, fx_master_key, fx_authorized_remote_set, fx_authorized_identity, fx_token_id, fx_key_store): public_key = RSAKey.generate(1024) fx_key_store.register(fx_authorized_identity, public_key) alias, remote = dict(fx_authorized_remote_set).popitem() with fx_app.test_client() as client: response = client.post( get_url('authorize_remote', token_id=fx_token_id, alias=alias) ) assert response.status_code == 200 assert response.mimetype == 'application/json' result = json.loads(response.data) assert result['success'] == 'authorized' assert result['remote'] == remote_dict(remote) expires_at = parse_date(result['expires_at']) thread, path, ev = fx_authorized_servers[remote.port] authorized_keys_path = path.join('.ssh', 'authorized_keys') with authorized_keys_path.open() as f: saved_keys = map(parse_openssh_pubkey, f) assert frozenset(saved_keys) == {fx_master_key, public_key} while datetime.datetime.now(datetime.timezone.utc) <= expires_at: time.sleep(1) time.sleep(1) with authorized_keys_path.open() as f: saved_keys = map(parse_openssh_pubkey, f) assert frozenset(saved_keys) == {fx_master_key}
def create_test_ssh_key(self): self.test_key = RSAKey.generate(1024) self.test_pubkey = "\nssh-rsa %s %s\n" % \ (self.test_key.get_base64(), Tests.TEST_KEY_COMMENT) f = open(os.path.expanduser("~/.ssh/authorized_keys"), "a") f.write(self.test_pubkey) f.close()
def gen_keys(key="", key_path_dir=""): """ 在KEY_DIR下创建一个 uuid命名的目录, 并且在该目录下 生产一对秘钥 :return: 返回目录名(uuid) """ key_basename = "key-" + uuid4().hex if not key_path_dir: key_path_dir = os.path.join(KEY_DIR, 'role_key', key_basename) private_key = os.path.join(key_path_dir, 'id_rsa') public_key = os.path.join(key_path_dir, 'id_rsa.pub') mkdir(key_path_dir, mode=755) if not key: key = RSAKey.generate(2048) key.write_private_key_file(private_key) else: key_file = os.path.join(key_path_dir, 'id_rsa') with open(key_file, 'w') as f: f.write(key) f.close() with open(key_file) as f: try: key = RSAKey.from_private_key(f) except SSHException, e: shutil.rmtree(key_path_dir, ignore_errors=True) raise SSHException(e)
def start_server(path: str, host: str, port: int, terminated: threading.Event): server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.settimeout(1) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind((host, port)) server_socket.listen(1) stub_cls = type('StubSFTPServer', (StubSFTPServer, ), {'ROOT': path}) host_key = RSAKey.generate(1024) def accept(server_socket, mask): conn, addr = server_socket.accept() transport = Transport(conn) transport.add_server_key(host_key) transport.set_subsystem_handler('sftp', SFTPServer, stub_cls) server = StubServer(path) transport.start_server(server=server) while not terminated.is_set(): channel = transport.accept(1) if channel is not None and not terminated.is_set(): while transport.is_active() and not terminated.is_set(): terminated.wait(1) break sel = selectors.DefaultSelector() sel.register(server_socket, selectors.EVENT_READ, accept) last_used = time.time() while not terminated.is_set() and last_used + 10 > time.time(): events = sel.select(1) for key, mask in events: key.data(key.fileobj, mask) last_used = time.time()
def test_get_public_key(fx_app, fx_key_store, fx_authorized_identity, fx_token_id): key = RSAKey.generate(1024) fx_key_store.register(fx_authorized_identity, key) with fx_app.test_request_context(): found = get_public_key(fx_token_id, key.get_fingerprint()) assert found == key
def __init__(self, cb, config=None, address='', port=58337, backlog=100): self.cb = cb # Parse config <3 if config is not None: with open(config, 'r') as f: cfg = yaml.load(f) else: cfg = {} logfile = cfg.get('logfile', None) if logfile is not None: paramiko.util.log_to_file(logile) host_key_path = cfg.get('host_key', 'server.key') host_key_password = cfg.get('host_key_password', None) try: self.host_key = RSAKey.from_private_key_file(host_key_path, host_key_password) except paramiko.ssh_exception.PasswordRequiredException: print 'Invalid host_key_password' sys.exit(1) except IOError: print '*****************************************' print '** host_key does not exists! **' print '** In the name of security by default, **' print '** Sheet will generate one for you. **' print '*****************************************' RSAKey.generate(2048).write_private_key_file(host_key_path, host_key_password) self.handler = Broker.get(cfg.get('auth_handler', 'BaseAuth')) self.handler_conf = cfg.get('auth_handler_config', {}) try: self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.socket.bind((address, port)) except Exception as e: print 'Bind failed: ', str(e) traceback.print_exc() sys.exit(1) try: self.socket.listen(backlog) except Exception as e: print 'Listen/accept failed:', str(e) traceback.print_exc() sys.exit(1)
def generate_rsa_keypair(cls: type): new_key = RSAKey.generate(4096) private_key = StringIO() new_key.write_private_key(private_key) return cls.objects.create(public_key=' '.join( [new_key.get_name(), new_key.get_base64()]), private_key=private_key.getvalue())
def test_add_public_key_415(fx_app, fx_key_store, fx_authorized_identity, fx_token_id): pkey = RSAKey.generate(1024) with fx_app.test_client() as c: response = c.post(get_url("add_public_key", token_id=fx_token_id), data={"key": format_openssh_pubkey(pkey)}) assert response.status_code == 415 error = json.loads(response.data) assert error["error"] == "unsupported-content-type" assert pkey not in fx_key_store.list_keys(fx_authorized_identity)
def test_cloud_master_public_key_store(): driver = KeyPairSupportedDummyNodeDriver("") actual_store = MemoryMasterKeyStore() store = CloudMasterPublicKeyStore(driver, "geofront-masterkey", actual_store) for _ in range(2): master_key = RSAKey.generate(1024) store.save(master_key) assert actual_store.load() == store.load() == master_key assert parse_openssh_pubkey(driver.get_key_pair("geofront-masterkey").public_key) == master_key
def ssh_keygen(): output = io.StringIO() try: key = RSAKey.generate(2048) key.write_private_key(output) private_key = output.getvalue() publick_key = '{HEAD} {KEY} {DOMAIN}'.format(HEAD='ssh-rsa', KEY=key.get_base64(), DOMAIN='*****@*****.**') except IOError as e: raise IOError('gen_keys: there was an error writing to the file') return private_key,publick_key
def generateKey(self): self.pkey = RSAKey.generate(bits=4096) try: self.pkey.write_private_key_file(KEYFILE_PATH) except IOError as e: print("Unable to write private key to disk: {0}".format(e)) return False else: return True
def test_fs_master_key_store_save(tmpdir): path = tmpdir.join('id_rsa') s = FileSystemMasterKeyStore(str(path)) with raises(EmptyStoreError): s.load() key = RSAKey.generate(1024) s.save(key) stored_key = s.load() assert isinstance(stored_key, RSAKey) assert stored_key.get_base64() == stored_key.get_base64()
def test_add_public_key_415(fx_app, fx_key_store, fx_authorized_identity, fx_token_id): pkey = RSAKey.generate(1024) with fx_app.test_client() as c: response = c.post(get_url('add_public_key', token_id=fx_token_id), data={'key': format_openssh_pubkey(pkey)}) assert response.status_code == 415 error = json.loads(response.get_data()) assert error['error'] == 'unsupported-content-type' assert pkey not in fx_key_store.list_keys(fx_authorized_identity)
def get_sshkey(self, email): output = io.StringIO() sbuffer = io.StringIO() key = RSAKey.generate(2048) key.write_private_key(output) private_key = output.getvalue() sbuffer.write("{} {} {}".format(key.get_name(), key.get_base64(), email)) public_key = sbuffer.getvalue() return private_key, public_key
def test_cloud_master_public_key_store(): driver = KeyPairSupportedDummyNodeDriver('') actual_store = MemoryMasterKeyStore() store = CloudMasterPublicKeyStore(driver, 'geofront-masterkey', actual_store) for _ in range(2): master_key = RSAKey.generate(1024) store.save(master_key) assert actual_store.load() == store.load() == master_key assert parse_openssh_pubkey( driver.get_key_pair('geofront-masterkey').public_key) == master_key
def test_add_public_key_duplicate_key(fx_app, fx_key_store, fx_authorized_identity, fx_token_id): pkey = RSAKey.generate(1024) fx_key_store.register(fx_authorized_identity, pkey) with fx_app.test_client() as c: response = c.post(get_url('add_public_key', token_id=fx_token_id), content_type='text/plain', data=format_openssh_pubkey(pkey).encode()) assert response.status_code == 400 error = json.loads(response.get_data()) assert error['error'] == 'duplicate-key'
def test_authorized_keys_list_extend(fx_authorized_sftp): sftp_client, path, keys = fx_authorized_sftp key_list = AuthorizedKeyList(sftp_client) new_keys = [RSAKey.generate(1024) for _ in range(3)] key_list.extend(new_keys) with path.join('.ssh', 'authorized_keys').open() as f: for i in range(6): assert parse_openssh_pubkey(f.readline().strip()) == keys[i] for i in range(3): assert parse_openssh_pubkey(f.readline().strip()) == new_keys[i] assert not f.readline().strip()
def test_authorized_keys_list_insert(fx_authorized_sftp): sftp_client, path, keys = fx_authorized_sftp key_list = AuthorizedKeyList(sftp_client) new_key = RSAKey.generate(1024) key_list.insert(2, new_key) with path.join('.ssh', 'authorized_keys').open() as f: assert parse_openssh_pubkey(f.readline().strip()) == keys[0] assert parse_openssh_pubkey(f.readline().strip()) == keys[1] assert parse_openssh_pubkey(f.readline().strip()) == new_key for i in range(2, 6): assert parse_openssh_pubkey(f.readline().strip()) == keys[i] assert not f.readline().strip()
def _get_key_name_pattern(self, identity: Identity) -> Pattern[str]: """Make the regex pattern from the format string. Put two different random keys, compare two outputs, and then replace the difference with wildcard. """ cls = type(self) sample_keys = cls._sample_keys if sample_keys is None: sample_keys = (RSAKey.generate(bits=512), RSAKey.generate(bits=512), ECDSAKey.generate(bits=256), ECDSAKey.generate(bits=256)) cls._sample_keys = sample_keys sample_names = [self._get_key_name(identity, k) for k in sample_keys] if len(frozenset(sample_names)) < 2: return re.compile('^' + re.escape(sample_names[0]) + '$') prefix = os.path.commonprefix(sample_names) postfix = os.path.commonprefix([n[::-1] for n in sample_names])[::-1] return re.compile('^{}.+?{}$'.format(re.escape(prefix), re.escape(postfix)))
def test_add_public_key_unsupported_type(fx_app, fx_key_store, fx_authorized_identity, fx_token_id): pkey = RSAKey.generate(1024) with fx_app.test_client() as c: response = c.post( get_url("add_public_key", token_id=fx_token_id), content_type="text/plain", data=("invalid-type " + format_openssh_pubkey(pkey)[7:]).encode(), ) assert response.status_code == 400 error = json.loads(response.data) assert error["error"] == "unsupported-key-type" assert pkey not in fx_key_store.list_keys(fx_authorized_identity)
def _get_key_name_pattern(self, identity: Identity): """Make the regex pattern from the format string. Put two different random keys, compare two outputs, and then replace the difference with wildcard. """ cls = type(self) try: sample_keys = cls.sample_keys except AttributeError: sample_keys = RSAKey.generate(1024), RSAKey.generate(1024) cls.sample_keys = sample_keys sample_name_a = self._get_key_name(identity, sample_keys[0]) sample_name_b = self._get_key_name(identity, sample_keys[1]) if sample_name_a == sample_name_b: return re.compile('^' + re.escape(sample_name_a) + '$') prefix = os.path.commonprefix([sample_name_a, sample_name_b]) postfix = os.path.commonprefix( [sample_name_a[::-1], sample_name_b[::-1]])[::-1] return re.compile('^{}.+?{}$'.format(re.escape(prefix), re.escape(postfix)))
def test_add_public_key_unsupported_type(fx_app, fx_key_store, fx_authorized_identity, fx_token_id): pkey = RSAKey.generate(1024) with fx_app.test_client() as c: response = c.post(get_url('add_public_key', token_id=fx_token_id), content_type='text/plain', data=('invalid-type ' + format_openssh_pubkey(pkey)[7:]).encode()) assert response.status_code == 400 error = json.loads(response.get_data()) assert error['error'] == 'unsupported-key-type' assert pkey not in fx_key_store.list_keys(fx_authorized_identity)
def test_add_public_key_duplicate_key(fx_app, fx_key_store, fx_authorized_identity, fx_token_id): pkey = RSAKey.generate(1024) fx_key_store.register(fx_authorized_identity, pkey) with fx_app.test_client() as c: response = c.post( get_url("add_public_key", token_id=fx_token_id), content_type="text/plain", data=format_openssh_pubkey(pkey).encode(), ) assert response.status_code == 400 error = json.loads(response.data) assert error["error"] == "duplicate-key"
def test_authorize(fx_sftpd): port, (thread, path, ev) = fx_sftpd.popitem() thread.start() master_key = RSAKey.generate(1024) public_keys = {RSAKey.generate(1024), RSAKey.generate(1024)} authorized_keys_path = path.mkdir('.ssh').join('authorized_keys') with authorized_keys_path.open('w') as f: print(format_openssh_pubkey(master_key), file=f) expires_at = authorize(public_keys, master_key, Remote('user', '127.0.0.1', port), timeout=datetime.timedelta(seconds=5)) with authorized_keys_path.open() as f: saved_keys = map(parse_openssh_pubkey, f) assert frozenset(saved_keys) == (public_keys | {master_key}) while datetime.datetime.now(datetime.timezone.utc) <= expires_at: time.sleep(1) time.sleep(1) with authorized_keys_path.open() as f: saved_keys = map(parse_openssh_pubkey, f) assert frozenset(saved_keys) == {master_key}
def generate_and_save_ssh_key(): keys = GlobalConfig.query.filter(GlobalConfig.name.in_(['ssh_private_key', 'ssh_public_key'])).all() if len(keys) == 0: key_obj = StringIO() key = RSAKey.generate(2048) key.write_private_key(key_obj) private_key, public_key = generate_ssh_key() GlobalConfig(name='ssh_private_key', value=private_key, desc='SSH私钥').add() GlobalConfig(name='ssh_public_key', value=public_key, desc='SSH公钥').save() return key, key.get_base64() else: raise Exception('Already has ssh key')
def __init__(self, private_key=None, private_key_path=None, pub_data=None, _key=None, password=None): if private_key: self._key = RSAKey(file_obj=io.StringIO(private_key)) elif private_key_path: self._key = RSAKey(filename=private_key_path, password=password) elif pub_data: if pub_data.startswith(self.SSH_PUB_KEY_PREFIX): pub_data = pub_data[len(self.SSH_PUB_KEY_PREFIX):] self._key = RSAKey(data=b64decode(pub_data.encode('utf-8'))) elif _key: self._key = _key else: self._key = RSAKey.generate(self.KEY_SIZE)
def _get_key_name_pattern(self, identity: Identity): """Make the regex pattern from the format string. Put two different random keys, compare two outputs, and then replace the difference with wildcard. """ cls = type(self) try: sample_keys = cls.sample_keys except AttributeError: sample_keys = RSAKey.generate(1024), RSAKey.generate(1024) cls.sample_keys = sample_keys sample_name_a = self._get_key_name(identity, sample_keys[0]) sample_name_b = self._get_key_name(identity, sample_keys[1]) if sample_name_a == sample_name_b: return re.compile('^' + re.escape(sample_name_a) + '$') prefix = os.path.commonprefix([sample_name_a, sample_name_b]) postfix = os.path.commonprefix([sample_name_a[::-1], sample_name_b[::-1]])[::-1] return re.compile( '^{}.+?{}$'.format(re.escape(prefix), re.escape(postfix)) )
def test_add_public_key(fx_app, fx_key_store, fx_authorized_identity, fx_token_id): pkey = RSAKey.generate(1024) with fx_app.test_client() as c: response = c.post(get_url('add_public_key', token_id=fx_token_id), content_type='text/plain', data=format_openssh_pubkey(pkey).encode()) assert response.status_code == 201 key_data = response.get_data() assert parse_openssh_pubkey(key_data.decode()) == pkey assert pkey in fx_key_store.list_keys(fx_authorized_identity) r = c.get(response.location) assert r.get_data() == key_data
def test_two_phase_renewal(fx_authorized_servers, fx_master_key): remote_set = { Remote('user', '127.0.0.1', port) for port in fx_authorized_servers } old_key = fx_master_key new_key = RSAKey.generate(1024) for t, path, ev in fx_authorized_servers.values(): assert authorized_key_set(path) == {old_key} with TwoPhaseRenewal(remote_set, old_key, new_key): for t, path, ev in fx_authorized_servers.values(): assert authorized_key_set(path) == {old_key, new_key} for t, path, ev in fx_authorized_servers.values(): assert authorized_key_set(path) == {new_key}
def _get_key_name_pattern(self, identity: Identity) -> Pattern[str]: """Make the regex pattern from the format string. Put two different random keys, compare two outputs, and then replace the difference with wildcard. """ cls = type(self) sample_keys = cls._sample_keys if sample_keys is None: sample_keys = (RSAKey.generate(bits=512), RSAKey.generate(bits=512), ECDSAKey.generate(bits=256), ECDSAKey.generate(bits=256)) cls._sample_keys = sample_keys sample_names = [self._get_key_name(identity, k) for k in sample_keys] if len(frozenset(sample_names)) < 2: return re.compile('^' + re.escape(sample_names[0]) + '$') prefix = os.path.commonprefix(sample_names) postfix = os.path.commonprefix([n[::-1] for n in sample_names])[::-1] return re.compile( '^{}.+?{}$'.format(re.escape(prefix), re.escape(postfix)) )
def test_list_public_keys(fx_app, fx_key_store, fx_authorized_identity, fx_token_id): with fx_app.test_client() as c: response = c.get(get_url("list_public_keys", token_id=fx_token_id)) assert response.status_code == 200 assert response.mimetype == "application/json" assert response.data == b"{}" key = RSAKey.generate(1024) fx_key_store.register(fx_authorized_identity, key) with fx_app.test_client() as c: response = c.get(get_url("list_public_keys", token_id=fx_token_id)) assert response.status_code == 200 assert response.mimetype == "application/json" data = {f: parse_openssh_pubkey(k) for f, k in json.loads(response.data).items()} assert data == {get_key_fingerprint(key): key}
def test_add_public_key(fx_app, fx_key_store, fx_authorized_identity, fx_token_id): pkey = RSAKey.generate(1024) with fx_app.test_client() as c: response = c.post( get_url("add_public_key", token_id=fx_token_id), content_type="text/plain", data=format_openssh_pubkey(pkey).encode(), ) assert response.status_code == 201 key_data = response.data assert parse_openssh_pubkey(key_data.decode()) == pkey assert pkey in fx_key_store.list_keys(fx_authorized_identity) r = c.get(response.location) assert r.data == key_data
def gen_keys(emial, key=""): """ 生成公钥 私钥 """ output = StringIO.StringIO() sbuffer = StringIO.StringIO() key_content = {} if not key: try: key = RSAKey.generate(2048) key.write_private_key(output) private_key = output.getvalue() except Exception, ex: return False, str(ex)
def test_authorize(fx_sftpd): port, (thread, path, ev) = fx_sftpd.popitem() thread.start() master_key = RSAKey.generate(1024) public_keys = {RSAKey.generate(1024), RSAKey.generate(1024)} authorized_keys_path = path.mkdir('.ssh').join('authorized_keys') with authorized_keys_path.open('w') as f: print(format_openssh_pubkey(master_key), file=f) expires_at = authorize( public_keys, master_key, Remote('user', '127.0.0.1', port), timeout=datetime.timedelta(seconds=5) ) with authorized_keys_path.open() as f: saved_keys = map(parse_openssh_pubkey, f) assert frozenset(saved_keys) == (public_keys | {master_key}) while datetime.datetime.now(datetime.timezone.utc) <= expires_at: time.sleep(1) time.sleep(1) with authorized_keys_path.open() as f: saved_keys = map(parse_openssh_pubkey, f) assert frozenset(saved_keys) == {master_key}
def generate_key_pair(cluster, girder_token=None): """ Task to generate a new key pair for a user. """ cluster_id = cluster['_id'] status_url = '%s/clusters/%s' \ % (cumulus.config.girder.baseUrl, cluster_id) log = get_cluster_logger(cluster, girder_token) headers = {'Girder-Token': girder_token} try: new_key = RSAKey.generate(bits=4096) passphrase = ''.join( random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(64)) key_path = os.path.join(cumulus.config.ssh.keyStore, cluster_id) new_key.write_private_key_file(key_path, password=passphrase) # Allow group read as well os.chmod(key_path, stat.S_IREAD | stat.S_IWRITE | stat.S_IRGRP) comment = 'cumulus generated access key' public_key = '%s %s %s' % (new_key.get_name(), new_key.get_base64(), comment) # Update passphrase and public key on cluster model config_update = { 'config': { 'ssh': { 'passphrase': passphrase, 'publicKey': public_key } }, 'status': 'created' } patch_url = '%s/clusters/%s' % (cumulus.config.girder.baseUrl, cluster_id) request = requests.patch(patch_url, json=config_update, headers=headers) check_status(request) except Exception as ex: r = requests.patch(status_url, headers=headers, json={'status': 'error'}) check_status(r) # Log the error message log.error(ex)
def fx_authorized_sftp(fx_sftpd, fx_authorized_keys): port, (thread, path, ev) = fx_sftpd.popitem() thread.start() key = RSAKey.generate(1024) dot_ssh = path.mkdir('.ssh') with dot_ssh.join('authorized_keys').open('w') as f: print(format_openssh_pubkey(key), file=f) for authorized_key in fx_authorized_keys: print(format_openssh_pubkey(authorized_key), file=f) transport = Transport(('127.0.0.1', port)) transport.connect(username='******', pkey=key) sftp_client = SFTPClient.from_transport(transport) yield sftp_client, path, [key] + fx_authorized_keys sftp_client.close() transport.close()
def generate_private_rsa_key_file(ssh_path, key_base_name): """ Generate a default PRIVATE SSH key file using RSA """ # paramiko uses pycrypto's RandomPool which throws a deprecation warning import warnings with warnings.catch_warnings(): warnings.simplefilter("ignore") from paramiko import RSAKey key = RSAKey.generate(2048) private_key_file_name = ssh_path + "/" + key_base_name key.write_private_key_file(private_key_file_name) # Ok, pass back private key object return key
def generate_key_pair(cluster, girder_token=None): ''' Task to generate a new key pair for a user. ''' cluster_id = cluster['_id'] status_url = '%s/clusters/%s' \ % (cumulus.config.girder.baseUrl, cluster_id) log = get_cluster_logger(cluster, girder_token) headers = {'Girder-Token': girder_token} try: new_key = RSAKey.generate(bits=4096) passphrase = ''.join(random.SystemRandom() .choice(string.ascii_uppercase + string.digits) for _ in range(64)) key_path = os.path.join(cumulus.config.ssh.keyStore, cluster_id) new_key.write_private_key_file(key_path, password=passphrase) # Allow group read as well os.chmod(key_path, stat.S_IREAD | stat.S_IWRITE | stat.S_IRGRP) comment = 'cumulus generated access key' public_key = '%s %s %s' % (new_key.get_name(), new_key.get_base64(), comment) # Update passphrase and public key on cluster model config_update = { 'config': { 'ssh': { 'passphrase': passphrase, 'publicKey': public_key } }, 'status': 'created' } patch_url = '%s/clusters/%s' % (cumulus.config.girder.baseUrl, cluster_id) request = requests.patch(patch_url, json=config_update, headers=headers) check_status(request) except Exception as ex: r = requests.patch(status_url, headers=headers, json={'status': 'error'}) check_status(r) # Log the error message log.error(ex.message)
def test_cloud_master_key_store(): driver = DummyStorageDriver('', '') container = driver.create_container('geofront-test') s = CloudMasterKeyStore(driver, container, 'test_id_rsa') with raises(EmptyStoreError): s.load() key = RSAKey.generate(1024) s.save(key) driver.get_object(container.name, 'test_id_rsa') # assert object exists # Mocking implementation with io.StringIO() as mock: key.write_private_key(mock) mock.seek(0) dummy.DummyFileObject = lambda *a, **k: mock stored_key = s.load() assert isinstance(stored_key, RSAKey) assert stored_key.get_base64() == stored_key.get_base64()
def test_two_phase_renewal_stop(fx_authorized_servers, fx_master_key): remote_set = { Remote('user', '127.0.0.1', port) for port in fx_authorized_servers } old_key = fx_master_key new_key = RSAKey.generate(1024) for t, path, ev in fx_authorized_servers.values(): assert authorized_key_set(path) == {old_key} SomeException = type('SomeException', (Exception,), {}) with raises(SomeException): with TwoPhaseRenewal(remote_set, old_key, new_key): for t, path, ev in fx_authorized_servers.values(): assert authorized_key_set(path) == {old_key, new_key} raise SomeException('something went wrong') for t, path, ev in fx_authorized_servers.values(): assert old_key in authorized_key_set(path)
def renew_master_key(servers: collections.abc.Set, key_store: MasterKeyStore, bits: int=2048) -> PKey: """Renew the master key. It creates a new master key, makes ``servers`` to authorize the new key, replaces the existing master key with the new key in the ``key_store``, and then makes ``servers`` to deauthorize the old key. All these operations are done in a two-phase renewal transaction. :param servers: servers to renew the master key. every element has to be an instance of :class:`~.remote.Remote` :type servers: :class:`collections.abc.Set` :param key_store: the master key store to update :type key_store: :class:`MasterKeyStore` :param bits: the number of bits the generated key should be. it has to be 1024 at least, and a multiple of 256. 2048 by default :type bits: :class:`int` :returns: the created new master key :rtype: :class:`paramiko.pkey.PKey` .. versionadded:: 0.2.0 The ``bits`` optional parameter. """ logger = logging.getLogger(__name__ + '.renew_master_key') logger.info('renew the master key...') old_key = key_store.load() logger.info('the existing master key: %s', get_key_fingerprint(old_key)) new_key = RSAKey.generate(bits) logger.info('created new master key: %s', get_key_fingerprint(new_key)) logger.info('authorize the new master key...') with TwoPhaseRenewal(servers, old_key, new_key): logger.info('the new master key is authorized; ' 'update the key store...') key_store.save(new_key) logger.info('master key store is successfully updated; ' 'deauthorize the existing master key...') logger.info('master key renewal has finished') return new_key