[Freeipa-devel] [PATCH] Password vault

Endi Sukma Dewata edewata at redhat.com
Fri May 15 00:17:14 UTC 2015


On 5/14/2015 1:42 PM, Jan Cholasta wrote:
>>> Question: Services in IPA are identified by Kerberos principal. Why are
>>> service vaults identified by hostname alone?
>>
>> The service vaults are actually identified by the hostname and service
>> name assuming the principal is in this format: <name>/<host>@<realm>.
>> The vault is stored in cn=<name>, cn=<host>, cn=services, cn=vaults,
>> <suffix>. When accessing a vault service you are supposed to specify the
>> name and the host (except for vault-find which will return all services
>> in the same host):
>>
>> $ ipa vault-find --host <host>
>> $ ipa vault-add <name> --host <host>
>>
>> Are there other service principal formats that we need to support? Do we
>> need to support services of different realms?
>
> Well, users are identified by username (uid attribute), hosts by
> hostname (fqdn attribute) and services by principal name
> (krbprincipalname attribute). Each of them has separate container and is
> also uniquely identified by principal name. I guess it would make sense
> to follow that for vaults as well, in which case service vaults should
> be called host vaults (because they are created in a host-specific
> container, not a service-specific one) and maybe "real" service vaults
> should be added.

There's no plan for host vaults in the design doc, but it's not 
impossible to add it in the future. What is the use case?

I suppose we can change the service vault into a container, and possibly 
add generic user vaults too (in addition to private user vaults), the 
interface will look like this:

$ ipa vault-add PrivateVault
$ ipa vault-add ServiceVault --service <name>/<hostname>
$ ipa vault-add SharedVault --shared
$ ipa vault-add UsersVault --user <username>
$ ipa vault-add HostVault --host <hostname>

Basically we'll need a new parameter for each new container. For the 
initial implementation we only need the first 2 or 3.

>> Do we
>> need to support services of different realms?
>
> That depends. Do we want to support vaults for users and services from
> AD trusts?

It wasn't mentioned in the design doc either, but probably in the future 
we can support external vaults too:

$ ipa vault-add ExternalVault --principal <principal>

   cn=vaults
   + cn=external
     + cn=<name>/<hostname>@<realm>
       + cn=<vault 1>
       + cn=<vault 2>
     + cn=<user>@<realm>
       + cn=<vault 3>
       + cn=<vault 4>

>> 1. The following code in get_dn() is causing problems for vault-find.
>>
>>    dn = super(vault, self).get_dn(*keys, **options)
>>    rdn = dn[0]
>>    container_dn = DN(*dn[1:])
>>
>> The super.get_dn() will return cn=vaults, <suffix>, so the rdn will
>> become cn=vaults and container_dn will become <suffix>. When combined
>> with the subcontainer (private/shared/service) it will produce an
>> invalid DN.
>
> Right, fixed.
>
> I should have tested the patch before posting it, my bad, sorry.

OK.

>> 2. Not sure if it'related to #1, the vault-find is failing.
>>
>> $ ipa vault-find
>> ipa: ERROR: an internal error has occurred
>>
>> The error_log shows TypeError: 'NoneType' object is not iterable
>
> Fixed. It was caused by missing return value in vault_find.exc_callback.

We can actually ignore all NotFound errors since now all containers are 
either created automatically or already created by default.

   if call_func.__name__ == 'find_entries':
       if isinstance(exc, errors.NotFound):
           shared = options.get('shared')

           # if private or service container has not been created, ignore
           if not shared:
               raise errors.EmptyResult(reason=str(exc))

The original code was only ignoring NotFound errors on user vaults 
because previously only the user containers was supposed to be created 
automatically, and there wasn't a plan to provide service container.

>> 3. The --shared option in vault-find is now requiring an argument even
>> though it's a Flag.
>>
>> $ ipa vault-find --shared
>> Usage: ipa [global-options] vault-find [CRITERIA] [options]
>>
>> ipa: error: --shared option requires an argument
>
> Fixed.

