[Kimchi-devel] [PATCH] [Kimchi] Issue #1063: Upon migrating guest to remote server, password less ssh is permanent

archus at linux.vnet.ibm.com archus at linux.vnet.ibm.com
Tue Nov 15 16:22:47 UTC 2016


From: Archana Singh <archus at linux.vnet.ibm.com>

Changes to ensure that password less login is removed if its setup by kimchi.
It also provide option for user to specify if user want to keep
the password less login setup by kimchi, if not specified password
less login setup by kimchi will be removed.
However if password less login is not setup by kimchi,
code does not remove the password less login.

Signed-off-by: Archana Singh <archus at linux.vnet.ibm.com>
---
 model/vms.py | 180 ++++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 129 insertions(+), 51 deletions(-)

diff --git a/model/vms.py b/model/vms.py
index bff7ed2..28aab76 100644
--- a/model/vms.py
+++ b/model/vms.py
@@ -1747,58 +1747,59 @@ class VMModel(object):
             if password is None:
                 raise OperationFailed("KCHVM0056E",
                                       {'host': remote_host, 'user': user})
-            else:
-                self._set_password_less_login(remote_host, user, password)
+            return False
+        return True
 
-    def _set_password_less_login(self, remote_host, user, passwd):
-        home_dir = '/root' if user is 'root' else '/home/%s' % user
+    def _read_id_rsa_pub_file(self, id_rsa_pub_file):
+        data = None
+        with open(id_rsa_pub_file, "r") as id_file:
+            data = id_file.read()
+        return data
 
-        id_rsa_file = "%s/.ssh/id_rsa" % home_dir
-        id_rsa_pub_file = id_rsa_file + '.pub'
-        ssh_port = 22
-        ssh_client = None
+    def _create_root_ssh_key_if_required(self, user, id_rsa_pub_file,
+                                         id_rsa_file):
+        if os.path.isfile(id_rsa_pub_file):
+            return
 
-        def read_id_rsa_pub_file():
-            data = None
-            with open(id_rsa_pub_file, "r") as id_file:
-                data = id_file.read()
-            return data
+        with open("/dev/zero") as zero_input:
+            cmd = ['ssh-keygen', '-q', '-N', '', '-f', id_rsa_file]
+            proc = subprocess.Popen(
+                cmd,
+                stdin=zero_input,
+                stdout=open(os.devnull, 'wb')
+            )
+            out, err = proc.communicate()
 
-        def create_root_ssh_key_if_required():
-            if os.path.isfile(id_rsa_pub_file):
-                return
+            if not os.path.isfile(id_rsa_pub_file):
+                raise OperationFailed("KCHVM0070E")
 
