├── 00-master ├── 00-master.sh ├── fail2ban │ └── filter.local ├── ldif │ ├── 01-logging.ldif │ ├── 02-letsencrypt.ldif │ ├── 03-configtls.ldif │ ├── 04-bind_anon.ldif │ ├── 05-set_require.ldif │ ├── 06-memberof_config.ldif │ ├── 07-refint1.ldif │ ├── 08-refint2.ldif │ ├── 09-ppolicy.ldif │ ├── 10-openssh-lpk.ldif │ ├── 11-sudo.ldif │ ├── 12-postfix.ldif │ ├── 20-users_and_groups.ldif │ ├── 21-import_ssh_pubkey.ldif │ ├── 22-system_access.ldif │ ├── 23-sudo_rules.ldif │ ├── 24-clients.ldif │ ├── 40-index.ldif │ └── 50-lower_logging.ldif └── rsyslog │ └── 10-slapd.conf ├── 01-client ├── 01-client_install.sh └── sssd.conf └── README.md /00-master/00-master.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # A shell script to automate importing of LDIFs within this folder 3 | # TODO: Check for dependencies (ldapmodify, ldapadd, etc) 4 | 5 | sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/ppolicy.ldif 6 | sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f ldif/01-logging.ldif 7 | sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f ldif/02-letsencrypt.ldif 8 | sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f ldif/03-configtls.ldif 9 | sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f ldif/04-bind_anon.ldif 10 | sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f ldif/05-set_require.ldif 11 | sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f ldif/06-memberof_config.ldif 12 | sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f ldif/07-refint1.ldif 13 | sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f ldif/08-refint2.ldif 14 | sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f ldif/09-ppolicy.ldif 15 | sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f ldif/10-openssh-lpk.ldif 16 | sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f ldif/11-sudo.ldif 17 | sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f ldif/12-postfix.ldif 18 | sudo ldapadd -x -D cn=admin,dc=example,dc=com -H ldaps://localhost:636 -W -f ldif/20-users_and_groups.ldif 19 | sudo ldapmodify -x -D cn=admin,dc=example,dc=com -H ldaps://localhost:636 -W -f ldif/21-import_ssh_pubkey.ldif 20 | sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f ldif/22-system_access.ldif 21 | sudo ldapadd -x -D cn=admin,dc=example,dc=com -H ldaps://localhost:636 -W -f ldif/23-sudo_rules.ldif 22 | sudo ldapadd -x -D cn=admin,dc=example,dc=com -H ldaps://localhost:636 -W -f ldif/24-clients.ldif 23 | sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f ldif/40-index.ldif 24 | -------------------------------------------------------------------------------- /00-master/fail2ban/filter.local: -------------------------------------------------------------------------------- 1 | # /etc/fail2ban/filter.local 2 | # 3 | # Add the following lines to the above specified file to enble 4 | # fail2ban monitoring of failed logins for slapd 5 | # 6 | [slapd] 7 | enabled = true 8 | port = ldap.ldaps 9 | logpath = /var/log/slapd.log 10 | -------------------------------------------------------------------------------- /00-master/ldif/01-logging.ldif: -------------------------------------------------------------------------------- 1 | # Configure logging on TheShire LDAP 2 | # use with ~$ sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f 01-logging.ldif 3 | # 4 | dn: cn=config 5 | changetype: modify 6 | # 7 | # loglevel [...] 8 | # Specify the level at which debugging statements and operation 9 | # statistics should be syslogged (currently logged to the 10 | # syslogd(8) LOG_LOCAL4 facility). They must be considered 11 | # subsystems rather than increasingly verbose log levels. Some 12 | # messages with higher priority are logged regardless of the 13 | # configured loglevel as soon as any logging is configured. Log 14 | # levels are additive, and available levels are: 15 | # 1 (0x1 trace) trace function calls 16 | # 2 (0x2 packets) debug packet handling 17 | # 4 (0x4 args) heavy trace debugging (function args) 18 | # 8 (0x8 conns) connection management 19 | # 16 (0x10 BER) print out packets sent and received 20 | # 32 (0x20 filter) search filter processing 21 | # 64 (0x40 config) configuration file processing 22 | # 128 (0x80 ACL) access control list processing 23 | # 256 (0x100 stats) connections, LDAP operations, 24 | # results (recommended) 25 | # 512 (0x200 stats2) stats log entries sent 26 | # 1024 (0x400 shell) print communication with shell 27 | # backends 28 | # 2048 (0x800 parse) entry parsing 29 | # 30 | # 16384 (0x4000 sync) LDAPSync replication 31 | # 32768 (0x8000 none) only messages that get logged 32 | # whatever log level is set 33 | # The desired log level can be input as a single integer that 34 | # combines the (ORed) desired levels, both in decimal or in 35 | # hexadecimal notation, as a list of integers (that are ORed 36 | # internally), or as a list of the names that are shown between 37 | # parentheses, such that 38 | # 39 | # loglevel 129 40 | # loglevel 0x81 41 | # loglevel 128 1 42 | # loglevel 0x80 0x1 43 | # loglevel acl trace 44 | # 45 | # are equivalent. The keyword any can be used as a shortcut to 46 | # enable logging at all levels (equivalent to -1). The keyword 47 | # none, or the equivalent integer representation, causes those 48 | # messages that are logged regardless of the configured loglevel 49 | # to be logged. In fact, if loglevel is set to 0, no logging 50 | # occurs, so at least the none level is required to have high 51 | # priority messages logged. 52 | # 53 | # The loglevel defaults to stats. This level should usually also 54 | # be included when using other loglevels, to help analyze the 55 | # logs. 56 | # 57 | replace: olcLogLevel 58 | olcLogLevel: stats 59 | -------------------------------------------------------------------------------- /00-master/ldif/02-letsencrypt.ldif: -------------------------------------------------------------------------------- 1 | # Configure SSL certificates for TheShire LDAP 2 | # use with ~$ sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f 02-letsencrypt.ldif 3 | # 4 | dn: cn=config 5 | # TLSCACertificateFile 6 | # Specifies the file that contains certificates for all of the 7 | # Certificate Authorities that slapd will recognize. The 8 | # certificate for the CA that signed the server certificate must 9 | # be included among these certificates. If the signing CA was not 10 | # a top-level (root) CA, certificates for the entire sequence of 11 | # CA's from the signing CA to the top-level CA should be present. 12 | # Multiple certificates are simply appended to the file; the order 13 | # is not significant. 14 | add: olcTLSCACertificateFile 15 | olcTLSCACertificateFile: /etc/letsencrypt/live/ldap.example.com/fullchain.pem 16 | - 17 | # TLSCertificateFile 18 | # Specifies the file that contains the slapd server certificate. 19 | # 20 | add: olcTLSCertificateFile 21 | olcTLSCertificateFile: /etc/letsencrypt/live/ldap.example.com/cert.pem 22 | - 23 | # TLSCertificateKeyFile 24 | # Specifies the file that contains the slapd server private key 25 | # that matches the certificate stored in the TLSCertificateFile 26 | # file. Currently, the private key must not be protected with a 27 | # password, so it is of critical importance that it is protected 28 | # carefully. 29 | # 30 | add: olcTLSCertificateKeyFile 31 | olcTLSCertificateKeyFile: /etc/letsencrypt/live/ldap.example.com/privkey.pem 32 | - 33 | # TLSCACertificatePath 34 | # Specifies the path of a directory that contains Certificate 35 | # Authority certificates in separate individual files. Usually 36 | # only one of this or the TLSCACertificateFile is used. This 37 | # directive is not supported when using GnuTLS. 38 | # 39 | # Note: This is likely ignored on TheShire LDAP as Ubuntu uses GnuTLS, but 40 | # is included for thoroughness 41 | # 42 | add: olcTLSCACertificatePath 43 | olcTLSCACertificatePath: /usr/share/ca-certificates/mozilla 44 | -------------------------------------------------------------------------------- /00-master/ldif/03-configtls.ldif: -------------------------------------------------------------------------------- 1 | # Configure TLS encryption on TheShire LDAP 2 | # use with ~$ sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f 03-configtls.ldif 3 | # 4 | dn: cn=config 5 | # TLSProtocolMin [.] 6 | # Specifies minimum SSL/TLS protocol version that will be 7 | # negotiated. If the server doesn't support at least that 8 | # version, the SSL handshake will fail. To require TLS 1.x or 9 | # higher, set this option to 3.(x+1), e.g., 10 | # 11 | # TLSProtocolMin 3.2 12 | # 13 | # would require TLS 1.1. Specifying a minimum that is higher than 14 | # that supported by the OpenLDAP implementation will result in it 15 | # requiring the highest level that it does support. This 16 | # directive is ignored with GnuTLS. 17 | # 18 | add: olcTLSProtocolMin 19 | olcTLSProtocolMin: 3.4 20 | - 21 | # Set allowed TLS ciphers 22 | # Per slapd.conf man page: 23 | # TLSCipherSuite 24 | # Permits configuring what ciphers will be accepted and the 25 | # preference order. should be a cipher 26 | # specification for the TLS library in use (OpenSSL, GnuTLS, or 27 | # Mozilla NSS). Example: 28 | # 29 | # OpenSSL: 30 | # TLSCipherSuite HIGH:MEDIUM:+SSLv2 31 | # 32 | # GnuTLS: 33 | # TLSCiphersuite SECURE256:!AES-128-CBC 34 | # 35 | add: olcTLSCipherSuite 36 | olcTLSCipherSuite: SECURE256:!AES-128-CBC 37 | -------------------------------------------------------------------------------- /00-master/ldif/04-bind_anon.ldif: -------------------------------------------------------------------------------- 1 | # Deny Anonymous BIND on TheShire LDAP 2 | # use with ~$ sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f 04-bind_anon.ldif 3 | # 4 | # Following insertion, `ldapsearch` must be provided with the BINDDN password 5 | # Example: ~$ ldapsearch -D cn=admin,dc=... -x -W 6 | # 7 | dn: cn=config 8 | changetype: modify 9 | # disallow 10 | # Specify a set of features (separated by white space) to disallow 11 | # (default none). bind_anon disables acceptance of anonymous bind 12 | # requests. Note that this setting does not prohibit anonymous 13 | # directory access (See "require authc"). bind_simple disables 14 | # simple (bind) authentication. tls_2_anon disables forcing 15 | # session to anonymous status (see also tls_authc) upon StartTLS 16 | # operation receipt. tls_authc disallows the StartTLS operation 17 | # if authenticated (see also tls_2_anon). 18 | # proxy_authz_non_critical disables acceptance of the proxied 19 | # authorization control (RFC4370) when criticality is FALSE. 20 | # dontusecopy_non_critical disables acceptance of the dontUseCopy 21 | # control (a work in progress) when criticality is FALSE. 22 | # 23 | add: olcDisallows 24 | olcDisallows: bind_anon 25 | -------------------------------------------------------------------------------- /00-master/ldif/05-set_require.ldif: -------------------------------------------------------------------------------- 1 | # Set required conditions for TheShire LDAP 2 | # use with ~$ sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f 05-set_require.ldif 3 | # 4 | # require 5 | # Specify a set of conditions (separated by white space) to 6 | # require (default none). The directive may be specified globally 7 | # and/or per-database; databases inherit global conditions, so 8 | # per-database specifications are additive. bind requires bind 9 | # operation prior to directory operations. LDAPv3 requires 10 | # session to be using LDAP version 3. authc requires 11 | # authentication prior to directory operations. SASL requires 12 | # SASL authentication prior to directory operations. strong 13 | # requires strong authentication prior to directory operations. 14 | # The strong keyword allows protected "simple" authentication as 15 | # well as SASL authentication. none may be used to require no 16 | # conditions (useful to clear out globally set conditions within a 17 | # particular database); it must occur first in the list of 18 | # conditions. 19 | # 20 | dn: olcDatabase={-1}frontend,cn=config 21 | add: olcRequires 22 | olcRequires: bind LDAPv3 authc strong 23 | 24 | dn: olcDatabase={1}mdb,cn=config 25 | add: olcRequires 26 | olcRequires: bind LDAPv3 authc strong 27 | 28 | # Note: This LDIF appears to work properly, but creates two entries for 29 | # olcRequires in each of the databases 30 | # ~$ sudo slapcat -b olcDatabase={1}mdb,cn=config |grep olcRequires 31 | -------------------------------------------------------------------------------- /00-master/ldif/06-memberof_config.ldif: -------------------------------------------------------------------------------- 1 | # Load the memberOf module to easily check if a user is member of a given group 2 | # Use with ~$ sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f 06-memberof_config.ldif 3 | # Note: memberOf does not work with groups of type posixGroup, users will have 4 | # to maintain a separate List with groups of type groupOfNames to use memberOf 5 | # 6 | dn: cn=module,cn=config 7 | cn: module 8 | objectClass: olcModuleList 9 | olcModuleLoad: memberof 10 | olcModulePath: /usr/lib/ldap 11 | 12 | dn: olcOverlay={0}memberof,olcDatabase={1}mdb,cn=config 13 | objectClass: olcConfig 14 | objectClass: olcMemberOf 15 | objectClass: olcOverlayConfig 16 | objectClass: top 17 | olcOverlay: memberof 18 | olcMemberOfDangling: ignore 19 | olcMemberOfRefInt: TRUE 20 | olcMemberOfGroupOC: groupOfNames 21 | olcMemberOfMemberAD: member 22 | olcMemberOfMemberOfAD: memberOf 23 | -------------------------------------------------------------------------------- /00-master/ldif/07-refint1.ldif: -------------------------------------------------------------------------------- 1 | # Load the refint module for referential integrity (needed for memberOf) 2 | # Use with ~$ sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f 07-refint1.ldif 3 | # 4 | dn: cn=module{1},cn=config 5 | add: olcmoduleload 6 | olcmoduleload: refint 7 | -------------------------------------------------------------------------------- /00-master/ldif/08-refint2.ldif: -------------------------------------------------------------------------------- 1 | # Load the refint module for referential integrity (needed for memberOf) 2 | # Use with ~$ sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f 08-refint2.ldif 3 | # 4 | dn: olcOverlay={1}refint,olcDatabase={1}mdb,cn=config 5 | objectClass: olcConfig 6 | objectClass: olcOverlayConfig 7 | objectClass: olcRefintConfig 8 | objectClass: top 9 | olcOverlay: {1}refint 10 | olcRefintAttribute: memberof member manager owner 11 | -------------------------------------------------------------------------------- /00-master/ldif/09-ppolicy.ldif: -------------------------------------------------------------------------------- 1 | # Load the the password policy module 2 | # Use with ~$ sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f 09-ppolicy.ldif 3 | # 4 | # 5 | # Intended to halt syslog errors such as: 6 | # slap_global_control: unrecognized control: 1.3.6.1.4.1.42.2.27.8.5.1 7 | # https://www.openldap.org/lists/openldap-software/200606/msg00024.html 8 | 9 | dn: cn=module,cn=config 10 | cn: module 11 | objectClass: olcModuleList 12 | olcModuleLoad: ppolicy 13 | olcModulePath: /usr/lib/ldap 14 | -------------------------------------------------------------------------------- /00-master/ldif/10-openssh-lpk.ldif: -------------------------------------------------------------------------------- 1 | # Add schema for OpenSSH Public Keys to LDAP Server 2 | # Use with ~$ sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f 10-openssh-lpk.ldif 3 | # 4 | dn: cn=openssh-lpk,cn=schema,cn=config 5 | objectClass: olcSchemaConfig 6 | cn: openssh-lpk 7 | olcAttributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' 8 | DESC 'MANDATORY: OpenSSH Public key' 9 | EQUALITY octetStringMatch 10 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) 11 | olcObjectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY 12 | DESC 'MANDATORY: OpenSSH LPK objectclass' 13 | MAY ( sshPublicKey $ uid ) 14 | ) 15 | -------------------------------------------------------------------------------- /00-master/ldif/11-sudo.ldif: -------------------------------------------------------------------------------- 1 | # Add schema for `sudo` permissions to LDAP Server 2 | # Use with ~$ sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f 11-sudo.ldif 3 | # 4 | dn: cn=sudo,cn=schema,cn=config 5 | objectClass: olcSchemaConfig 6 | cn: sudo 7 | olcAttributeTypes: ( 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 ) 8 | olcAttributeTypes: ( 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 ) 9 | olcAttributeTypes: ( 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 ) 10 | olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.4 NAME 'sudoRunAs' DESC 'User(s) impersonated by sudo (deprecated)' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) 11 | olcAttributeTypes: ( 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 ) 12 | olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.6 NAME 'sudoRunAsUser' DESC 'User(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) 13 | olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.7 NAME 'sudoRunAsGroup' DESC 'Group(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) 14 | olcObjectClasses: ( 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 $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ description ) ) 15 | -------------------------------------------------------------------------------- /00-master/ldif/12-postfix.ldif: -------------------------------------------------------------------------------- 1 | # Schema as required by Postfix: http://www.postfix.org/LDAP_README.html 2 | # Use with ~$ sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f 12-postfix.ldif 3 | # Source: https://github.com/credativ/postfix-ldap-schema 4 | # 5 | dn: cn=postfix,cn=schema,cn=config 6 | objectClass: olcSchemaConfig 7 | cn: postfix 8 | olcAttributeTypes: ( 1.3.6.1.4.1.4203.666.1.200 NAME 'mailacceptinggeneralid' DESC 'Postfix mail local address alias attribute' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} ) 9 | olcAttributeTypes: ( 1.3.6.1.4.1.4203.666.1.201 NAME 'maildrop' DESC 'Postfix mail final destination attribute' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} ) 10 | olcObjectClasses: ( 1.3.6.1.4.1.4203.666.1.100 NAME 'postfixUser' DESC 'Postfix mail user class' SUP top AUXILIARY MAY ( mailacceptinggeneralid $ maildrop ) ) 11 | -------------------------------------------------------------------------------- /00-master/ldif/20-users_and_groups.ldif: -------------------------------------------------------------------------------- 1 | # Initial population of LDAP Server 2 | # Use with ~$ ldapadd -x -D cn=admin,dc=... -W -f 20-users_and_groups.ldif 3 | # 4 | # Create an LDAP Suffix for User accounts 5 | dn: ou=People,dc=example,dc=com 6 | objectClass: organizationalUnit 7 | ou: People 8 | 9 | # Create an LDAP Suffix for posixGroup entries 10 | # These will be groups on Linux systems 11 | dn: ou=Groups,dc=example,dc=com 12 | objectClass: organizationalUnit 13 | ou: Groups 14 | 15 | # Create an LDAP Suffix for groupOfNames entires 16 | # These will be used for system access permissions 17 | dn: ou=Lists,dc=example,dc=com 18 | objectClass: organizationalUnit 19 | ou: Lists 20 | 21 | # Create an LDAP Group 'user1' 22 | # Group IDs (GID) will start at 10000 23 | dn: cn=user1,ou=Groups,dc=example,dc=com 24 | objectClass: posixGroup 25 | cn: user1 26 | gidNumber: 10000 27 | description: User One 28 | memberUid: user1 29 | 30 | # Create an LDAP Group `admin` 31 | # Note: This is a posixGroup which will show on Linux Clients as a system group 32 | # It will not support memberOf lookups for access control via SSSD 33 | # Further: gidNumber will start at 15000 to allow each user to have their own 34 | # posixGroup with matching uidNumber and gidNumber 35 | # Even Further: 'user1' is specified as a member of 'admin' and will have 36 | # SUDO access on all Client systems 37 | dn: cn=admin,ou=Groups,dc=example,dc=com 38 | objectClass: posixGroup 39 | cn: admin 40 | gidNumber: 15000 41 | description: Admin Users 42 | memberUid: user1 43 | 44 | # Create an LDAP User `user1` 45 | # User IDs (UID) will start at 10000 46 | dn: uid=user1,ou=People,dc=example,dc=com 47 | objectClass: inetOrgPerson 48 | objectClass: posixAccount 49 | objectClass: shadowAccount 50 | objectClass: postfixUser 51 | uid: user1 52 | sn: One 53 | givenName: User 54 | cn: User One 55 | displayName: User One 56 | uidNumber: 10000 57 | gidNumber: 10000 58 | # Passwords are created using the `slappasswd` utility and can be pasted here 59 | # Execute the following command to create a password 60 | # ~$ slappasswd -H {SSHA} 61 | # Enter password when promted 62 | userPassword: {SSHA}a_bunch_of_characters_from_slappasswd 63 | gecos: User One 64 | loginShell: /bin/bash 65 | homeDirectory: /home/user1 66 | mail: user1@example.com 67 | mailacceptinggeneralid: user1 68 | maildrop: user1 69 | 70 | # Create an LDAP List 'linux' 71 | # Note: This is a groupofNames which will NOT show on Linux Clients 72 | # It WILL support memberOf lookups, and will be used by SSSD for 73 | # controlling Linux Client Access 74 | dn: cn=linux,ou=Lists,dc=example,dc=com 75 | objectClass: groupofNames 76 | cn: linux 77 | description: Linux Users 78 | member: uid=user1,ou=People,dc=example,dc=com 79 | 80 | # Create an LDAP List `git` 81 | # Note: This is a groupofNames which will NOT show on Linux Clients 82 | # It WILL support memberOf lookups, and can be used by other 83 | # supporting Clients such as Gitea or Gogs to control user access 84 | # Further: `user1` is specified as a member and will have access to any service 85 | # configured to use this LDAP List for access 86 | dn: cn=git,ou=Lists,dc=example,dc=com 87 | objectClass: groupOfNames 88 | cn: git 89 | description: git Users 90 | member: uid=user1,ou=People,dc=example,dc=com 91 | 92 | # Create an LDAP List 'admin' 93 | # Note: This is a groupofNames which will NOT show on Linux Clients 94 | # It WILL support memberOf lookups, and can be used by other 95 | # supporting Clients such as Gitea or Gogs to control admin access 96 | # Further: `user1` is specified as a member and will have administrative access 97 | # to any service configured to use this LDAP List for access 98 | dn: cn=admin,ou=Lists,dc=example,dc=com 99 | objectClass: groupOfNames 100 | cn: admin 101 | description: Admin Users 102 | member: uid=user1,ou=People,dc=example,dc=com 103 | -------------------------------------------------------------------------------- /00-master/ldif/21-import_ssh_pubkey.ldif: -------------------------------------------------------------------------------- 1 | # Add SSH key for LDAP User `user1` 2 | # Use with ~$ ldapmodify -x -D "cn=admin,dc=..." -W -f 21-import_ssh_pubkey.ldif 3 | # 4 | dn: uid=user1,ou=People,dc=example,dc=me 5 | changetype: modify 6 | add: objectClass 7 | objectClass: ldapPublicKey 8 | - 9 | add: sshPublicKey 10 | sshPublicKey: ssh-rsa big_ascii_string user1@Client1 11 | - 12 | add: sshPublicKey 13 | sshPublicKey: ssh-rsa another_big_ascii_strong user1@Client2 14 | -------------------------------------------------------------------------------- /00-master/ldif/22-system_access.ldif: -------------------------------------------------------------------------------- 1 | # Set permissions for the Client systems 2 | # use with ~$ sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f 22-system_access.ldif 3 | # 4 | dn: olcDatabase={1}mdb,cn=config 5 | changetype: modify 6 | # allow Clients access to userPassword for POSIX authentication 7 | add: olcAccess 8 | olcAccess: {3}to dn.children="ou=People,dc=example,dc=com" attrs=userPassword 9 | by dn.exact="ou=Clients,dc=example,dc=com" read 10 | -------------------------------------------------------------------------------- /00-master/ldif/23-sudo_rules.ldif: -------------------------------------------------------------------------------- 1 | # Create SUDO rules 2 | # Use with ~$ ldapadd -x -D cn=admin,dc=... -W -f 23-sudo_rules.ldif 3 | # 4 | # Create an LDAP Suffix for SUDO rules 5 | dn: ou=SUDO,dc=example,dc=com 6 | objectClass: top 7 | objectClass: organizationalUnit 8 | ou: SUDO 9 | 10 | # Create a SUDO rule containing default options inherited by all rules 11 | # SUDO Option !requiretty does not require user to be logged into real TTY 12 | dn: cn=defaults,ou=SUDO,dc=example,dc=com 13 | objectClass: sudoRole 14 | cn: defaults 15 | sudoOption: !requiretty 16 | # Allow members of %admin to SUDO without password 17 | # Commented out - not currently used 18 | #sudoOption: !authenticate 19 | 20 | # Allow members of %admin to run ALL commands via SUDO on ALL hosts 21 | dn: cn=%admin,ou=SUDO,dc=example,dc=com 22 | objectClass: sudoRole 23 | cn: %admin 24 | sudoUser: %admin 25 | sudoHost: ALL 26 | sudoCommand: ALL 27 | -------------------------------------------------------------------------------- /00-master/ldif/24-clients.ldif: -------------------------------------------------------------------------------- 1 | # Create unique BindDN and Password for every Client system 2 | # Use with ~$ ldapadd -x -D cn=admin,dc=... -W -f 24-clients.ldif 3 | # 4 | # Create an LDAP Suffix for Client systems 5 | dn: ou=Clients,dc=example,dc=com 6 | objectClass: top 7 | objectClass: organizationalUnit 8 | ou: Clients 9 | 10 | # Create a Client system `ubuntu1` 11 | dn: cn=ubuntu1,ou=Clients,dc=example,dc=com 12 | cn: ubuntu1 13 | objectClass: simpleSecurityObject 14 | objectClass: organizationalRole 15 | userPassword: {SSHA}generate_with_slappasswd 16 | 17 | # Create a Client system 'ubuntu2' 18 | dn: cn=ubuntu2,ou=Clients,dc=example,dc=com 19 | cn: ubuntu2 20 | objectClass: simpleSecurityObject 21 | objectClass: organizationalRole 22 | userPassword: {SSHA}generate_with_slappasswd 23 | -------------------------------------------------------------------------------- /00-master/ldif/40-index.ldif: -------------------------------------------------------------------------------- 1 | # Add an index to the mdb config 2 | # Uesr with ~$ sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f 40-index.ldif 3 | # 4 | ## This file is an attempt to correct syslog errors of the form: 5 | ## <= mdb_equality_candidates: (sudoHost) not indexed 6 | ## <= mdb_inequality_candidates: (modifyTimestamp) not indexed 7 | ## Where sudoHost or modifyTimestamp could be any LDAP attribute 8 | ## 9 | ## Reference: https://github.com/cveda/cveda_databank/issues/1 10 | # 11 | dn: olcDatabase={1}mdb,cn=config 12 | changetype: modify 13 | add: olcDbIndex 14 | olcDbIndex: uniqueMember eq 15 | - 16 | add: olcDbIndex 17 | olcDbIndex: sudoHost eq, sub 18 | - 19 | add: olcDbIndex 20 | olcDbIndex: modifyTimeStamp eq 21 | - 22 | add: olcDbIndex 23 | olcDbIndex: mailacceptinggeneralid eq,sub 24 | - 25 | add: olcDbIndex 26 | olcDbIndex: mail eq,sub 27 | - 28 | add: olcDbIndex 29 | olcDbIndex: memberOf eq 30 | - 31 | add: olcDbIndex 32 | olcDbIndex: uid eq 33 | - 34 | add: olcDbIndex 35 | olcDbIndex: objectClass eq 36 | - 37 | add: olcDbIndex 38 | olcDbIndex: memberUid eq 39 | - 40 | add: olcDbIndex 41 | olcDbIndex: cn eq 42 | - 43 | add: olcDbIndex 44 | olcDbIndex: gidNumber eq 45 | - 46 | add: olcDbIndex 47 | olcDbIndex: uidNumber eq 48 | -------------------------------------------------------------------------------- /00-master/ldif/50-lower_logging.ldif: -------------------------------------------------------------------------------- 1 | # Configure logging on LDAP Server 2 | # use with ~$ sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f 50-lower_logging.ldif 3 | # 4 | dn: cn=config 5 | changetype: modify 6 | # 7 | # loglevel [...] 8 | # Specify the level at which debugging statements and operation 9 | # statistics should be syslogged (currently logged to the 10 | # syslogd(8) LOG_LOCAL4 facility). They must be considered 11 | # subsystems rather than increasingly verbose log levels. Some 12 | # messages with higher priority are logged regardless of the 13 | # configured loglevel as soon as any logging is configured. Log 14 | # levels are additive, and available levels are: 15 | # 1 (0x1 trace) trace function calls 16 | # 2 (0x2 packets) debug packet handling 17 | # 4 (0x4 args) heavy trace debugging (function args) 18 | # 8 (0x8 conns) connection management 19 | # 16 (0x10 BER) print out packets sent and received 20 | # 32 (0x20 filter) search filter processing 21 | # 64 (0x40 config) configuration file processing 22 | # 128 (0x80 ACL) access control list processing 23 | # 256 (0x100 stats) connections, LDAP operations, 24 | # results (recommended) 25 | # 512 (0x200 stats2) stats log entries sent 26 | # 1024 (0x400 shell) print communication with shell 27 | # backends 28 | # 2048 (0x800 parse) entry parsing 29 | # 30 | # 16384 (0x4000 sync) LDAPSync replication 31 | # 32768 (0x8000 none) only messages that get logged 32 | # whatever log level is set 33 | # The desired log level can be input as a single integer that 34 | # combines the (ORed) desired levels, both in decimal or in 35 | # hexadecimal notation, as a list of integers (that are ORed 36 | # internally), or as a list of the names that are shown between 37 | # parentheses, such that 38 | # 39 | # loglevel 129 40 | # loglevel 0x81 41 | # loglevel 128 1 42 | # loglevel 0x80 0x1 43 | # loglevel acl trace 44 | # 45 | # are equivalent. The keyword any can be used as a shortcut to 46 | # enable logging at all levels (equivalent to -1). The keyword 47 | # none, or the equivalent integer representation, causes those 48 | # messages that are logged regardless of the configured loglevel 49 | # to be logged. In fact, if loglevel is set to 0, no logging 50 | # occurs, so at least the none level is required to have high 51 | # priority messages logged. 52 | # 53 | # The loglevel defaults to stats. This level should usually also 54 | # be included when using other loglevels, to help analyze the 55 | # logs. 56 | # 57 | replace: olcLogLevel 58 | olcLogLevel: none 59 | -------------------------------------------------------------------------------- /00-master/rsyslog/10-slapd.conf: -------------------------------------------------------------------------------- 1 | # /etc/rsyslog.d/10-slapd.conf 2 | # Specify an alternate file location for OpenLDAP logging 3 | # 4 | # Create the specified location by executing: 5 | # sudo touch /var/log/slapd.log 6 | # sudo chown root:adm /var/log/slapd.log 7 | # 8 | local4.* /var/log/slapd.log 9 | -------------------------------------------------------------------------------- /01-client/01-client_install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # A shell script to configure system as LDAP Client for authentication 3 | # 4 | sudo apt -y install sssd libpam-sss libnss-sss libsss-sudo 5 | sudo cp sssd.conf /etc/sssd/ 6 | sudo systemctl restart sssd 7 | sudo systemctl restart sshd 8 | sudo pam-auth-update --enable mkhomedir 9 | -------------------------------------------------------------------------------- /01-client/sssd.conf: -------------------------------------------------------------------------------- 1 | # /etc/sssd/sssd.conf 2 | # SSSD settings for EXAMPLE.COM 3 | 4 | [sssd] 5 | config_file_version = 2 6 | reconnection_retries = 3 7 | services = nss, pam, ssh, sudo 8 | domains = example 9 | 10 | [nss] 11 | filter_groups = root 12 | filter_users = root ldap.bind 13 | 14 | [pam] 15 | offline_credentials_expiration = 30 16 | 17 | [sudo] 18 | 19 | [ssh] 20 | 21 | [domain/example] 22 | debug_level = 0 23 | enumerate = true 24 | id_provider = ldap 25 | auth_provider = ldap 26 | cache_credentials = true 27 | ldap_uri = ldaps://ldap.example.com:636 28 | ldap_search_base = ou=People,dc=example,dc=com 29 | ldap_default_bind_dn = cn=clientsystem,ou=Clients,dc=example,dc=com 30 | ldap_default_authtok = client_system_password 31 | ldap_group_search_base = ou=Groups,dc=example,dc=com 32 | ldap_group_member = memberUid 33 | ldap_user_ssh_public_key = sshPublicKey 34 | ldap_tls_reqceret = demand 35 | sudo_provider = ldap 36 | ldap_sudo_search_base = ou=SUDO,dc=example,dc=com 37 | access_provider = ldap 38 | ldap_access_filter = memberOf=cn=linux,ou=Lists,dc=example,dc=com 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EasyLDAP: Easy Configuration of OpenLDAP for Linux User Authentication 2 | 3 | This guide contains scripts and configuration files to **easily**: 4 | 1. Install the [OpenLDAP](https://openldap.org) Server 5 | 2. Encrypt LDAP traffic using [LetsEncrypt](https://letsencrypt.org) Certs 6 | 3. Store SSH keys for each User on the LDAP Server 7 | 4. Manage SUDO rules for each Client System on the LDAP Server 8 | 5. Cache User information on Client Systems to mitigate LDAP Server downtime 9 | 6. Create User Home Directories on first login to each Client System 10 | 11 | This configuration is intended for a small number of Users (< 100) with a 12 | similar number of Groups. It should be extensible beyond that, but has not 13 | been tested. 14 | 15 | All of these capabilities will be accomplished with relatively small memory and 16 | filesystem usage to run on a low-cost hosted virtual machine shared with other 17 | services. 18 | 19 | Management of the LDAP Server can be performed using web-based tools such as 20 | [LDAP Account Manager](https://www.ldap-account-manager.org) or terminal-based 21 | tools such as [LDAPScripts](https://packages.ubuntu.com/bionic/ldapscripts). 22 | 23 | ## Background 24 | 25 | Managing user accounts, SSH keys, and SUDO permissions across multiple Linux 26 | systems is difficult and can be insecure. There are a variety of tools and 27 | services available to address this problem, each with benefits and drawbacks. 28 | 29 | 1. [FreeIPA](https://freeipa.org): The gold standard in user and system 30 | management. While it is robust and highly extensible, it has steep memory 31 | and storage requirements. It also is challenging to configure on some hosting 32 | providers, such as [AWS](https://aws.amazon.com), due to public/private IP 33 | addresses. 34 | 35 | 2. [OpenLDAP](https://openldap.org): An open source implementation of the 36 | Lightweight Directory Access Protocol (LDAP), OpenLDAP is robust and flexible 37 | but is widely seen as difficult to use. Its memory and storage requirements 38 | are well within the capacity of modern compute equipment and services. 39 | 40 | 3. [JumpCloud](https://jumpcloud.com): A Directory-as-a-Service provider, 41 | JumpCloud is free for up to ten (10) User accounts. While it supports LDAP, 42 | it relies on *agent* software to be installed for SUDO rules. The *agent* is 43 | very flexible and easy to install, but does not support ARM-based systems such 44 | as Raspberry Pi. 45 | 46 | 4. [FoxPass](https://foxpass.com): A Directory-as-a-Service provider, FoxPass 47 | is free for a small number of User accounts. It supports LDAP, and has scripts 48 | that make installation incredibly simple and works on many architectures. 49 | Support for SUDO rules costs extra. 50 | 51 | My goal was to have a central Directory for User information that supports **SSH 52 | key management**, **SUDO rules**, and can withstand days of **Server downtime** 53 | without losing access to the Client Systems. It should work over the internet 54 | or within a private network, and require **no custom certificates** between 55 | the Server and Client for encrypted connections. 56 | 57 | With much patience and perseverance, [OpenLDAP](https://openldap.org) can 58 | provide all of these capabilities using only packages available in modern 59 | Linux distributions. All of the scripts and configurations in this guide have 60 | been tested against [Ubuntu](https://ubuntu.org) 18.04, 19.04, and 20.04, 61 | as well as [Debian](https://debian.org) 10. 62 | 63 | ## Systems and Software 64 | 65 | For the purposes of this guide, the LDAP Server can be any **Linux system** 66 | with a **fully qualified domain name** and **accessible on port 636**. 67 | Scripts provided have only been tested on [Ubuntu](https://ubuntu.org) 18.04, 19.04, and 20.04 as well as [Debian](https://debian.org) 10. 68 | 69 | The configuration of OpenLDAP described here has been successfully tested 70 | on an [AWS](https://aws.amazon.com) EC2 instance with a static IP address, as 71 | well as bare metal behind a home firewall with a changing IP address, dynamic 72 | DNS service, and port forwarding. 73 | 74 | ### OpenLDAP 75 | 76 | [OpenLDAP](https://openldap.org) is available in the standard package 77 | repositories of every major Linux distribution. On Ubuntu, the package name 78 | is [slapd](https://packages.ubuntu.com/bionic/slapd). It should be installed 79 | with the package [ldap-utils](https://packages.ubuntu.com/bionic/ldap-utils) 80 | which is required for the scripts in this guide and very useful for managing 81 | the settings and content of the OpenLDAP Server. 82 | 83 | Older documentation for [OpenLDAP](https://openldap.org) (prior to ~2015) will 84 | refer to changing settings via configuration files in `/etc/ldap`. These files 85 | are deprecated in recent versions of OpenLDAP, and almost all settings for 86 | OpenLDAP are contained within the database itself. This guide will demonstrate 87 | the use of ldap-utils such as `ldapadd` and `ldapmodify` to configure and manage 88 | the OpenLDAP server. 89 | 90 | OpenLDAP supports [replication](https://help.ubuntu.com/lts/serverguide/openldap-server.html#openldap-server-replication) 91 | to other Servers for high availability, however that functionality is not used 92 | in this guide. Rather than hosting multiple LDAP Servers, we will cache 93 | credentials on Client Systems to maintain User access even if the LDAP Server 94 | is down for extended periods. 95 | 96 | ### SSSD 97 | 98 | System Security Services Daemon, or [SSSD](https://pagure.io/SSSD/sssd/), is a 99 | set of daemons to manage access to systems through authentication mechanisms 100 | such as LDAP, Kerberos, and FreeIPA. If you decided to use FreeIPA instead of 101 | OpenLDAP to manage User accounts and access controls, you would still use SSSD 102 | on client systems. 103 | 104 | On Ubuntu (and Debian), SSSD is provided by the metapackage 105 | [sssd](https://packages.ubuntu.com/bionic/sssd) and should be installed on 106 | clients along with related packages 107 | [libpam-sss](https://packages.ubuntu.com/bionic/libpam-sss), 108 | [libnss-sss](https://packages.ubuntu.com/bionic/libnss-sss), 109 | and [libsss-sudo](https://packages.ubuntu.com/bionic/libsss-sudo). These 110 | packages provide modules and libraries for 111 | [PAM authentication](https://en.wikipedia.org/wiki/Linux_PAM), name resolution 112 | by [NSS](https://en.wikipedia.org/wiki/Name_Service_Switch), and 113 | [SUDO](https://en.wikipedia.org/wiki/Sudo) to support User login, permissions, 114 | and SUDO rules from the LDAP Server via SSSD. Home Directories for each User 115 | will even be created on their first login to each Client System. 116 | 117 | As previously noted, we will avoid the need to set up a second LDAP Server as 118 | a replica of the first to maintain high availability. SSSD natively supports 119 | [caching](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/sssd-cache-cred) 120 | credentials for when the LDAP Server is unavailable. 121 | 122 | ### Certbot 123 | 124 | Most guides to configuring OpenLDAP rely upon self-signed certificates for 125 | network traffic encryption. [Let'sEncrypt](https://letsencrypt.org) provides 126 | free certificates signed by a trusted Certificate Authority. With the 127 | [certbot](https://packages.ubuntu.com/bionic/certbot) package installed, 128 | OpenLDAP can be configured to use signed encryption certificates from 129 | Let'sEncrypt for SSL connections. 130 | 131 | This guide will show how to configure OpenLDAP to use certificates from 132 | Let'sEncrypt, however configuration of certbot to acquire those certificates is 133 | left to the reader. Instructions are 134 | [available](https://certbot.eff.org/lets-encrypt/ubuntubionic-apache.html) 135 | [for](https://certbot.eff.org/lets-encrypt/ubuntubionic-nginx) 136 | [a](https://certbot.eff.org/lets-encrypt/debianbuster-nginx) 137 | [variety](https://certbot-dns-route53.readthedocs.io/en/stable/) 138 | [of](https://www.digitalocean.com/community/tutorials/how-to-use-certbot-standalone-mode-to-retrieve-let-s-encrypt-ssl-certificates-on-ubuntu-1804) 139 | [methods](https://medium.com/@jeremygale/how-to-set-up-a-free-dynamic-hostname-with-ssl-cert-using-google-domains-58929fdfbb7a). 140 | 141 | Please note that the Let'sEncrypt certificates must be installed on the 142 | OpenLDAP server in `/etc/letsencrypt/live`, and so readers should be careful 143 | if using a Docker container to run 144 | [certbot](https://hub.docker.com/r/certbot/certbot/). 145 | 146 | ### OpenSSH 147 | 148 | It is likely that you already have [OpenSSH](https://www.openssh.com) installed 149 | for remote terminal and file system access to each Linux system. Ideally, you 150 | also use 151 | [public key authentication](https://www.debian.org/devel/passwordlessssh), as it 152 | is far more secure than passwords. 153 | 154 | Versions of OpenSSH distributed with recent Linux distributions, such as the 155 | [openssh-server](https://packages.ubuntu.com/bionic/openssh-server) package for 156 | Ubuntu, have configuration options to retrieve public keys from an LDAP Server 157 | via SSSD. In this guide, we will show how to properly configure OpenSSH to 158 | allow password-less authentication via keys stored in your LDAP Server. 159 | 160 | ## Server Installation 161 | 162 | This guide assumes the reader is decently familiar with Linux system 163 | administration. Certain steps, such as package installation and management, 164 | are particular to Ubuntu (or Debian) distributions. Readers using other 165 | distributions should be able to adapt them easily. Installation requires root 166 | (or SUDO) access to the desired Linux system. The LDAP Server must 167 | be accessible to any Clients on port 636. 168 | 169 | For the purposes of this guide, the base Domain Name will be *example.com*. The 170 | LDAP Server itself will use the hostname *ldap.example.com*. 171 | 172 | ### OpenLDAP 173 | 174 | Ensure hostname is set appropriately: 175 | ``` 176 | sudo hostnamectl set-hostname ldap.example.com 177 | ``` 178 | 179 | Install OpenLDAP and the LDAP Utilities: 180 | ``` 181 | sudo apt install slapd ldap-utils 182 | ``` 183 | 184 | The installation routine will prompt you for an Administrator password. It can 185 | be left blank at this time, as we will immediately reconfigure the *slapd* 186 | installation. 187 | ``` 188 | sudo dpkg-reconfigure slapd 189 | ``` 190 | For each screen of the reconfiguration script, enter the following: 191 | 1. Omit OpenLDAP Server Configuration: **NO** 192 | 2. DNS Domain Name: **example.com** 193 | 3. Organization Name: **example.com** 194 | 4. Administrator Password: **YOUR_ADMIN_PASSWORD** 195 | 5. Confirm Password: **YOUR_ADMIN_PASSWORD_AGAIN** 196 | 6. Database Backend to Use: **MDB** 197 | 7. Do you want the database to be removed with slapd is purged: **NO** 198 | 8. Move old database? **YES** 199 | 200 | **Note:** Configuration of the LDAP Server can be restarted at any time by 201 | repeating the `dpkg-reconfigure slapd` process as shown here. This can be 202 | useful if a mistake is made during the configuration process. 203 | 204 | Edit `/etc/defaults/slapd` to configure *slapd* for SSL/TLS connections. Look 205 | for the line: 206 | ``` 207 | SLAPD_SERVICES="ldap:/// ldapi:///" 208 | ``` 209 | and edit it to include `ldaps:///`. 210 | ``` 211 | SLAPD_SERVICES="ldap:/// ldapi:/// ldaps:///" 212 | ``` 213 | Note: You can also remove the `ldap:///` portion of this configuration if you 214 | want to disable non-encrypted LDAP traffic entirely. 215 | 216 | Restart *slapd* 217 | ``` 218 | sudo systemctl restart slapd 219 | ``` 220 | 221 | ### Let'sEncrypt 222 | 223 | As noted previously, this guide assumes that the reader has configured Certbot 224 | for their particular IP address and DNS provider. Your LDAP Server should 225 | have a folder named *ldap.example.com* in */etc/letsencrypt/live*. 226 | ``` 227 | root@ldap:~# sudo ls -l /etc/letsencrypt/live/ 228 | total 4 229 | drwxr-xr-x 2 root root 4096 Oct 13 14:55 ldap.example.com 230 | ``` 231 | 232 | On Ubuntu (and Debian) systems, the *slapd* process is run by the System User 233 | *openldap*. Because of the permissions on the folder */etc/letsencrypt/live*, 234 | the System User *openldap* is unable to read the Let'sEncrypt certificates 235 | without additional access control settings. Fortunately, modern Linux 236 | distributions also include enhanced access control utilities. 237 | 238 | Ensure that the package [acl](https://packages.ubuntu.com/bionic/acl) is 239 | installed: 240 | ``` 241 | sudo apt install acl 242 | ``` 243 | Now set the access controls for the certificate files we will use for OpenLDAP. 244 | ``` 245 | sudo setfacl -m u:openldap:rx /etc/letsencrypt/live 246 | sudo setfacl -m u:openldap:rx /etc/letsencrypt/archive 247 | sudo setfacl -m u:openldap:r /etc/letsencrypt/live/ldap.example.com/fullchain.pem 248 | sudo setfacl -m u:openldap:r /etc/letsencrypt/live/ldap.example.com/cert.pem 249 | sudo setfacl -m u:openldap:r /etc/letsencrypt/live/ldap.example.com/privkey.pem 250 | ``` 251 | 252 | Since Let'sEncrypt certificates are renewed regularly by Certbot, these 253 | permissions need to be reset following certificate renewal. That can be done 254 | by creating a renewal post-hook in `/etc/letsencrypt/renewal-hooks/post`: 255 | ``` 256 | #!/bin/sh 257 | # 258 | # /etc/letsencrypt/renewal-hooks/post/reload_services_letsencrypt.sh 259 | # 260 | # Reload services that use LetsEncrypt certificates if the certificate is 261 | # renewed by certbot. Only restarts the services if renewal is both 262 | # required and successful. 263 | # 264 | # To add additional services, enter additional lies with the form: 265 | # systemctl reload *service_name* 266 | # or 267 | # systemctl restart *service_name* 268 | # where *service_name* is the name of a service like nginx or dovecot 269 | 270 | # Restore permissions for LDAP server (slapd) to keys and restart 271 | setfacl -m u:openldap:rx /etc/letsencrypt/live 272 | setfacl -m u:openldap:rx /etc/letsencrypt/archive 273 | setfacl -m u:openldap:r /etc/letsencrypt/live/ldap.example.com/fullchain.pem 274 | setfacl -m u:openldap:r /etc/letsencrypt/live/ldap.example.com/cert.pem 275 | setfacl -m u:openldap:r /etc/letsencrypt/live/ldap.example.com/privkey.pem 276 | systemctl restart slapd 277 | ``` 278 | 279 | Ensure that the post-hook script is executable ('chmod a+x'). 280 | 281 | Additionally, if your Linux distribution uses [AppArmor](https://en.wikipedia.org/wiki/AppArmor), 282 | you need to edit `/etc/apparmor.d/local/usr.sbin.slapd` to contain: 283 | ``` 284 | /etc/letsencrypt/live/ldap.example.com r, 285 | /etc/letsencrypt/archive/ldap.example.com r, 286 | /etc/letsencrypt/archive/ldap.example.com/** r, 287 | ``` 288 | 289 | With all of these configurations in place, the Let'sEncrypt certificates should 290 | be accessible to *slapd* on modern Linux distributions. These have been tested 291 | on Ubuntu 18.04, 19.04, 20.04, and Debian 10. 292 | 293 | During a later step we will configure *slapd* to load these certificates for 294 | encryption. If you receive error code 80 at that time, it means that the 295 | certificates are not accessible by *slapd*. 296 | 297 | ## Server Configuration 298 | 299 | Configuration of *slapd* on modern Linux distributions is performed by changing 300 | settings within the database itself. There is a section of the database, 301 | `cn=config`, which exists for *slapd* configuration parameters. Modifications 302 | to the database are made by using the *ldapadd* or *ldapmodify* commands, and 303 | can draw information from *LDIF* files to simplify. 304 | 305 | This guide includes a set of *LDIF* files which, when modified appropriately, 306 | will completely configure *slapd* to support the stated objectives above. 307 | 308 | It is **highly** recommended that the reader creates a **private** repository 309 | of the *LDIF* files that are appropriately modified for their needs. This 310 | includes editing hostnames, User names, details, passwords, and keys, as well 311 | as Client system names and passwords. This will allow for version control 312 | of the modified configuration files tailored to their LDAP Server. 313 | 314 | All of the *LDIF* files needed are contained in [00-master/ldif](00-master/ldif) 315 | and contain comments to explain their function and implementation: 316 | 1. [01-logging](00-master/ldif/01-logging.ldif): Sets the logging level for 317 | OpenLDAP to be fairly verbose, allowing for troubleshooting during configuration. 318 | 2. [02-letsencrypt](00-master/ldif/02-letsencrypt.ldif): Configures *slapd* to 319 | use the LetsEncrypt certificates specified above for encrypted traffic with 320 | Client systems. **This file must be modified in three places to point to the 321 | correct location on the LDAP Server.** (Replace `ldap.example.com` with the 322 | appropriate FQDN). 323 | 3. [03-configtls](00-master/ldif/03-configtls.ldif): Sets the encryption 324 | protocols to be used for traffic with Client systems. 325 | 4. [04-bind_anon](00-master/ldif/04-bind_anon.ldif): Disallows anonymous bind 326 | to the LDAP Server (Clients must have an established password). 327 | 5. [05-set_require](00-master/ldif/05-set_require.ldif): Sets required 328 | conditions for authentication to the LDAP Server. 329 | 6. [06-memberof_config.ldif](00-master/ldif/06-memberof_config.ldif): Loads 330 | the memberOf module to easily check if a user is member of a given group. This 331 | is useful for restricting access to various Client systems. 332 | 7. [07-refint1.ldif](00-master/ldif/07-refint1.ldif): Loads a module to 333 | enable the memberOf functionality. 334 | 8. [08-refint2.ldif](00-master/ldif/08-refint2.ldif): Loads another module 335 | required for memberOf functionality. 336 | 9. [09-ppolicy.ldif](00-master/ldif/09-ppolicy.ldif): Loads another module 337 | required for password policy functionality (avoids syslog errors). 338 | 10. [10-openssh-lpk.ldif](00-master/ldif/10-openssh-lpk.ldif): Loads the 339 | OpenSSH Public Key schema so that keys can be added for Users. 340 | 12. [11-sudo.ldif](00-master/ldif/11-sudo.ldif): Loads the SUDO schema so that 341 | SUDO rules can be managed on the LDAP Server for each User. 342 | 12. [12-postfix.ldif](00-master/ldif/12-postfix.ldif): Loads the schema for 343 | mail routing so that Users can send/receive email. 344 | 13. [20-users_and_groups.ldif](00-master/ldif/20-users_and_groups.ldif): 345 | Populates users and groups for the LDAP Server. **This file must be modified 346 | in MANY places to have the User and Group settings desired by the reader.** The 347 | appropriate modifications should be intuitive from the comments but include 348 | setting the appropriate LDAP domain (*dc=example,dc=com*), User name (*user1*), 349 | and many other settings. 350 | 14. [21-import_ssh_pubkey.ldif](00-master/ldif/21-import_ssh_pubkey.ldif): 351 | Adds SSH Public Keys to the specified User. **This file must be modified in 352 | MANY places to add the reader's SSH Public Keys**. The appropriate modifications 353 | should be intuitive from the comments. 354 | 15. [22-system_access.ldif](00-master/ldif/22-system_access.ldif): Sets LDAP 355 | access permissions so that Client systems can allow User authentication. **This 356 | file must be modified in two places to point to the appropriate LDAP domain.** 357 | Replace the *dc=example,dc=com* as appropriate. 358 | 16. [23-sudo_rules.ldif](00-master/ldif/23-sudo_rules.ldif): Sets the SUDO 359 | rules for Client systems. **This file must be modified in three places to point 360 | to the appropraite LDAP domain.** Replace the *dc=example,dc=com* as 361 | appropriate. 362 | 17. [24-clients.ldif](00-master/ldif/24-clients.ldif): Creates a unique 363 | password for every Client system (so that they can be disabled individually if 364 | needed). **This file must be modified in multiple places.** The appropriate 365 | modiifcations should be intuitive from the examples and comments. 366 | Replace the *dc=example,dc=com* as appropriate. 367 | 18. [40-index.ldif](00-master/ldif/40-index.ldif): Attempts to correct 368 | various system logging errors that complain about missing database indices. 369 | These errors seem to have no impact on system performance, but are easily 370 | corrected. 371 | 18. [50-lower_logging](00-master/ldif/50-lower_logging.ldif): Reduces the 372 | quantity of logs generated once properly configured. 373 | 374 | A [script](00-master/00-master.sh) is provided to automate the incorporation of these database 375 | configuration files. **It must be modified in multiple places to point to the 376 | appropraite LDAP domain.** 377 | 378 | If all of these scripts are maintained in a **private** repository and 379 | configured appropriately, the reader can configure the LDAP Server quickly 380 | by executing `./00-master.sh` from the `00-master` folder of the repository. 381 | 382 | Further, all Users, Groups, and Clients can be maintained in this **private** 383 | repository allowing for rapid reconstitution of the LDAP Server in the event of 384 | system failure. 385 | 386 | ### LDAP Server Logging 387 | 388 | Log events generated by *slapd* can be sent to a dedicated log file if desired. 389 | An *rsyslog* configuration file is [provided](rsyslog/10-slapd.conf) with 390 | comments explaining how to implement. 391 | 392 | Previous versions of this LDAP configuration resulted in repeated log events 393 | regarding lack of database indices. The file 394 | [40-index.ldif](00-master/ldif/40-index.ldif) has been updated 395 | extensively to avoid these. Configuration can be easily seen be executing the 396 | command: 397 | ``` 398 | sudo cat /etc/ldap/slapd.d/cn=config/olcDatabase={1}mdb.ldif 399 | ``` 400 | 401 | This file should not be modified directly. Further updates to indexing should 402 | be made through [40-index.ldif](00-master/ldif/40-index.ldif). 403 | 404 | ### LDAP Server Protection 405 | 406 | If the reader users *fail2ban* to protect against attempted intrusions, it 407 | can be configred to protect the Open LDAP server. Simply add the following 408 | lines to `/etc/fail2ban/filter.local`. 409 | 410 | ``` 411 | [slapd] 412 | enabled = true 413 | port = ldap.ldaps 414 | logpath = /var/log/slapd.log 415 | ``` 416 | 417 | ## Client Installation 418 | 419 | Using LDAP for login authentication requires the installation of some software 420 | that integrates LDAP with 421 | [Linux-PAM (Pluggable Authentication Modules for Linux)](http://www.linux-pam.org). 422 | There are two primary choices for this, [pam-ldap](https://wiki.debian.org/LDAP/PAM) 423 | and [SSSD](https://en.wikipedia.org/wiki/System_Security_Services_Daemon)]. 424 | This guide will focus on *SSSD* as it better integrates remote and local groups 425 | as well as SSH keys. 426 | 427 | On every Client system, install the _sssd_ package and dependencies. 428 | 429 | ``` 430 | sudo apt -y install sssd libpam-sss libnss-sss libsss-sudo sssd-tools 431 | ``` 432 | 433 | ## Client Configuration 434 | 435 | Configuration of your Client Systems to authenticate against the LDAP Server 436 | involves the following steps: 437 | 438 | 1. Enable automatic creation of Home Directories upon a User's first login 439 | 2. Configure OpenSSH to check against Public Keys stored on the LDAP Server 440 | 3. Appropriately configure *SSSD* to connect to your LDAP Server 441 | 442 | ### Home Directories 443 | 444 | On Ubuntu (and Debian) based systems, automatic creation of User Home 445 | Directories can be easily enabled by the command: 446 | 447 | ``` 448 | sudo pam-auth-update --enable mkhomedir 449 | ``` 450 | 451 | For other Linux distributions, methods may vary. Documentation on the PAM 452 | *mkhomedir* module is 453 | [available here](http://www.linux-pam.org/Linux-PAM-html/sag-pam_mkhomedir.html). 454 | 455 | ### Configure OpenSSH 456 | 457 | This guide assumes that the reader already has OpenSSH configured appropriately 458 | (such as disabling password authentication). 459 | 460 | Edit the file `/etc/ssh/sshd_config` and include the following settings: 461 | ``` 462 | AuthorizedKeysCommand /usr/bin/sss_ssh_authorizedkeys 463 | AuthorizedKeysCommandUser root 464 | ``` 465 | Most Linux distributions ship with a default *sshd_config* file that has these 466 | settings commented out. 467 | 468 | Now restart the OpenSSH server: 469 | ``` 470 | sudo systemctl restart sshd 471 | ``` 472 | 473 | ### Configure SSSD 474 | 475 | Before doing this step, ensure that you have root access to the Client System 476 | with a User account that is not shared with accounts you've configured on the 477 | LDAP Server to avoid being locked out by a mis-configuration. 478 | 479 | Edit the file `/etc/sssd/sssd.conf` (it may not yet exist), and enter the 480 | following contents (assuming you've configured the LDAP Server as shown in this 481 | guide). 482 | 483 | ``` 484 | # /etc/sssd/sssd.conf 485 | # SSSD settings for EXAMPLE.COM 486 | 487 | [sssd] 488 | config_file_version = 2 489 | reconnection_retries = 3 490 | # The services line is not needed in Ubuntu 20.04 and causes errors 491 | # Uncomment it for earlier versions 492 | # services = nss, pam, ssh, sudo 493 | domains = example 494 | 495 | [nss] 496 | filter_groups = root 497 | filter_users = root ldap.bind 498 | 499 | [pam] 500 | offline_credentials_expiration = 30 501 | 502 | [sudo] 503 | 504 | [ssh] 505 | 506 | [domain/example] 507 | debug_level = 0 508 | enumerate = true 509 | id_provider = ldap 510 | auth_provider = ldap 511 | cache_credentials = true 512 | ldap_uri = ldaps://ldap.example.com:636 513 | ldap_search_base = ou=People,dc=example,dc=com 514 | ldap_default_bind_dn = cn=clientsystem,ou=Clients,dc=example,dc=com 515 | ldap_default_authtok = client_system_password 516 | ldap_group_search_base = ou=Groups,dc=example,dc=com 517 | ldap_group_member = memberUid 518 | ldap_user_ssh_public_key = sshPublicKey 519 | ldap_tls_reqcert = demand 520 | sudo_provider = ldap 521 | ldap_sudo_search_base = ou=SUDO,dc=example,dc=com 522 | access_provider = ldap 523 | ldap_access_filter = memberOf=cn=linux,ou=Lists,dc=example,dc=com 524 | ``` 525 | 526 | Set permissions appropriately for `/etc/sssd/sssd.conf` 527 | ``` 528 | sudo chmod 600 /etc/sssd/sssd.conf 529 | ``` 530 | 531 | Now restart *SSSD* 532 | ``` 533 | sudo systemctl restart sssd 534 | ``` 535 | 536 | If appropriately configured, Users configured on the LDAP Server should 537 | show with execution of the command `getent passwd` 538 | ``` 539 | ~$ getent passwd 540 | *LOCAL USER INFORMATION* 541 | user1:*:10000:10000:User One:/home/user1:/bin/bash 542 | ``` 543 | --------------------------------------------------------------------------------