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