-            with open("/dev/zero") as zero_input:
-                cmd = ['ssh-keygen', '-q', '-N', '', '-f', id_rsa_file]
-                proc = subprocess.Popen(
-                    cmd,
-                    stdin=zero_input,
-                    stdout=open(os.devnull, 'wb')
+            if user != 'root':
+                id_rsa_content = self._read_id_rsa_pub_file(id_rsa_pub_file)
+                updated_content = id_rsa_content.replace(
+                    ' root@', ' %s@' % user
                 )
-                out, err = proc.communicate()
+                with open(id_rsa_pub_file, 'w+') as f:
+                    f.write(updated_content)
 
-                if not os.path.isfile(id_rsa_pub_file):
-                    raise OperationFailed("KCHVM0070E")
+                user_uid = pwd.getpwnam(user).pw_uid
+                user_gid = pwd.getpwnam(user).pw_gid
+                os.chown(id_rsa_pub_file, user_uid, user_gid)
+                os.chown(id_rsa_file, user_uid, user_gid)
 
-                if user is not 'root':
-                    id_rsa_content = read_id_rsa_pub_file()
-                    updated_content = id_rsa_content.replace(
-                        ' root@', ' %s@' % user
-                    )
-                    with open(id_rsa_pub_file, 'w+') as f:
-                        f.write(updated_content)
+    def _get_ssh_client(self, remote_host, user, passwd, ssh_port):
+        ssh_client = paramiko.SSHClient()
+        ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+        ssh_client.connect(remote_host, ssh_port, username=user,
+                           password=passwd, timeout=4)
+        return ssh_client
 
-                    user_uid = pwd.getpwnam(user).pw_uid
-                    user_gid = pwd.getpwnam(user).pw_gid
-                    os.chown(id_rsa_pub_file, user_uid, user_gid)
-                    os.chown(id_rsa_file, user_uid, user_gid)
+    def _set_password_less_login(self, remote_host, user, passwd):
+        home_dir = '/root' if user == 'root' else '/home/%s' % user
 
-        def get_ssh_client(remote_host, user, passwd):
-            ssh_client = paramiko.SSHClient()
-            ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
-            ssh_client.connect(remote_host, ssh_port, username=user,
-                               password=passwd, timeout=4)
-            return ssh_client
+        id_rsa_file = "%s/.ssh/id_rsa" % home_dir
+        id_rsa_pub_file = id_rsa_file + '.pub'
+        ssh_port = 22
+        ssh_client = None
 
         def append_id_rsa_to_remote_authorized_keys(ssh_client, id_rsa_data):
             sftp_client = ssh_client.open_sftp()
@@ -1824,9 +1825,11 @@ class VMModel(object):
             sftp_client.close()
 
         try:
-            create_root_ssh_key_if_required()
-            id_rsa_data = read_id_rsa_pub_file()
-            ssh_client = get_ssh_client(remote_host, user, passwd)
+            self._create_root_ssh_key_if_required(user, id_rsa_pub_file,
+                                                  id_rsa_file)
+            id_rsa_data = self._read_id_rsa_pub_file(id_rsa_pub_file)
+            ssh_client = self._get_ssh_client(remote_host, user, passwd,
+                                              ssh_port)
             append_id_rsa_to_remote_authorized_keys(
                 ssh_client,
                 id_rsa_data
@@ -1865,17 +1868,21 @@ class VMModel(object):
 
     def migration_pre_check(self, remote_host, user, password):
         self._check_if_host_not_localhost(remote_host)
-        self._check_if_password_less_login_enabled(
+        default_passless_status = self._check_if_password_less_login_enabled(
             remote_host,
             user,
             password
         )
-        self._check_remote_libvirt_conn(remote_host, user)
+        if not default_passless_status:
+            self._set_password_less_login(remote_host, user, password)
+
         self._check_if_migrating_same_arch_hypervisor(remote_host, user)
 
         if platform.machine() in ['ppc64', 'ppc64le']:
             self._check_ppc64_subcores_per_core(remote_host, user)
 
+        return default_passless_status
+
     def _check_if_path_exists_in_remote_host(self, path, remote_host, user):
         username_host = "%s@%s" % (user, remote_host)
         cmd = ['ssh', '-oStrictHostKeyChecking=no', username_host,
@@ -1957,15 +1964,22 @@ class VMModel(object):
                         user
                     )
 
-    def migrate(self, name, remote_host, user=None, password=None):
+    def migrate(self, name, remote_host, user=None, password=None,
+                remove_passless_login=True):
         name = name.decode('utf-8')
         remote_host = remote_host.decode('utf-8')
 
         if user is None:
             user = 'root'
+        user = user.encode('utf-8')
+
+        default_passless_status = self.migration_pre_check(remote_host, user,
+                                                           password)
 
-        self.migration_pre_check(remote_host, user, password)
-        dest_conn = self._get_remote_libvirt_conn(remote_host, user)
+        if default_passless_status:
+            remove_passless_login = False
+
+        dest_conn = self._get_remote_libvirt_conn(remote_host)
 
         non_shared = self._check_if_nonshared_migration(
             name,
@@ -1977,18 +1991,80 @@ class VMModel(object):
                   'dest_conn': dest_conn,
                   'non_shared': non_shared,
                   'remote_host': remote_host,
-                  'user': user}
+                  'user': user,
+                  'password': password,
+                  'remove_passless_login': remove_passless_login}
         task_id = AsyncTask('/plugins/kimchi/vms/%s/migrate' % name,
                             self._migrate_task, params).id
 
         return self.task.lookup(task_id)
 
+    def _remove_password_less_login(self, remote_host, user, passwd):
+        home_dir = '/root' if user == 'root' else '/home/%s' % user
+
+        id_rsa_file = "%s/.ssh/id_rsa" % home_dir
+        id_rsa_pub_file = id_rsa_file + '.pub'
+        ssh_port = 22
+        ssh_client = None
+
+        def remove_id_rsa_to_remote_authorized_keys(ssh_client, id_rsa_data):
+            sftp_client = ssh_client.open_sftp()
+            ssh_dir = '%s/.ssh' % home_dir
+
+            try:
+                sftp_client.chdir(ssh_dir)
+            except IOError:
+                raise OperationFailed(
+                    "KCHVM0089E",
+                    {'host': remote_host, 'user': user, 'sshdir': ssh_dir}
+                )
+            file_handler = sftp_client.file(
+                '%s/.ssh/authorized_keys' % home_dir,
+                mode='r',
+                bufsize=1
+            )
+            lines = file_handler.readlines()
+            try:
+                lines.remove(id_rsa_data)
+            except ValueError:
+                pass
+            file_handler = sftp_client.file(
+                 '%s/.ssh/authorized_keys' % home_dir,
+                 mode='w',
+                 bufsize=1
+            )
+            file_handler.writelines(lines)
+            file_handler.flush()
+            file_handler.close()
+            sftp_client.close()
+
+        try:
+            self._create_root_ssh_key_if_required(user, id_rsa_pub_file,
+                                                  id_rsa_file)
+            id_rsa_data = self._read_id_rsa_pub_file(id_rsa_pub_file)
+            ssh_client = self._get_ssh_client(remote_host, user, passwd,
+                                              ssh_port)
+            remove_id_rsa_to_remote_authorized_keys(
+                ssh_client,
+                id_rsa_data
+            )
+        except Exception, e:
+            raise OperationFailed(
+                "KCHVM0068E",
+                {'host': remote_host, 'user': user, 'error': e}
+            )
+        finally:
+            if ssh_client:
+                ssh_client.close()
+
     def _migrate_task(self, cb, params):
         name = params['name'].decode('utf-8')
         dest_conn = params['dest_conn']
         non_shared = params['non_shared']
         remote_host = params['remote_host']
         user = params['user']
+        password = params['password']
+        remove_passless_login = params['remove_passless_login']
 
         cb('starting a migration')
 
@@ -2022,6 +2098,8 @@ class VMModel(object):
             raise OperationFailed('KCHVM0058E', {'err': e.message,
                                                  'name': name})
         finally:
+            if remove_passless_login:
+                self._remove_password_less_login(remote_host, user, password)
             dest_conn.close()
 
         cb('Migrate finished', True)
-- 
2.7.4




More information about the Kimchi-devel mailing list