[BACK]Return to README.LDAP CVS log [TXT][DIR] Up to [local] / src / usr.bin / sudo

Annotation of src/usr.bin/sudo/README.LDAP, Revision 1.4

1.1       millert     1: This file explains how to use the optional LDAP functionality of SUDO to
                      2: store /etc/sudoers information.  This feature is distinct from LDAP passwords.
                      3:
                      4: LDAP philosophy
                      5: ===============
                      6: As times change and servers become cheap, an enterprise can easily have 500+
                      7: UNIX servers.  Using LDAP to synchronize Users, Groups, Hosts, Mounts, and
                      8: others across an enterprise can greatly reduce the administrative overhead.
                      9:
                     10: Sudo in the past has only used a single local configuration file /etc/sudoers.
                     11: Some have attempted to workaround this by synchronizing changes via
                     12: RCS/CVS/RSYNC/RDIST/RCP/SCP and even NFS.  Many have asked for a Hesiod, NIS,
                     13: or LDAP patch for sudo, so here is my attempt at LDAP'izing sudo.
                     14:
1.2       millert    15: For information on OpenLDAP, please see http://www.openldap.org/.
                     16:
1.1       millert    17: Definitions
                     18: ===========
                     19: Many times the word 'Directory' is used in the document to refer to the LDAP
                     20: server, structure and contents.
                     21:
                     22: Many times 'options' are used in this document to refer to sudoer 'defaults'.
                     23: They are one and the same.
                     24:
                     25: Design Features
                     26: ===============
                     27:
                     28:   * Sudo no longer needs to read sudoers in its entirety.  Parsing of
                     29:     /etc/sudoers requires the entire file to be read.  The LDAP feature of sudo
                     30:     uses two (sometimes three) LDAP queries per invocation.  It never reads all
                     31:     the sudoer entries in the LDAP store.  This makes it especially fast and
                     32:     particularly usable in LDAP environments.  The first query is to parse
                     33:     default options (see below).  The second is to match against the username or
                     34:     groups a user belongs to.  (The special ALL tag is matched in this query
                     35:     too.) If no match is made against the username, the third query pulls the
                     36:     entries that match against user netgroups to compare back to the user.
                     37:
                     38:   * Sudo no longer blows up if there is a typo.  Parsing of /etc/sudoers can
                     39:     still blow up when sudo is invoked.  However when using the LDAP feature of
                     40:     sudo, LDAP syntax rules are applied before the data is uploaded into the
                     41:     LDAP server, so proper syntax is always guaranteed!  One can of course still
                     42:     insert a bogus hostname or username, but sudo will not care.
                     43:
                     44:   * Options inside of entries now override global default options.
                     45:     /etc/sudoers allowed for only default options and limited options associated
                     46:     with user/host/command aliases.  The syntax can be difficult for the newbie.
                     47:     The LDAP feature attempts to simplify this and yet still provide maximum
                     48:     flexibility.
                     49:
                     50:     Sudo first looks for an entry called 'cn=default' in the SUDOers container.
                     51:     If found, the multi-valued sudoOption attribute is parsed the same way the
                     52:     global 'Defaults' line in /etc/sudoers is parsed.
                     53:
                     54:     If on the second or third query, a response contains a sudoRole which
                     55:     matches against the user, host, and command, then the matched object is
                     56:     scanned for a additional options to override the top-level defaults.  See
                     57:     the example LDAP content below for more information.
                     58:
                     59:   * Visudo is no longer needed.  Visudo provides locking and syntax checking
                     60:     against the /etc/sudoers file.  Since LDAP updates are atomic, locking is no
                     61:     longer necessary.  Because syntax is checked when the data is inserted into
                     62:     LDAP, the sudoers syntax check becomes unnecessary.
                     63:
                     64:   * Aliases are no longer needed.  User, Host, and Command Aliases were setup
                     65:     to allow simplification and readability of the sudoers files.  Since the
                     66:     LDAP sudoer entry allows multiple values for each of its attributes and
                     67:     since most LDAP browsers are graphical and easy to work with, original
                     68:     aliases are no longer needed.
                     69:
                     70:     If you want to specify lots of users into an entry or want to have similar
                     71:     entries with identical users, then use either groups or user netgroups.
                     72:     Thats what groups and netgroups are for and Sudo handles this well.
                     73:     Alternately, one can just paste them all into the LDAP record.
                     74:
                     75:     If you want to specify lots of hosts into an entry, use netgroups or IP
                     76:     address matches (10.2.3.4/255.255.0.0).  Thats what netgroups are for and
                     77:     Sudo handles this well.  Or just past them all into the LDAP record.
                     78:
                     79:     If you want to specify lots of commands, use directories or wildcards, or
                     80:     just paste them all into LDAP.  That's what it's for.
                     81:
                     82:   * The /etc/sudoers file can be disabled.  Paranoid security administrators
                     83:     can now disallow parsing of any local /etc/sudoers file by an LDAP
                     84:     sudoOption 'ignore_local_sudoers'.  This way all sudoers can be controlled
                     85:     and audited in one place because local entries are not allowed.
                     86:     In fact, if this option is included in the cn=defaults object of LDAP,
                     87:     sudo won't even look for a /etc/sudoers file.
                     88:
                     89:   * The sudo binary compiled with LDAP support should be totally backward
                     90:     compatible and be syntactically and source code equivalent to its non
                     91:     LDAP-enabled build.
                     92:
                     93:
                     94: Build instructions
                     95: ==================
                     96: The most simplest way to build sudo with LDAP support is to include the
