Self Hosted: Episode 6 - Authentication
Software used:
- FreeBSD 14.2 (jail)
- OpenLDAP 2.6 (from ports)
It has been said: "Three people can keep a secret, if two are dead." Fortunately, it doesn't need to come to that.
Authentication
As with many things in computing there needs to be a source of truth. This is true for user accounts. Where we have one account, we will need more. Good, bad, or indifferent, the defacto way of keeping user and group information is using LDAP.
Update DNS with new address
To begin with we will need to be able to resolve the new server. To do this update the example.org and 30.168.192.in-addr.arpa zone files on the DNS servers respectively.
ldap IN A 192.168.30.13
record for example.org zone file
13 IN PTR ldap.example.org.
record for the 30.168.192.in-addr.arpa zone file
Don't forget to update the zone serial number and restart the named service.
Setup LDAP server
Just like with the CA server, the LDAP server will be setup using a jail. If you have not already setup the Jail infrastructure review Episode 3 - Setting up FreeBSD Jail. For this jail we will be using the following file.
# LDAP server jail file
ldap {
# STARTUP / LOGGING
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.consolelog = "/var/log/jail_console_${name}.log";
# PERMISSIONS
allow.raw_sockets;
exec.clean;
mount.devfs;
allow.reserved_ports = true;
# HOSTNAME / PATH
host.hostname = "${name}";
path = "/usr/local/jails/containers/${name}";
# NETWORK
vnet;
vnet.interface = "${epair}b";
# NETWORKS/INTERFACES
$id = "12";
$ip = "192.168.30.${id}";
$mask = "255.255.255.0";
$gateway = "192.168.30.1";
$bridge = "net-dmz";
$epair = "epair${id}";
exec.prestart += "ifconfig ${epair} create up";
exec.prestart += "ifconfig ${epair}a up descr jail:${name}";
exec.prestart += "ifconfig ${bridge} addm ${epair}a up";
exec.start += "ifconfig ${epair}b ${ip} netmask ${mask} up";
exec.start += "route add default ${gateway}";
exec.poststop += "ifconfig ${bridge} deletem ${epair}a";
exec.poststop += "ifconfig ${epair}a destroy";
}
Start the LDAP jail
service jail start ldap
Install the LDAP server packages
pkg -j ldap -y update
pkg -j ldap -y install openldap-server openldap-client
Connect to the new jail
jexec ldap /bin/sh
Edit ldap config file
The LDAP server has a server configuration files called slapd.conf located in the /usr/local/etc/openldap directory. This file consists of several parts defined in the config file. Each part has been commented.
# Import Schemas to support
include /usr/local/etc/openldap/schema/core.schema
include /usr/local/etc/openldap/schema/cosine.schema
include /usr/local/etc/openldap/schema/inetorgperson.schema
include /usr/local/etc/openldap/schema/nis.schema
# specify paths for restarting
pidfile /var/run/openldap/slapd.pid
argsfile /var/run/openldap/slapd.args
# load the DB module for storate
modulepath /usr/local/libexec/openldap
moduleload back_mdb
# Set access controls on different keys
# NOTE: rootdn can always read and write EVERYTHING!
# Access Control
access to attrs=userPassword
by group/groupOfNames/member="ou=services,dc=example,dc=org" read
by self write
by * none
access to attrs=description
by group/groupOfNames/member="ou=services,dc=example,dc=org" read
by self write
by * none
# TLS
TLSCACertificateFile /usr/local/share/certs/example.org_root_ca.pem
TLSCertificateFile /usr/local/etc/ssl/ldap_fullchain.pem
TLSCertificateKeyFile /usr/local/etc/ssl/ldap.key
#TLSVerifyClient never
# enable database config definitions
database config
# configure storage DB settings
database mdb
maxsize 1073741824
suffix "dc=example,dc=org"
rootdn "cn=ldapadmin,dc=example,dc=org"
rootpw change_me_please!
directory /var/db/openldap-data
# Indices to maintain
index objectClass eq
index cn,sn,mail pres,eq,approx,sub
index uid eq
# enable DB monitoring
database monitor
/usr/local/etc/openldap/slapd.conf
Get LDAP certificate
Get a new certificate from the CA for the LDAP server
Add and trust the root cert
test -d /usr/local/share/certs || mkdir -p /usr/local/share/certs
fetch --no-verify-peer --no-verify-hostname -o /usr/local/share/certs/root_ca.crt https://certauth.example.org/roots.pem
certctl rehash
commands to install and trust the CA certificate
Install the acme package
pkg install -y acme.sh
command to install the acme.sh package
Generate the certificate.
export CRTP=/usr/local/etc/ssl
test -f $CRTP || mkdir -p $CRTP
acme.sh --issue --standalone -d $(hostname) --cert-file $CRTP/$(hostname -s).crt --key-file $CRTP/$(hostname -s).key --fullchain-file $CRTP/$(hostname -s)_fullchain.pem --server https://certauth.example.org/acme/acme/directory
commands to generate new certifiate
Start the LDAP server
service openldap start
command to start the ldap server
Forward logs to logging server
Create the /usr/local/etc/syslog.d directory if it doesn't exist.
[ -f /usr/local/etc/syslog.d ] || mkdir -p /usr/local/etc/syslog.d
command to create the syslog.d directory
Next, create the syslog config file
Send log messages to log server
*.* @192.168.30.12
/usr/local/etc/syslog.d/remote.conf
Finally, restart syslogd
service syslogd restart
command to restart syslogd
LDAP Setup
Now that the server is running we need to setup the structure and add some user accounts.
Setup structure
#
# Simple LDAP Schema
#
dn: dc=example,dc=org
objectclass: dcObject
objectclass: organization
dc: example
o: example.org LDAP Server
description: Root entry for example.org
# First level
dn: ou=users,dc=example,dc=org
objectclass: organizationalUnit
ou: users
description: All people in organization
dn: ou=groups,dc=example,dc=org
objectclass: organizationalUnit
ou: groups
description: All groups in organization
dn: ou=domains,dc=example,dc=org
objectclass: organizationalUnit
ou: domains
description: All domains in organization
dn: ou=serviceaccounts,dc=example,dc=org
objectclass: organizationalUnit
ou: serviceaccounts
description: All sevice accounts in organization
init_schema.ldif
Load the ldif data to the openldap server
ldapadd -W -H ldap://127.0.0.1:389 -D "cn=ldapadmin,dc=example,dc=org" -f init_schema.ldif
Add a user account
Now the server is up and running let's add a user account. Updates to the LDAP server are made using LDIF files. Create a LDIF file from the example below with the appropriate user information.
Create a SSHA password
export PASS=letmein
export RND_SALT=`openssl rand -base64 6`
export PASS_HASH=`echo -n "$PASS$RND_SALT" | openssl dgst -sha1 -binary | openssl enc -base64 -A`
export LDAP_PASS_HASH=`(echo -n "$PASS_HASH" | openssl base64 -d -A; echo -n "$RND_SALT";) | openssl enc -base64 -A | awk '{print "{SSHA}"$0 }'`
echo $LDAP_PASS_HASH
unset RND_SALT
unset PASS_HASH
unset LDAP_PASS_HASH
unset PASS
shell to create a SSHA password
Edit the ldif as needed.
#
# Create User alice
#
dn: uid=2e86409ff65ff189,ou=users,dc=example,dc=org
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
uid: 2e86409ff65ff189
cn: alice
sn: user
uidNumber: 5000
gidNumber: 5000
homeDirectory: /home/alice
givenName: alice
displayName: alice user
mail: [email protected]
mail: @example.org
userPassword:: e1NTSEF9WmdwcCt6ZE90UC9KcEhXNjIxUGd5Wm5MZlV0RGExUjZNVzk2V0E9PQ=
=
description: $2b$10$JxGxv8v2hGw4/dytUMRjbOlHrzg7wyCRqZX6YtFdAEaruH.OsIvWm
add_user.ldif
Load the user account.
ldapadd -W -H ldap://127.0.0.1:389 -D "cn=ldapadmin,dc=example,dc=org" -f add_user.ldif
Modify a user account
From time to time updates/changes are going to need to be made to a user account. Updates to LDAP also use LDIF files to preform updates. Use the follow script to create an update LDIF.
dn: uid=juser,ou=users,dc=example,dc=org
changetype: modify
replace: userPassword
userPassword: {SSHA}adsfasdfasdfadfasdfadfas
-
update_user.ldif
Load the updated password
ldapmodify -W -H ldap://127.0.0.1:389 -D "cn=ldapadmin,dc=example,dc=org" -f update_user.ldif
Delete a user account
User accounts that are no longer needed should be deleted. Use the following script to help delete an old user account.
uid=juser,ou=users,dc=example,dc=org
delete_user.ldif
Load the delete ldif
ldapdelete -W -H ldap://127.0.0.1:389 -D "cn=ldapadmin,dc=dc=example,dc=org" -f delete_user.ldif
An easier way...
While we can manipulate the LDAP users and attributes by hand I have created a few scripts that will make the daily maintenance of users much easier. These scripts can be fetched from mgraves00/misc-scripts/ldap.
Conclusion
While this seems like a lot of work to setup a self hosted environment for just one person (and it is), once we have the infrastructure setup, adding new self hosted service will be much easier.