3131from . import clidisplay
3232from . import term
3333from . import lock
34+ from . import userdir
3435
3536
3637LOG_FILE = "/var/log/crmsh/ha-cluster-bootstrap.log"
4243SYSCONFIG_FW_CLUSTER = "/etc/sysconfig/SuSEfirewall2.d/services/cluster"
4344PCMK_REMOTE_AUTH = "/etc/pacemaker/authkey"
4445COROSYNC_CONF_ORIG = tmpfiles .create ()[1 ]
45- RSA_PRIVATE_KEY = "/root/.ssh/id_rsa"
46- RSA_PUBLIC_KEY = "/root/.ssh/id_rsa.pub"
47- AUTHORIZED_KEYS_FILE = "/root/.ssh/authorized_keys"
4846SERVICES_STOP_LIST = ["corosync-qdevice.service" , "corosync.service" , "hawk.service" ]
47+ USER_LIST = ["root" , "hacluster" ]
4948
5049INIT_STAGES = ("ssh" , "ssh_remote" , "csync2" , "csync2_remote" , "corosync" , "storage" , "sbd" , "cluster" , "vgfs" , "admin" , "qdevice" )
5150
@@ -95,6 +94,7 @@ def __init__(self):
9594 self .args = None
9695 self .ui_context = None
9796 self .interfaces_inst = None
97+ self .with_other_user = True
9898 self .default_nic_list = []
9999 self .default_ip_list = []
100100 self .local_ip_list = []
@@ -1134,22 +1134,66 @@ def init_ssh():
11341134 Configure passwordless SSH.
11351135 """
11361136 utils .start_service ("sshd.service" , enable = True )
1137- configure_local_ssh_key ()
1137+ for user in USER_LIST :
1138+ configure_local_ssh_key (user )
11381139
11391140
1140- def configure_local_ssh_key ():
1141+ def key_files (user ):
1142+ """
1143+ Find home directory for user and return key files with abspath
1144+ """
1145+ keyfile_dict = {}
1146+ home_dir = userdir .gethomedir (user )
1147+ keyfile_dict ['private' ] = "{}/.ssh/id_rsa" .format (home_dir )
1148+ keyfile_dict ['public' ] = "{}/.ssh/id_rsa.pub" .format (home_dir )
1149+ keyfile_dict ['authorized' ] = "{}/.ssh/authorized_keys" .format (home_dir )
1150+ return keyfile_dict
1151+
1152+
1153+ def is_nologin (user ):
1154+ """
1155+ Check if user's shell is /sbin/nologin
1156+ """
1157+ with open ("/etc/passwd" ) as f :
1158+ return re .search ("{}:.*:/sbin/nologin" .format (user ), f .read ())
1159+
1160+
1161+ def change_user_shell (user ):
1162+ """
1163+ To change user's login shell
1164+ """
1165+ if user != "root" and is_nologin (user ):
1166+ if not _context .yes_to_all :
1167+ status ("""
1168+ User {} will be changed the login shell as /bin/bash, and
1169+ be setted up authorized ssh access among cluster nodes""" .format (user ))
1170+ if not confirm ("Continue?" ):
1171+ _context .with_other_user = False
1172+ return
1173+ invoke ("usermod -s /bin/bash {}" .format (user ))
1174+
1175+
1176+ def configure_local_ssh_key (user = "root" ):
11411177 """
11421178 Configure ssh rsa key locally
11431179
1144- If /root /.ssh/id_rsa not exist, generate a new one
1145- Add /root/ .ssh/id_rsa.pub to /root /.ssh/authorized_keys anyway, make sure itself authorized
1180+ If <home_dir> /.ssh/id_rsa not exist, generate a new one
1181+ Add <home_dir>/ .ssh/id_rsa.pub to <home_dir> /.ssh/authorized_keys anyway, make sure itself authorized
11461182 """
1147- if not os .path .exists (RSA_PRIVATE_KEY ):
1148- status ("Generating SSH key" )
1149- invoke ("ssh-keygen -q -f {} -C 'Cluster Internal on {}' -N ''" .format (RSA_PRIVATE_KEY , utils .this_node ()))
1150- if not os .path .exists (AUTHORIZED_KEYS_FILE ):
1151- open (AUTHORIZED_KEYS_FILE , 'w' ).close ()
1152- append_unique (RSA_PUBLIC_KEY , AUTHORIZED_KEYS_FILE )
1183+ change_user_shell (user )
1184+
1185+ private_key , public_key , authorized_file = key_files (user ).values ()
1186+ if not os .path .exists (private_key ):
1187+ status ("Generating SSH key for {}" .format (user ))
1188+ cmd = "ssh-keygen -q -f {} -C 'Cluster Internal on {}' -N ''" .format (private_key , utils .this_node ())
1189+ cmd = utils .add_su (cmd , user )
1190+ rc , _ , err = invoke (cmd )
1191+ if not rc :
1192+ error ("Failed to generate ssh key for {}: {}" .format (user , err ))
1193+
1194+ if not os .path .exists (authorized_file ):
1195+ open (authorized_file , 'w' ).close ()
1196+ append_unique (public_key , authorized_file )
11531197
11541198
11551199def init_ssh_remote ():
@@ -1871,8 +1915,9 @@ def join_ssh(seed_host):
18711915 error ("No existing IP/hostname specified (use -c option)" )
18721916
18731917 utils .start_service ("sshd.service" , enable = True )
1874- configure_local_ssh_key ()
1875- swap_public_ssh_key (seed_host )
1918+ for user in USER_LIST :
1919+ configure_local_ssh_key (user )
1920+ swap_public_ssh_key (seed_host , user )
18761921
18771922 # This makes sure the seed host has its own SSH keys in its own
18781923 # authorized_keys file (again, to help with the case where the
@@ -1883,30 +1928,34 @@ def join_ssh(seed_host):
18831928 error ("Can't invoke crm cluster init -i {} ssh_remote on {}: {}" .format (_context .default_nic_list [0 ], seed_host , err ))
18841929
18851930
1886- def swap_public_ssh_key (remote_node ):
1931+ def swap_public_ssh_key (remote_node , user = "root" ):
18871932 """
18881933 Swap public ssh key between remote_node and local
18891934 """
1935+ if user != "root" and not _context .with_other_user :
1936+ return
1937+
1938+ _ , public_key , authorized_file = key_files (user ).values ()
18901939 # Detect whether need password to login to remote_node
1891- if utils .check_ssh_passwd_need (remote_node ):
1940+ if utils .check_ssh_passwd_need (remote_node , user ):
18921941 # If no passwordless configured, paste /root/.ssh/id_rsa.pub to remote_node's /root/.ssh/authorized_keys
1893- status ("Configuring SSH passwordless with root @{}" .format (remote_node ))
1942+ status ("Configuring SSH passwordless with {} @{}" .format (user , remote_node ))
18941943 # After this, login to remote_node is passwordless
1895- append_to_remote_file (RSA_PUBLIC_KEY , remote_node , AUTHORIZED_KEYS_FILE )
1944+ append_to_remote_file (public_key , remote_node , authorized_file )
18961945
18971946 try :
18981947 # Fetch public key file from remote_node
1899- public_key_file_remote = fetch_public_key_from_remote_node (remote_node )
1948+ public_key_file_remote = fetch_public_key_from_remote_node (remote_node , user )
19001949 except ValueError as err :
19011950 warn (err )
19021951 return
19031952 # Append public key file from remote_node to local's /root/.ssh/authorized_keys
19041953 # After this, login from remote_node is passwordless
19051954 # Should do this step even passwordless is True, to make sure we got two-way passwordless
1906- append_unique (public_key_file_remote , AUTHORIZED_KEYS_FILE )
1955+ append_unique (public_key_file_remote , authorized_file )
19071956
19081957
1909- def fetch_public_key_from_remote_node (node ):
1958+ def fetch_public_key_from_remote_node (node , user = "root" ):
19101959 """
19111960 Fetch public key file from remote node
19121961 Return a temp file contains public key
@@ -1915,8 +1964,9 @@ def fetch_public_key_from_remote_node(node):
19151964
19161965 # For dsa, might need to add PubkeyAcceptedKeyTypes=+ssh-dss to config file, see
19171966 # https://superuser.com/questions/1016989/ssh-dsa-keys-no-longer-work-for-password-less-authentication
1967+ home_dir = userdir .gethomedir (user )
19181968 for key in ("id_rsa" , "id_ecdsa" , "id_ed25519" , "id_dsa" ):
1919- public_key_file = "/root/ .ssh/{}.pub" .format (key )
1969+ public_key_file = "{}/ .ssh/{}.pub" .format (home_dir , key )
19201970 cmd = "ssh -oStrictHostKeyChecking=no root@{} 'test -f {}'" .format (node , public_key_file )
19211971 if not invokerc (cmd ):
19221972 continue
@@ -2128,7 +2178,8 @@ def setup_passwordless_with_other_nodes(init_node):
21282178
21292179 # Swap ssh public key between join node and other cluster nodes
21302180 for node in cluster_nodes_list :
2131- swap_public_ssh_key (node )
2181+ for user in USER_LIST :
2182+ swap_public_ssh_key (node , user )
21322183
21332184
21342185def join_cluster (seed_host ):
@@ -2487,7 +2538,7 @@ def bootstrap_join(context):
24872538 check_tty ()
24882539
24892540 corosync_active = utils .service_is_active ("corosync.service" )
2490- if corosync_active :
2541+ if corosync_active and _context . stage != "ssh" :
24912542 error ("Abort: Cluster is currently active. Run this command on a node joining the cluster." )
24922543
24932544 if not check_prereqs ("join" ):
0 commit comments