1.2       millert    97: '--with-ldap' option.
1.1       millert    98:
1.2       millert    99:   $ ./configure --with-ldap
1.1       millert   100:
1.2       millert   101: If your ldap libraries and headers are in a non-standard place, you will need
                    102: to specify them at configure time.  E.g.
1.1       millert   103:
1.2       millert   104:   $ ./configure --with-ldap=/usr/local/ldapsdk
1.1       millert   105:
1.2       millert   106: Sudo is developed using OpenLDAP.  Other LDAP implementations may
                    107: require adding '-lldif' to SUDO_LIBS in the Makefile.
1.1       millert   108:
1.2       millert   109: Your Mileage may vary.  Please let the sudo workers mailing list
                    110: <sudo-workers@sudo.ws> know what combinations worked best for your
                    111: OS and LDAP Combinations so we can improve sudo.
1.1       millert   112:
                    113: More Build Notes:
                    114: HP-UX 11.23 (gcc3) Galen Johnson <Galen.Johnson@sas.com>
                    115:   CFLAGS="-D__10_10_compat_code" LDFLAGS="-L/opt/ldapux/lib"
                    116:
                    117: Schema Changes
                    118: ==============
1.2       millert   119: Add the appropriate schema to your LDAP server so that it may contain
                    120: sudoers content.
1.1       millert   121:
1.2       millert   122: For OpenLDAP, simply copy schema.OpenLDAP to the schema directory
                    123: (e.g. /etc/openldap/schema) and 'include' it in your slapd.conf and
                    124: restart slapd.  For other LDAP servers, provide this to your LDAP
                    125: Administrator.  Make sure to index the attribute 'sudoUser'.
1.1       millert   126:
1.3       millert   127: For netscape-derived LDAP servers such as SunONE, iPlanet or Fedora
                    128: Directory, use the schema.iPlanet file.
1.1       millert   129:
                    130: Importing /etc/sudoers to LDAP
                    131: ==============================
                    132: Importing is a two step process.
                    133:
                    134: Step 1:
                    135: Ask your LDAP Administrator where to create the ou=SUDOers container.
1.2       millert   136:
                    137: For instance, if using OpenLDAP:
                    138:
                    139:   dn: ou=SUDOers,dc=example,dc=com
                    140:   objectClass: top
                    141:   objectClass: organizationalUnit
                    142:   ou: SUDOers
                    143:
1.1       millert   144: (An example location is shown below).  Then use the provided script to convert
                    145: your sudoers file into LDIF format.  The script will also convert any default
                    146: options.
                    147:
                    148:   # SUDOERS_BASE=ou=SUDOers,dc=example,dc=com
                    149:   # export SUDOERS_BASE
                    150:   # ./sudoers2ldif /etc/sudoers > /tmp/sudoers.ldif
                    151:
                    152: Step 2:
                    153: Import into your directory server.  If you are using OpenLDAP, do the following
                    154: if you are using another directory, provide the LDIF file to your LDAP
                    155: Administrator.  An example is shown below.
                    156:
                    157:   # ldapadd -f /tmp/sudoers.ldif -h ldapserver \
                    158:   > -D cn=Manager,dc=example,dc=com -W -x
                    159:
                    160: Example sudoers Entries in LDAP
                    161: ===============================
                    162: The equivalent of a sudoer in LDAP is a 'sudoRole'.  It contains sudoUser(s),
                    163: sudoHost, sudoCommand and optional sudoOption(s) and sudoRunAs(s).
1.3       millert   164:
                    165: The following example allows users in group wheel to run any
                    166: command on any host through sudo:
                    167:
                    168: dn: cn=%wheel,ou=SUDOers,dc=example,dc=com
                    169: objectClass: top
                    170: objectClass: sudoRole
                    171: cn: %wheel
                    172: sudoUser: %wheel
                    173: sudoHost: ALL
                    174: sudoCommand: ALL
