![Oliver Walsh](/assets/img/avatar_default.png)
This reuses the existing password generation mistral action to generate an ssh keypair to be used for nova cold migration Paramiko is used to generate the ssh key, based on the existing approach in the nova keypair api. Also update validation ssh key generation to reuse the same method. Change-Id: I9e7a1862911312ad942233ac8fc828f4e1be1dcf
113 lines
4.1 KiB
Python
113 lines
4.1 KiB
Python
# Copyright 2016 Red Hat, Inc.
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
import base64
|
|
import logging
|
|
import os
|
|
import paramiko
|
|
import struct
|
|
import time
|
|
import uuid
|
|
|
|
import passlib.utils as passutils
|
|
import six
|
|
|
|
from tripleo_common import constants
|
|
|
|
|
|
_MIN_PASSWORD_SIZE = 25
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
def generate_passwords(mistralclient=None, stack_env=None):
|
|
"""Create the passwords needed for deploying OpenStack via t-h-t.
|
|
|
|
This will create the set of passwords required by the undercloud and
|
|
overcloud installers that use tripleo-heat-templates and return them
|
|
as a dict. The mistralclient is optional and only used to obtain
|
|
the previously stored SnmpdReadonlyUserPassword supplied by the
|
|
undercloud to the overcloud deployment.
|
|
"""
|
|
|
|
passwords = {}
|
|
|
|
for name in constants.PASSWORD_PARAMETER_NAMES:
|
|
# Support users upgrading from Mitaka or otherwise creating a plan for
|
|
# a Heat stack that already exists.
|
|
if stack_env and name in stack_env.get('parameter_defaults', {}):
|
|
passwords[name] = stack_env['parameter_defaults'][name]
|
|
elif name.startswith("Ceph"):
|
|
if name == "CephClusterFSID":
|
|
# The FSID must be a UUID
|
|
passwords[name] = six.text_type(uuid.uuid1())
|
|
else:
|
|
# CephX keys aren't random strings
|
|
passwords[name] = create_cephx_key()
|
|
# Since by default generate_password uses all digits and ascii upper
|
|
# & lowercase letters, it provides ~5.95 entropy per character.
|
|
# Make the size of the default authkey 4096 bytes, which should give us
|
|
# ~24000 bits of randomness
|
|
elif name.startswith("PacemakerRemoteAuthkey"):
|
|
passwords[name] = passutils.generate_password(
|
|
size=4096)
|
|
# The underclouds SnmpdReadonlyUserPassword is stored in a mistral env
|
|
# for the overcloud.
|
|
elif mistralclient and name == 'SnmpdReadonlyUserPassword':
|
|
passwords[name] = get_snmpd_readonly_user_password(mistralclient)
|
|
elif name in ('KeystoneCredential0', 'KeystoneCredential1',
|
|
'KeystoneFernetKey0', 'KeystoneFernetKey1'):
|
|
passwords[name] = create_keystone_credential()
|
|
elif name == 'MigrationSshKey':
|
|
passwords[name] = create_ssh_keypair()
|
|
else:
|
|
passwords[name] = passutils.generate_password(
|
|
size=_MIN_PASSWORD_SIZE)
|
|
return passwords
|
|
|
|
|
|
def create_cephx_key():
|
|
# NOTE(gfidente): Taken from
|
|
# https://github.com/ceph/ceph-deploy/blob/master/ceph_deploy/new.py#L21
|
|
key = os.urandom(16)
|
|
header = struct.pack("<hiih", 1, int(time.time()), 0, len(key))
|
|
return base64.b64encode(header + key)
|
|
|
|
|
|
def get_snmpd_readonly_user_password(mistralclient):
|
|
mistral_env = mistralclient.environments.get("tripleo.undercloud-config")
|
|
try:
|
|
return mistral_env.variables['undercloud_ceilometer_snmpd_password']
|
|
except KeyError:
|
|
LOG.error("Undercloud ceilometer SNMPd password missing!")
|
|
raise
|
|
|
|
|
|
def create_keystone_credential():
|
|
return base64.urlsafe_b64encode(os.urandom(32))
|
|
|
|
|
|
def create_ssh_keypair(comment=None, bits=2048):
|
|
"""Generate an ssh keypair for use on the overcloud"""
|
|
if comment is None:
|
|
comment = "Generated by TripleO"
|
|
key = paramiko.RSAKey.generate(bits)
|
|
keyout = six.StringIO()
|
|
key.write_private_key(keyout)
|
|
private_key = keyout.getvalue()
|
|
public_key = '{} {} {}'.format(key.get_name(), key.get_base64(), comment)
|
|
return {
|
|
'private_key': private_key,
|
|
'public_key': public_key,
|
|
}
|