Whitespace fixes covering the whole document.

Translators can ignore them.
This commit is contained in:
Benedict Reuschling 2014-05-26 17:43:18 +00:00
parent 2d07b07efe
commit 802ecf1845
Notes: svn2git 2020-12-08 03:00:23 +00:00
svn path=/head/; revision=44962

View file

@ -1,14 +1,24 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE article PUBLIC "-//FreeBSD//DTD DocBook XML V5.0-Based Extension//EN"
"http://www.FreeBSD.org/XML/share/xml/freebsd50.dtd">
<article xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" xml:lang="en">
<info><title>LDAP Authentication</title>
<article xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:lang="en">
<info>
<title>LDAP Authentication</title>
<authorgroup>
<author><personname><firstname>Toby</firstname><surname>Burress</surname></personname><affiliation>
<address><email>kurin@causa-sui.net</email></address>
</affiliation></author>
<author>
<personname>
<firstname>Toby</firstname>
<surname>Burress</surname>
</personname>
<affiliation>
<address>
<email>kurin@causa-sui.net</email>
</address>
</affiliation>
</author>
</authorgroup>
<copyright>
@ -28,10 +38,11 @@
<abstract>
<para>This document is intended as a guide for the configuration
of an LDAP server (principally an <application>OpenLDAP</application>
server) for authentication on &os;. This is useful for situations
where many servers need the same user accounts, for example as a
replacement for <application>NIS</application>.</para>
of an LDAP server (principally an
<application>OpenLDAP</application> server) for authentication
on &os;. This is useful for situations where many servers
need the same user accounts, for example as a replacement for
<application>NIS</application>.</para>
</abstract>
</info>
@ -39,65 +50,73 @@
<title>Preface</title>
<para>This document is intended to give the reader enough of an
understanding of LDAP to configure an LDAP server. This document will
attempt to provide an
explanation of <package>net/nss_ldap</package>
and <package>security/pam_ldap</package> for use with
client machines services for use with the LDAP server.</para>
understanding of LDAP to configure an LDAP server. This
document will attempt to provide an explanation of
<package>net/nss_ldap</package> and
<package>security/pam_ldap</package> for use with client
machines services for use with the LDAP server.</para>
<para>When finished, the reader should be able to configure and
deploy a &os; server that can host an LDAP directory, and to
configure and deploy a &os; server which can authenticate against
an LDAP directory.</para>
configure and deploy a &os; server which can authenticate
against an LDAP directory.</para>
<para>This article is not intended to be an exhaustive account of
the security, robustness, or best practice considerations for
configuring LDAP or the other services discussed herein. While the author
takes care to do everything correctly, he does not
address security issues beyond a general scope. This article should be
considered to lay the theoretical groundwork only, and any actual
implementation should be accompanied by careful requirement
analysis.</para>
configuring LDAP or the other services discussed herein. While
the author takes care to do everything correctly, he does not
address security issues beyond a general scope. This article
should be considered to lay the theoretical groundwork only, and
any actual implementation should be accompanied by careful
requirement analysis.</para>
</sect1>
<sect1 xml:id="ldap">
<title>Configuring LDAP</title>
<para>LDAP stands for <quote>Lightweight Directory Access
Protocol</quote> and is a subset of the X.500 Directory Access
Protocol. Its most recent specifications are in <link xlink:href="http://www.ietf.org/rfc/rfc4510.txt">RFC4510</link> and
friends. Essentially it is a database that expects to be read from
more often than it is written to.</para>
Protocol</quote> and is a subset of the X.500 Directory Access
Protocol. Its most recent specifications are in <link
xlink:href="http://www.ietf.org/rfc/rfc4510.txt">RFC4510</link>
and friends. Essentially it is a database that expects to be
read from more often than it is written to.</para>
<para>The LDAP server <link xlink:href="http://www.openldap.org/">OpenLDAP</link> will be used in the
examples in this document; while the principles here should be
generally applicable to many different servers, most of the
concrete administration is
<para>The LDAP server <link
xlink:href="http://www.openldap.org/">OpenLDAP</link> will be
used in the examples in this document; while the principles here
should be generally applicable to many different servers, most
of the concrete administration is
<application>OpenLDAP</application>-specific. There are several
server versions in ports, for example <package>net/openldap24-server</package>. Client servers
will need the corresponding <package>net/openldap24-client</package> libraries.</para>
server versions in ports, for example
<package>net/openldap24-server</package>. Client servers will
need the corresponding <package>net/openldap24-client</package>
libraries.</para>
<para>There are (basically) two areas of the LDAP service which need
configuration. The first is setting up a server to receive
<para>There are (basically) two areas of the LDAP service which
need configuration. The first is setting up a server to receive
connections properly, and the second is adding entries to the
server's directory so that &os; tools know how to interact with it.</para>
server's directory so that &os; tools know how to interact with
it.</para>
<sect2 xml:id="ldap-connect">
<title>Setting Up the Server for Connections</title>
<note>
<para>This section is specific to
<application>OpenLDAP</application>. If you are using another
server, you will need to consult that server's
<application>OpenLDAP</application>. If you are using
another server, you will need to consult that server's
documentation.</para>
</note>
<sect3 xml:id="ldap-connect-install">
<title>Installing <application>OpenLDAP</application></title>
<para>First, install <application>OpenLDAP</application>:</para>
<para>First, install
<application>OpenLDAP</application>:</para>
<example xml:id="oldap-install">
<title>Installing <application>OpenLDAP</application></title>
<title>Installing
<application>OpenLDAP</application></title>
<screen>&prompt.root; <userinput>cd /usr/ports/net/openldap24-server</userinput>
&prompt.root; make install clean</screen>
@ -114,38 +133,39 @@
<para>Next we must configure
<application>OpenLDAP</application>.</para>
<para>You will want to require encryption in your
connections to the LDAP server; otherwise your users' passwords
will be transferred in plain text, which is considered
insecure. The tools we will be using support two very similar kinds
of encryption, SSL and TLS.</para>
<para>You will want to require encryption in your connections
to the LDAP server; otherwise your users' passwords will be
transferred in plain text, which is considered insecure.
The tools we will be using support two very similar kinds of
encryption, SSL and TLS.</para>
<para>TLS stands for <quote>Transportation Layer Security</quote>.
Services that employ TLS tend to connect on the
<emphasis>same</emphasis> ports as the same services without
TLS; thus an SMTP server which supports TLS will listen for
connections on port 25, and an LDAP server will listen on 389.</para>
<para>TLS stands for <quote>Transportation Layer
Security</quote>. Services that employ TLS tend to
connect on the <emphasis>same</emphasis> ports as the same
services without TLS; thus an SMTP server which supports TLS
will listen for connections on port 25, and an LDAP server
will listen on 389.</para>
<para>SSL stands for <quote>Secure Sockets Layer</quote>, and
services that implement SSL do <emphasis>not</emphasis> listen on
the same ports as their non-SSL counterparts. Thus SMTPS listens
on port 465 (not 25), HTTPS listens on 443, and LDAPS on
636.</para>
services that implement SSL do <emphasis>not</emphasis>
listen on the same ports as their non-SSL counterparts.
Thus SMTPS listens on port 465 (not 25), HTTPS listens on
443, and LDAPS on 636.</para>
<para>The reason SSL uses a different port than TLS is because a
TLS connection begins as plain text, and switches to encrypted
traffic after the <literal>STARTTLS</literal> directive. SSL
connections are encrypted from the beginning. Other than that
there are no substantial differences between the two.</para>
<para>The reason SSL uses a different port than TLS is because
a TLS connection begins as plain text, and switches to
encrypted traffic after the <literal>STARTTLS</literal>
directive. SSL connections are encrypted from the
beginning. Other than that there are no substantial
differences between the two.</para>
<note>
<para>We will adjust
<application>OpenLDAP</application> to use TLS, as SSL is
considered deprecated.</para>
<para>We will adjust <application>OpenLDAP</application> to
use TLS, as SSL is considered deprecated.</para>
</note>
<para>Once <application>OpenLDAP</application> is installed via
ports, the following configuration parameters in
<para>Once <application>OpenLDAP</application> is installed
via ports, the following configuration parameters in
<filename>/usr/local/etc/openldap/slapd.conf</filename> will
enable TLS:</para>
@ -158,17 +178,18 @@ TLSCACertificateFile /path/to/your/cacert.crt</programlisting>
<para>Here, <literal>ssf=128</literal> tells
<application>OpenLDAP</application> to require 128-bit
encryption for all connections, both search and update. This
parameter may be configured based on the security needs of your
site, but rarely you need to weaken it, as most LDAP client
libraries support strong encryption.</para>
encryption for all connections, both search and update.
This parameter may be configured based on the security needs
of your site, but rarely you need to weaken it, as most LDAP
client libraries support strong encryption.</para>
<para>The <filename>cert.crt</filename>,
<filename>cert.key</filename>, and
<filename>cacert.crt</filename> files are necessary for clients
to authenticate <emphasis>you</emphasis> as the valid LDAP
server. If you simply want a server that runs, you can create a
self-signed certificate with OpenSSL:</para>
<filename>cacert.crt</filename> files are necessary for
clients to authenticate <emphasis>you</emphasis> as the
valid LDAP server. If you simply want a server that runs,
you can create a self-signed certificate with
OpenSSL:</para>
<example xml:id="genrsa">
<title>Generating an RSA Key</title>
@ -181,16 +202,16 @@ e is 65537 (0x10001)
&prompt.user; <userinput>openssl req -new -key cert.key -out cert.csr</userinput></screen>
</example>
<para>At this point you should be prompted for some values. You
may enter whatever values you like; however, it is important the
<quote>Common Name</quote> value be the fully qualified domain
name of the <application>OpenLDAP</application> server.
In our case, and the examples here, the server is
<replaceable>server.example.org</replaceable>.
Incorrectly setting this value will cause clients to fail when
making connections. This can the
cause of great frustration, so ensure that you follow these
steps closely.</para>
<para>At this point you should be prompted for some values.
You may enter whatever values you like; however, it is
important the <quote>Common Name</quote> value be the fully
qualified domain name of the
<application>OpenLDAP</application> server. In our case,
and the examples here, the server is
<replaceable>server.example.org</replaceable>. Incorrectly
setting this value will cause clients to fail when making
connections. This can the cause of great frustration, so
ensure that you follow these steps closely.</para>
<para>Finally, the certificate signing request needs to be
signed:</para>
@ -207,11 +228,12 @@ Getting Private key</screen>
<para>This will create a self-signed certificate that can be
used for the directives in <filename>slapd.conf</filename>,
where <filename>cert.crt</filename> and
<filename>cacert.crt</filename> are the same file. If you are
going to use many <application>OpenLDAP</application> servers
(for replication via <literal>slurpd</literal>) you will want to
see <xref linkend="ssl-ca"/> to generate a CA key and use it to
sign individual server certificates.</para>
<filename>cacert.crt</filename> are the same file. If you
are going to use many <application>OpenLDAP</application>
servers (for replication via <literal>slurpd</literal>) you
will want to see <xref linkend="ssl-ca"/> to generate a CA
key and use it to sign individual server
certificates.</para>
<para>Once this is done, put the following in
<filename>/etc/rc.conf</filename>:</para>
@ -230,16 +252,18 @@ ldap slapd 3261 7 tcp4 *:389 *:*</screen>
<sect3 xml:id="ldap-connect-client">
<title>Configuring the Client</title>
<para>Install the <package>net/openldap24-client</package> port for the
<application>OpenLDAP</application> libraries. The client
machines will always have <application>OpenLDAP</application>
libraries since that is all <package>security/pam_ldap</package> and <package>net/nss_ldap</package> support, at least for the
<para>Install the <package>net/openldap24-client</package>
port for the <application>OpenLDAP</application> libraries.
The client machines will always have
<application>OpenLDAP</application> libraries since that is
all <package>security/pam_ldap</package> and
<package>net/nss_ldap</package> support, at least for the
moment.</para>
<para>The configuration file for the
<application>OpenLDAP</application> libraries is
<filename>/usr/local/etc/openldap/ldap.conf</filename>. Edit
this file to contain the following values:</para>
<filename>/usr/local/etc/openldap/ldap.conf</filename>.
Edit this file to contain the following values:</para>
<programlisting>base dc=example,dc=org
uri ldap://server.example.org/
@ -248,17 +272,17 @@ tls_cacert /path/to/your/cacert.crt</programlisting>
<note>
<para>It is important that your clients have access to
<filename>cacert.crt</filename>, otherwise they will not be
able to connect.</para>
<filename>cacert.crt</filename>, otherwise they will not
be able to connect.</para>
</note>
<note>
<para>There are two files called
<filename>ldap.conf</filename>. The first is this file, which
is for the <application>OpenLDAP</application> libraries and
defines how to talk to the server. The second is
<filename>/usr/local/etc/ldap.conf</filename>, and is for
<application>pam_ldap</application>.</para>
<filename>ldap.conf</filename>. The first is this file,
which is for the <application>OpenLDAP</application>
libraries and defines how to talk to the server. The
second is <filename>/usr/local/etc/ldap.conf</filename>,
and is for <application>pam_ldap</application>.</para>
</note>
<para>At this point you should be able to run
@ -266,8 +290,9 @@ tls_cacert /path/to/your/cacert.crt</programlisting>
<option>-Z</option> means <quote>use TLS</quote>. If you
encounter an error, then something is configured wrong; most
likely it is your certificates. Use &man.openssl.1;'s
<command>s_client</command> and <command>s_server</command> to
ensure you have them configured and signed properly.</para>
<command>s_client</command> and <command>s_server</command>
to ensure you have them configured and signed
properly.</para>
</sect3>
</sect2>
@ -275,22 +300,23 @@ tls_cacert /path/to/your/cacert.crt</programlisting>
<title>Entries in the Database</title>
<para>Authentication against an LDAP directory is generally
accomplished by attempting to bind to the directory as the connecting user.
This is done by establishing a <quote>simple</quote>
bind on the directory with the user name supplied. If there is an
entry with the <literal>uid</literal> equal to the user name and
that entry's <literal>userPassword</literal> attribute matches the
password supplied, then the bind is successful.</para>
accomplished by attempting to bind to the directory as the
connecting user. This is done by establishing a
<quote>simple</quote> bind on the directory with the user name
supplied. If there is an entry with the
<literal>uid</literal> equal to the user name and that entry's
<literal>userPassword</literal> attribute matches the password
supplied, then the bind is successful.</para>
<para>The first thing we have to do is figure out is where in the
directory our users will live.</para>
<para>The first thing we have to do is figure out is where in
the directory our users will live.</para>
<para>The base entry for our database is
<literal>dc=example,dc=org</literal>. The default location for
users that most clients seem to expect is something like
<literal>ou=people,<replaceable>base</replaceable></literal>, so
that is what will be used here. However keep in mind that this is
configurable.</para>
<literal>dc=example,dc=org</literal>. The default location
for users that most clients seem to expect is something like
<literal>ou=people,<replaceable>base</replaceable></literal>,
so that is what will be used here. However keep in mind that
this is configurable.</para>
<para>So the ldif entry for the <literal>people</literal>
organizational unit will look like:</para>
@ -306,17 +332,18 @@ ou: people</programlisting>
<para>Some thought might be given to the object class your users
will belong to. Most tools by default will use
<literal>people</literal>, which is fine if you simply want to
provide entries against which to authenticate. However, if you
are going to store user information in the LDAP database as well,
you will probably want to use <literal>inetOrgPerson</literal>,
which has many useful attributes. In either case, the relevant
schemas need to be loaded in
<filename>slapd.conf</filename>.</para>
provide entries against which to authenticate. However, if
you are going to store user information in the LDAP database
as well, you will probably want to use
<literal>inetOrgPerson</literal>, which has many useful
attributes. In either case, the relevant schemas need to be
loaded in <filename>slapd.conf</filename>.</para>
<para>For this example we will use the <literal>person</literal>
object class. If you are using <literal>inetOrgPerson</literal>,
the steps are basically identical, except that the
<literal>sn</literal> attribute is required.</para>
object class. If you are using
<literal>inetOrgPerson</literal>, the steps are basically
identical, except that the <literal>sn</literal> attribute is
required.</para>
<para>To add a user <literal>testuser</literal>, the ldif would
be:</para>
@ -333,9 +360,9 @@ loginShell: /bin/csh
uid: tuser
cn: tuser</programlisting>
<para>I start my LDAP users' UIDs at 10000 to avoid collisions with
system accounts; you can configure whatever number you wish here,
as long as it is less than 65536.</para>
<para>I start my LDAP users' UIDs at 10000 to avoid collisions
with system accounts; you can configure whatever number you
wish here, as long as it is less than 65536.</para>
<para>We also need group entries. They are as configurable as
user entries, but we will use the defaults below:</para>
@ -352,13 +379,14 @@ gidNumber: 10000
cn: tuser</programlisting>
<para>To enter these into your database, you can use
<command>slapadd</command> or <command>ldapadd</command>
on a file containing these entries. Alternatively, you can use
<command>slapadd</command> or <command>ldapadd</command> on a
file containing these entries. Alternatively, you can use
<package>sysutils/ldapvi</package>.</para>
<para>The <command>ldapsearch</command> utility on the client machine
should now return these entries. If it does, your database is
properly configured to be used as an LDAP authentication server.</para>
<para>The <command>ldapsearch</command> utility on the client
machine should now return these entries. If it does, your
database is properly configured to be used as an LDAP
authentication server.</para>
</sect2>
</sect1>
@ -366,27 +394,29 @@ cn: tuser</programlisting>
<title>Client Configuration</title>
<para>The client should already have
<application>OpenLDAP</application> libraries from <xref linkend="ldap-connect-client"/>, but if you are installing several
client machines you will need to install <package>net/openldap24-client</package> on each of
them.</para>
<application>OpenLDAP</application> libraries from <xref
linkend="ldap-connect-client"/>, but if you are installing
several client machines you will need to install
<package>net/openldap24-client</package> on each of them.</para>
<para>&os; requires two ports to be installed to authenticate
against an LDAP server, <package>security/pam_ldap</package> and <package>net/nss_ldap</package>.</para>
against an LDAP server, <package>security/pam_ldap</package> and
<package>net/nss_ldap</package>.</para>
<sect2 xml:id="client-auth">
<title>Authentication</title>
<para><package>security/pam_ldap</package> is
configured via <filename>/usr/local/etc/ldap.conf</filename>.</para>
<para><package>security/pam_ldap</package> is configured via
<filename>/usr/local/etc/ldap.conf</filename>.</para>
<note>
<para>This is a <emphasis>different file</emphasis> than the
<application>OpenLDAP</application> library functions'
configuration file,
<filename>/usr/local/etc/openldap/ldap.conf</filename>; however,
it takes many of the same options; in fact it is a superset of
that file. For the rest of this section, references to
<filename>ldap.conf</filename> will mean
<filename>/usr/local/etc/openldap/ldap.conf</filename>;
however, it takes many of the same options; in fact it is a
superset of that file. For the rest of this section,
references to <filename>ldap.conf</filename> will mean
<filename>/usr/local/etc/ldap.conf</filename>.</para>
</note>
@ -394,11 +424,12 @@ cn: tuser</programlisting>
configuration parameters from
<filename>openldap/ldap.conf</filename> to the new
<filename>ldap.conf</filename>. Once this is done, we want to
tell <package>security/pam_ldap</package> what to
look for on the directory server.</para>
tell <package>security/pam_ldap</package> what to look for on
the directory server.</para>
<para>We are identifying our users with the <literal>uid</literal>
attribute. To configure this (though it is the default), set the
<para>We are identifying our users with the
<literal>uid</literal> attribute. To configure this (though
it is the default), set the
<literal>pam_login_attribute</literal> directive in
<filename>ldap.conf</filename>:</para>
@ -408,46 +439,51 @@ cn: tuser</programlisting>
<programlisting>pam_login_attribute uid</programlisting>
</example>
<para>With this set, <package>security/pam_ldap</package> will search the entire
LDAP directory under <literal>base</literal> for the value
<literal>uid=<replaceable>username</replaceable></literal>. If it
finds one and only one entry, it will attempt to bind as that user
with the password it was given. If it binds correctly, then it
will allow access. Otherwise it will fail.</para>
<para>With this set, <package>security/pam_ldap</package> will
search the entire LDAP directory under <literal>base</literal>
for the value
<literal>uid=<replaceable>username</replaceable></literal>.
If it finds one and only one entry, it will attempt to bind as
that user with the password it was given. If it binds
correctly, then it will allow access. Otherwise it will
fail.</para>
<sect3 xml:id="client-auth-pam">
<title>PAM</title>
<para>PAM, which stands for <quote>Pluggable Authentication
Modules</quote>, is the method by which &os; authenticates most
of its sessions. To tell &os; we wish to use an LDAP server, we
will have to add a line to the appropriate PAM file.</para>
Modules</quote>, is the method by which &os; authenticates
most of its sessions. To tell &os; we wish to use an LDAP
server, we will have to add a line to the appropriate PAM
file.</para>
<para>Most of the time the appropriate PAM file is
<filename>/etc/pam.d/sshd</filename>, if you want to use
<application>SSH</application> (remember to set the relevant
options in <filename>/etc/ssh/sshd_config</filename>, otherwise
<application>SSH</application> will not use PAM).</para>
options in <filename>/etc/ssh/sshd_config</filename>,
otherwise <application>SSH</application> will not use
PAM).</para>
<para>To use PAM for authentication, add the line</para>
<programlisting>auth sufficient /usr/local/lib/pam_ldap.so no_warn</programlisting>
<para>Exactly where this line shows up in the file and which
options appear in the fourth column determine the exact behavior
of the authentication mechanism; see &man.pam.d.5;</para>
options appear in the fourth column determine the exact
behavior of the authentication mechanism; see
&man.pam.d.5;</para>
<para>With this configuration you should be able to authenticate
a user against an LDAP directory.
<para>With this configuration you should be able to
authenticate a user against an LDAP directory.
<application>PAM</application> will perform a bind with your
credentials, and if successful will tell
<application>SSH</application> to allow access.</para>
<para>However it is not a good idea to allow
<emphasis>every</emphasis> user in the directory into
<emphasis>every</emphasis> client machine. With the
current configuration, all that a user needs to log into a
machine is an LDAP entry. Fortunately there are a few ways to
<emphasis>every</emphasis> client machine. With the current
configuration, all that a user needs to log into a machine
is an LDAP entry. Fortunately there are a few ways to
restrict user access.</para>
<para><filename>ldap.conf</filename> supports a
@ -458,27 +494,28 @@ cn: tuser</programlisting>
<programlisting>pam_groupdn cn=servername,ou=accessgroups,dc=example,dc=org</programlisting>
<para>in <filename>ldap.conf</filename>, then only members of
that group will be able to log in. There are a few things to
bear in mind, however.</para>
that group will be able to log in. There are a few things
to bear in mind, however.</para>
<para>Members of this group are specified in one or more
<literal>memberUid</literal> attributes, and each attribute must
have the full distinguished name of the member. So
<literal>memberUid: someuser</literal> will not work; it must
be:</para>
<literal>memberUid</literal> attributes, and each attribute
must have the full distinguished name of the member. So
<literal>memberUid: someuser</literal> will not work; it
must be:</para>
<programlisting>memberUid: uid=someuser,ou=people,dc=example,dc=org</programlisting>
<para>Additionally, this directive is not checked in PAM during
authentication, it is checked during account management, so you
will need a second line in your PAM files under
<literal>account</literal>. This will require, in turn,
<emphasis>every</emphasis> user to be listed in the group, which
is not necessarily what we want. To avoid blocking users that
are not in LDAP, you should enable the
<literal>ignore_unknown_user</literal> attribute. Finally, you
should set the <literal>ignore_authinfo_unavail</literal> option
so that you are not locked out of every computer when the LDAP
<para>Additionally, this directive is not checked in PAM
during authentication, it is checked during account
management, so you will need a second line in your PAM files
under <literal>account</literal>. This will require, in
turn, <emphasis>every</emphasis> user to be listed in the
group, which is not necessarily what we want. To avoid
blocking users that are not in LDAP, you should enable the
<literal>ignore_unknown_user</literal> attribute. Finally,
you should set the
<literal>ignore_authinfo_unavail</literal> option so that
you are not locked out of every computer when the LDAP
server is unavailable.</para>
<para>Your <filename>pam.d/sshd</filename> might then end up
@ -499,11 +536,12 @@ account required /usr/local/lib/pam_ldap.so no_warn ignore_a
<note>
<para>Since we are adding these lines specifically to
<filename>pam.d/sshd</filename>, this will only have an effect
on <application>SSH</application> sessions. LDAP users will
be unable to log in at the console. To change this behavior,
examine the other files in <filename>/etc/pam.d</filename> and
modify them accordingly.</para>
<filename>pam.d/sshd</filename>, this will only have an
effect on <application>SSH</application> sessions. LDAP
users will be unable to log in at the console. To change
this behavior, examine the other files in
<filename>/etc/pam.d</filename> and modify them
accordingly.</para>
</note>
</sect3>
</sect2>
@ -512,21 +550,23 @@ account required /usr/local/lib/pam_ldap.so no_warn ignore_a
<title>Name Service Switch</title>
<para><application>NSS</application> is the service that maps
attributes to names. So, for example, if a file is owned by user
<literal>1001</literal>, an application will query
attributes to names. So, for example, if a file is owned by
user <literal>1001</literal>, an application will query
<application>NSS</application> for the name of
<literal>1001</literal>, and it might get <literal>bob</literal>
or <literal>ted</literal> or whatever the user's name is.</para>
<literal>1001</literal>, and it might get
<literal>bob</literal> or <literal>ted</literal> or whatever
the user's name is.</para>
<para>Now that our user information is kept in LDAP, we need to
tell <application>NSS</application> to look there when
queried.</para>
<para>The <package>net/nss_ldap</package> port
does this. It uses the same configuration file as <package>security/pam_ldap</package>, and should not need
any extra parameters once it is installed. Instead, what is left
is simply to edit <filename>/etc/nsswitch.conf</filename> to take
advantage of the directory. Simply replace the following
<para>The <package>net/nss_ldap</package> port does this. It
uses the same configuration file as
<package>security/pam_ldap</package>, and should not need any
extra parameters once it is installed. Instead, what is left
is simply to edit <filename>/etc/nsswitch.conf</filename> to
take advantage of the directory. Simply replace the following
lines:</para>
<programlisting>group: compat
@ -547,12 +587,13 @@ passwd: files ldap</programlisting>
<sect2 xml:id="caveats">
<title>Caveats</title>
<para>Unfortunately, as of the time this was written &os; did not
support changing user passwords with &man.passwd.1;. Because of
this, most administrators are left to implement a solution
themselves. I provide some examples here. Note that if you write
your own password change script, there are some security issues
you should be made aware of; see <xref linkend="security-passwd"/></para>
<para>Unfortunately, as of the time this was written &os; did
not support changing user passwords with &man.passwd.1;.
Because of this, most administrators are left to implement a
solution themselves. I provide some examples here. Note that
if you write your own password change script, there are some
security issues you should be made aware of; see <xref
linkend="security-passwd"/></para>
<example xml:id="chpw-shell">
<title>Shell Script for Changing Passwords</title>
@ -580,17 +621,17 @@ ldappasswd -D uid="$USER",ou=people,dc=example,dc=org \
<para>This script does hardly any error checking, but more
important it is very cavalier about how it stores your
passwords. If you do anything like this, at least adjust
the <literal>security.bsd.see_other_uids</literal>
sysctl value:</para>
the <literal>security.bsd.see_other_uids</literal> sysctl
value:</para>
<screen>&prompt.root; <userinput>sysctl security.bsd.see_other_uids=0</userinput>.</screen>
</caution>
<para>A more flexible (and probably more secure) approach can be
used by writing a custom program, or even a web interface. The
following is part of a <application>Ruby</application> library
that can change LDAP passwords. It sees use both on the command
line, and on the web.</para>
used by writing a custom program, or even a web interface.
The following is part of a <application>Ruby</application>
library that can change LDAP passwords. It sees use both on
the command line, and on the web.</para>
<example xml:id="chpw-ruby">
<title>Ruby Script for Changing Passwords</title>
@ -634,8 +675,9 @@ conn.modify(luser, [replace])]]></programlisting>
</example>
<para>Although not guaranteed to be free of security holes (the
password is kept in memory, for example) this is cleaner and more
flexible than a simple <command>sh</command> script.</para>
password is kept in memory, for example) this is cleaner and
more flexible than a simple <command>sh</command>
script.</para>
</sect2>
</sect1>
@ -658,13 +700,15 @@ conn.modify(luser, [replace])]]></programlisting>
<para>Several attributes in LDAP should be read-only. If left
writable by the user, for example, a user could change his
<literal>uidNumber</literal> attribute to <literal>0</literal> and
get <systemitem class="username">root</systemitem> access!</para>
<literal>uidNumber</literal> attribute to <literal>0</literal>
and get <systemitem class="username">root</systemitem>
access!</para>
<para>To begin with, the <literal>userPassword</literal> attribute
should not be world-readable. By default, anyone who can connect
to the LDAP server can read this attribute. To disable this, put
the following in <filename>slapd.conf</filename>:</para>
<para>To begin with, the <literal>userPassword</literal>
attribute should not be world-readable. By default, anyone
who can connect to the LDAP server can read this attribute.
To disable this, put the following in
<filename>slapd.conf</filename>:</para>
<example xml:id="hide-userpass">
<title>Hide Passwords</title>
@ -681,14 +725,14 @@ access to *
</example>
<para>This will disallow reading of the
<literal>userPassword</literal> attribute, while still allowing
users to change their own passwords.</para>
<literal>userPassword</literal> attribute, while still
allowing users to change their own passwords.</para>
<para>Additionally, you'll want to keep users from changing some
of their own attributes. By default, users can change any
attribute (except for those which the LDAP schemas themselves deny
changes), such as <literal>uidNumber</literal>. To close this
hole, modify the above to</para>
attribute (except for those which the LDAP schemas themselves
deny changes), such as <literal>uidNumber</literal>. To close
this hole, modify the above to</para>
<example xml:id="attrib-readonly">
<title>Read-only Attributes</title>
@ -707,35 +751,38 @@ access to *
by * read</programlisting>
</example>
<para>This will stop users from being able to masquerade as other
users.</para>
<para>This will stop users from being able to masquerade as
other users.</para>
</sect2>
<sect2 xml:id="secure-root">
<title><systemitem class="username">root</systemitem> Account Definition</title>
<title><systemitem class="username">root</systemitem> Account
Definition</title>
<para>Often the <systemitem class="username">root</systemitem> or manager account for
the LDAP service will be defined in the configuration file.
<application>OpenLDAP</application> supports this, for example,
and it works, but it can lead to trouble if
<filename>slapd.conf</filename> is compromised. It may be better
to use this only to bootstrap yourself into LDAP, and then define
a <systemitem class="username">root</systemitem> account there.</para>
<para>Often the <systemitem class="username">root</systemitem>
or manager account for the LDAP service will be defined in the
configuration file. <application>OpenLDAP</application>
supports this, for example, and it works, but it can lead to
trouble if <filename>slapd.conf</filename> is compromised. It
may be better to use this only to bootstrap yourself into
LDAP, and then define a <systemitem
class="username">root</systemitem> account there.</para>
<para>Even better is to define accounts that have limited
permissions, and omit a <systemitem class="username">root</systemitem> account entirely.
For example, users that can add or remove user accounts are added to
one group, but they cannot themselves change the membership of
this group. Such a security policy would help mitigate the effects
of a leaked password.</para>
permissions, and omit a <systemitem
class="username">root</systemitem> account entirely. For
example, users that can add or remove user accounts are added
to one group, but they cannot themselves change the membership
of this group. Such a security policy would help mitigate the
effects of a leaked password.</para>
<sect3 xml:id="manager-acct">
<title>Creating a Management Group</title>
<para>Say you want your IT department to be able to change home
directories for users, but you do not want all of them to be able
to add or remove users. The way to do this is to add a group
for these admins:</para>
<para>Say you want your IT department to be able to change
home directories for users, but you do not want all of them
to be able to add or remove users. The way to do this is to
add a group for these admins:</para>
<example xml:id="manager-acct-dn">
<title>Creating a Management Group</title>
@ -755,21 +802,24 @@ memberUid: uid=user2,ou=people,dc=example,dc=org</programlisting>
<example xml:id="management-acct-acl">
<title>ACLs for a Home Directory Management Group</title>
<programlisting>access to dn.subtree="ou=people,dc=example,dc=org"
<programlisting>access to dn.subtree="ou=people,dc=example,dc=org"
attr=homeDirectory
by dn="cn=homemanagement,dc=example,dc=org"
dnattr=memberUid write</programlisting>
</example>
<para>Now <systemitem class="username">tuser</systemitem> and <systemitem class="username">user2</systemitem>
can change other users' home directories.</para>
<para>Now <systemitem class="username">tuser</systemitem> and
<systemitem class="username">user2</systemitem> can change
other users' home directories.</para>
<para>In this example we have given a subset of administrative
power to certain users without giving them power in other
domains. The idea is that soon no single user account has the
power of a <systemitem class="username">root</systemitem> account, but every power
root had is had by at least one user. The <systemitem class="username">root</systemitem>
account then becomes unnecessary and can be removed.</para>
domains. The idea is that soon no single user account has
the power of a <systemitem
class="username">root</systemitem> account, but every
power root had is had by at least one user. The <systemitem
class="username">root</systemitem> account then becomes
unnecessary and can be removed.</para>
</sect3>
</sect2>
@ -777,14 +827,15 @@ memberUid: uid=user2,ou=people,dc=example,dc=org</programlisting>
<title>Password Storage</title>
<para>By default <application>OpenLDAP</application> will store
the value of the <literal>userPassword</literal> attribute as it
stores any other data: in the clear. Most of the time it is base
64 encoded, which provides enough protection to keep an honest
administrator from knowing your password, but little else.</para>
the value of the <literal>userPassword</literal> attribute as
it stores any other data: in the clear. Most of the time it
is base 64 encoded, which provides enough protection to keep
an honest administrator from knowing your password, but little
else.</para>
<para>It is a good idea, then, to store passwords in a more secure
format, such as SSHA (salted SHA). This is done by whatever
program you use to change users' passwords.</para>
<para>It is a good idea, then, to store passwords in a more
secure format, such as SSHA (salted SHA). This is done by
whatever program you use to change users' passwords.</para>
</sect2>
</sect1>
@ -795,42 +846,43 @@ memberUid: uid=user2,ou=people,dc=example,dc=org</programlisting>
particularly if you have many users and do not want to configure
everything manually.</para>
<para><package>security/pam_mkhomedir</package> is
a PAM module that always succeeds; its purpose is to create home
directories for users which do not have them. If you have dozens of
client servers and hundreds of users, it is much easier to use this
and set up skeleton directories than to prepare every home
<para><package>security/pam_mkhomedir</package> is a PAM module
that always succeeds; its purpose is to create home directories
for users which do not have them. If you have dozens of client
servers and hundreds of users, it is much easier to use this and
set up skeleton directories than to prepare every home
directory.</para>
<para><package>sysutils/cpu</package> is a
&man.pw.8;-like utility that can be used to manage users in the LDAP
directory. You can call it directly, or wrap scripts around it. It
can handle both TLS (with the <option>-x</option> flag) and
SSL (directly).</para>
<para><package>sysutils/cpu</package> is a &man.pw.8;-like utility
that can be used to manage users in the LDAP directory. You can
call it directly, or wrap scripts around it. It can handle both
TLS (with the <option>-x</option> flag) and SSL
(directly).</para>
<para><package>sysutils/ldapvi</package> is a great
utility for editing LDAP values in an LDIF-like syntax. The
directory (or subsection of the directory) is presented in the
editor chosen by the <envar>EDITOR</envar> environment variable.
This makes it easy to enable large-scale changes in the directory
without having to write a custom tool.</para>
<para><package>sysutils/ldapvi</package> is a great utility for
editing LDAP values in an LDIF-like syntax. The directory (or
subsection of the directory) is presented in the editor chosen
by the <envar>EDITOR</envar> environment variable. This makes
it easy to enable large-scale changes in the directory without
having to write a custom tool.</para>
<para><package>security/openssh-portable</package>
has the ability to contact an LDAP server to verify
<application>SSH</application> keys. This is extremely nice if you
have many servers and do not want to copy your public keys across
all of them.</para>
<para><package>security/openssh-portable</package> has the ability
to contact an LDAP server to verify
<application>SSH</application> keys. This is extremely nice if
you have many servers and do not want to copy your public keys
across all of them.</para>
</appendix>
<appendix xml:id="ssl-ca">
<title><application>OpenSSL</application> Certificates for LDAP</title>
<title><application>OpenSSL</application> Certificates for
LDAP</title>
<para>If you are hosting two or more LDAP servers, you will probably
not want to use self-signed certificates, since each client will
have to be configured to work with each certificate. While this is
possible, it is not nearly as simple as creating your own
certificate authority, and signing your servers' certificates with
that.</para>
<para>If you are hosting two or more LDAP servers, you will
probably not want to use self-signed certificates, since each
client will have to be configured to work with each certificate.
While this is possible, it is not nearly as simple as creating
your own certificate authority, and signing your servers'
certificates with that.</para>
<para>The steps here are presented as they are with very little
attempt at explaining what is going on&mdash;further explanation
@ -849,22 +901,23 @@ memberUid: uid=user2,ou=people,dc=example,dc=org</programlisting>
</example>
<para>These will be your root CA key and certificate. You will
probably want to encrypt the key and store it in a cool, dry place;
anyone with access to it can masquerade as one of your LDAP
servers.</para>
probably want to encrypt the key and store it in a cool, dry
place; anyone with access to it can masquerade as one of your
LDAP servers.</para>
<para>Next, using the first two steps above create a key
<filename>ldap-server-one.key</filename> and certificate signing
request <filename>ldap-server-one.csr</filename>. Once you sign the
signing request with <filename>root.key</filename>, you will be able
to use <filename>ldap-server-one.*</filename> on your LDAP
servers.</para>
request <filename>ldap-server-one.csr</filename>. Once you sign
the signing request with <filename>root.key</filename>, you will
be able to use <filename>ldap-server-one.*</filename> on your
LDAP servers.</para>
<note>
<para>Do not forget to use the fully qualified domain name for the
<quote>common name</quote> attribute when generating the
<para>Do not forget to use the fully qualified domain name for
the <quote>common name</quote> attribute when generating the
certificate signing request; otherwise clients will reject a
connection with you, and it can be very tricky to diagnose.</para>
connection with you, and it can be very tricky to
diagnose.</para>
</note>
<para>To sign the key, use <option>-CA</option> and
@ -879,13 +932,13 @@ memberUid: uid=user2,ou=people,dc=example,dc=org</programlisting>
-out ldap-server-one.crt</userinput></screen>
</example>
<para>The resulting file will be the certificate that you can use on
your LDAP servers.</para>
<para>The resulting file will be the certificate that you can use
on your LDAP servers.</para>
<para>Finally, for clients to trust all your servers, distribute
<filename>root.crt</filename> (the <emphasis>certificate</emphasis>,
not the key!) to each client, and specify it in the
<literal>TLSCACertificateFile</literal> directive in
<filename>ldap.conf</filename>.</para>
<filename>root.crt</filename> (the
<emphasis>certificate</emphasis>, not the key!) to each client,
and specify it in the <literal>TLSCACertificateFile</literal>
directive in <filename>ldap.conf</filename>.</para>
</appendix>
</article>