mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-01-09 15:53:00 -06:00
304 lines
12 KiB
Markdown
304 lines
12 KiB
Markdown
|
# Disable Stale Users
|
||
|
|
||
|
**DESIGN STAGE**
|
||
|
|
||
|
## Overview
|
||
|
|
||
|
Some regulations call for accounts that have not been used for a specific
|
||
|
amount of time be automatically disabled in the identity management system.
|
||
|
|
||
|
FreeIPA does not keep track of successful authentication events.
|
||
|
The krbLastSuccessfulAuth attribute is not updated by default since
|
||
|
https://pagure.io/freeipa/issue/5313 for reliability reasons.
|
||
|
Therefore distinguishing between stale and active accounts cannot be done with
|
||
|
existing logon data.
|
||
|
|
||
|
|
||
|
## Possible approaches
|
||
|
|
||
|
### Environments with mandatory, periodic password changes
|
||
|
|
||
|
The problem is easy to solve in environments where user passwords must be
|
||
|
changed regularly. A user account whose associated password is past its due
|
||
|
change date can be considered stale and therefore be disabled by the system.
|
||
|
In this case, a grace period must be provided between password expiration and
|
||
|
the actual account locking event.
|
||
|
Total writes to LDAP using this approach due to the disable stale users tooling
|
||
|
are minimal (only nsAccountLock). However, password-change related writes are
|
||
|
needed every 90 days (by default).
|
||
|
Each password change updates the krbLastPwdChange, krbPasswordExpiration,
|
||
|
userPassword, krbPrincipalKey, and krbExtraData attributes.
|
||
|
|
||
|
The Disable Stale Users (DSU) tooling proposes to make sure no non-locked
|
||
|
account has a password expired since N days, N being 7 by default.
|
||
|
|
||
|
### Environments with no mandatory password changes
|
||
|
|
||
|
For environments where user passwords never expire, a new mechanism must be
|
||
|
added to FreeIPA plugins ipa-kdb and ipa-lockout to account for each user
|
||
|
account authentication events. Since updating a LDAP user account attribute on
|
||
|
each authentication event must be avoided as the update frequency could easily
|
||
|
be high, (see https://pagure.io/freeipa/issue/5313 for background
|
||
|
information), a coarse update mechanism is proposed.
|
||
|
|
||
|
An attribute containing a timestamp is added to each user:
|
||
|
coarseSuccessfulAuthTime. It will be added at account creation time (set to
|
||
|
current date).
|
||
|
The timestamp contained therein is not precise. It is updated by IPA plugins
|
||
|
whenever a successful authentication event happens, but only if the current
|
||
|
timestamp is sufficiently in the past. The update interval is configurable, but
|
||
|
to avoid replication storms, it is randomized. To achieve this, a randomized
|
||
|
value is added to a fixed time interval.
|
||
|
|
||
|
Some attributes must be added to the cn=ipaConfig schema:
|
||
|
* the first one to activate the mechanism (default: not present):
|
||
|
```
|
||
|
ipaConfigString: DSU:RecordSuccessfulAuth
|
||
|
```
|
||
|
* the second attribute contains the fixed time period (default: 28 days):
|
||
|
```
|
||
|
ipaDSURecordSucessfulAuthTimeInterval: 2419200
|
||
|
```
|
||
|
* the third one contains a time period to be added. The actual value used is
|
||
|
randomized between 0 and the attribute's value (default: 7 days) whenever
|
||
|
a user successfully authenticates.
|
||
|
```
|
||
|
ipaDSURecordSucessfulAuthRandomizedTimeInterval: 604800
|
||
|
```
|
||
|
|
||
|
Updating this (replicated) timestamp attribute every ~30 days requires less
|
||
|
LDAP writes than mandating password changes every 90 days as the latter would
|
||
|
imply updating five (replicated) attributes at least once in that 90-day
|
||
|
period.
|
||
|
|
||
|
The Disable Stale Users (DSU) tooling, when the above mechanism is active,
|
||
|
proposes to make sure no non-locked account has a timestamp attribute 90 days
|
||
|
(by default) in the past.
|
||
|
|
||
|
On a successful authentication event:
|
||
|
|
||
|
```
|
||
|
current_date = datetime.now(timezone.utc)
|
||
|
last_update = coarseSuccessfulAuthTime
|
||
|
update_internal = ipaDSURecordSucessfulAuthTimeInterval
|
||
|
+ randint(0, ipaDSURecordSucessfulAuthRandomizedTimeInterval)
|
||
|
if current_date - last_update > update_internal:
|
||
|
coarseSuccessfulAuthTime = current_date
|
||
|
```
|
||
|
|
||
|
As a rule of thumb, if the requirement is to disable users not seen for 90 days
|
||
|
maximum, updating the attribute roughly every 35 days is good enough.
|
||
|
At worst, the user would have authenticated the first day and the last day of
|
||
|
the 35-day maximum update interval and the randomized time interval would have
|
||
|
been 7 days.
|
||
|
The attribute would therefore contain the date from the first day, as day #35
|
||
|
would have been considered too close to the existing timestamp to warrant
|
||
|
updating it. DSU would then proceed to disable the user account 90 days after
|
||
|
the existing coarseSuccessfulAuthTime timestamp - this is only after 55 day
|
||
|
(90-35) of real inactivity, which fits the requirement (albeit loosely).
|
||
|
|
||
|
Having a 90-day inactive user disabling requirement would by default disable
|
||
|
accounts really inactive for 55 (90-35) to 90 days.
|
||
|
|
||
|
In short:
|
||
|
|
||
|
```
|
||
|
if (current_date - 90d) > coarseSuccessfulAuthTime:
|
||
|
disable_account()
|
||
|
```
|
||
|
|
||
|
The 90-day default value is configurable (see appropriate section below).
|
||
|
|
||
|
|
||
|
### Notes
|
||
|
|
||
|
Installing the DSU tooling will not change the behavior of existing clusters.
|
||
|
DSU has to be explicitly configured and enabled to start disabling stale
|
||
|
accounts.
|
||
|
|
||
|
Accounts are locked out by setting the nsAccountLock attribute
|
||
|
(OID: 2.16.840.1.113730.3.1.610) to True.
|
||
|
|
||
|
FreeeIPA is not directly involved when a user logs in using an ssh key so it
|
||
|
cannot make decisions on whether an account is "active" or not. However,
|
||
|
setting nsaccountlock = TRUE will block all logins including those using ssh
|
||
|
key authentication.
|
||
|
For passwordless environments, S4U2Self is proposed to be added to SSSD to
|
||
|
account for successful user logon events through ipa-kdb:
|
||
|
https://pagure.io/SSSD/sssd/issue/4077
|
||
|
The mechanism laid out in "Environments with no mandatory password changes"
|
||
|
would then be applied as-is.
|
||
|
|
||
|
There is always the possibility that a long-inactive user account will be
|
||
|
disabled (nsAccountLock'd) by DSU even if that user managed to logon the
|
||
|
previous few seconds before or during the DSU window due to:
|
||
|
* the time it takes for the timestamp attribute to be replicated to the DSU
|
||
|
runner
|
||
|
* the time it takes for nsAccountLock to be replicated from the DSU runner
|
||
|
to the replica this user uses.
|
||
|
|
||
|
There is no way to prevent that from happening with the present design, but
|
||
|
the probability of that happening is low.
|
||
|
|
||
|
|
||
|
## Example
|
||
|
|
||
|
### Environments with mandatory, periodic password changes
|
||
|
|
||
|
Given the following requirements and facts:
|
||
|
* stale accounts must be disabled after 90 days' inactivity
|
||
|
* grace period is decided to be 7 days
|
||
|
* the tool runs every day
|
||
|
* replication is expected to complete in 2h maximum
|
||
|
|
||
|
setting the maximum password lifetime to 80 days or less would meet the
|
||
|
guidelines as 80+7+1 (give or take 2h) is less than 90.
|
||
|
|
||
|
### Environments with no mandatory password changes
|
||
|
|
||
|
If the requirement is to disable users not seen for 90 days maximum, updating
|
||
|
the attribute every 35 days is good enough.
|
||
|
At worst, the user would have authenticated the first day and at least once
|
||
|
during this 35 day period, say day #29. The attribute would therefore contain
|
||
|
the date from the first day, as day #29 would have been considered too close to
|
||
|
the existing timestamp to warrant updating it. The user account would then be
|
||
|
disabled after 61 days of inactivity which fits (loosely) the requirement.
|
||
|
In short, having a 90-day inactive user disabling requirement would by default
|
||
|
disable accounts inactive for 55 (90-35) to 90 days.
|
||
|
|
||
|
|
||
|
## Limitations
|
||
|
|
||
|
### Environments with mandatory, periodic password changes
|
||
|
|
||
|
If regulations call for stale/inactive accounts to be disabled within X
|
||
|
number of days, then the lifetime of the passwords for these accounts must be
|
||
|
set to a value lower than:
|
||
|
* X,
|
||
|
* minus the expected grace period mentioned above,
|
||
|
* minus the maximum amount of time between two invocations of the DSU tool,
|
||
|
* minus the expected maximum replication delay from the replica the DSU tool is
|
||
|
installed on to the farthest point of the cluster.
|
||
|
|
||
|
### Environments with no mandatory password changes
|
||
|
|
||
|
The longer the time period, the less update activity for the timestamp
|
||
|
attribute. But using a longer period runs the risk of disabling users who have
|
||
|
been gone for too short a time. For instance, setting the update period to 65
|
||
|
days would disable accounts inactive for the last 25 to 90 days. Whether this
|
||
|
fits the site's requirements is up to the administrators to determine.
|
||
|
|
||
|
Sites requiring a better accuracy must take care not to set the update period
|
||
|
too low for performance reasons. It is strongly recommended to make sure the
|
||
|
update period is longer than the expected maximum PTO or simply "away from IPA"
|
||
|
period for most user accounts to avoid replication storms when users come back.
|
||
|
This is especially true when these away periods are in sync, like in schools.
|
||
|
|
||
|
|
||
|
## Multiple runners
|
||
|
|
||
|
DSU can be installed on more than a single replica. This provides redundancy.
|
||
|
Having multiple DSU instances active at the same time provides no advantage,
|
||
|
so the systemd timer helper script includes a randomized time wait period.
|
||
|
|
||
|
On very busy clusters, using dedicated replicas (hidden replicas) for DSU is
|
||
|
recommended.
|
||
|
|
||
|
|
||
|
## How to Use DSU
|
||
|
|
||
|
### Installation
|
||
|
|
||
|
The Disable Stale Users tooling will be shipped with a new version of the
|
||
|
FreeIPA server package so it will be included in default installs.
|
||
|
|
||
|
### Configuration
|
||
|
|
||
|
#### Environments with mandatory, periodic password changes
|
||
|
|
||
|
|
||
|
The following attributes are added to the schema.
|
||
|
```
|
||
|
ipaConfigString: DSU:EnablePasswordBasedDSU
|
||
|
PasswordBasedDSUGracePeriod: 604800
|
||
|
DSUIgnoreGroups: admins
|
||
|
DSUVerbosity: 1
|
||
|
```
|
||
|
Adding DSU:EnablePasswordBasedDSU to the cn=ipaconfig schema will let
|
||
|
DSU disable accounts after a grace period defined in
|
||
|
PasswordBasedDSUGracePeriod (by default 604800 seconds).
|
||
|
This is the time delta after password expiry date on which to disable accounts.
|
||
|
|
||
|
The DSU:IgnoreGroups is multi-valued. Users belonging directly or
|
||
|
indirectly to these groups will not be affected.
|
||
|
|
||
|
DSUVerbosity's default value is "1".
|
||
|
A value of "1" makes the DSU tool log actions to systemd.
|
||
|
A value of "0" disables logging.
|
||
|
Other values are ignored and treated like "1".
|
||
|
|
||
|
|
||
|
#### Environments with no mandatory password changes
|
||
|
|
||
|
The following attributes are added to the schema:
|
||
|
```
|
||
|
ipaConfigString: DSU:EnableTimeStampBasedDSU
|
||
|
TimeStampBasedDSUInactivePeriod: 7776000
|
||
|
DSUIgnoreGroups: admins
|
||
|
DSUVerbosity: 1
|
||
|
```
|
||
|
|
||
|
Adding DSU:EnableTimeStampBasedDSU to the cn=ipaconfig schema will let
|
||
|
DSU disable accounts when the account's coarseSuccessfulAuthTime is more
|
||
|
than TimeStampBasedDSUInactivePeriod in the past.
|
||
|
|
||
|
The other variables behave the same way as the password-based-dsu case.
|
||
|
|
||
|
|
||
|
### Usage
|
||
|
|
||
|
The DSU tool is not a UNIX daemon. It is a CLI tool that can be triggered
|
||
|
by a systemd timer.
|
||
|
|
||
|
Running ``ipa-dsu`` is enough to start the tool. If DSU is enabled (see above),
|
||
|
it will disable stale accounts appopriately.
|
||
|
|
||
|
The dry-run mode ``ipa-dsu --dry-run`` does not disable/lock accounts in any
|
||
|
way. Rather, it shows what would be done, essentially acting as a verbose mode
|
||
|
with "disable_accounts" set to False. The output is JSON.
|
||
|
|
||
|
There is no verbose mode combined with disable_accounts set to True. The tool
|
||
|
logs what it does and the reason for each account disabling action into
|
||
|
journald if DSUVerbosity is set to 1.
|
||
|
|
||
|
|
||
|
### Activation
|
||
|
|
||
|
Activate the DSU tool to run every night using the provided systemd timer:
|
||
|
``systemctl enable ipa-dsu.timer``
|
||
|
|
||
|
|
||
|
### Logs
|
||
|
|
||
|
The DSU tool logs each action in journald. Sample output:
|
||
|
```
|
||
|
ipa-dsu: disabled account uid=alice,cn=users,cn=accounts,dc=example,dc=com - password expired on 20191001.
|
||
|
```
|
||
|
```
|
||
|
ipa-dsu: disabled account uid=bob,cn=users,cn=accounts,dc=example,dc=com - user not seen since 20190701.
|
||
|
```
|
||
|
|
||
|
## Proposed Enhancements to DSU
|
||
|
|
||
|
DSU could reset passwords of locked-out accounts to a random, long string
|
||
|
after a second grace period.
|
||
|
|
||
|
DSU could offer a way for admins to display which account(s) would be
|
||
|
disabled past a certain date using a CLI knob that would modify --dry-run.
|
||
|
|
||
|
The DSU-mandated modifications to ipa-kdb and ipa-lockout described in
|
||
|
"Environments with no mandatory password changes" could also update the
|
||
|
timestamp attribute on password changes. That way, the DSU logic could be
|
||
|
switched to being logon timestamp-based only.
|
||
|
|