OK.

>> 4. The following code in get_dn() is incorrect:
>>
>>    principal = getattr(context, 'principal')
>>    (name, realm) = split_principal(principal)
>>    name = name.split('/')
>>    if len(name) == 1:
>>        container_dn = DN(('cn', 'users'), container_dn)
>>    else:
>>        container_dn = DN(('cn', 'services'), container_dn)
>>    container_dn = DN(('cn', name[-1]), container_dn)
>>
>> A service does not have a private container like users (cn=<username>,
>> cn=users, cn=vaults). The entry cn=<name>, cn=<host>, cn=services,
>> cn=vaults is a service vault, not a container. The service vault is used
>> by the admin to provide a secret for a service.
>>
>> I'm not sure what the behavior should be if a service is executing a
>> vault command that uses a private container such as:
>>
>>    $ ipa vault-add test
>>
>> Maybe it should just generate an error.
>
> Users, hosts and services are all user-like objects, is there a reason
> not to support private vaults for all of them?

As mentioned above, it's not required in the design doc, but we can add 
it if there's a clear use case. I agree that at least for now we can 
change the service vault into a service container to store multiple 
service's private vaults.

>> 5. In create_container() why do you need to reconstruct the container_dn
>> on each invocation even though the value is fixed?
>>
>>    container_dn = DN(self.container_dn, self.api.env.basedn)
>
> Because self.api may not necessarily be the same as ipalib.api.

Under what scenario would that be a problem? The original code seems to 
be working fine with ipalib.api.

If it is a problem, why do we still use ipalib.api to initialize 
container_dn vault class attribute?

   container_dn = api.env.container_vault

Then in get_dn() we basically construct the container_dn variable with 
values from both self.api and ipalib.api:

   container_dn = DN(self.container_dn, self.api.env.basedn)

When is the self.api actually initialized? Can we initialize the 
container_dn (or base_dn as in the original code) attribute immediately 
after that?

>> 6. The loop in create_container() is incorrect. Suppose we're creating a
>> container cn=A, cn=B, <suffix> and the parent container cn=B, <suffix>
>> doesn't exist yet. The first add_entry() invocation will fail as
>> expected, but instead of adding the parent entry the whole method will
>> fail.
>
> Right, fixed.

It's still not working. The new code is trying to add cn=vaults first, 
and it stops because it already exists, but the intermediary entries are 
still not added. Also the DN displayed in the message misleading:

$ ipa vault-add test
ipa: ERROR: container entry (cn=vaults) not found

$ ipa vault-add test --host server.example.com
ipa: ERROR: container entry (cn=vaults) not found

The unit tests are failing because of this.

>> 7. The host and shared parameters are no longer available in vault-show
>> and vault-del commands. The unit tests are failing because of that. Why
>> do these commands not automatically inherit all parameters from the
>> class?
>
> The parameters of Object plugins represent attributes of the object, so
> they are all provided in commands which allow setting values of the
> attributes (-add and -mod). Other commands need to only know which
> object to look up, so they provide only the primary key, which is
> supposed to uniquely identify the object.
>
> The issue with vaults is that they are in fact identified by
> (vault_name, host, shared) tuple, but the primary_key is just
> vault_name. Fixed by reverting to your original approach.

OK. As discussed above, the vault may need to be identified by even more 
parameters, e.g. service, user, principal.

> Updated patch attached.

8. There's a new PEP8 error:

.../ipalib/plugins/vault.py:98:1: E302 expected 2 blank lines, found 1

9. The API.txt needs to be regenerated.

> Also attached is a modified patch, which implements hierarchical vault
> container objects. It is very hacky, but functional and self-contained.
> You can use it if you want.

Let's circle back to this after we get the essential vault functionality 
checked in. The latest plan was to merge vaultcontainer into vault.

-- 
Endi S. Dewata




More information about the Freeipa-devel mailing list