-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
210 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
--- | ||
title: LDAP | ||
author: | ||
- m1cr0man | ||
tags: | ||
- ldap | ||
- icarus | ||
- daedalus | ||
--- | ||
|
||
# LDAP - `m1cr0man` | ||
|
||
LDAP is our directory service. It stores usernames, passwords, UIDs, quotas, and other user specific info. | ||
|
||
LDAP's structure is different to most other database systems. If you are not familiar with it, I recommend investing some time into looking at how schemas and distinguished names work. | ||
|
||
## Deployment | ||
|
||
- OpenLDAP is deployed with Nix to Daedalus and Icarus | ||
- Daedalus is the master, Icarus is slaved to it and can be used as a read only failover | ||
- `ldap.internal` and `ldap2.internal` are slaved to Daedalus + Icarus respectively | ||
- Both servers store their data in `/var/db/openldap` | ||
- The ldap.secret, which should **ALWAYS** have permissions `400`, and owned by the openldap user, is stored in `/var/secrets`. It is not automatically created and must be copied when setting up new hosts | ||
- `rb-ldap` and `useradm` are wrappers around LDAP that are custom built | ||
|
||
## Redbrick Special Notes | ||
|
||
- The root user password is in the passwordsafe | ||
- The OID for most of the schema is [DCU's](http://www.oid-info.com/cgi-bin/display?oid=1.3.6.1.4.1.9736&submit=Display&action=display) | ||
- The configs that exist for NixOS were mostly ported from our last | ||
LDAP server ([`paphos`](../hardware/paphos.md)) to maintain compatibility | ||
- At the time of writing, LDAP is not configured with TLS | ||
- There are 2 scripts to manage quotas on /storage that run on the server serving NFS (`zfsquota` and `zfsquotaquery`). They are covered under the NFS documentation. | ||
- There's a user in ldap called testing, for testing. The password is in `pwsafe`. | ||
|
||
## Operation | ||
|
||
The `ldap*` suite of commands can be used to manage LDAP. Their man pages are very well documented, but we've provided most common operations below. | ||
|
||
Note that the ldap.secret is a crypted file, and not equal to the actual password you need to run ldap commands. | ||
|
||
### Ldapsearch Recipes | ||
|
||
`ldapsearch` can be used with and without authenticating as root. Without root, some fields (such as the password hash, altmail) will be hidden. | ||
|
||
```bash | ||
# Dump the entire LDAP database in LDIF form, which can be used as a form of backup | ||
ldapsearch -b o=redbrick -xLLL -D cn=root,ou=ldap,o=redbrick -y /path/to/passwd.txt | ||
|
||
# Find a user by name, and print their altmail | ||
ldapsearch -b o=redbrick -xLLL -D cn=root,ou=ldap,o=redbrick -y /path/to/passwd.txt uid=m1cr0man altmail | ||
|
||
# Find quotas for all users edited by m1cr0man | ||
ldapsearch -b o=redbrick -xLLL updatedby=m1cr0man quota | ||
|
||
# Find all member's usernames | ||
ldapsearch -b o=redbrick -xLLL objectClass=member uid | ||
|
||
# Find all expired users. Notice here that you can query by hidden fields, but you can't read them | ||
ldapsearch -b o=redbrick -xLLL 'yearsPaid < 1' uid | ||
``` | ||
|
||
### Ldapmodify Recipes | ||
|
||
You can instead pass a file with `-f` when necessary. | ||
|
||
To test a command add `-n` for no-op mode. | ||
|
||
Changing `updatedby` and `updated` is added to each command as good practise. | ||
|
||
```bash | ||
# Add quota info to a user | ||
ldapmodify -x -D cn=root,ou=ldap,o=redbrick -y /path/to/passwd.txt << EOF | ||
dn: uid=testing,ou=accounts,o=redbrick | ||
changetype: modify | ||
add: quota | ||
quota: 3G | ||
- | ||
replace: updatedby | ||
updatedby: $USER | ||
- | ||
replace: updated | ||
updated: $(date +'%F %X') | ||
EOF | ||
|
||
# Change a user's shell | ||
ldapmodify -x -D cn=root,ou=ldap,o=redbrick -y /path/to/passwd.txt << EOF | ||
dn: uid=testing,ou=accounts,o=redbrick | ||
changetype: modify | ||
replace: loginShell | ||
loginShell: /usr/local/shells/disusered | ||
- | ||
replace: updatedby | ||
updatedby: $USER | ||
- | ||
replace: updated | ||
updated: $(date +'%F %X') | ||
EOF | ||
|
||
# Update yearsPaid | ||
ldapmodify -x -D cn=root,ou=ldap,o=redbrick -y /path/to/passwd.txt << EOF | ||
dn: uid=testing,ou=accounts,o=redbrick | ||
changetype: modify | ||
replace: yearsPaid | ||
yearsPaid: 1 | ||
- | ||
replace: updatedby | ||
updatedby: $USER | ||
- | ||
replace: updated | ||
updated: $(date +'%F %X') | ||
EOF | ||
``` | ||
|
||
### Ldapadd Recipes | ||
|
||
Occasionally you'll need to add people or things to ldap manually, such as a user you're recreating from backups, or a reserved system name such as a new machine. This is where ldapadd comes in. | ||
|
||
```bash | ||
# Create a file to read the new entry from | ||
cat > add.ldif << EOF | ||
dn: uid=redbrick,ou=reserved,o=redbrick | ||
uid: redbrick | ||
description: DNS entry | ||
objectClass: reserved | ||
objectClass: top | ||
EOF | ||
|
||
# Import the ldif | ||
ldapadd -x -D cn=root,ou=ldap,o=redbrick -y /path/to/passwd.txt -f add.ldif | ||
|
||
# Note if you are importing a full ldif onto a new server, use slapadd instead | ||
# Ensure slapd is not running first | ||
slapadd -v -l backup.ldif | ||
``` | ||
|
||
### Other Recipes | ||
|
||
On a yearly basis, the `yearsPaid` fields must be incremented for every users, and last year's newbies need to be not newbies anymore. | ||
|
||
Remember to take off `-n` when you are ready to rock. | ||
|
||
Adding the `updated` and `updatedby` fields from above to these queries would be a good idea. | ||
|
||
```bash | ||
# Decrement yearsPaid | ||
# WARNING NOT IDEMPOTENT, RUN ONCE | ||
ldapsearch -b o=redbrick -xLLL -D cn=root,ou=ldap,o=redbrick -y /path/to/passwd.txt objectClass=member yearsPaid |\ | ||
tee yearsPaid-$(date +'%F').backup.ldif |\ | ||
awk '/yearsPaid/ { print "changetype: modify\nreplace: yearsPaid\nyearsPaid: " $2 - 1 } ! /yearsPaid/ {print $0}' |\ | ||
ldapmodify -x -D cn=root,ou=ldap,o=redbrick -y /path/to/passwd.txt -n | ||
|
||
# De-newbie last year's users | ||
ldapsearch -b o=redbrick -xLLL -D cn=root,ou=ldap,o=redbrick -y /path/to/passwd.txt newbie=TRUE dn |\ | ||
tee newbie-$(date +'%F').backup.ldif |\ | ||
awk '/^dn/ {print $0"\nchangetype: modify\nreplace: newbie\nnewbie: FALSE\n"}' |\ | ||
ldapmodify -x -D cn=root,ou=ldap,o=redbrick -y /path/to/passwd.txt -n | ||
|
||
# Set quotas of users without quotas | ||
ldapsearch -b o=redbrick -xLLL '(&(objectClass=posixAccount)(!(quota=*)))' dn |\ | ||
awk '/^dn/ {print $0"\nchangetype: modify\nadd: quota\nquota: 2G\n"}' |\ | ||
ldapmodify -x -D cn=root,ou=ldap,o=redbrick -y /path/to/passwd.txt -n | ||
``` | ||
|
||
## Troubleshooting | ||
|
||
First off, it's worth calling out that if you are coming here to find help with a client side issue, chances are the DNS rule applies: | ||
|
||
>It's probably not LDAP | ||
With that out of the way, here's some things to check - in order. | ||
|
||
### Check Reachability of LDAP | ||
|
||
Run from the master and also from the problem client. It should return `m1cr0man`'s details. If you get an `invalid credentials` or `object not found` check that the LDAP auth config hasn't changed. If you get a connection error then restart the service. | ||
|
||
```bash | ||
ldapsearch -h ldap.internal -p 389 -xLLL -b o=redbrick uid=m1cr0man | ||
``` | ||
|
||
### Verify LDAP Can Be Written to | ||
|
||
Get the password from the passwordsafe. Run this from the master. | ||
|
||
```bash | ||
ldapmodify -D cn=root,ou=ldap,o=redbrick -x -y filewithpwd.txt << EOF | ||
dn: uid=m1cr0man,ou=accounts,o=redbrick | ||
changetype: modify | ||
replace: quota | ||
quota: 3G | ||
EOF | ||
``` | ||
|
||
Run the command from the first troubleshooting step to verify the value changed. | ||
|
||
If it fails with an auth issue, triple check your password file (it should contain the plain text password). If it fails with a non-auth issue, then check the service logs. | ||
|
||
### Enable Debug Logging | ||
|
||
OpenLDAP produces a nice set of logs when the `loglevel` is _not_ set. | ||
|
||
Remove `loglevel` from `extraConfig` in the Nix config and switch, then run this command to tail the logs: | ||
|
||
```bash | ||
journalctl -fu openldap | ||
``` | ||
|
||
### Re-syncing Secondary LDAP Server(s) | ||
|
||
In the event a secondary server becomes out of sync with the master, it can be synced by stopping the server, deleting its database files, then restarting the server. Do this after ensuring that `config.redbrick.ldapSlaveTo` is set correctly. |