service: allow creating services without a host to manage them

Add --skip-host-check option to ipa service-add command to allow
creating services without corresponding host object. This is needed to
cover use cases where Kerberos services created to handle client
authentication in a dynamically generated environment like Kubernetes.

Fixes: https://pagure.io/freeipa/issue/7514
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
This commit is contained in:
Alexander Bokovoy
2018-04-26 11:08:33 +03:00
committed by Rob Crittenden
parent 2a58fe6a32
commit 9e8fb94e87
4 changed files with 49 additions and 10 deletions

View File

@@ -4457,7 +4457,7 @@ output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: service_add/1
args: 1,13,3
args: 1,14,3
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
option: Str('addattr*', cli_name='addattr')
option: Flag('all', autofill=True, cli_name='all', default=False)
@@ -4470,6 +4470,7 @@ option: Str('krbprincipalauthind*', cli_name='auth_ind')
option: Flag('no_members', autofill=True, default=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: Str('setattr*', cli_name='setattr')
option: Flag('skip_host_check', autofill=True, default=False)
option: Certificate('usercertificate*', cli_name='certificate')
option: Str('version?')
output: Entry('result')

View File

@@ -407,6 +407,7 @@ return {
other_entity: 'host',
other_field: 'fqdn',
label: '@i18n:objects.service.host',
editable: true,
required: true,
z_index: 1
},
@@ -414,6 +415,11 @@ return {
$type: 'checkbox',
name: 'force',
metadata: '@mc-opt:service_add:force'
},
{
$type: 'checkbox',
name: 'skip_host_check',
metadata: '@mc-opt:service_add:skip_host_check'
}
]
}
@@ -543,6 +549,9 @@ IPA.service_adder_dialog = function(spec) {
field = that.fields.get_field('force');
record['force'] = field.save();
field = that.fields.get_field('skip_host_check');
record['skip_host_check'] = field.save();
};
init();

View File

@@ -601,9 +601,14 @@ class service_add(LDAPCreate):
has_output_params = LDAPCreate.has_output_params + output_params
takes_options = LDAPCreate.takes_options + (
Flag('force',
label=_('Force'),
doc=_('force principal name even if not in DNS'),
label=_('Force'),
doc=_('force principal name even if host not in DNS'),
),
Flag('skip_host_check',
label=_('Skip host check'),
doc=_('force service to be created even when host '
'object does not exist to manage it'),
),
)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
@@ -614,12 +619,13 @@ class service_add(LDAPCreate):
if principal.is_host and not options['force']:
raise errors.HostService()
try:
hostresult = self.api.Command['host_show'](hostname)['result']
except errors.NotFound:
raise errors.NotFound(
reason=_("The host '%s' does not exist to add a service to.") %
hostname)
if not options['skip_host_check']:
try:
hostresult = self.api.Command['host_show'](hostname)['result']
except errors.NotFound:
raise errors.NotFound(reason=_(
"The host '%s' does not exist to add a service to.") %
hostname)
self.obj.validate_ipakrbauthzdata(entry_attrs)
@@ -628,7 +634,7 @@ class service_add(LDAPCreate):
# really want to discourage creating services for hosts that
# don't exist in DNS.
util.verify_host_resolvable(hostname)
if not 'managedby' in entry_attrs:
if not (options['skip_host_check'] or 'managedby' in entry_attrs):
entry_attrs['managedby'] = hostresult['dn']
# Enforce ipaKrbPrincipalAlias to aid case-insensitive searches

View File

@@ -47,6 +47,11 @@ service1dn = DN(('krbprincipalname',service1),('cn','services'),('cn','accounts'
host1dn = DN(('fqdn',fqdn1),('cn','computers'),('cn','accounts'),api.env.basedn)
host2dn = DN(('fqdn',fqdn2),('cn','computers'),('cn','accounts'),api.env.basedn)
host3dn = DN(('fqdn',fqdn3),('cn','computers'),('cn','accounts'),api.env.basedn)
d_service_no_realm = u'some/at.some.arbitrary.name'
d_service = u'%s@%s' % (d_service_no_realm, api.env.realm)
d_servicedn = DN(('krbprincipalname', d_service),
('cn', 'services'), ('cn', 'accounts'),
api.env.basedn)
role1 = u'Test Role'
role1_dn = DN(('cn', role1), api.env.container_rolegroup, api.env.basedn)
@@ -87,6 +92,7 @@ class test_service(Declarative):
('host_del', [fqdn2], {}),
('host_del', [fqdn3], {}),
('service_del', [service1], {}),
('service_del', [d_service], {}),
]
tests = [
@@ -732,6 +738,23 @@ class test_service(Declarative):
),
# Create a service disconnected from any host
dict(
desc='Try to create service %r without any host' % d_service,
command=('service_add', [d_service_no_realm],
dict(force=True, skip_host_check=True),),
expected=dict(
value=d_service,
summary=u'Added service "%s"' % d_service,
result=dict(
dn=d_servicedn,
krbprincipalname=[d_service],
krbcanonicalname=[d_service],
objectclass=objectclasses.service,
ipauniqueid=[fuzzy_uuid],
),
),
),
]