1.1       millert   175:
                    176: Managing LDAP entries
                    177: =====================
                    178: Doing a one-time bulk load of your ldap entries is fine.  However what if you
                    179: need to make minor changes on a daily basis?  It doesn't make sense to delete
                    180: and re-add objects.  (You can, but this is tedious).
                    181:
                    182: I recommend using any of the following LDAP browsers to administer your SUDOers.
                    183:   * GQ - The gentleman's LDAP client - Open Source - I use this a lot on Linux
                    184:     and since it is Schema aware, I don't need to create a sudoRole template.
                    185:        http://biot.com/gq/
                    186:
                    187:   * LDAP Browser/Editor - by Jarek Gawor - I use this a lot on Windows
                    188:     and Solaris.  It runs anywhere in a Java Virtual Machine including
                    189:     web pages.  You have to make a template from an existing sudoRole entry.
                    190:        http://www.iit.edu/~gawojar/ldap
                    191:        http://www.mcs.anl.gov/~gawor/ldap
                    192:        http://ldapmanager.com
                    193:
1.3       millert   194:   * Apache Directory Studio - Open Source - an Eclipse-based LDAP
                    195:     development platform.  Includes an LDAP browser, and LDIF editor,
                    196:     a schema editor and more.
                    197:     http://directory.apache.org/studio
                    198:
                    199:   There are dozens of others, some Open Source, some free, some not.
1.1       millert   200:
                    201:
                    202: Configure your /etc/ldap.conf
                    203: =============================
                    204: The /etc/ldap.conf file is meant to be shared between sudo, pam_ldap, nss_ldap
                    205: and other ldap applications and modules.  IBM Secureway unfortunately uses
                    206: the same filename but has a different syntax.  If you need to rename where
1.3       millert   207: this file is stored, re-run configure with the --with-ldap-conf-file=filename
                    208: option.
1.1       millert   209:
                    210: Make sure you sudoers_base matches exactly with the location you specified
                    211: when you imported the sudoers.  Below is an example /etc/ldap.conf
                    212:
1.4     ! millert   213:   # Either specify one or more URIs or one or more host:port pairs.
        !           214:   # If neither is specified sudo will default to localhost, port 389.
        !           215:   #
1.1       millert   216:   #host          ldapserver
1.4     ! millert   217:   #host          ldapserver1 ldapserver2:390
        !           218:   #
        !           219:   # Default port if host is specified without one, defaults to 389.
1.1       millert   220:   #port          389
                    221:   #
1.4     ! millert   222:   # URI will override the host and port settings.
1.1       millert   223:   uri            ldap://ldapserver
                    224:   #uri            ldaps://secureldapserver
1.4     ! millert   225:   #uri            ldaps://secureldapserver ldap://ldapserver
        !           226:   #
        !           227:   # The amount of time, in seconds, to wait while trying to connect to
        !           228:   # an LDAP server.
        !           229:   bind_timelimit 30
        !           230:   #
        !           231:   # The amount of time, in seconds, to wait while performing an LDAP query.
        !           232:   timelimit 30
1.1       millert   233:   #
                    234:   # must be set or sudo will ignore LDAP
                    235:   sudoers_base   ou=SUDOers,dc=example,dc=com
                    236:   #
                    237:   # verbose sudoers matching from ldap
                    238:   #sudoers_debug 2
                    239:   #
                    240:   # optional proxy credentials
                    241:   #binddn        <who to search as>
                    242:   #bindpw        <password>
1.2       millert   243:   #rootbinddn    <who to search as, uses /etc/ldap.passwd for bindpw>
1.1       millert   244:   #
1.3       millert   245:   # LDAP protocol version, defaults to 3
1.1       millert   246:   #ldap_version 3
                    247:   #
1.3       millert   248:   # Define if you want to use an encrypted LDAP connection.
                    249:   # Typically, you must also set the port to 636 (ldaps).
                    250:   #ssl on
                    251:   #
1.1       millert   252:   # Define if you want to use port 389 and switch to
1.3       millert   253:   # encryption before the bind credentials are sent.
                    254:   # Only supported by LDAP servers that support the start_tls
                    255:   # extension such as OpenLDAP.
1.1       millert   256:   #ssl start_tls
                    257:   #
1.3       millert   258:   # Additional TLS options follow that allow tweaking of the
                    259:   # SSL/TLS connection.  Only supported when using OpenLDAP.
1.1       millert   260:   #
                    261:   #tls_checkpeer yes # verify server SSL certificate
                    262:   #tls_checkpeer no  # ignore server SSL certificate
                    263:   #
                    264:   # If you enable tls_checkpeer, specify either tls_cacertfile
