docs: Add application passwords design document (#2427)

Related to  #41.

Signed-off-by: Samuel Cabrero <scabrero@suse.de>
Pair-Programmed-With: Firstyear <william@blackhats.net.au>
This commit is contained in:
Samuel Cabrero 2024-02-01 02:18:05 +01:00 committed by GitHub
parent ed2bd846cc
commit 492c3da36c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -0,0 +1,212 @@
# Rationale
Kanidm exists to provide an authentication source for external applications.
These applications need to have standardised ways to integrate with Kanidm to
allow that application to interact and trust Kanidm's authentication results.
For web based applications we offer Oauth2/OIDC. For Linux machines we offer a
Kanidm specific HTTPS channel for identifying users (UNIX integration).
Currently, for applications that don't support other protocols we offer an LDAPS
gateway that allows users to bind using their UNIX password.
However this has the issue that due to how limited Linux authentication is, UNIX
passwords are always single factor. We also don't want the same UNIX credentials
that are used, e.g. for sudo on machines, to be leaked and used for applications
like email.
To improve this we need a way to offer authentication services to applications
that are unable to support anything modern.
Since LDAP is the "lingua franca" of authentication and almost universally
implemented as an authentication for all applications, we can use this to
provide *application specific* password based authentication and remove the
ability to bind with the UNIX password.
# User experience
The administrator configures two applications on their Kanidm instance. One is
"mail" for a generic SMTP+IMAP service. The other is HTTP basic auth to a legacy
web server. Then the administrator configures which users will be able to use
application passwords for each application.
The mail services and web services are configured to point to Kanidm's LDAP
gateway with a customized search base DN.
The users can login to the webui or command line and list what linked
applications exist on their accounts that require application passwords.
The users can then request a new "application password" for the mail server for
their laptop and another one for their phone. They can copy-paste the generated
passwords to their mail clients which uses this password on their behalf.
Similarly, they can request a new application password to access the web server
basic auth.
# Technical Details
## Client
Currently the LDAP basedn is configurable by an admin, or generated from domain.
For example, example.com <http://example.com/> becomes dc=example,dc=com.
Each configured application will define a new naming context, like
app=mail,dc=example,dc=com or app=httpd,dc=example,dc=com
(NOTE: Should this be app=? Some broken clients could try to validate this rdn
and error, so perhaps it should be a standard rdn value like cn?)
The application then uses this app=mail,dc=example,dc=com as their search base
rather than dc=example,dc=com. Within this search base, we show the same content
from dc=example,dc=com.
(NOTE: We could limit this to application only entries via group membership, but
the issue then is when you have a group for allowing access to the application,
but then still need other groups reflected into the subtree. In this case, if we
limited the view to application access only, we wouldn't be displaying the
non-access groups that the application may still rely on. Ultimately, in this
case the application needs to make it's own authorisation decisions to an
extend. Kanidm can limit which users are members of the access allowed group as
only they can bind still as an extra layer of defence)
The application must bind with its api-token if it wishes to read extended user
information. With this, only basic info limited to anonymous rights are granted.
(NOTE: We can't assume these DNs are private - I did consider making these
app=<secret key>,dc=example,dc=com, but client applications may disclose this
basedn in ui elements).
When a user authenticates the binddn of the account is set to
spn=user,app=name,dc=example,dc=com. This difference in base DN triggers Kanidm
to re-route the authentication to the application specific password, rather than
the UNIX one.
## Kanidm
### Application Entries
A new class for applications will be added. Each application will have a single
associated group so only members of this group will be able to bind with the
application password for the associated application.
Creating a new application will not create an associated group automatically. It
will be the administrator who will configure the association after creating the
application and optionally a new group. It will be possible to associate
`idm_all_persons` to an application. Removing an application will not delete the
associated group nor its members.
When users are removed from a group associated to an application all of their
application passwords for the application will be disabled.
Application schema class will supplement service account class to allow
generating tokens for them. These are optional since an anonymous bind to kanidm
and searching under the basedn or application base dn will continue to work.
Application should have a URL reference to help admins identify where the
application may be located or accessed.
(NOTE: Future, it could be good to allow customisable instructions for users on
where to go to use their app password?)
### Accounts
The user may wish to have multiple passwords per application. Each password must
have, at minimum, a label to identify it. For example:
```
MAIL
iphone: abcd...
laptop: bcde...
HTTP
workstation: cdef...
```
Person accounts will need a new `Attribute::ApplicationPassword` that stores a
`ValueSetApplicationPassword`. Each value in the set is a new type to manage these
secrets and their labeling and the references to the applications.
```
struct ApplicationPAssword {
label: String,
password: Password,
}
type ApplicationPasswords = BTreeMap<Uuid, ApplicationPassword>;
^ ^
| |
| +-> Application password
+-> Application password UUID
type ApplicationUuid = Uuid;
struct ValueSetApplicationPassword {
map: Map<ApplicationUuid, ApplicationPasswords>
}
```
Each value in the set is queried by its UUID. This defines the value as
`Value::ApplicationPassword(Uuid, ApplicationPassword)`. The
`ApplicationPassword` type implements `PartialEq` so two application passwords
are equal if their label is equal and they refer to the same application.
The user must be able to delete credentials individually. The generated password
is only displayed once when the user creates it and it is not possible to
recover the clear-text form, only hashed form is stored. It is not allowed to
store duplicated application passwords (same app refer and label).
We do not need temporary locks or holds - users can delete and recreate as
needed.
### Reference integrity
Since application passwords are related to applications, on delete of an
application all entries that have a bound application password should be removed
from user accounts.
### Access controls
The "Application administrators" group will manage the applications, and
applications will allow "managed by" so that they can have delegated
administration.
The "Application user passwords administrators" group will be able to list the
users's application passwords and delete them but only the users will be able
to, additionally to listing and deleting, self-create their own application
passwords.
### LDAP
The bind DN regular expression needs to adjusted to detect and determine the
bind dn if it is related to an application or not. The application bind dn
regular expression will capture the user name, and the application name.
If the session is related to an application we should only accept application
passwords in the bind. The user needs to be a member of the associated
application group. Binds to an application password must be limited by account
validity and expiration.
We need to add a cache of available applications for lookup.
(NOTE: Caching and reload needs more explanation)
An application can bind with its api-token because the application may need to
search LDAP with elevated read permissions.
### kanidm CLI
The `kanidm` command line tool will be extended to satisfy the following
configuration requirements:
* List applications
* Create an application
* Delete an application
* Manage application - group association
* Manage the application api-token
* List application passwords
* Create application password
* Delete application password