Commit a9542a4f authored by Thomas Thrainer's avatar Thomas Thrainer
Browse files

Support DSA SSH keys in bootstrap



As outlined in issue 338, Ganeti failed to initialize a cluster if no
RSA SSH key is present on the master node. This patch extends Ganetis
support to DSA keys, so clusters with only DSA keys are possible now.

This fixes issue 338.
Signed-off-by: default avatarThomas Thrainer <thomasth@google.com>
Reviewed-by: default avatarHelga Velroyen <helgav@google.com>
parent 026f444f
......@@ -577,8 +577,17 @@ def InitCluster(cluster_name, mac_prefix, # pylint: disable=R0913, R0914
errors.ECODE_INVAL)
# set up ssh config and /etc/hosts
sshline = utils.ReadFile(pathutils.SSH_HOST_RSA_PUB)
sshkey = sshline.split(" ")[1]
rsa_sshkey = ""
dsa_sshkey = ""
if os.path.isfile(pathutils.SSH_HOST_RSA_PUB):
sshline = utils.ReadFile(pathutils.SSH_HOST_RSA_PUB)
rsa_sshkey = sshline.split(" ")[1]
if os.path.isfile(pathutils.SSH_HOST_DSA_PUB):
sshline = utils.ReadFile(pathutils.SSH_HOST_DSA_PUB)
dsa_sshkey = sshline.split(" ")[1]
if not rsa_sshkey and not dsa_sshkey:
raise errors.OpPrereqError("Failed to find SSH public keys",
errors.ECODE_ENVIRON)
if modify_etc_hosts:
utils.AddHostToEtcHosts(hostname.name, hostname.ip)
......@@ -606,7 +615,8 @@ def InitCluster(cluster_name, mac_prefix, # pylint: disable=R0913, R0914
# init of cluster config file
cluster_config = objects.Cluster(
serial_no=1,
rsahostkeypub=sshkey,
rsahostkeypub=rsa_sshkey,
dsahostkeypub=dsa_sshkey,
highest_used_port=(constants.FIRST_DRBD_PORT - 1),
mac_prefix=mac_prefix,
volume_group_name=vg_name,
......
......@@ -1190,7 +1190,7 @@ class ConfigWriter:
return self._config_data.cluster.enabled_hypervisors[0]
@locking.ssynchronized(_config_lock, shared=1)
def GetHostKey(self):
def GetRsaHostKey(self):
"""Return the rsa hostkey from the config.
@rtype: string
......@@ -1199,6 +1199,16 @@ class ConfigWriter:
"""
return self._config_data.cluster.rsahostkeypub
@locking.ssynchronized(_config_lock, shared=1)
def GetDsaHostKey(self):
"""Return the dsa hostkey from the config.
@rtype: string
@return: the dsa hostkey
"""
return self._config_data.cluster.dsahostkeypub
@locking.ssynchronized(_config_lock, shared=1)
def GetDefaultIAllocator(self):
"""Get the default instance allocator for this cluster.
......
......@@ -1519,6 +1519,7 @@ class Cluster(TaggableObject):
__slots__ = [
"serial_no",
"rsahostkeypub",
"dsahostkeypub",
"highest_used_port",
"tcpudp_port_pool",
"mac_prefix",
......
......@@ -328,6 +328,10 @@ def WriteKnownHostsFile(cfg, file_name):
"""Writes the cluster-wide equally known_hosts file.
"""
utils.WriteFile(file_name, mode=0600,
data="%s ssh-rsa %s\n" % (cfg.GetClusterName(),
cfg.GetHostKey()))
data = ""
if cfg.GetRsaHostKey():
data += "%s ssh-rsa %s\n" % (cfg.GetClusterName(), cfg.GetRsaHostKey())
if cfg.GetDsaHostKey():
data += "%s ssh-dss %s\n" % (cfg.GetClusterName(), cfg.GetDsaHostKey())
utils.WriteFile(file_name, mode=0600, data=data)
......@@ -669,6 +669,7 @@ type UidPool = [(Int, Int)]
-- * Cluster definitions
$(buildObject "Cluster" "cluster" $
[ simpleField "rsahostkeypub" [t| String |]
, simpleField "dsahostkeypub" [t| String |]
, simpleField "highest_used_port" [t| Int |]
, simpleField "tcpudp_port_pool" [t| [Int] |]
, simpleField "mac_prefix" [t| String |]
......
......@@ -76,6 +76,7 @@ class TestConfigRunner(unittest.TestCase):
cluster_config = objects.Cluster(
serial_no=1,
rsahostkeypub="",
dsahostkeypub="",
highest_used_port=(constants.FIRST_DRBD_PORT - 1),
mac_prefix="aa:00:00",
volume_group_name="xenvg",
......
......@@ -46,8 +46,9 @@ class TestKnownHosts(testutils.GanetiTestCase):
cfg = mocks.FakeConfig()
ssh.WriteKnownHostsFile(cfg, self.tmpfile)
self.assertFileContent(self.tmpfile,
"%s ssh-rsa %s\n" % (cfg.GetClusterName(),
mocks.FAKE_CLUSTER_KEY))
"%s ssh-rsa %s\n%s ssh-dss %s\n" %
(cfg.GetClusterName(), mocks.FAKE_CLUSTER_KEY,
cfg.GetClusterName(), mocks.FAKE_CLUSTER_KEY))
class TestGetUserFiles(unittest.TestCase):
......
......@@ -46,7 +46,10 @@ class FakeConfig:
def GetNodeList(self):
return ["a", "b", "c"]
def GetHostKey(self):
def GetRsaHostKey(self):
return FAKE_CLUSTER_KEY
def GetDsaHostKey(self):
return FAKE_CLUSTER_KEY
def GetClusterName(self):
......
......@@ -85,6 +85,7 @@ def SanitizeSecrets(opts, cfg): # pylint: disable=W0613
"""
cfg["cluster"]["rsahostkeypub"] = ""
cfg["cluster"]["dsahostkeypub"] = ""
for instance in cfg["instances"].values():
for disk in instance["disks"]:
RandomizeDiskSecrets(disk)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment