Remove appliance's hard-coded password in favor of ssh pub key
This removes the hard-coded password from the appliance VM's user-data
and replaces it with a SSH public key, which is read from a file whos
path is configured in rug.ini.
It also disables password logins for the user. Another patch to
akanda-appliance-builder will allow developers to include a specified
debug user to allow debugging in dev environments.
Change-Id: I7db92bc7fd3743d89d73ab2a0b8da14685c30c69
(cherry picked from commit a06dbe7ab3
)
This commit is contained in:
parent
aad3802b53
commit
0d20d363bf
@ -19,9 +19,19 @@ import logging
|
|||||||
|
|
||||||
from novaclient.v1_1 import client
|
from novaclient.v1_1 import client
|
||||||
|
|
||||||
|
from oslo.config import cfg
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
OPTIONS = [
|
||||||
|
cfg.StrOpt(
|
||||||
|
'router_ssh_public_key',
|
||||||
|
help="Path to the SSH public key for the 'akanda' user within "
|
||||||
|
"router appliance VMs",
|
||||||
|
default='/etc/akanda-rug/akanda.pub')
|
||||||
|
]
|
||||||
|
cfg.CONF.register_opts(OPTIONS)
|
||||||
|
|
||||||
|
|
||||||
class InstanceInfo(object):
|
class InstanceInfo(object):
|
||||||
def __init__(self, instance_id, name, management_port=None, ports=(),
|
def __init__(self, instance_id, name, management_port=None, ports=(),
|
||||||
@ -181,7 +191,7 @@ debug:
|
|||||||
- verbose: true
|
- verbose: true
|
||||||
|
|
||||||
bootcmd:
|
bootcmd:
|
||||||
- /usr/local/bin/akanda-configure-management %s %s/64
|
- /usr/local/bin/akanda-configure-management %(mac_address)s %(ip_address)s/64
|
||||||
|
|
||||||
users:
|
users:
|
||||||
- name: akanda
|
- name: akanda
|
||||||
@ -189,12 +199,30 @@ users:
|
|||||||
groups: users
|
groups: users
|
||||||
shell: /bin/bash
|
shell: /bin/bash
|
||||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||||
passwd: $6$rounds=4096$zxaBh6omTayBSA$rI1.FNliuUl7R2SMdkj7zWv.FBhqGVd1lLYDatJd6MiE9WqEQx0M.o7bLyp5nA0CxV6ahoDb0m8Y5OQMDHx1V/
|
lock-passwd: true
|
||||||
lock-passwd: false
|
ssh-authorized-keys:
|
||||||
|
- %(ssh_public_key)s
|
||||||
|
|
||||||
final_message: "Akanda appliance is running"
|
final_message: "Akanda appliance is running"
|
||||||
""" # noqa
|
""" # noqa
|
||||||
|
|
||||||
|
|
||||||
|
def _router_ssh_key():
|
||||||
|
key = cfg.CONF.router_ssh_public_key
|
||||||
|
if not key:
|
||||||
|
return ''
|
||||||
|
try:
|
||||||
|
with open(key) as out:
|
||||||
|
return out.read()
|
||||||
|
except IOError:
|
||||||
|
LOG.warning('Could not load router ssh public key from %s' % key)
|
||||||
|
return ''
|
||||||
|
|
||||||
|
|
||||||
def _format_userdata(mgt_port):
|
def _format_userdata(mgt_port):
|
||||||
return TEMPLATE % (mgt_port.mac_address, mgt_port.fixed_ips[0].ip_address)
|
ctxt = {
|
||||||
|
'ssh_public_key': _router_ssh_key(),
|
||||||
|
'mac_address': mgt_port.mac_address,
|
||||||
|
'ip_address': mgt_port.fixed_ips[0].ip_address,
|
||||||
|
}
|
||||||
|
return TEMPLATE % ctxt
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import mock
|
import mock
|
||||||
import unittest2 as unittest
|
import unittest2 as unittest
|
||||||
|
from six.moves import builtins as __builtins__
|
||||||
from akanda.rug.api import nova
|
from akanda.rug.api import nova
|
||||||
|
|
||||||
|
|
||||||
@ -65,6 +65,40 @@ class FakeConf:
|
|||||||
router_instance_flavor = 1
|
router_instance_flavor = 1
|
||||||
|
|
||||||
|
|
||||||
|
EXPECTED_USERDATA = """
|
||||||
|
#cloud-config
|
||||||
|
|
||||||
|
cloud_config_modules:
|
||||||
|
- emit_upstart
|
||||||
|
- set_hostname
|
||||||
|
- locale
|
||||||
|
- set-passwords
|
||||||
|
- timezone
|
||||||
|
- disable-ec2-metadata
|
||||||
|
- runcmd
|
||||||
|
|
||||||
|
output: {all: '| tee -a /var/log/cloud-init-output.log'}
|
||||||
|
|
||||||
|
debug:
|
||||||
|
- verbose: true
|
||||||
|
|
||||||
|
bootcmd:
|
||||||
|
- /usr/local/bin/akanda-configure-management aa:aa:aa:aa:aa:aa 192.168.1.1/64
|
||||||
|
|
||||||
|
users:
|
||||||
|
- name: akanda
|
||||||
|
gecos: Akanda
|
||||||
|
groups: users
|
||||||
|
shell: /bin/bash
|
||||||
|
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||||
|
lock-passwd: true
|
||||||
|
ssh-authorized-keys:
|
||||||
|
- fake_key
|
||||||
|
|
||||||
|
final_message: "Akanda appliance is running"
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def fake_make_ports_callback():
|
def fake_make_ports_callback():
|
||||||
return (fake_mgt_port, [fake_ext_port, fake_int_port])
|
return (fake_mgt_port, [fake_ext_port, fake_int_port])
|
||||||
|
|
||||||
@ -149,3 +183,26 @@ class TestNovaWrapper(unittest.TestCase):
|
|||||||
def test_destroy_router_instance(self):
|
def test_destroy_router_instance(self):
|
||||||
self.nova.destroy_instance(self.INSTANCE_INFO)
|
self.nova.destroy_instance(self.INSTANCE_INFO)
|
||||||
self.client.servers.delete.assert_called_with(self.INSTANCE_INFO.id_)
|
self.client.servers.delete.assert_called_with(self.INSTANCE_INFO.id_)
|
||||||
|
|
||||||
|
@mock.patch.object(nova, '_router_ssh_key')
|
||||||
|
def test_format_userdata(self, fake_ssh_key):
|
||||||
|
fake_ssh_key.return_value = 'fake_key'
|
||||||
|
result = nova._format_userdata(fake_int_port)
|
||||||
|
self.assertEqual(result.strip(), EXPECTED_USERDATA.strip())
|
||||||
|
|
||||||
|
@mock.patch.object(__builtins__, 'open', autospec=True)
|
||||||
|
def test_router_ssh_key(self, fake_open):
|
||||||
|
mock_key_file = mock.MagicMock(spec=file)
|
||||||
|
mock_key_file.read.return_value = 'fake-key'
|
||||||
|
mock_key_file.__enter__.return_value = mock_key_file
|
||||||
|
fake_open.return_value = mock_key_file
|
||||||
|
result = nova._router_ssh_key()
|
||||||
|
self.assertEqual(result, 'fake-key')
|
||||||
|
|
||||||
|
@mock.patch.object(nova, 'LOG', autospec=True)
|
||||||
|
@mock.patch.object(__builtins__, 'open', autospec=True)
|
||||||
|
def test_router_ssh_key_not_found(self, fake_open, fake_log):
|
||||||
|
fake_open.side_effect = IOError
|
||||||
|
result = nova._router_ssh_key()
|
||||||
|
self.assertEqual(result, '')
|
||||||
|
self.assertTrue(fake_log.warning.called)
|
||||||
|
@ -32,6 +32,10 @@ AKANDA_RUG_MANAGEMENT_PORT=${AKANDA_RUG_MANAGEMENT_PORT:-5000}
|
|||||||
|
|
||||||
HORIZON_LOCAL_SETTINGS=$HORIZON_DIR/openstack_dashboard/local/local_settings.py
|
HORIZON_LOCAL_SETTINGS=$HORIZON_DIR/openstack_dashboard/local/local_settings.py
|
||||||
|
|
||||||
|
# Path to public ssh key that will be added to the 'akanda' users authorized_keys
|
||||||
|
# within the appliance VM.
|
||||||
|
AKANDA_APPLIANCE_SSH_PUBLIC_KEY=${AKANDA_APPLIANCE_SSH_PUBLIC_KEY:-/home/$STACK_USER/.ssh/id_rsa.pub}
|
||||||
|
|
||||||
function configure_akanda() {
|
function configure_akanda() {
|
||||||
if [[ ! -d $AKANDA_CONF_DIR ]]; then
|
if [[ ! -d $AKANDA_CONF_DIR ]]; then
|
||||||
sudo mkdir -p $AKANDA_CONF_DIR
|
sudo mkdir -p $AKANDA_CONF_DIR
|
||||||
@ -59,6 +63,8 @@ function configure_akanda() {
|
|||||||
if [[ "$Q_AGENT" == "linuxbridge" ]]; then
|
if [[ "$Q_AGENT" == "linuxbridge" ]]; then
|
||||||
iniset $AKANDA_RUG_CONF DEFAULT interface_driver "akanda.rug.common.linux.interface.BridgeInterfaceDriver"
|
iniset $AKANDA_RUG_CONF DEFAULT interface_driver "akanda.rug.common.linux.interface.BridgeInterfaceDriver"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
iniset $AKANDA_RUG_CONF DEFAULT router_ssh_public_key $AKANDA_APPLIANCE_SSH_PUBLIC_KEY
|
||||||
}
|
}
|
||||||
|
|
||||||
function configure_akanda_nova() {
|
function configure_akanda_nova() {
|
||||||
@ -172,9 +178,11 @@ function pre_start_akanda() {
|
|||||||
# Point DIB at the devstack checkout of the akanda-appliance repo
|
# Point DIB at the devstack checkout of the akanda-appliance repo
|
||||||
DIB_REPOLOCATION_akanda=$AKANDA_APPLIANCE_DIR \
|
DIB_REPOLOCATION_akanda=$AKANDA_APPLIANCE_DIR \
|
||||||
DIB_REPOREF_akanda="$(cd $AKANDA_APPLIANCE_DIR && git rev-parse HEAD)" \
|
DIB_REPOREF_akanda="$(cd $AKANDA_APPLIANCE_DIR && git rev-parse HEAD)" \
|
||||||
|
DIB_AKANDA_APPLIANCE_DEBUG_USER=$ADMIN_USERNAME \
|
||||||
|
DIB_AKANDA_APPLIANCE_DEBUG_PASSWORD=$ADMIN_PASSWORD \
|
||||||
http_proxy=$AKANDA_DEV_APPLIANCE_BUILD_PROXY \
|
http_proxy=$AKANDA_DEV_APPLIANCE_BUILD_PROXY \
|
||||||
ELEMENTS_PATH=$AKANDA_APPLIANCE_BUILDER_DIR/diskimage-builder/elements \
|
ELEMENTS_PATH=$AKANDA_APPLIANCE_BUILDER_DIR/diskimage-builder/elements \
|
||||||
DIB_RELEASE=wheezy DIB_EXTLINUX=1 disk-image-create debian vm akanda \
|
DIB_RELEASE=wheezy DIB_EXTLINUX=1 disk-image-create debian vm akanda debug-user \
|
||||||
-o $TOP_DIR/files/akanda
|
-o $TOP_DIR/files/akanda
|
||||||
akanda_dev_image_src=$AKANDA_DEV_APPLIANCE_FILE
|
akanda_dev_image_src=$AKANDA_DEV_APPLIANCE_FILE
|
||||||
else
|
else
|
||||||
@ -250,11 +258,20 @@ function set_demo_tenant_sec_group_dhcp_rules() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function check_prereqs() {
|
||||||
|
# Fail devstack as early as possible if system does not satisfy some known
|
||||||
|
# prerequisites
|
||||||
|
if [ ! -e "$AKANDA_APPLIANCE_SSH_PUBLIC_KEY" ]; then
|
||||||
|
die $LINENO "Public SSH key not found at $AKANDA_APPLIANCE_SSH_PUBLIC_KEY. Please copy one there or " \
|
||||||
|
"set AKANDA_APPLIANCE_SSH_PUBLIC_KEY accordingly."
|
||||||
|
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if is_service_enabled ak-rug; then
|
if is_service_enabled ak-rug; then
|
||||||
if [[ "$1" == "source" ]]; then
|
if [[ "$1" == "source" ]]; then
|
||||||
# no-op
|
check_prereqs
|
||||||
:
|
|
||||||
|
|
||||||
elif [[ "$1" == "stack" && "$2" == "install" ]]; then
|
elif [[ "$1" == "stack" && "$2" == "install" ]]; then
|
||||||
echo_summary "Installing Akanda"
|
echo_summary "Installing Akanda"
|
||||||
|
@ -20,6 +20,7 @@ plug_external_port=True
|
|||||||
|
|
||||||
router_image_uuid=1e9c16f3-e070-47b7-b49c-ffcf38df5f9a
|
router_image_uuid=1e9c16f3-e070-47b7-b49c-ffcf38df5f9a
|
||||||
router_instance_flavor=1
|
router_instance_flavor=1
|
||||||
|
router_ssh_public_key=/etc/akanda/akanda.pub
|
||||||
|
|
||||||
# to plug in rug interface
|
# to plug in rug interface
|
||||||
interface_driver=akanda.rug.common.linux.interface.OVSInterfaceDriver
|
interface_driver=akanda.rug.common.linux.interface.OVSInterfaceDriver
|
||||||
|
@ -8,3 +8,4 @@ iso8601
|
|||||||
mox==0.5.3
|
mox==0.5.3
|
||||||
testtools
|
testtools
|
||||||
fixtures
|
fixtures
|
||||||
|
six>=1.9.0
|
||||||
|
Loading…
Reference in New Issue
Block a user