1.3       millert   265:   # or tls_cacertdir.  Only supported when using OpenLDAP.
1.1       millert   266:   #
                    267:   #tls_cacertfile /etc/certs/trusted_signers.pem
                    268:   #tls_cacertdir  /etc/certs
                    269:   #
                    270:   # For systems that don't have /dev/random
                    271:   # use this along with PRNGD or EGD.pl to seed the
                    272:   # random number pool to generate cryptographic session keys.
1.3       millert   273:   # Only supported when using OpenLDAP.
1.1       millert   274:   #
                    275:   #tls_randfile /etc/egd-pool
                    276:   #
                    277:   # You may restrict which ciphers are used.  Consult your SSL
                    278:   # documentation for which options go here.
1.3       millert   279:   # Only supported when using OpenLDAP.
1.1       millert   280:   #
                    281:   #tls_ciphers <cipher-list>
                    282:   #
                    283:   # Sudo can provide a client certificate when communicating to
                    284:   # the LDAP server.
                    285:   # Tips:
                    286:   #   * Enable both lines at the same time.
                    287:   #   * Do not password protect the key file.
                    288:   #   * Ensure the keyfile is only readable by root.
                    289:   #
1.3       millert   290:   # For OpenLDAP:
1.1       millert   291:   #tls_cert /etc/certs/client_cert.pem
                    292:   #tls_key  /etc/certs/client_key.pem
                    293:   #
1.3       millert   294:   # For SunONE or iPlanet LDAP, the file specified by tls_cert may
                    295:   # contain CA certs and/or the client's cert.  If the client's
                    296:   # cert is included, tls_key should be specified as well.
                    297:   # For backward compatibility, sslpath may be used in place of tls_cert.
                    298:   #tls_cert /var/ldap/cert7.db
                    299:   #tls_key /var/ldap/key3.db
1.1       millert   300:
                    301: Debugging your LDAP configuration
                    302: =================================
                    303: Enable debugging if you believe sudo is not parsing LDAP the way you think it
                    304: it should.  A value of 1 shows moderate debugging.  A value of 2 shows the
                    305: results of the matches themselves.  Make sure to set the value back to zero
                    306: so that other users don't get confused by the debugging messages.  This value
                    307: is 'sudoers_debug' in the /etc/ldap.conf.
                    308:
                    309: Parsing Differences between /etc/sudoers and LDAP
                    310: =================================================
                    311: There are some subtle differences in the way sudoers is handled once in LDAP.
                    312: Probably the biggest is that according to the RFC, LDAP's ordering is
                    313: arbitrary and you cannot expect that Attributes & Entries are returned in
                    314: any order.  If there are conflicting command rules on an entry, the negative
                    315: takes precedence.  This is called paranoid behavior (not necessarily the
                    316: most specific match).
                    317:
                    318: Here is an example:
                    319:
                    320:   # /etc/sudoers:
                    321:   # Allow all commands except shell
                    322:   johnny  ALL=(root) ALL,!/bin/sh
                    323:   # Always allows all commands because ALL is matched last
                    324:   puddles ALL=(root) !/bin/sh,ALL
                    325:
                    326:   # LDAP equivalent of Johnny
                    327:   # Allows all commands except shell
                    328:   dn: cn=role1,ou=Sudoers,dc=my-domain,dc=com
                    329:   objectClass: sudoRole
                    330:   objectClass: top
                    331:   cn: role1
                    332:   sudoUser: johnny
                    333:   sudoHost: ALL
                    334:   sudoCommand: ALL
                    335:   sudoCommand: !/bin/sh
                    336:
                    337:   # LDAP equivalent of Puddles
                    338:   # Notice that even though ALL comes last, it still behaves like
                    339:   # role1 since the LDAP code assumes the more paranoid configuration
                    340:   dn: cn=role2,ou=Sudoers,dc=my-domain,dc=com
                    341:   objectClass: sudoRole
                    342:   objectClass: top
                    343:   cn: role2
                    344:   sudoUser: puddles
                    345:   sudoHost: ALL
                    346:   sudoCommand: !/bin/sh
                    347:   sudoCommand: ALL
                    348:
1.2       millert   349: Another difference is that negations on the Host, User or Runas are
1.4     ! millert   350: currently ignorred.  For example, these attributes do not work how
        !           351: they first seem.
1.1       millert   352:
                    353:   # does not match all but joe
                    354:   # rather, does not match anyone
                    355:   sudoUser: !joe
                    356:
                    357:   # does not match all but joe
                    358:   # rather, matches everyone including Joe
                    359:   sudoUser: ALL
                    360:   sudoUser: !joe
                    361:
                    362:   # does not match all but web01
                    363:   # rather, matches all hosts including web01
                    364:   sudoHost: ALL
                    365:   sudoHost: !web01