Get root password for build image from settings
Image building process reads from settings hashed version of root password and apply it instead of default. Conflicts: bareon/drivers/data/nailgun.py bareon/drivers/deploy/nailgun.py bareon/utils/utils.py fuel_agent/tests/test_manager.py Change-Id: Ibb614ddd1973c8fae25dae8217d207ffc92f1b15 Partial-Bug: #1537496 Depends-On: I2092bfca78fb721a8df3c8c6e4e6fd18e64ba353
This commit is contained in:
parent
b6f7ee6935
commit
10687832f2
@ -42,6 +42,7 @@ LOG = logging.getLogger(__name__)
|
||||
CONF = cfg.CONF
|
||||
CONF.import_opt('prepare_configdrive', 'bareon.drivers.deploy.nailgun')
|
||||
CONF.import_opt('config_drive_path', 'bareon.drivers.deploy.nailgun')
|
||||
CONF.import_opt('default_root_password', 'bareon.drivers.deploy.nailgun')
|
||||
|
||||
|
||||
def match_device(hu_disk, ks_disk):
|
||||
@ -827,6 +828,21 @@ class NailgunBuildImage(BaseDataDriver,
|
||||
|
||||
os = objects.Ubuntu(repos=repos, packages=packages, major=14, minor=4,
|
||||
proxies=proxies)
|
||||
|
||||
# add root account
|
||||
root_password = self.data.get('root_password')
|
||||
hashed_root_password = self.data.get('hashed_root_password')
|
||||
|
||||
# for backward compatibily set default password is no password provided
|
||||
if root_password is None and hashed_root_password is None:
|
||||
root_password = CONF.default_root_password
|
||||
|
||||
os.add_user_account(
|
||||
name='root',
|
||||
password=root_password,
|
||||
homedir='/root',
|
||||
hashed_password=hashed_root_password,
|
||||
)
|
||||
return os
|
||||
|
||||
def parse_schemes(self):
|
||||
|
@ -108,6 +108,11 @@ opts = [
|
||||
default=True,
|
||||
help='Add udev rules for NIC remapping'
|
||||
),
|
||||
cfg.StrOpt(
|
||||
'default_root_password',
|
||||
default='r00tme',
|
||||
help='Default password for root user',
|
||||
)
|
||||
]
|
||||
|
||||
cli_opts = [
|
||||
@ -492,7 +497,10 @@ class Manager(BaseDeployDriver):
|
||||
'etc/nailgun-agent/config.yaml'))
|
||||
bu.append_lvm_devices_filter(chroot, CONF.multipath_lvm_filter,
|
||||
CONF.lvm_conf_path)
|
||||
|
||||
root = driver_os.get_user_by_name('root')
|
||||
bu.do_post_inst(chroot,
|
||||
hashed_root_password=root.hashed_password,
|
||||
allow_unsigned_file=CONF.allow_unsigned_file,
|
||||
force_ipv4_file=CONF.force_ipv4_file)
|
||||
# restore disabled hosts/resolv files
|
||||
@ -594,7 +602,9 @@ class Manager(BaseDeployDriver):
|
||||
attempts=CONF.fetch_packages_attempts)
|
||||
|
||||
LOG.debug('Post-install OS configuration')
|
||||
root = driver_os.get_user_by_name('root')
|
||||
bu.do_post_inst(chroot,
|
||||
hashed_root_password=root.hashed_password,
|
||||
allow_unsigned_file=CONF.allow_unsigned_file,
|
||||
force_ipv4_file=CONF.force_ipv4_file)
|
||||
|
||||
|
@ -28,6 +28,15 @@ class OperatingSystem(object):
|
||||
def add_user_account(self, **kwargs):
|
||||
self.user_accounts.append(users.User(**kwargs))
|
||||
|
||||
def get_user_by_name(self, name):
|
||||
"""Get User object by name from user_accounts.
|
||||
|
||||
If there is no users with such name return None
|
||||
"""
|
||||
for user in self.user_accounts:
|
||||
if user.name == name:
|
||||
return user
|
||||
|
||||
def to_dict(self):
|
||||
return {'major': self.major,
|
||||
'minor': self.minor,
|
||||
|
@ -12,13 +12,28 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import crypt
|
||||
|
||||
from bareon.utils import utils
|
||||
|
||||
|
||||
class User(object):
|
||||
def __init__(self, name, password, homedir, sudo=None, ssh_keys=None,
|
||||
shell="/bin/bash"):
|
||||
shell="/bin/bash", hashed_password=None):
|
||||
self.name = name
|
||||
self.password = password
|
||||
self.homedir = homedir
|
||||
self.sudo = sudo or []
|
||||
self.ssh_keys = ssh_keys or []
|
||||
self.shell = shell
|
||||
self._hashed_password = hashed_password
|
||||
|
||||
@property
|
||||
def hashed_password(self):
|
||||
if self.password is None:
|
||||
return self._hashed_password
|
||||
|
||||
if self._hashed_password is None:
|
||||
self._hashed_password = crypt.crypt(self.password, utils.gensalt())
|
||||
|
||||
return self._hashed_password
|
||||
|
@ -181,14 +181,22 @@ class BuildUtilsTestCase(unittest2.TestCase):
|
||||
mock_open):
|
||||
mock_path.join.return_value = 'fake_path'
|
||||
mock_path.exists.return_value = True
|
||||
bu.do_post_inst('chroot', allow_unsigned_file='fake_unsigned',
|
||||
|
||||
# crypt.crypt('qwerty')
|
||||
password = ('$6$KyOsgFgf9cLbGNST$Ej0Usihfy7W/WT2H0z0mC1DapC/IUpA0jF'
|
||||
'.Fs83mFIdkGYHL9IOYykRCjfssH.YL4lHbmrvOd/6TIfiyh1hDY1')
|
||||
|
||||
bu.do_post_inst('chroot',
|
||||
hashed_root_password=password,
|
||||
allow_unsigned_file='fake_unsigned',
|
||||
force_ipv4_file='fake_force_ipv4')
|
||||
file_handle_mock = mock_open.return_value.__enter__.return_value
|
||||
file_handle_mock.write.assert_called_once_with('manual\n')
|
||||
mock_exec_expected_calls = [
|
||||
mock.call('sed', '-i', 's%root:[\*,\!]%root:$6$IInX3Cqo$5xytL1VZb'
|
||||
'ZTusOewFnG6couuF0Ia61yS3rbC6P5YbZP2TYclwHqMq9e3Tg8rvQx'
|
||||
'hxSlBXP1DZhdUamxdOBXK0.%', 'fake_path'),
|
||||
mock.call('sed',
|
||||
'-i',
|
||||
's%root:[\*,\!]%root:{}%'.format(password),
|
||||
'fake_path'),
|
||||
mock.call('chroot', 'chroot', 'update-rc.d', 'puppet', 'disable'),
|
||||
mock.call('chroot', 'chroot', 'dpkg-divert', '--local', '--add',
|
||||
'fake_path'),
|
||||
|
@ -40,6 +40,12 @@ class TestImageBuild(unittest2.TestCase):
|
||||
def setUp(self, mock_driver, mock_http, mock_yaml):
|
||||
super(self.__class__, self).setUp()
|
||||
mock_driver.return_value = nailgun_data.NailgunBuildImage
|
||||
|
||||
# TEST_ROOT_PASSWORD = crypt.crypt('qwerty')
|
||||
self.TEST_ROOT_PASSWORD = ('$6$KyOsgFgf9cLbGNST$Ej0Usihfy7W/WT2H0z0mC'
|
||||
'1DapC/IUpA0jF.Fs83mFIdkGYHL9IOYykRCjfssH.'
|
||||
'YL4lHbmrvOd/6TIfiyh1hDY1')
|
||||
|
||||
image_conf = {
|
||||
"image_data": {
|
||||
"/": {
|
||||
@ -59,7 +65,8 @@ class TestImageBuild(unittest2.TestCase):
|
||||
'priority': 1001
|
||||
}
|
||||
],
|
||||
"codename": "trusty"
|
||||
"codename": "trusty",
|
||||
"hashed_root_password": self.TEST_ROOT_PASSWORD,
|
||||
}
|
||||
self.mgr = nailgun_deploy.Manager(
|
||||
nailgun_data.NailgunBuildImage(image_conf))
|
||||
@ -99,7 +106,10 @@ class TestImageBuild(unittest2.TestCase):
|
||||
'trusty', 'fakesection', priority=None),
|
||||
objects.DEBRepo('mos', 'http://fakemos',
|
||||
'mosX.Y', 'fakesection', priority=1000)],
|
||||
packages=['fakepackage1', 'fakepackage2'])
|
||||
packages=['fakepackage1', 'fakepackage2'],
|
||||
user_accounts=[
|
||||
objects.User(name='root', password=None, homedir='/root',
|
||||
hashed_password=self.TEST_ROOT_PASSWORD)])
|
||||
self.mgr.driver.operating_system.proxies = objects.RepoProxies(
|
||||
proxies={'fake': 'fake'},
|
||||
direct_repo_addr_list='fake_addr')
|
||||
@ -187,7 +197,9 @@ class TestImageBuild(unittest2.TestCase):
|
||||
'/tmp/imgdir', packages=['fakepackage1', 'fakepackage2'],
|
||||
attempts=CONF.fetch_packages_attempts)
|
||||
mock_bu.do_post_inst.assert_called_once_with(
|
||||
'/tmp/imgdir', allow_unsigned_file=CONF.allow_unsigned_file,
|
||||
'/tmp/imgdir',
|
||||
hashed_root_password=self.TEST_ROOT_PASSWORD,
|
||||
allow_unsigned_file=CONF.allow_unsigned_file,
|
||||
force_ipv4_file=CONF.force_ipv4_file)
|
||||
|
||||
signal_calls = mock_bu.stop_chrooted_processes.call_args_list
|
||||
|
@ -56,10 +56,6 @@ PROXY_PROTOCOLS = {
|
||||
ADDITIONAL_DEBOOTSTRAP_PACKAGES = ['ca-certificates',
|
||||
'apt-transport-https']
|
||||
|
||||
# NOTE(agordeev): hardcoded to r00tme
|
||||
ROOT_PASSWORD = '$6$IInX3Cqo$5xytL1VZbZTusOewFnG6couuF0Ia61yS3rbC6P5YbZP2TYcl'\
|
||||
'wHqMq9e3Tg8rvQxhxSlBXP1DZhdUamxdOBXK0.'
|
||||
|
||||
|
||||
def run_debootstrap(uri, suite, chroot, arch='amd64', eatmydata=False,
|
||||
attempts=10, proxies=None, direct_repo_addr=None):
|
||||
@ -180,11 +176,12 @@ def clean_apt_settings(chroot, allow_unsigned_file='allow_unsigned_packages',
|
||||
clean_dirs(chroot, dirs)
|
||||
|
||||
|
||||
def do_post_inst(chroot, allow_unsigned_file='allow_unsigned_packages',
|
||||
def do_post_inst(chroot, hashed_root_password,
|
||||
allow_unsigned_file='allow_unsigned_packages',
|
||||
force_ipv4_file='force_ipv4'):
|
||||
# NOTE(agordeev): set up password for root
|
||||
utils.execute('sed', '-i',
|
||||
's%root:[\*,\!]%root:' + ROOT_PASSWORD + '%',
|
||||
's%root:[\*,\!]%root:' + hashed_root_password + '%',
|
||||
os.path.join(chroot, 'etc/shadow'))
|
||||
# NOTE(agordeev): backport from bash-script:
|
||||
# in order to prevent the later puppet workflow outage, puppet service
|
||||
|
@ -18,9 +18,11 @@ import json
|
||||
import locale
|
||||
import math
|
||||
import os
|
||||
import random as _random
|
||||
import re
|
||||
import shlex
|
||||
import socket
|
||||
import string
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
@ -36,6 +38,7 @@ import urllib3
|
||||
from bareon import errors
|
||||
from bareon.openstack.common import log as logging
|
||||
|
||||
random = _random.SystemRandom()
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -419,6 +422,14 @@ def udevadm_settle():
|
||||
execute('udevadm', 'settle', check_exit_code=[0])
|
||||
|
||||
|
||||
def gensalt():
|
||||
"""Generate SHA-512 salt for crypt.crypt function."""
|
||||
letters = string.ascii_letters + string.digits + './'
|
||||
sha512prefix = "$6$"
|
||||
random_letters = ''.join(random.choice(letters) for _ in range(16))
|
||||
return sha512prefix + random_letters
|
||||
|
||||
|
||||
def dict_diff(dict1, dict2, sfrom="from", sto="to"):
|
||||
j1 = json.dumps(dict1, indent=2)
|
||||
j2 = json.dumps(dict2, indent=2)
|
||||
|
@ -189,6 +189,13 @@ class BuildCommand(command.Command):
|
||||
" files",
|
||||
action='append'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--root-password',
|
||||
type=str,
|
||||
help=("Root password for bootstrap image. PasswordAuthentication"
|
||||
" by ssh still rejected by default! This password actual"
|
||||
" only for tty login!"),
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
|
@ -116,3 +116,5 @@ active_bootstrap_symlink: "/var/www/nailgun/bootstraps/active_bootstrap"
|
||||
# "user": "admin"
|
||||
# "password": "admin"
|
||||
|
||||
# User can provide default hashed root password for bootstrap image
|
||||
# hashed_root_password: "$6$IInX3Cqo$5xytL1VZbZTusOewFnG6couuF0Ia61yS3rbC6P5YbZP2TYclwHqMq9e3Tg8rvQxhxSlBXP1DZhdUamxdOBXK0."
|
||||
|
@ -72,6 +72,12 @@ class BootstrapDataBuilder(object):
|
||||
|
||||
self.certs = data.get('certs')
|
||||
|
||||
self.root_password = data.get('root_password')
|
||||
self.hashed_root_password = None
|
||||
|
||||
if self.root_password is None:
|
||||
self.hashed_root_password = CONF.hashed_root_password
|
||||
|
||||
def build(self):
|
||||
return {
|
||||
'bootstrap': {
|
||||
@ -93,7 +99,9 @@ class BootstrapDataBuilder(object):
|
||||
'codename': self.ubuntu_release,
|
||||
'output': self.output,
|
||||
'packages': self._get_packages(),
|
||||
'image_data': self._prepare_image_data()
|
||||
'image_data': self._prepare_image_data(),
|
||||
'hashed_root_password': self.hashed_root_password,
|
||||
'root_password': self.root_password,
|
||||
}
|
||||
|
||||
def _get_extra_dirs(self):
|
||||
|
@ -209,3 +209,6 @@ log_file=/var/log/bareon.log
|
||||
#execute_retry_delay=2.0
|
||||
|
||||
|
||||
# Default password for root user
|
||||
# (string value)
|
||||
default_root_password=r00tme
|
||||
|
Loading…
Reference in New Issue
Block a user