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