Create non-root user account during image build process
Extended Nailgun data driver to parse new ks_meta keys. Extended Ubuntu cloud-init config template to create a non-root account. Root login is being disabled, however, this setting will only be effective until osnailyfacter::ssh puppet class will have been evaluated during deployment as it overrides sshd_config values. This means, that PermitRootLogin should be managed by library as well. Blueprint: fuel-nonroot-openstack-nodes Depends-On: Ia18305e07d07377886783c3b3e44abe93cef2da5 Conflicts: bareon/tests/test_configdrive.py Change-Id: I69831fe0327ef9ac55bed99301d2c3732b87ed88
This commit is contained in:
parent
6f3c24eace
commit
c5b4e5dfca
@ -302,9 +302,28 @@ class Nailgun(BaseDataDriver,
|
|||||||
def parse_operating_system(self):
|
def parse_operating_system(self):
|
||||||
LOG.debug('--- Preparing operating system data ---')
|
LOG.debug('--- Preparing operating system data ---')
|
||||||
os_release = self._image_meta.get('os', None)
|
os_release = self._image_meta.get('os', None)
|
||||||
return self.get_os_by_image_meta(os_release) or \
|
|
||||||
|
os = self.get_os_by_image_meta(os_release) or \
|
||||||
self.get_os_by_profile(self.data['profile'].lower())
|
self.get_os_by_profile(self.data['profile'].lower())
|
||||||
|
|
||||||
|
# FIXME(dnikishov): until fuel-agent-versioning BP
|
||||||
|
# will have been implemented, we need to deal with the case when
|
||||||
|
# 9.0 fuel-agent will be managing 6.1 to 8.0 environments, whose
|
||||||
|
# provisioning serializers on Nailgun side will not have
|
||||||
|
# user_accounts in the ks_meta dict
|
||||||
|
try:
|
||||||
|
user_accounts = self.data['ks_meta']['user_accounts']
|
||||||
|
except KeyError:
|
||||||
|
LOG.warn(('This environment does not support non-root accounts '
|
||||||
|
'on the target nodes. Non-root user accounts will not '
|
||||||
|
'be created'))
|
||||||
|
user_accounts = []
|
||||||
|
|
||||||
|
for account in user_accounts:
|
||||||
|
os.add_user_account(**account)
|
||||||
|
|
||||||
|
return os
|
||||||
|
|
||||||
def parse_partition_scheme(self):
|
def parse_partition_scheme(self):
|
||||||
LOG.debug('--- Preparing partition scheme ---')
|
LOG.debug('--- Preparing partition scheme ---')
|
||||||
data = self.partition_data()
|
data = self.partition_data()
|
||||||
@ -537,7 +556,9 @@ class Nailgun(BaseDataDriver,
|
|||||||
def parse_configdrive_scheme(self):
|
def parse_configdrive_scheme(self):
|
||||||
LOG.debug('--- Preparing configdrive scheme ---')
|
LOG.debug('--- Preparing configdrive scheme ---')
|
||||||
data = self.data
|
data = self.data
|
||||||
configdrive_scheme = objects.ConfigDriveScheme()
|
configdrive_scheme = objects.ConfigDriveScheme(
|
||||||
|
user_accounts=self.operating_system.user_accounts
|
||||||
|
)
|
||||||
|
|
||||||
LOG.debug('Adding common parameters')
|
LOG.debug('Adding common parameters')
|
||||||
|
|
||||||
|
@ -58,12 +58,14 @@ class ConfigDriveMcollective(object):
|
|||||||
|
|
||||||
class ConfigDriveScheme(object):
|
class ConfigDriveScheme(object):
|
||||||
def __init__(self, common=None, puppet=None,
|
def __init__(self, common=None, puppet=None,
|
||||||
mcollective=None, profile=None, templates=None):
|
mcollective=None, profile=None, templates=None,
|
||||||
|
user_accounts=None):
|
||||||
self.common = common
|
self.common = common
|
||||||
self.puppet = puppet
|
self.puppet = puppet
|
||||||
self.mcollective = mcollective
|
self.mcollective = mcollective
|
||||||
self._profile = profile or 'ubuntu'
|
self._profile = profile or 'ubuntu'
|
||||||
self.templates = templates or {}
|
self.templates = templates or {}
|
||||||
|
self.user_accounts = user_accounts or []
|
||||||
|
|
||||||
# TODO(kozhukalov) make it possible to validate scheme according to
|
# TODO(kozhukalov) make it possible to validate scheme according to
|
||||||
# chosen profile which means chosen set of cloud-init templates.
|
# chosen profile which means chosen set of cloud-init templates.
|
||||||
@ -87,6 +89,8 @@ class ConfigDriveScheme(object):
|
|||||||
template_data.update(puppet=self.puppet)
|
template_data.update(puppet=self.puppet)
|
||||||
if self.mcollective is not None:
|
if self.mcollective is not None:
|
||||||
template_data.update(mcollective=self.mcollective)
|
template_data.update(mcollective=self.mcollective)
|
||||||
|
if self.user_accounts:
|
||||||
|
template_data.update(user_accounts=self.user_accounts)
|
||||||
return template_data
|
return template_data
|
||||||
|
|
||||||
def set_profile(self, profile):
|
def set_profile(self, profile):
|
||||||
|
@ -12,15 +12,21 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
from bareon.objects import users
|
||||||
|
|
||||||
|
|
||||||
class OperatingSystem(object):
|
class OperatingSystem(object):
|
||||||
def __init__(self, repos, packages, major='unknown', minor='unknown',
|
def __init__(self, repos, packages, major='unknown', minor='unknown',
|
||||||
proxies=None):
|
proxies=None, user_accounts=None):
|
||||||
self.repos = repos
|
self.repos = repos
|
||||||
self.packages = packages
|
self.packages = packages
|
||||||
self.major = major
|
self.major = major
|
||||||
self.minor = minor
|
self.minor = minor
|
||||||
self.proxies = proxies
|
self.proxies = proxies
|
||||||
|
self.user_accounts = user_accounts or []
|
||||||
|
|
||||||
|
def add_user_account(self, **kwargs):
|
||||||
|
self.user_accounts.append(users.User(**kwargs))
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
return {'major': self.major,
|
return {'major': self.major,
|
||||||
|
24
bareon/tests/fixtures/simple_nailgun_driver.json
vendored
24
bareon/tests/fixtures/simple_nailgun_driver.json
vendored
@ -88,7 +88,29 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"timezone": "America/Los_Angeles"
|
"timezone": "America/Los_Angeles",
|
||||||
|
"user_accounts": [
|
||||||
|
{
|
||||||
|
"name": "fueladmin",
|
||||||
|
"password": "fueladmin",
|
||||||
|
"homedir": "/home/fueladmin",
|
||||||
|
"sudo": [],
|
||||||
|
"ssh_keys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "fuel",
|
||||||
|
"password": "fuel",
|
||||||
|
"homedir": "/var/lib/fuel",
|
||||||
|
"sudo": ["ALL=(ALL) NOPASSWD: ALL"],
|
||||||
|
"ssh_keys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "root",
|
||||||
|
"password": "r00tme",
|
||||||
|
"homedir": "/root",
|
||||||
|
"ssh_keys": []
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"name": "node-1",
|
"name": "node-1",
|
||||||
"name_servers": "\"10.20.0.2\"",
|
"name_servers": "\"10.20.0.2\"",
|
||||||
|
@ -17,6 +17,7 @@ import unittest2
|
|||||||
|
|
||||||
from bareon import errors
|
from bareon import errors
|
||||||
from bareon.objects import configdrive
|
from bareon.objects import configdrive
|
||||||
|
from bareon.objects import User
|
||||||
|
|
||||||
|
|
||||||
class TestConfigDriveScheme(unittest2.TestCase):
|
class TestConfigDriveScheme(unittest2.TestCase):
|
||||||
@ -64,10 +65,17 @@ class TestConfigDriveScheme(unittest2.TestCase):
|
|||||||
cd_puppet = configdrive.ConfigDrivePuppet('master', 0)
|
cd_puppet = configdrive.ConfigDrivePuppet('master', 0)
|
||||||
cd_mcollective = configdrive.ConfigDriveMcollective(
|
cd_mcollective = configdrive.ConfigDriveMcollective(
|
||||||
'pskey', 'vhost', 'host', 'user', 'password', 'connector', 1, -1)
|
'pskey', 'vhost', 'host', 'user', 'password', 'connector', 1, -1)
|
||||||
|
cd_user_accounts = []
|
||||||
|
cd_user_accounts.append(User('fuel', 'fuel', '/var/lib/fuel',
|
||||||
|
['ALL=(ALL) NOPASSWD: ALL']))
|
||||||
|
cd_user_accounts.append(User('test', 'test', '/home/test',
|
||||||
|
['SUDO'], ['KEY']))
|
||||||
self.cd_scheme.common = cd_common
|
self.cd_scheme.common = cd_common
|
||||||
self.cd_scheme.puppet = cd_puppet
|
self.cd_scheme.puppet = cd_puppet
|
||||||
self.cd_scheme.mcollective = cd_mcollective
|
self.cd_scheme.mcollective = cd_mcollective
|
||||||
|
self.cd_scheme.user_accounts = cd_user_accounts
|
||||||
template_data = self.cd_scheme.template_data()
|
template_data = self.cd_scheme.template_data()
|
||||||
self.assertEqual(cd_common, template_data['common'])
|
self.assertEqual(cd_common, template_data['common'])
|
||||||
self.assertEqual(cd_puppet, template_data['puppet'])
|
self.assertEqual(cd_puppet, template_data['puppet'])
|
||||||
self.assertEqual(cd_mcollective, template_data['mcollective'])
|
self.assertEqual(cd_mcollective, template_data['mcollective'])
|
||||||
|
self.assertEqual(cd_user_accounts, template_data['user_accounts'])
|
||||||
|
@ -326,7 +326,29 @@ PROVISION_SAMPLE_DATA = {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mco_connector": "rabbitmq",
|
"mco_connector": "rabbitmq",
|
||||||
"mco_host": "10.20.0.2"
|
"mco_host": "10.20.0.2",
|
||||||
|
"user_accounts": [
|
||||||
|
{
|
||||||
|
"name": "fueladmin",
|
||||||
|
"password": "fueladmin",
|
||||||
|
"homedir": "/home/fueladmin",
|
||||||
|
"sudo": [],
|
||||||
|
"ssh_keys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "fuel",
|
||||||
|
"password": "fuel",
|
||||||
|
"homedir": "/var/lib/fuel",
|
||||||
|
"sudo": ["ALL=(ALL) NOPASSWD: ALL"],
|
||||||
|
"ssh_keys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "root",
|
||||||
|
"password": "r00tme",
|
||||||
|
"homedir": "/root",
|
||||||
|
"ssh_keys": []
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"name": "node-1",
|
"name": "node-1",
|
||||||
"hostname": "node-1.domain.tld",
|
"hostname": "node-1.domain.tld",
|
||||||
|
@ -213,6 +213,21 @@ class TestFullDataRead(unittest2.TestCase):
|
|||||||
|
|
||||||
PROVISION_DATA = base.load_fixture('simple_nailgun_driver.json')
|
PROVISION_DATA = base.load_fixture('simple_nailgun_driver.json')
|
||||||
|
|
||||||
|
def test_read_61_70_80_with_no_error(self, mock_requests):
|
||||||
|
PROVISION_DATA_61_70_80 = dict(self.PROVISION_DATA)
|
||||||
|
del PROVISION_DATA_61_70_80['ks_meta']['user_accounts']
|
||||||
|
|
||||||
|
mock_requests.get('http://fake.host.org:123/imgs/fake_image.img.gz',
|
||||||
|
text='{}')
|
||||||
|
driver = simple.NailgunSimpleDriver(PROVISION_DATA_61_70_80)
|
||||||
|
scheme = driver.partition_scheme
|
||||||
|
assert len(scheme.fss) == 5
|
||||||
|
assert len(scheme.lvs) == 3
|
||||||
|
assert len(scheme.mds) == 0
|
||||||
|
assert len(scheme.parteds) == 2
|
||||||
|
assert len(scheme.pvs) == 4
|
||||||
|
assert len(scheme.vgs) == 2
|
||||||
|
|
||||||
def test_read_with_no_error(self, mock_requests):
|
def test_read_with_no_error(self, mock_requests):
|
||||||
mock_requests.get('http://fake.host.org:123/imgs/fake_image.img.gz',
|
mock_requests.get('http://fake.host.org:123/imgs/fake_image.img.gz',
|
||||||
text='{}')
|
text='{}')
|
||||||
|
@ -4,14 +4,28 @@ growpart:
|
|||||||
mode: false
|
mode: false
|
||||||
disable_ec2_metadata: true
|
disable_ec2_metadata: true
|
||||||
disable_root: false
|
disable_root: false
|
||||||
user: root
|
users:
|
||||||
password: r00tme
|
{% for user in user_accounts %}
|
||||||
|
- name: {{ user.name }}
|
||||||
|
plain_text_passwd: {{ user.password }}
|
||||||
|
lock_passwd: False
|
||||||
|
homedir: {{ user.homedir }}
|
||||||
|
shell: {{ user.shell }}
|
||||||
|
{% if user.ssh_keys|length > 0 %}
|
||||||
|
ssh_authorized_keys:
|
||||||
|
{% for key in user.ssh_keys %}
|
||||||
|
- {{ key }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if user.sudo|length > 0 %}
|
||||||
|
sudo:
|
||||||
|
{% for entry in user.sudo %}
|
||||||
|
- "{{ entry }}"
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
chpasswd: { expire: false }
|
chpasswd: { expire: false }
|
||||||
ssh_pwauth: false
|
ssh_pwauth: false
|
||||||
ssh_authorized_keys:
|
|
||||||
{% for key in common.ssh_auth_keys %}
|
|
||||||
- {{ key }}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
# set the locale to a given locale
|
# set the locale to a given locale
|
||||||
# default: en_US.UTF-8
|
# default: en_US.UTF-8
|
||||||
|
Loading…
Reference in New Issue
Block a user