⚠️ This repository has been deprecated and the development of freeipa-manager has been stopped. Feel free to apply in case you want to take over the ownership. ⚠️
freeipa-manager is a tool for management of FreeIPA entities. It makes it easier to setup and maintain identity management using FreeIPA by keeping the configuration of users, groups, rules and other entities in files that can be easily version-controlled.
The main purpose of the tool is to enable a FreeIPA administrator to keep FreeIPA entity configuration in a VCS. This means that the definition of FreeIPA users, groups, rules, and other entities can be committed to, for instance, a Git repo, which enables one to:
- backup and restore entities easily,
- easily transfer entity structure from one FreeIPA domain to another,
- enforce entity configuration from a version-controlled and reviewed state,
- keep track of entity changes made via FreeIPA UI in a repository,
- define (and enforce) a meta-structure over entities.
The ultimate goal of the tool is the ability to implement the role-based access control (RBAC) philosophy, which would be tedious and impractical without a clean control over entities that version control grants us.
The following examples assume that the configuration directory (as described below in the Configuration section) is located in a path called config.
ipamanager check config
The most basic only verifies that the entities defined in the config follow the pre-defined structure/integrity rules.
Integrity check verifies basic consistency of entities, such as:
- whether entities are only members of existing entities,
- whether entities are only members of entities of allowed types,
- that there are no cycles in the membership,
- that HBAC/sudo rules have a member hostgroup & user group.
The integrity check module also supports additional settings and constraints on the entity structure, such as:
- that users can only be (direct) members of groups with given naming convention (e.g., a group must be named '*-users' to be able to contain users directly),
- that nesting of group membership can only go up to a certain level (e.g., max. group1 -> group2 -> group3 - maximum nesting level 2),
- ...
ipamanager push config
The push
command, after verifying the entities (like check
), configures
the defined entities on the FreeIPA server.
The default mode of this command is a dry run, overriden by the --force
flag.
The address of the FreeIPA server is parsed by the ipalib
package from the
/etc/ipa/default.conf
config file.
ipamanager pull config
Analogically to push
, the pull
command dumps the current state of entities
on a FreeIPA server to files in the config directory.
Additionally, using the ipamanager-pull-request
command from the included
ipamanager.tools
package, a GitHub pull request can be opened against the config
repository with the dumped changes.
ipamanager diff folder1 folder2
The diff
command is useful for listing entities that are extra in folder1
compared to folder2
, e.g.:
- listing users defined for one domain but not for another (see Multiple domains below for details), or
- listing HBAC rules with no corresponding sudo rule with the same name.
ipamanager template template.yaml config
The template
command creates all the entities for a subcluster defined in the
template.yaml
to the repo
locally. Entities needs to be reviewed and then commited
to the config repository manually.
Example of the template.yaml
file with decsription can be found in tests/example_template.yaml
ipamanager roundtrip config
The roundtrip
command can be used to load entities from config files
(like the check
command, but without integrity checking), then store
them right back to the configuration files.
This can be useful when your config is technically correct, but there are
style issues in it (e.g., the memberOf
lists values are unsorted).
Round-trip will fix these issues. Alternatively, a pull
operation would
fix such issues in the config of entities changed on the FreeIPA server as well,
but such a commit would contain both server-side changes and style fixes;
this could lead to a confusing diff, which may be undesirable.
There is a separate ipamanager.tools
sub-package, providing tools that are not
required for the core tool's functionality but can be used to enhance workflows.
Create a GitHub pull request from the given branch of the config repo.
Can be useful with the pull
action.
ipamanager-pull-request -b new-changes -B master -o my-organization -r config-repo -u github-user -c # commit changes
ipamanager-pull-request -b new-changes -B master -o my-organization -r config-repo -u github-user -p # commit changes & create PR
Query the config repo for various meta-values or relationships between entities.
The member
query functionality enables searching for nested membership relations
between entities. For example, to find if a group called group1
is a member of
the group group2
(including indirect membership), run:
ipamanager-query member <config-repo> -m <group:group1> -e <group:group2>
The labels
functionality allows defining security labels that can be assigned
to users and groups; a user is then required to have the security labels that match
those of the groups they are a member of.
The labels are defined as a key in the entities' metaparams
mapping. For instance,
we could have a user and a group with the following labels:
---
user1:
...
metaparams:
labels: [label1, label2]
---
group1:
...
metaparams:
labels: [label2, label3]
In this case, user1
would need to be granted the label3
label in order to be
able to be a member of group1
.
The labels
command, along with appropriate subcommand, is used to access this
functionality via CLI.
# check if label is required by group
ipamanager-query labels check label <group> <config-repo>
# list labels that a user is missing, based on their groups
ipamanager-query labels missing <user> <config-repo>
# list all labels required by a group
ipamanager-query labels necessary <group> <config-repo>
# check if user has all labels required to be a member of group
ipamanager-query labels user <user> <group> <config-repo>
The QueryTool functionality can also be imported to use from other Python code:
from ipamanager.tools.query_tool import load_query_tool
querytool = load_query_tool('config_repo', 'settings.yaml')
querytool.check_user_membership('user.name', 'group-name') # True/False
for group in querytool.list_groups('user.name'): # returns iterator
print group
querytool.check_label_necessary('label', 'group') # True/False
for label in querytool.list_user_missing_labels('user'):
print label
for label in querytool.list_necessary_labels('group'):
print label
querytool.check_user_necessary_labels('user', 'group') # True/False
The dry run mode can be choosen with -d
or --dry-run
flag.
The most practical way of keeping configuration for the tool is to dedicate a separate repository for the purpose.
Inside the repository, there should be a subfolder per each entity type, like this:
groups/
hbacrules/
hbacsvcgroups/
hbacsvcs/
hostgroups/
permissions/
privileges/
roles/
services/
sudorules/
users/
Alternatively, it is possible to keep configuration for several FreeIPA domains in a single repository, by dividing it into per-domain subfolders, e.g.:
domain1/
groups/
hbacrules/
hostgroups/
domain2/
hostgroups/
users/
groups/
...
Entity types you don't wish to manage using freeipa-manager do not need to have
their own folders in the structure; however, please note they may be deleted
by the push
command run unless you specify the ignore settings correctly (see
the Settings file#Ignored entities stanza below for details).
The entity configuration is kept in files of the YAML format.
There should be a separate configuration file for each entity. The entity should
be defined as a mapping, where the only top-level key is the entity's id
in FreeIPA
while the nested keys are the particular values of its parameters.
FreeIPA permits several relationships between entities to be defined, such as:
- users can be members of user groups,
- hosts can be members of host groups,
- HBAC & sudo rules have users, hosts & groups as members,
- ...
In freeipa-manager, these relationships are captured by two ways:
- The memberOf attribute. This is useful where we want to model the relationships on the side of the member, e.g., for users (where memberOf contains a list of a given user's groups) or groups (what other group a given group is a member of).
- The member(Host|User) attribute. This is used wherever we want to capture the membership relation of entities on the side of the target entity. Currently, this is used for HBAC rules & sudo rules.
See the per-type entity config descriptions below for more details.
In addition to the FreeIPA-mandated entity structure, a special parameter, called metaparams, can be defined for any entity type. This key can contain an arbitrary mapping of keys and values, for instance:
entity1:
...
metaparams:
metakey1: value1
key2:
subkey: subvalue
another: [value, value2]
The value of this key is ignored by the tool (and preserved even with the pull
command).
Meta parameters can be useful for defining a separate data structure on top of the
FreeIPA entities; for example, you could have a key called approval
inside
metaparams
for user groups and check whether an approval is needed for an user
to be added to a given group (e.g., as part of pull request testing). While you
would currently need to write a separate tooling for that, native support for
meta parameter processing is planned in freeipa-manager as well.
Each entity type has its own set of parameters that FreeIPA supports. The structure
that the tool expects for an entity configuration is defined in the ipamanager/schemas.py
module and parsed by the voluptuous
package.
The user entity type is the most parametrized one; a maximum record can look like the following:
user.name:
firstName: Test # required
lastName: User # required
initials: TU
emailAddress: testuser@example.com # can also be a list of addresses
organizationUnit: Department1
manager: some.manager # ID of another existing user
githubLogin: abclogin1 # maps to the 'carlicense' attribute
title: SW Engineer
memberOf:
group: [group1, other-group]
metaparams:
param1: value1
param2: value2
A user can be a member of any number of user groups. However, the default
membership in the ipausers
group is not captured in the config; it is added
automatically to each user entity by the tool itself.
The user group entity is much simpler; a minimal example could look like this:
group1:
A maximum example:
group1:
description: A sample group.
posix: False
memberOf:
group:
- group2
metaparams: ...
User groups can be members of other user groups.
Note that the user group type is just called group
, not usergroup
, since that
is the way that FreeIPA references the type as well (e.g., in the ipa group-add
command).
Host groups are analogical to user groups, minus the POSIX option:
group1:
description: A sample group.
posix: False
memberOf:
hostgroup:
- group2
metaparams: ...
HBAC rules define a mapping of access between user groups and host groups.
rule1:
description: An example HBAC rule.
memberHost: [hostgroup1, hostgroup2]
memberUser: [usergroup1, usergroup2]
memberService: httpd # mutually exclusive with serviceCategory
serviceCategory: all # mutually exclusive with memberService
NOTE: FreeIPA allows defining users and hosts as direct members of HBAC rules; however, since our use cases always required a structure where only groups are allowed to be members of rules, we decided to disregard such a possibility in the configuration.
Additionally, our config requires HBAC rules to have at least one memberHost
and at least one memberUser
.
Sudo rules are similar to HBAC rules in terms of memberHost
/memberUser
, but
they have some specific options:
rule1:
description: An example HBAC rule.
memberHost: [hostgroup1, hostgroup2]
memberUser: [usergroup1, usergroup2]
cmdCategory: all
options: # maps to the ipasudoopt attribute
- !authenticate
runAsGroupCategory: all
runAsUserCategory: all
NOTE: FreeIPA allows defining users and hosts as direct members of sudo rules; however, since our use cases always required a structure where only groups are allowed to be members of rules, we decided to disregard such a possibility in the configuration.
Additionally, our config requires HBAC rules to have at least one memberHost
and at least one memberUser
.
service1:
description: A sample service managed by HBAC rules.
memberOf:
hbacsvcgroups:
- servicegroup1
- servicegroup2
Since FreeIPA defines quite a comprehensive set of HBAC services (such as sshd
or httpd
) by default, one may not ever need to define additional entities of type
type, but it's nevertheless possible.
servicegroup1:
description: A group of HBAC services.
metaparams:
param1: [value1, value1.1]
Roles are usually used to define access to functionalities inside FreeIPA itself.
They can be members of privilege
entities:
role-one:
description: A role.
memberOf:
privilege: [privilege1]
Privileges serve as "middleware" between roles
and permissions
:
sample-privilege:
description: A sample privilege entity.
memberOf:
permission:
- 'System: Add Groups'
- another-permission
Permissions are the final level of access definition inside FreeIPA; they can allow access to specific FreeIPA functions by granting read/write access to the relevant parts of the underlying LDAP tree structure.
There are pre-defined "System:" permissions, and you can also define your own:
new-permission:
description: A permission to do something in FreeIPA.
subtree: subtree-name
attributes:
- firstName
- lastName
- initials
grantedRights: [read, write] # can also be just a string
defaultAttr: initials
location: cn=users,cn=accounts,dc=example,dc=com
Services are the per-host principals that allow getting keytabs & certificates.
HTTP/host1.example.com:
managedBy: [host1.example.com] # can also be just a string
description: A sample HTTP service for host1.example.com.
metaparams:
param1: value2
If hosts in your domain change often, you might find it impractical to manage services via this tool; however, it might be useful if your hosts are largely static.
In addition to definitions of entities themselves, a settings file is needed to provide additional configuration of the tool itself.
Like entity config files, the settings file uses the YAML format. Currently, the following settings are supported:
Defines a list of regexes for each entity type; if a name of an entity of the given type matches any of the relevant expressions, it will not be noticed by the tool, whether encountered in the config files or on FreeIPA server.
This key is optional, and it does not have to contain every entity type; by default, no entity is ignored.
# example
ignore:
user: [admin, test.+]
service: [.*]
Defines a pattern that user group entities' names must match for them to be allowed to contain users directly. This is useful when defining a strict, nested group structure.
If this key's value is set to an empty string (''
), this is not enforced and any
user group can contain users directly.
Defines maximum nesting level of group membership. E.g., a level of 3 means that entities can be nested at most like this:
group1 -> group2 -> group3 -> group4
This should be a number. If this is not provided, nesting limit is not enforced.
Defines configuration for alerting plugins that should send a result of the tool's run to a monitoring service. Several plugins can be configured:
# example
alerting:
test-monitoring:
module: test_monitoring
class: TestMonitoringPlugin
config:
key1: value1
key2: value2
other-alerting:
module: other.test
class: OtherAlertingPlugin
This would instantiate the plugins alerting.test_monitoring.TestMonitoringPlugin
and alerting.other.testOtherAlertingPlugin
. The config
dictionary value is
passed to the plugin instance without modification.
A settings file can be included inside another one; this permits us, for example, to define common settings for several use cases, and then include this common config file to other configs that will extend it for specific use cases:
# common config
nesting-limit: 4
ignore:
user: [test]
---
# specific config:
include:
- "common.yaml"
alerting:
test-monitoring:
module: test_monitoring
class: TestMonitoringPlugin
The merge\_include
parameter defines whether matching dict-type keys in included
configs should be merged with the value in the current file, rather then overwritten:
include: ["common.yaml"]
merge_include: true
Several new features of freeipa-manager are planned for the future, such as:
It should be possible to define a structure of labels in metaparams for users that will define roles (in accordance with RBAC) necessary for membership in certain groups. The tool should process these labels and ensure that group membership is only granted if all the defined criteria are met.
Since freeipa-manager is a tool for Linux environment, distributing a manual entry
with it would be reasonable, since it's the standard for Linux tools.
Similarly, Tab
key auto-completion of commands is a standard and would be useful.
The tool could possibly interface LDAP directly instead of the higher-level FreeIPA API. This would enable a wider range of applications.