Break IPA configuration into a separate module and installer
When installing via puppet the configuration changes aren't necessary and in fact can cause problems. All that really needs to happen is the IPA work to add the permissions, privilege and role and create the nova service and fetch the keytab. This is broken out into a separate class that can be called from either the existing novajoin-install or the new novajoin-ipa-setup. The bash script equivalent was removed.
This commit is contained in:
parent
7fb07ad480
commit
5c0ad416f4
|
@ -0,0 +1,208 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
import getpass
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import pwd
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
from ipalib import api
|
||||||
|
from ipalib import errors
|
||||||
|
from ipapython.ipautil import run, kinit_password, user_input
|
||||||
|
from novajoin.errors import ConfigurationError
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class NovajoinRole(object):
|
||||||
|
"""
|
||||||
|
One-stop shopping for creating the IPA permissions, privilege and role.
|
||||||
|
|
||||||
|
Assumes that ipalib is imported and initialized and an RPC context
|
||||||
|
already exists.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, keytab='/etc/join/krb5.keytab', user='nova'):
|
||||||
|
self.keytab = keytab
|
||||||
|
self.user = user
|
||||||
|
self.service = u'nova/%s' % self._get_fqdn()
|
||||||
|
self.ccache_name = None
|
||||||
|
|
||||||
|
def _get_fqdn(self):
|
||||||
|
"""
|
||||||
|
Try to determine the fully-qualfied domain name of this box
|
||||||
|
"""
|
||||||
|
fqdn = ""
|
||||||
|
try:
|
||||||
|
fqdn = socket.getfqdn()
|
||||||
|
except Exception: # pylint: disable=broad-except
|
||||||
|
try:
|
||||||
|
# assume it is in the IPA domain if it comes back
|
||||||
|
# not fully-qualified
|
||||||
|
fqdn = socket.gethostname()
|
||||||
|
fqdn = fqdn + '.' + api.env.domain
|
||||||
|
except Exception: # pylint: disable=broad-except
|
||||||
|
fqdn = ""
|
||||||
|
return fqdn
|
||||||
|
|
||||||
|
def kinit(self, principal, password):
|
||||||
|
ccache_dir = tempfile.mkdtemp(prefix='krbcc')
|
||||||
|
self.ccache_name = os.path.join(ccache_dir, 'ccache')
|
||||||
|
|
||||||
|
current_ccache = os.environ.get('KRB5CCNAME')
|
||||||
|
os.environ['KRB5CCNAME'] = self.ccache_name
|
||||||
|
|
||||||
|
if principal.find('@') == -1:
|
||||||
|
principal = '%s@%s' % (principal, api.env.realm)
|
||||||
|
|
||||||
|
try:
|
||||||
|
kinit_password(principal, password, self.ccache_name)
|
||||||
|
except RuntimeError as e:
|
||||||
|
raise ConfigurationError("Kerberos authentication failed: %s" % e)
|
||||||
|
finally:
|
||||||
|
if current_ccache:
|
||||||
|
os.environ['KRB5CCNAME'] = current_ccache
|
||||||
|
|
||||||
|
def _call_ipa(self, command, args, kw):
|
||||||
|
"""
|
||||||
|
Call into the IPA API.
|
||||||
|
|
||||||
|
Duplicates are ignored to be idempotent. Other errors are
|
||||||
|
ignored implitly because they are encapsulated in the result
|
||||||
|
for some calls.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
api.Command[command](args, **kw)
|
||||||
|
except errors.DuplicateEntry:
|
||||||
|
pass
|
||||||
|
except Exception as e: # pylint: disable=broad-except
|
||||||
|
logger.error("Unhandled exception: %s", e)
|
||||||
|
|
||||||
|
def _add_permissions(self):
|
||||||
|
self._call_ipa(u'permission_add', u'Modify host password',
|
||||||
|
{'ipapermright': u'write',
|
||||||
|
'type': u'host',
|
||||||
|
'attrs': u'userpassword'})
|
||||||
|
self._call_ipa(u'permission_add', u'Write host certificate',
|
||||||
|
{'ipapermright': u'write',
|
||||||
|
'type': u'host',
|
||||||
|
'attrs': u'usercertificate'})
|
||||||
|
self._call_ipa(u'permission_add', u'Modify host userclass',
|
||||||
|
{'ipapermright': u'write',
|
||||||
|
'type': u'host',
|
||||||
|
'attrs': u'userclass'})
|
||||||
|
|
||||||
|
def _add_privileges(self):
|
||||||
|
self._call_ipa(u'privilege_add', u'Nova Host Management',
|
||||||
|
{'description': u'Nova Host Management'})
|
||||||
|
|
||||||
|
self._call_ipa(u'privilege_add_permission', u'Nova Host Management',
|
||||||
|
{u'permission': [
|
||||||
|
u'System: add hosts',
|
||||||
|
u'System: remove hosts',
|
||||||
|
u'modify host password',
|
||||||
|
u'modify host userclass',
|
||||||
|
u'modify hosts',
|
||||||
|
u'System: revoke certificate',
|
||||||
|
u'System: manage host keytab',
|
||||||
|
u'System: write host certificate',
|
||||||
|
u'System: retrieve certificates from the ca',
|
||||||
|
u'System: modify services',
|
||||||
|
u'System: manage service keytab',
|
||||||
|
u'System: read dns entries',
|
||||||
|
u'System: remove dns entries',
|
||||||
|
u'System: add dns entries',
|
||||||
|
u'System: update dns entries']})
|
||||||
|
|
||||||
|
def _add_role(self):
|
||||||
|
self._call_ipa(u'role_add', u'Nova Host Manager',
|
||||||
|
{'description': u'Nova Host Manager'})
|
||||||
|
self._call_ipa(u'role_add_privilege', u'Nova Host Manager',
|
||||||
|
{'privilege': u'Nova Host Management'})
|
||||||
|
self._call_ipa(u'role_add_member', u'Nova Host Manager',
|
||||||
|
{u'service': self.service})
|
||||||
|
|
||||||
|
def _add_service(self):
|
||||||
|
self._call_ipa(u'service_add', self.service, {'force': True})
|
||||||
|
|
||||||
|
def _get_keytab(self):
|
||||||
|
if self.ccache_name:
|
||||||
|
current_ccache = os.environ.get('KRB5CCNAME')
|
||||||
|
os.environ['KRB5CCNAME'] = self.ccache_name
|
||||||
|
|
||||||
|
try:
|
||||||
|
if os.path.exists(self.keytab):
|
||||||
|
os.unlink(self.keytab)
|
||||||
|
except OSError as e:
|
||||||
|
sys.exit('Could not remove %s: %s' % (self.keytab, e))
|
||||||
|
|
||||||
|
try:
|
||||||
|
run(['ipa-getkeytab',
|
||||||
|
'-s', api.env.server,
|
||||||
|
'-p', self.service,
|
||||||
|
'-k', self.keytab])
|
||||||
|
finally:
|
||||||
|
if current_ccache:
|
||||||
|
os.environ['KRB5CCNAME'] = current_ccache
|
||||||
|
|
||||||
|
# s/b already validated
|
||||||
|
user = pwd.getpwnam(self.user)
|
||||||
|
|
||||||
|
os.chown(self.keytab, user.pw_uid, user.pw_gid)
|
||||||
|
os.chmod(self.keytab, 0o600)
|
||||||
|
|
||||||
|
def configure_ipa(self):
|
||||||
|
self._add_service()
|
||||||
|
self._get_keytab()
|
||||||
|
self._add_permissions()
|
||||||
|
self._add_privileges()
|
||||||
|
self._add_role()
|
||||||
|
|
||||||
|
|
||||||
|
def ipa_options(parser):
|
||||||
|
parser.add_argument('--no-kinit',
|
||||||
|
help='Assume the user has already done a kinit',
|
||||||
|
action="store_true", default=False)
|
||||||
|
parser.add_argument('--user',
|
||||||
|
help='User that nova services run as',
|
||||||
|
default='nova')
|
||||||
|
parser.add_argument('--principal', dest='principal', default='admin',
|
||||||
|
help='principal to use to setup IPA integration')
|
||||||
|
parser.add_argument('--password', dest='password',
|
||||||
|
help='password for the principal')
|
||||||
|
parser.add_argument('--password-file', dest='passwordfile',
|
||||||
|
help='path to file containing password for '
|
||||||
|
'the principal')
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def validate_options(args):
|
||||||
|
if args.get('no_kinit', False):
|
||||||
|
return args
|
||||||
|
|
||||||
|
if not args['principal']:
|
||||||
|
args['principal'] = user_input("IPA admin user", "admin",
|
||||||
|
allow_empty=False)
|
||||||
|
|
||||||
|
if args['passwordfile']:
|
||||||
|
try:
|
||||||
|
with open(args['passwordfile']) as f:
|
||||||
|
args['password'] = f.read()
|
||||||
|
except IOError as e:
|
||||||
|
raise ConfigurationError('Unable to read password file: %s'
|
||||||
|
% e)
|
||||||
|
if not args['password']:
|
||||||
|
try:
|
||||||
|
args['password'] = getpass.getpass("Password for %s: " %
|
||||||
|
args['principal'])
|
||||||
|
except EOFError:
|
||||||
|
args['password'] = None
|
||||||
|
if not args['password']:
|
||||||
|
raise ConfigurationError('Password must be provided.')
|
||||||
|
|
||||||
|
try:
|
||||||
|
pwd.getpwnam(args['user'])
|
||||||
|
except KeyError:
|
||||||
|
raise ConfigurationError('User: %s not found on the system' %
|
||||||
|
args['user'])
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Copyright 2016 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigurationError(StandardError):
|
||||||
|
|
||||||
|
def __init__(self, message):
|
||||||
|
StandardError.__init__(self, message)
|
|
@ -24,27 +24,23 @@ import sys
|
||||||
import time
|
import time
|
||||||
import copy
|
import copy
|
||||||
import tempfile
|
import tempfile
|
||||||
from subprocess import CalledProcessError
|
|
||||||
import getpass
|
import getpass
|
||||||
from string import Template
|
|
||||||
from six.moves import input
|
|
||||||
from six.moves.configparser import ConfigParser
|
|
||||||
from ipapython.ipautil import run, kinit_password, user_input
|
from ipapython.ipautil import run, kinit_password, user_input
|
||||||
from ipalib import api
|
from ipalib import api
|
||||||
from ipalib import errors
|
from ipalib import errors
|
||||||
|
from novajoin.errors import ConfigurationError
|
||||||
|
from novajoin import configure_ipa
|
||||||
|
from six.moves import input
|
||||||
|
from six.moves.configparser import ConfigParser
|
||||||
|
from subprocess import CalledProcessError
|
||||||
|
from string import Template
|
||||||
|
|
||||||
|
|
||||||
DATADIR = '/usr/share/novajoin'
|
DATADIR = '/usr/share/novajoin'
|
||||||
NOVADIR = '/etc/nova'
|
NOVADIR = '/etc/nova'
|
||||||
IPACONF = '/etc/ipa/default.conf'
|
IPACONF = '/etc/ipa/default.conf'
|
||||||
|
NOVACONF = '/etc/nova/nova.conf'
|
||||||
JOINCONF = '/etc/join/join.conf'
|
JOINCONF = '/etc/join/join.conf'
|
||||||
KEYTAB = '/etc/join/krb5.keytab'
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigurationError(StandardError):
|
|
||||||
|
|
||||||
def __init__(self, message):
|
|
||||||
StandardError.__init__(self, message)
|
|
||||||
|
|
||||||
|
|
||||||
LOGFILE = '/var/log/novajoin-install.log'
|
LOGFILE = '/var/log/novajoin-install.log'
|
||||||
|
@ -91,7 +87,7 @@ def write_from_template(destfile, template, opts):
|
||||||
def install(args):
|
def install(args):
|
||||||
logger.info('Installation initiated')
|
logger.info('Installation initiated')
|
||||||
|
|
||||||
if not os.path.exists('/etc/ipa/default.conf'):
|
if not os.path.exists(IPACONF):
|
||||||
raise ConfigurationError('Must be enrolled in IPA')
|
raise ConfigurationError('Must be enrolled in IPA')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -105,48 +101,16 @@ def install(args):
|
||||||
api.bootstrap(context='novajoin')
|
api.bootstrap(context='novajoin')
|
||||||
api.finalize()
|
api.finalize()
|
||||||
|
|
||||||
ccache_dir = tempfile.mkdtemp(prefix='krbcc')
|
try:
|
||||||
|
api.Backend.rpcclient.connect()
|
||||||
ccache_name = os.path.join(ccache_dir, 'ccache')
|
except errors.CCacheError:
|
||||||
env = {"PATH":
|
raise ConfigurationError("No Kerberos credentials")
|
||||||
"/bin:/sbin:/usr/kerberos/bin:/usr/kerberos/sbin:/usr/bin:/usr/sbin"
|
|
||||||
}
|
|
||||||
env['KRB5CCNAME'] = os.environ['KRB5CCNAME'] = ccache_name
|
|
||||||
|
|
||||||
principal = args['principal']
|
|
||||||
if principal.find('@') == -1:
|
|
||||||
principal = '%s@%s' % (principal, api.env.realm)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
kinit_password(principal, args['password'], ccache_name)
|
user = pwd.getpwnam(args['user'])
|
||||||
except RuntimeError as e:
|
except KeyError:
|
||||||
raise ConfigurationError("Kerberos authentication failed: %s" % e)
|
raise ConfigurationError('User: %s not found on the system' %
|
||||||
|
args['user'])
|
||||||
api.Backend.rpcclient.connect()
|
|
||||||
|
|
||||||
try:
|
|
||||||
result = api.Command.service_add(u'nova/%s@%s' %
|
|
||||||
(args['hostname'], api.env.realm),
|
|
||||||
force=True)
|
|
||||||
except errors.DuplicateEntry:
|
|
||||||
pass
|
|
||||||
except Exception as e:
|
|
||||||
raise ConfigurationError(
|
|
||||||
'Failed to add service: %s' % e)
|
|
||||||
|
|
||||||
try:
|
|
||||||
if os.path.exists(KEYTAB):
|
|
||||||
os.unlink(KEYTAB)
|
|
||||||
except OSError as e:
|
|
||||||
raise ConfigurationError(
|
|
||||||
'Could not remove %s: %s' % (KEYTAB, e)
|
|
||||||
)
|
|
||||||
|
|
||||||
run(['ipa-getkeytab',
|
|
||||||
'-s', api.env.server,
|
|
||||||
'-p', 'nova/%s@%s' % (args['hostname'], api.env.realm),
|
|
||||||
'-k', KEYTAB],
|
|
||||||
env=env)
|
|
||||||
|
|
||||||
logger.info('Installing default config files')
|
logger.info('Installing default config files')
|
||||||
|
|
||||||
|
@ -169,7 +133,7 @@ def install(args):
|
||||||
shutil.copyfile(source, dst)
|
shutil.copyfile(source, dst)
|
||||||
|
|
||||||
config = ConfigParser()
|
config = ConfigParser()
|
||||||
config.read('/etc/nova/nova.conf')
|
config.read(NOVACONF)
|
||||||
config.set('DEFAULT',
|
config.set('DEFAULT',
|
||||||
'vendordata_jsonfile_path',
|
'vendordata_jsonfile_path',
|
||||||
'/etc/nova/cloud-config.json')
|
'/etc/nova/cloud-config.json')
|
||||||
|
@ -203,7 +167,7 @@ def install(args):
|
||||||
except ConfigParser.NoOptionError:
|
except ConfigParser.NoOptionError:
|
||||||
transport_url = None
|
transport_url = None
|
||||||
|
|
||||||
with open('/etc/nova/nova.conf', 'w') as f:
|
with open(NOVACONF, 'w') as f:
|
||||||
config.write(f)
|
config.write(f)
|
||||||
|
|
||||||
if transport_url:
|
if transport_url:
|
||||||
|
@ -213,15 +177,6 @@ def install(args):
|
||||||
with open(JOINCONF, 'w') as f:
|
with open(JOINCONF, 'w') as f:
|
||||||
join_config.write(f)
|
join_config.write(f)
|
||||||
|
|
||||||
try:
|
|
||||||
user = pwd.getpwnam(args['user'])
|
|
||||||
except KeyError:
|
|
||||||
raise ConfigurationError('User: %s not found on the system' %
|
|
||||||
args['user'])
|
|
||||||
|
|
||||||
os.chown(KEYTAB, user.pw_uid, user.pw_gid)
|
|
||||||
os.chmod(KEYTAB, 0o600)
|
|
||||||
|
|
||||||
logger.info('Importing IPA metadata')
|
logger.info('Importing IPA metadata')
|
||||||
(stdout, stderr, returncode) = run(
|
(stdout, stderr, returncode) = run(
|
||||||
['glance',
|
['glance',
|
||||||
|
@ -234,52 +189,26 @@ def install(args):
|
||||||
logger.error('Adding IPA metadata failed: %s' % stderr)
|
logger.error('Adding IPA metadata failed: %s' % stderr)
|
||||||
|
|
||||||
logger.info('Creating IPA permissions')
|
logger.info('Creating IPA permissions')
|
||||||
(stdout, stderr, returncode) = run(
|
|
||||||
['/usr/libexec/novajoin-ipa-setup.sh'], raiseonerr=False)
|
novajoin = configure_ipa.NovajoinRole(user=args.get('user'))
|
||||||
if returncode != 0:
|
if not args.get('no_kinit', False):
|
||||||
logger.error('Creating IPA permissions failed')
|
novajoin.kinit(args.get('principal'), args.get('password'))
|
||||||
|
novajoin.configure_ipa()
|
||||||
|
|
||||||
|
|
||||||
def parse_args():
|
def parse_args():
|
||||||
parser = argparse.ArgumentParser(description='Nova join Install Options')
|
parser = argparse.ArgumentParser(description='Nova join Install Options')
|
||||||
parser.add_argument('--hostname',
|
parser.add_argument('--hostname',
|
||||||
help='Machine\'s fully qualified host name')
|
help='Machine\'s fully qualified host name')
|
||||||
parser.add_argument('--user',
|
|
||||||
help='User that nova services run as',
|
|
||||||
default='nova')
|
|
||||||
parser.add_argument('--principal', dest='principal', default='admin',
|
|
||||||
help='principal to use to setup IPA integration')
|
|
||||||
parser.add_argument('--password', dest='password',
|
|
||||||
help='password for the principal')
|
|
||||||
parser.add_argument('--password-file', dest='passwordfile',
|
|
||||||
help='path to file containing password for '
|
|
||||||
'the principal')
|
|
||||||
parser.add_argument('--keystone-auth-url', dest='keystone_auth_url',
|
parser.add_argument('--keystone-auth-url', dest='keystone_auth_url',
|
||||||
help='Keystone auth URL')
|
help='Keystone auth URL')
|
||||||
parser.add_argument('--nova-password', dest='nova_password',
|
parser.add_argument('--nova-password', dest='nova_password',
|
||||||
help='Nova service user password')
|
help='Nova service user password')
|
||||||
|
parser = configure_ipa.ipa_options(parser)
|
||||||
|
|
||||||
args = vars(parser.parse_args())
|
args = vars(parser.parse_args())
|
||||||
|
|
||||||
if not args['principal']:
|
configure_ipa.validate_options(args)
|
||||||
args['principal'] = user_input("IPA admin user", "admin",
|
|
||||||
allow_empty=False)
|
|
||||||
|
|
||||||
if args['passwordfile']:
|
|
||||||
try:
|
|
||||||
with open(args['passwordfile']) as f:
|
|
||||||
args['password'] = f.read()
|
|
||||||
except IOError as e:
|
|
||||||
raise ConfigurationError('Unable to read password file: %s'
|
|
||||||
% e)
|
|
||||||
if not args['password']:
|
|
||||||
try:
|
|
||||||
args['password'] = getpass.getpass("Password for %s: " %
|
|
||||||
args['principal'])
|
|
||||||
except EOFError:
|
|
||||||
args['password'] = None
|
|
||||||
if not args['password']:
|
|
||||||
raise ConfigurationError('Password must be provided.')
|
|
||||||
|
|
||||||
if not args['hostname']:
|
if not args['hostname']:
|
||||||
args['hostname'] = socket.getfqdn()
|
args['hostname'] = socket.getfqdn()
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from ipalib import api, errors
|
||||||
|
from novajoin import configure_ipa
|
||||||
|
from novajoin.errors import ConfigurationError
|
||||||
|
|
||||||
|
|
||||||
|
IPACONF = '/etc/ipa/default.conf'
|
||||||
|
LOGFILE = '/var/log/novajoin-install.log'
|
||||||
|
|
||||||
|
logging.basicConfig()
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
if not os.path.exists(IPACONF):
|
||||||
|
sys.exit('Must be enrolled in IPA')
|
||||||
|
|
||||||
|
api.bootstrap(context='novajoin')
|
||||||
|
api.finalize()
|
||||||
|
|
||||||
|
try:
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description='Nova join Install Options'
|
||||||
|
)
|
||||||
|
parser = configure_ipa.ipa_options(parser)
|
||||||
|
args = vars(parser.parse_args())
|
||||||
|
configure_ipa.validate_options(args)
|
||||||
|
except ConfigurationError as e: # pylint: disable=broad-except
|
||||||
|
logger.info(str(e)) # emit message to console
|
||||||
|
logger.debug(e, exc_info=1) # add backtrace information to logfile
|
||||||
|
|
||||||
|
logger.info('Installation aborted.')
|
||||||
|
logger.info('See log file %s for details' % LOGFILE)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
novajoin = configure_ipa.NovajoinRole(user=args.get('user'))
|
||||||
|
if not args.get('no_kinit', False):
|
||||||
|
novajoin.kinit(args.get('principal'), args.get('password'))
|
||||||
|
|
||||||
|
try:
|
||||||
|
api.Backend.rpcclient.connect()
|
||||||
|
except errors.CCacheError:
|
||||||
|
sys.exit("No Kerberos credentials")
|
||||||
|
|
||||||
|
novajoin.configure_ipa()
|
|
@ -1,30 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
ipa privilege-add 'Nova Host Management' --desc='Nova Host Management'
|
|
||||||
|
|
||||||
ipa permission-add 'modify host password' --permissions='write' --type='host' --attrs='userpassword'
|
|
||||||
ipa permission-add 'write host certificate' --permissions='write' --type='host' --attrs='usercertificate'
|
|
||||||
ipa permission-add 'modify host userclass' --permissions='write' --type='host' --attrs='userclass'
|
|
||||||
|
|
||||||
ipa privilege-add-permission 'Nova Host Management' \
|
|
||||||
--permissions='System: add hosts' \
|
|
||||||
--permissions='System: remove hosts' \
|
|
||||||
--permissions='modify host password' \
|
|
||||||
--permissions='modify host userclass' \
|
|
||||||
--permissions='modify hosts' \
|
|
||||||
--permissions='System: revoke certificate' \
|
|
||||||
--permissions='System: manage host keytab' \
|
|
||||||
--permissions='System: write host certificate' \
|
|
||||||
--permissions='System: retrieve certificates from the ca' \
|
|
||||||
--permissions='System: modify services' \
|
|
||||||
--permissions='System: manage service keytab' \
|
|
||||||
--permissions='System: read dns entries' \
|
|
||||||
--permissions='System: remove dns entries' \
|
|
||||||
--permissions='System: add dns entries' \
|
|
||||||
--permissions='System: update dns entries'
|
|
||||||
|
|
||||||
ipa role-add 'Nova Host Manager' --desc='Nova host management'
|
|
||||||
|
|
||||||
ipa role-add-privilege 'Nova Host Manager' --privilege='Nova Host Management'
|
|
||||||
|
|
||||||
ipa role-add-member 'Nova Host Manager' --services=nova/`hostname`
|
|
Loading…
Reference in New Issue