guix-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

LDAP authentication + Configuring PAM


From: Ricardo Wurmus
Subject: LDAP authentication + Configuring PAM
Date: Thu, 22 Aug 2019 16:03:24 +0200
User-agent: mu4e 1.2.0; emacs 26.2

Hi Guix,

in the past few days I’ve been playing on and off with configuring a
Guix System where accounts are authenticated against Active Directory
via LDAP.

My findings so far:

* NSCD *must* be extended with caches for “passwd” and “group”
  databases or else applications will make the lookup for user accounts
  directly and will not consult LDAP at all.

* the default PAM rules provided by nslcd-service-type are either
  incomplete or incorrect, because of the many “unix-pam-service”
  defaults.

* as a result awkward PAM configuration is required to make this work.

* it’s a pity that “name-service-switch” is not a system service and has
  to be extended manually.  … Or is this perhaps how we should treat PAM
  configuration as well?

PAM is the mechanism to use if we want to allow applications to
authenticate users that don’t have local accounts.  For local accounts
the “pam_unix.so” authentication module is used, and we say that it is
required for authentication with “unix-pam-service”.

“required” is an important word here, because that’s one of the keywords
for the PAM module stack.  Some terminology:

* there are four resources: “auth” (for authentication of valid
  accounts), “session” (for setting up a user’s session once
  authenticated), “password” (for changing the user’s password), and
  “account” (to determine if a user account is valid).

* there is a file in /etc/pam.d for each application that should use
  PAM, such as “/etc/pam.d/su” for “su”, “/etc/pam.d/sshd” for the SSH
  daemon, etc.

* each of these files specifies a stack of PAM modules that should be
  consulted for each of the four resources.

* each stack is evaluated from top to bottom.

* each module can be “required”, “sufficient”, “optional”, or a
  “requisite”.

The last point is confusing.  Let’s only look at “required” and
“sufficient”.

Here’s a stack for authenticating a user:

  auth required pam_foo.so
  auth sufficient pam_bar.so
  auth sufficient pam_baz.so
  auth required pam_deny.so

Stacks are evaluated top to bottom.  First pam_foo.so is evaluated.  It
is “required” meaning that it must succeed for authentication to be
successful.  If it returns failure the *next module will be evaluated*,
but no matter what happens authentication will *always fail*.  This is
important.

A module that is “sufficient” will be evaluated.  If it fails the next
module will be tried.  If it succeeds, however, no other module in the
stack will be considered.  Authentication will have succeeded.

So in the above stack we need “pam_foo.so” and one of “pam_bar.so” or
“pam_baz.so” to succeed.  If “pam_bar.so” succeeds “pam_baz.so” will not
be considered, nor will “pam_deny.so” be considered.  If both
“pam_bar.so” and “pam_baz.so” fail “pam_deny.so” is evaluated which will
always return failure — so authentication will fail.

As you can see, the order of modules in the stack is of significant
importance.  Even worse, modules can take arguments such as
“try_first_pass” to use the same password that was provided in an
earlier step.  Mixing up the order of modules here could lead to
unexpected, frustrating behaviour.  Debugging this isn’t easy, because
PAM isn’t very chatty even when “debug” is added as an argument to all
modules.

But back to the problem of authenticating users via LDAP.  With our
default unix-pam-service “pam_unix.so” (which checks that a user account
exists locally and checks its password) is required, so LDAP
authentication will always fail.

I extended the pam-root-service-type with a service that matches on all
pam_unix.so modules and makes them use the “sufficient” keyword instead
to overcome this.  This is problematic when nslcd-service-type is
involved because it extends pam-root-service-type to add entries for
pam_ldap.so.  Instead of using a string “pam_ldap.so” it uses a
G-expression to compute the absolute file name of “pam_ldap.so”.  When
extending the service and matching on PAM entries, however, we don’t
have a string of the absolute file name to match on — we have a
G-expression that is really awkward to match against.

I worked around this (by lowering the G-expression first), but it’s
ugly.  And even then I still have the problem that I can’t control the
order of PAM entries at all.

Perhaps we should implement a different mechanism for specifying PAM
entries for the system, perhaps similar to what the name-service-switch
field does?

I also recommend using “sufficient” as the default keyword for
“pam_unix.so” and ending the stack with “required pam_deny.so”.  This
would make it easier to extend the stack without having to rewrite
existing module entries.

What do you think?

--
Ricardo




reply via email to

[Prev in Thread] Current Thread [Next in Thread]