[caribou,r=james-page,t=james-page] SSH key exchange in large environments
In large OpenStack deployments, the length of the base64 encoded SSH keys and authorized hosts file exceeds the maximum command line parameter length. Pass keys/lines individually to work around this issue.
This commit is contained in:
commit
ac08bebbb1
@ -25,7 +25,7 @@ options:
|
||||
rabbit-vhost:
|
||||
default: openstack
|
||||
type: string
|
||||
decsription: Rabbitmq vhost
|
||||
description: Rabbitmq vhost
|
||||
use-syslog:
|
||||
type: boolean
|
||||
default: False
|
||||
|
@ -337,26 +337,46 @@ def import_authorized_keys(user='root', prefix=None):
|
||||
"""Import SSH authorized_keys + known_hosts from a cloud-compute relation
|
||||
and store in user's $HOME/.ssh.
|
||||
"""
|
||||
known_hosts = []
|
||||
authorized_keys = []
|
||||
if prefix:
|
||||
hosts = relation_get('{}_known_hosts'.format(prefix))
|
||||
auth_keys = relation_get('{}_authorized_keys'.format(prefix))
|
||||
known_hosts_index = relation_get(
|
||||
'{}_known_hosts_max_index'.format(prefix))
|
||||
if known_hosts_index:
|
||||
for index in range(0, int(known_hosts_index)):
|
||||
known_hosts.append(relation_get(
|
||||
'{}_known_hosts_{}'.format(prefix, index)))
|
||||
authorized_keys_index = relation_get(
|
||||
'{}_authorized_keys_max_index'.format(prefix))
|
||||
if authorized_keys_index:
|
||||
for index in range(0, int(authorized_keys_index)):
|
||||
authorized_keys.append(relation_get(
|
||||
'{}_authorized_keys_{}'.format(prefix, index)))
|
||||
else:
|
||||
# XXX: Should this be managed via templates + contexts?
|
||||
hosts = relation_get('known_hosts')
|
||||
auth_keys = relation_get('authorized_keys')
|
||||
known_hosts_index = relation_get('known_hosts_max_index')
|
||||
if known_hosts_index:
|
||||
for index in range(0, int(known_hosts_index)):
|
||||
known_hosts.append(relation_get(
|
||||
'known_hosts_{}'.format(index)))
|
||||
authorized_keys_index = relation_get('authorized_keys_max_index')
|
||||
if authorized_keys_index:
|
||||
for index in range(0, int(authorized_keys_index)):
|
||||
authorized_keys.append(relation_get(
|
||||
'authorized_keys_{}'.format(index)))
|
||||
|
||||
# XXX: Need to fix charm-helpers to return None for empty settings,
|
||||
# in all cases.
|
||||
if not hosts or not auth_keys:
|
||||
# XXX: Should partial return of known_hosts or authorized_keys
|
||||
# be allowed ?
|
||||
if not len(known_hosts) or not len(authorized_keys):
|
||||
return
|
||||
|
||||
dest = os.path.join(pwd.getpwnam(user).pw_dir, '.ssh')
|
||||
log('Saving new known_hosts and authorized_keys file to: %s.' % dest)
|
||||
|
||||
with open(os.path.join(dest, 'authorized_keys'), 'wb') as _keys:
|
||||
_keys.write(b64decode(auth_keys))
|
||||
with open(os.path.join(dest, 'known_hosts'), 'wb') as _hosts:
|
||||
_hosts.write(b64decode(hosts))
|
||||
for index in range(0, int(known_hosts_index)):
|
||||
_hosts.write('{}\n'.format(known_hosts[index]))
|
||||
with open(os.path.join(dest, 'authorized_keys'), 'wb') as _keys:
|
||||
for index in range(0, int(authorized_keys_index)):
|
||||
_keys.write('{}\n'.format(authorized_keys[index]))
|
||||
|
||||
|
||||
def do_openstack_upgrade():
|
||||
|
@ -185,55 +185,89 @@ class NovaComputeUtilsTests(CharmTestCase):
|
||||
def _test_import_authorized_keys_base(self, getpwnam, prefix=None):
|
||||
getpwnam.return_value = self.fake_user('foo')
|
||||
self.relation_get.side_effect = [
|
||||
'Zm9vX2tleQo=', # relation_get('known_hosts')
|
||||
'Zm9vX2hvc3QK', # relation_get('authorized_keys')
|
||||
3, # relation_get('known_hosts_max_index')
|
||||
'k_h_0', # relation_get_('known_hosts_0')
|
||||
'k_h_1', # relation_get_('known_hosts_1')
|
||||
'k_h_2', # relation_get_('known_hosts_2')
|
||||
3, # relation_get('authorized_keys_max_index')
|
||||
'auth_0', # relation_get('authorized_keys_0')
|
||||
'auth_1', # relation_get('authorized_keys_1')
|
||||
'auth_2', # relation_get('authorized_keys_2')
|
||||
]
|
||||
|
||||
ex_open = [
|
||||
call('/home/foo/.ssh/authorized_keys', 'wb'),
|
||||
call('/home/foo/.ssh/known_hosts', 'wb')
|
||||
call('/home/foo/.ssh/known_hosts', 'wb'),
|
||||
call('/home/foo/.ssh/authorized_keys', 'wb')
|
||||
]
|
||||
ex_write = [
|
||||
call('foo_host\n'),
|
||||
call('foo_key\n'),
|
||||
call('k_h_0\n'),
|
||||
call('k_h_1\n'),
|
||||
call('k_h_2\n'),
|
||||
call('auth_0\n'),
|
||||
call('auth_1\n'),
|
||||
call('auth_2\n')
|
||||
]
|
||||
|
||||
with patch_open() as (_open, _file):
|
||||
utils.import_authorized_keys(user='foo')
|
||||
self.assertEquals(ex_open, _open.call_args_list)
|
||||
self.assertEquals(ex_write, _file.write.call_args_list)
|
||||
|
||||
self.relation_get.assert_has_called([
|
||||
call('known_hosts').
|
||||
call('authorized_keys')
|
||||
])
|
||||
expected_relations = [
|
||||
call('known_hosts_max_index'),
|
||||
call('known_hosts_0'),
|
||||
call('known_hosts_1'),
|
||||
call('known_hosts_2'),
|
||||
call('authorized_keys_max_index'),
|
||||
call('authorized_keys_0'),
|
||||
call('authorized_keys_1'),
|
||||
call('authorized_keys_2')
|
||||
]
|
||||
self.assertEquals(sorted(self.relation_get.call_args_list),
|
||||
sorted(expected_relations))
|
||||
|
||||
@patch('pwd.getpwnam')
|
||||
def test_import_authorized_keys_prefix(self, getpwnam):
|
||||
getpwnam.return_value = self.fake_user('foo')
|
||||
self.relation_get.side_effect = [
|
||||
'Zm9vX2tleQo=', # relation_get('known_hosts')
|
||||
'Zm9vX2hvc3QK', # relation_get('authorized_keys')
|
||||
3, # relation_get('bar_known_hosts_max_index')
|
||||
'k_h_0', # relation_get_('bar_known_hosts_0')
|
||||
'k_h_1', # relation_get_('bar_known_hosts_1')
|
||||
'k_h_2', # relation_get_('bar_known_hosts_2')
|
||||
3, # relation_get('bar_authorized_keys_max_index')
|
||||
'auth_0', # relation_get('bar_authorized_keys_0')
|
||||
'auth_1', # relation_get('bar_authorized_keys_1')
|
||||
'auth_2', # relation_get('bar_authorized_keys_2')
|
||||
]
|
||||
|
||||
ex_open = [
|
||||
call('/home/foo/.ssh/authorized_keys', 'wb'),
|
||||
call('/home/foo/.ssh/known_hosts', 'wb')
|
||||
call('/home/foo/.ssh/known_hosts', 'wb'),
|
||||
call('/home/foo/.ssh/authorized_keys', 'wb')
|
||||
]
|
||||
ex_write = [
|
||||
call('foo_host\n'),
|
||||
call('foo_key\n'),
|
||||
call('k_h_0\n'),
|
||||
call('k_h_1\n'),
|
||||
call('k_h_2\n'),
|
||||
call('auth_0\n'),
|
||||
call('auth_1\n'),
|
||||
call('auth_2\n')
|
||||
]
|
||||
|
||||
with patch_open() as (_open, _file):
|
||||
utils.import_authorized_keys(user='foo', prefix='bar')
|
||||
self.assertEquals(ex_open, _open.call_args_list)
|
||||
self.assertEquals(ex_write, _file.write.call_args_list)
|
||||
|
||||
self.relation_get.assert_has_called([
|
||||
call('bar_known_hosts').
|
||||
call('bar_authorized_keys')
|
||||
])
|
||||
expected_relations = [
|
||||
call('bar_known_hosts_max_index'),
|
||||
call('bar_known_hosts_0'),
|
||||
call('bar_known_hosts_1'),
|
||||
call('bar_known_hosts_2'),
|
||||
call('bar_authorized_keys_max_index'),
|
||||
call('bar_authorized_keys_0'),
|
||||
call('bar_authorized_keys_1'),
|
||||
call('bar_authorized_keys_2')
|
||||
]
|
||||
self.assertEquals(sorted(self.relation_get.call_args_list),
|
||||
sorted(expected_relations))
|
||||
|
||||
@patch('subprocess.check_call')
|
||||
def test_import_keystone_cert_missing_data(self, check_call):
|
||||
|
Loading…
x
Reference in New Issue
Block a user