]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
cephadm: add sudo ssh user option
authorDaniel-Pivonka <dpivonka@redhat.com>
Thu, 11 Jun 2020 14:28:44 +0000 (10:28 -0400)
committerSebastian Wagner <sebastian.wagner@suse.com>
Tue, 14 Jul 2020 09:39:06 +0000 (11:39 +0200)
add the ability to use a non-root users for connecting to hosts, this user requires pass wordless sudo access

useful for clusters that have root ssh access disabled

Fixes: https://tracker.ceph.com/issues/44866
Signed-off-by: Daniel-Pivonka <dpivonka@redhat.com>
(cherry picked from commit 1052b9db7bdc50f61705e1f1331c5cbb20120586)

doc/cephadm/install.rst
doc/cephadm/operations.rst
doc/man/8/cephadm.rst
src/cephadm/cephadm
src/pybind/mgr/cephadm/module.py

index c172b903dab6c01c7c890151ba4a4d30fae9daef..3a1463a56053707a0558f7240dffd952c073be9a 100644 (file)
@@ -105,6 +105,11 @@ or run ``cephadm bootstrap -h`` to see all available options:
   cluster by putting them in a standard ini-style configuration file
   and using the ``--config *<config-file>*`` option.
 
+* You can choose the ssh user cephadm will use to connect to hosts by
+  using the ``--ssh-user *<user>*`` option. The ssh key will be added
+  to ``/home/*<user>*/.ssh/authorized_keys``. This user will require
+  passwordless sudo access. 
+
 
 Enable Ceph CLI
 ===============
index d7f5ee7128efd11476f6c4fe12b4edfdf51150a5..198286a3a3046c70b3d95be1e5c982cf731fbbaf 100644 (file)
@@ -141,6 +141,21 @@ You will then need to restart the mgr daemon to reload the configuration with::
 
   ceph mgr fail
 
+Configuring a different SSH user
+----------------------------------
+
+Cephadm must be able to log into all the Ceph cluster nodes as an user
+that has enough privileges to download container images, start containers
+and execute commands without prompting for a password. If you do not want
+to use the "root" user (default option in cephadm), you must provide
+cephadm the name of the user that is going to be used to perform all the
+cephadm operations. Use the command::
+
+  ceph cephadm set-user <user>
+
+Prior to running this the cluster ssh key needs to be added to this users
+authorized_keys file and non-root users must have passwordless sudo access.
+
 
 Customizing the SSH configuration
 ---------------------------------
index 39859554cbc44379b43c8de7a943f2279b222676..6c7ddb2508e9949c254fcd460f4b2dbed2a808dc 100644 (file)
@@ -64,7 +64,8 @@ Synopsis
 |                           [--dashboard-crt DASHBOARD_CRT]
 |                           [--ssh-config SSH_CONFIG]
 |                           [--ssh-private-key SSH_PRIVATE_KEY]
-|                           [--ssh-public-key SSH_PUBLIC_KEY] [--skip-mon-network]
+|                           [--ssh-public-key SSH_PUBLIC_KEY] 
+|                           [--ssh-user SSH_USER] [--skip-mon-network]
 |                           [--skip-dashboard] [--dashboard-password-noupdate]
 |                           [--no-minimize-config] [--skip-ping-check]
 |                           [--skip-pull] [--skip-firewalld] [--allow-overwrite]
@@ -206,6 +207,7 @@ Arguments:
 * [--ssh-config SSH_CONFIG] SSH config
 * [--ssh-private-key SSH_PRIVATE_KEY] SSH private key
 * [--ssh-public-key SSH_PUBLIC_KEY] SSH public key
+* [--ssh-user SSH_USER]           set user for SSHing to cluster hosts, passwordless sudo will be needed for non-root users'
 * [--skip-mon-network]            set mon public_network based on bootstrap mon ip
 * [--skip-dashboard]              do not enable the Ceph Dashboard
 * [--dashboard-password-noupdate] stop forced dashboard password change
index 8e0482abdd9606d2e878a8ce91514dec71ff83d7..3981607ef6833a7b375253b76ba10b358ee8c57f 100755 (executable)
@@ -46,6 +46,7 @@ import json
 import logging
 import os
 import platform
+import pwd
 import random
 import re
 import select
@@ -2668,6 +2669,8 @@ def command_bootstrap():
 
     # ssh
     if not args.skip_ssh:
+        cli(['config-key', 'set', 'mgr/cephadm/ssh_user', args.ssh_user])
+
         logger.info('Enabling cephadm module...')
         cli(['mgr', 'module', 'enable', 'cephadm'])
         wait_for_mgr_restart()
@@ -2699,11 +2702,21 @@ def command_bootstrap():
                 f.write(ssh_pub)
             logger.info('Wrote public SSH key to to %s' % args.output_pub_ssh_key)
 
-            logger.info('Adding key to root@localhost\'s authorized_keys...')
-            if not os.path.exists('/root/.ssh'):
-                os.mkdir('/root/.ssh', 0o700)
-            auth_keys_file = '/root/.ssh/authorized_keys'
+            logger.info('Adding key to %s@localhost\'s authorized_keys...' % args.ssh_user)
+            try:
+                s_pwd = pwd.getpwnam(args.ssh_user)
+            except KeyError as e:
+                raise Error('Cannot find uid/gid for ssh-user: %s' % (args.ssh_user))
+            ssh_uid = s_pwd.pw_uid
+            ssh_gid = s_pwd.pw_gid
+            ssh_dir = os.path.join(s_pwd.pw_dir, '.ssh')
+
+            if not os.path.exists(ssh_dir):
+                makedirs(ssh_dir, ssh_uid, ssh_gid, 0o700)
+                       
+            auth_keys_file = '%s/authorized_keys' % ssh_dir
             add_newline = False
+
             if os.path.exists(auth_keys_file):
                 with open(auth_keys_file, 'r') as f:
                     f.seek(0, os.SEEK_END)
@@ -2711,7 +2724,9 @@ def command_bootstrap():
                         f.seek(f.tell()-1, os.SEEK_SET) # go to last char
                         if f.read() != '\n':
                             add_newline = True
+
             with open(auth_keys_file, 'a') as f:
+                os.fchown(f.fileno(), ssh_uid, ssh_gid) # just in case we created it
                 os.fchmod(f.fileno(), 0o600)  # just in case we created it
                 if add_newline:
                     f.write('\n')
@@ -2786,7 +2801,7 @@ def command_bootstrap():
                         ssh_key = '/etc/ceph/ceph.pub'
                         if args.ssh_public_key:
                             ssh_key = args.ssh_public_key.name
-                        out, err, code = call_throws(['ssh-copy-id', '-f', '-i', ssh_key, 'root@%s' % split[1]])
+                        out, err, code = call_throws(['ssh-copy-id', '-f', '-i', ssh_key, '%s@%s' % (args.ssh_user, split[1])])
 
         mounts = {}
         mounts[pathify(args.apply_spec)] = '/tmp/spec.yml:z'
@@ -4645,6 +4660,10 @@ def _get_parser():
         '--ssh-public-key',
         type=argparse.FileType('r'),
         help='SSH public key')
+    parser_bootstrap.add_argument(
+        '--ssh-user',
+        default='root',
+        help='set user for SSHing to cluster hosts, passwordless sudo will be needed for non-root users')
 
     parser_bootstrap.add_argument(
         '--skip-mon-network',
index 0e1cd3f7c6a0e08550eee07fb9b1bc1584e097ea..29a6c9fbbc1f279ce7b626eb1a82853480bad2fd 100644 (file)
@@ -633,7 +633,7 @@ class CephadmOrchestrator(orchestrator.Orchestrator, MgrModule):
             self._ssh_options = None
 
         if self.mode == 'root':
-            self.ssh_user = 'root'
+            self.ssh_user = self.get_store('ssh_user', default='root')
         elif self.mode == 'cephadm-package':
             self.ssh_user = 'cephadm'
 
@@ -812,6 +812,30 @@ class CephadmOrchestrator(orchestrator.Orchestrator, MgrModule):
     def _get_user(self):
         return 0, self.ssh_user, ''
 
+    @orchestrator._cli_read_command(
+        'cephadm set-user',
+        'name=user,type=CephString',
+        'Set user for SSHing to cluster hosts, passwordless sudo will be needed for non-root users')
+    def set_ssh_user(self, user):
+        current_user = self.ssh_user
+
+        self.set_store('ssh_user', user)
+        self._reconfig_ssh()
+
+        host = self.cache.get_hosts()[0]
+        r = self._check_host(host)
+        if r is not None:
+            #connection failed reset user
+            self.set_store('ssh_user', current_user)
+            self._reconfig_ssh()
+            return -errno.EINVAL, '', 'ssh connection %s@%s failed' % (user, host)
+
+        msg = 'ssh user set to %s' % user
+        if user != 'root':
+            msg += ' sudo will be used'
+        self.log.info(msg)
+        return 0, msg, ''
+
     @orchestrator._cli_read_command(
         'cephadm check-host',
         'name=host,type=CephString '
@@ -871,7 +895,8 @@ class CephadmOrchestrator(orchestrator.Orchestrator, MgrModule):
         conn = remoto.Connection(
             n,
             logger=child_logger,
-            ssh_options=self._ssh_options)
+            ssh_options=self._ssh_options,
+            sudo=True if self.ssh_user != 'root' else False)
 
         r = conn.import_module(remotes)
         self._cons[host] = conn, r
@@ -921,7 +946,7 @@ class CephadmOrchestrator(orchestrator.Orchestrator, MgrModule):
             self.offline_hosts.add(host)
             self._reset_con(host)
 
-            user = 'root' if self.mode == 'root' else 'cephadm'
+            user = self.ssh_user if self.mode == 'root' else 'cephadm'
             msg = f'''Failed to connect to {host} ({addr}).
 Check that the host is reachable and accepts connections using the cephadm SSH key
 
@@ -1006,9 +1031,9 @@ you may want to run:
                             host, remotes.PYTHONS, remotes.PATH))
                 try:
                     out, err, code = remoto.process.check(
-                        conn,
-                        [python, '-u'],
-                        stdin=script.encode('utf-8'))
+                    conn,
+                    [python, '-u'],
+                    stdin=script.encode('utf-8'))
                 except RuntimeError as e:
                     self._reset_con(host)
                     if error_ok: