diff --git a/files/ldap/autofs/auto_master b/files/ldap/autofs/auto_master
new file mode 100644
index 0000000000000000000000000000000000000000..f77f33cfeb02b8e584c725f97722785ecd45da88
--- /dev/null
+++ b/files/ldap/autofs/auto_master
@@ -0,0 +1,10 @@
+# $FreeBSD: releng/12.1/usr.sbin/autofs/auto_master 337749 2018-08-14 13:52:08Z trasz $
+#
+# Automounter master map, see auto_master(5) for details.
+#
+#/net		-hosts		-nobrowse,nosuid,intr
+# When using the -media special map, make sure to edit devd.conf(5)
+# to move the call to "automount -c" out of the comments section.
+#/media		-media		-nosuid,noatime,autoro
+#/-		-noauto
++auto.master
diff --git a/files/ldap/autofs/include_ldap b/files/ldap/autofs/include_ldap
new file mode 100755
index 0000000000000000000000000000000000000000..3639b1366e4134d432b7325a4fe13ec07196b3d0
--- /dev/null
+++ b/files/ldap/autofs/include_ldap
@@ -0,0 +1,57 @@
+#!/bin/sh
+#
+# $FreeBSD: releng/12.1/usr.sbin/autofs/autofs/include_ldap 280321 2015-03-21 09:42:37Z trasz $
+#
+
+# Modify this to suit your needs.  The "$1" is the map name, eg. "auto_master".
+# To debug, simply run this script with map name as the only parameter.  It's
+# supposed to output map contents ("key location" pairs) to standard output.
+SEARCHBASE="automountmapname=$1,cn=default,cn=automount,dc=ad,dc=lysator,dc=liu,dc=se"
+ENTRY_ATTRIBUTE="description"
+VALUE_ATTRIBUTE="automountInformation"
+
+# fstype=nfs4 fungerar inte på FreeBSD då det inte finns något
+# NFS-filsystem. Använd sed för att byta det till något vettigare.
+/usr/local/bin/ldapsearch -LLL -x -o ldif-wrap=no -b "$SEARCHBASE" "$ENTRY_ATTRIBUTE" "$VALUE_ATTRIBUTE" | sed 's/fstype=nfs4/nfsv4,minorversion=1/' | awk '
+$1 == "'$ENTRY_ATTRIBUTE':" {
+	key = $2
+}
+
+$1 == "'$VALUE_ATTRIBUTE':" {
+	for (i = 2; i <= NF; i++) {
+		value[i] = $(i)
+	}
+	nvalues = NF
+	b64 = 0
+}
+
+# Double colon after attribute name means the value is in Base64.
+$1 == "'$VALUE_ATTRIBUTE'::" {
+	for (i = 2; i <= NF; i++) {
+		value[i] = $(i)
+	}
+	nvalues = NF
+	b64 = 1
+}
+
+# Empty line - end of record.
+NF == 0 && key != "" && nvalues > 0 {
+	printf "%s%s", key, OFS
+	for (i = 2; i < nvalues; i++) {
+		printf "%s%s", value[i], OFS
+	}
+	if (b64 == 1) {
+		printf "%s", value[nvalues] | "b64decode -rp"
+		close("b64decode -rp")
+		printf "%s", ORS
+	} else {
+		printf "%s%s", value[nvalues], ORS
+	}
+}
+
+NF == 0 {
+	key = ""
+	nvalues = 0
+	delete value
+}
+'
diff --git a/files/ldap/ipa/ca.crt b/files/ldap/ipa/ca.crt
new file mode 100644
index 0000000000000000000000000000000000000000..08d2fb3c8928e7d0c546dc674760f187f4d65ed7
--- /dev/null
+++ b/files/ldap/ipa/ca.crt
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEnTCCAwWgAwIBAgIBATANBgkqhkiG9w0BAQsFADA8MRowGAYDVQQKDBFBRC5M
+WVNBVE9SLkxJVS5TRTEeMBwGA1UEAwwVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4X
+DTIwMDMyMDE5MTgzNloXDTQwMDMyMDE5MTgzNlowPDEaMBgGA1UECgwRQUQuTFlT
+QVRPUi5MSVUuU0UxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTCCAaIw
+DQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBANaYjKUVykk27iKciufzJ487fyBq
+/0l+EC4PKYHHthV6o+n73wV0FVXHoxk5Wdy8kjiJsH1FSCs7dRjHhLu4Vq2fhTg+
+NSom0xV/Y5PiJrAJ1qasOrQo7hPTPRFChl9v+yMkBrA5ARFwE4H2T1Z6vr/Qvzyf
+XZhO2gLz5Ff7UJ3EnVXhnSI2Z6Tt3PbGMzkFLZ6NG1R6W400oB3LcF53prmUREvb
+oslacAURsRRVwERHsTWZRlTwdY9knnZbqY07s0f7GbCGgEjPW49DEEkCwg3i2O7M
+PRNMmnkeT/tJi15B6paXTZyG8OEGv4atZuoPOS0ObsmLTRkAlAUvRADLLC+HeGKG
+4i9voTn1gjMYaBKw50Yb7ZlCGlfRJ7Tv3TPtAwErjEXn+IoLBS7UikYdDUmFXeAa
+I452366kWcBTNln7k8vJJGxTWEoJ7Y79wBBPVvLB/HwrMSx7wYnpZ00zKdt76tKE
+4qn4kCUi+BuBVKAS8UggJHltKwum63yOXFQYNwIDAQABo4GpMIGmMB8GA1UdIwQY
+MBaAFDACxsxc7j+qqmvXpMAtG42t28UtMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
+AQH/BAQDAgHGMB0GA1UdDgQWBBQwAsbMXO4/qqpr16TALRuNrdvFLTBDBggrBgEF
+BQcBAQQ3MDUwMwYIKwYBBQUHMAGGJ2h0dHA6Ly9pcGEtY2EuYWQubHlzYXRvci5s
+aXUuc2UvY2Evb2NzcDANBgkqhkiG9w0BAQsFAAOCAYEAfBMrVvWgsZEbLO291/Xt
+lrjIpY8Fz8N5QgeBHckvgL/Uu21/svKPchEWLXcqlFkAXUMHKRomkM9nxeEg0p8X
+yTHQnaOIi9z/Meb/zXRYCZeK4QWEDvwTlApkCSzN6gz3Pq2IPb04dshsL5eQYzBl
+p50v0MHrJVYlxOkYFJKZ+SbTlKuwU8zfaVtXA5A//7c+3dBHMbomgMRp9qJzCV1w
+ek+R8AX5ozdGxC1Oy70xT7IOqBTdD/VI5UrEc5SwnVXJD5CY8QwEsLvcs59GrZCK
+cR+mQF7prRShbu57pHqJsnm56wjDnSVRVfjg6UNLcFDWWrj8LBQjpYB8HtjFSwIl
+wf70W3zRBReuqyXEGc8J/bDdc1+QGeoVcQ0e1JyzxP+BwPdUAQFAkf/5vttK0Yc2
+485EmZuaigHXXBUYUYsIH0cOYkzql4fe2RpUVTbturRr1lT9EzQpTIF2E2ie0Fhe
+CCSKN2wpR+HTytkPoo6dHPp9jslnEEu/Y36lDWx3tNbm
+-----END CERTIFICATE-----
diff --git a/files/ldap/krb5.conf b/files/ldap/krb5.conf
new file mode 100644
index 0000000000000000000000000000000000000000..553bfc58488417ee106d4efafe16eb7a1d2e39e7
--- /dev/null
+++ b/files/ldap/krb5.conf
@@ -0,0 +1,28 @@
+[libdefaults]
+	default_realm = AD.LYSATOR.LIU.SE
+	dns_lookup_realm = true
+	dns_lookup_kdc = true
+	rdns = false
+	dns_canonicalize_hostname = false
+	ticket_lifetime = 24h
+	forwardable = true
+	udp_preference_limit = 0
+	default_ccache_name = KEYRING:persistent:%{uid}
+
+[realms]
+	AD.LYSATOR.LIU.SE = {
+		pkinit_anchors = FILE:/var/lib/ipa-client/pki/kdc-ca-bundle.pem
+		pkinit_pool = FILE:/var/lib/ipa-client/pki/ca-bundle.pem
+		kdc = trocca.ad.lysator.liu.se
+	}
+
+[domain_realm]
+	ad.lysator.liu.se = AD.LYSATOR.LIU.SE
+	.ad.lysator.liu.se = AD.LYSATOR.LIU.SE
+	.lysator.liu.se = AD.LYSATOR.LIU.SE
+	lysator.liu.se = AD.LYSATOR.LIU.SE
+
+[logging]
+        default = FILE:/var/log/krb5libs.log
+        kdc = FILE:/var/log/krb5kdc.log
+        admin_server = FILE:/var/log/kadmin.log
diff --git a/files/ldap/nslcd.conf b/files/ldap/nslcd.conf
new file mode 100644
index 0000000000000000000000000000000000000000..7c3a14eae474bb5f5b9cc6a25f4174a1444c2ccd
--- /dev/null
+++ b/files/ldap/nslcd.conf
@@ -0,0 +1,145 @@
+# This is the configuration file for the LDAP nameservice
+# switch library's nslcd daemon. It configures the mapping
+# between NSS names (see /etc/nsswitch.conf) and LDAP
+# information in the directory.
+# See the manual page nslcd.conf(5) for more information.
+
+# The user and group nslcd should run as.
+uid nslcd
+gid nslcd
+
+# The uri pointing to the LDAP server to use for name lookups.
+# Multiple entries may be specified. The address that is used
+# here should be resolvable without using LDAP (obviously).
+#uri ldap://127.0.0.1/
+#uri ldaps://127.0.0.1/
+#uri ldapi://%2fvar%2frun%2fldapi_sock/
+# Note: %2f encodes the '/' used as directory separator
+uri ldap://trocca.ad.lysator.liu.se/
+
+# The LDAP version to use (defaults to 3
+# if supported by client library)
+#ldap_version 3
+
+# The distinguished name of the search base.
+base cn=compat,dc=ad,dc=lysator,dc=liu,dc=se
+base group cn=groups,cn=compat,dc=ad,dc=lysator,dc=liu,dc=se
+base passwd cn=users,cn=accounts,dc=ad,dc=lysator,dc=liu,dc=se
+#base shadow cn=shadow,dc=ad,dc=lysator,dc=liu,dc=se
+
+# The distinguished name to bind to the server with.
+# Optional: default is to bind anonymously.
+#binddn cn=proxyuser,dc=example,dc=com
+
+# The credentials to bind with.
+# Optional: default is no credentials.
+# Note that if you set a bindpw you should check the permissions of this file.
+#bindpw secret
+
+# The distinguished name to perform password modifications by root by.
+#rootpwmoddn cn=admin,dc=example,dc=com
+
+# The default search scope.
+scope sub
+#scope one
+#scope base
+
+# Customize certain database lookups.
+#base   group  ou=Groups,dc=example,dc=com
+#base   passwd ou=People,dc=example,dc=com
+#base   shadow ou=People,dc=example,dc=com
+#scope  group  onelevel
+#scope  hosts  sub
+
+# Bind/connect timelimit.
+#bind_timelimit 30
+
+# Search timelimit.
+#timelimit 30
+
+# Idle timelimit. nslcd will close connections if the
+# server has not been contacted for the number of seconds.
+#idle_timelimit 3600
+
+# Use StartTLS without verifying the server certificate.
+ssl start_tls
+#tls_reqcert never
+
+# CA certificates for server certificate verification
+#tls_cacertdir /etc/ssl/certs
+tls_cacertfile /usr/local/etc/ipa/ca.crt
+
+# Seed the PRNG if /dev/urandom is not provided
+#tls_randfile /var/run/egd-pool
+
+# SSL cipher suite
+# See man ciphers for syntax
+#tls_ciphers TLSv1
+
+# Client certificate and key
+# Use these, if your server requires client authentication.
+#tls_cert
+#tls_key
+
+# Mappings for Services for UNIX 3.5
+#filter passwd (objectClass=User)
+#map    passwd uid              msSFU30Name
+#map    passwd userPassword     msSFU30Password
+#map    passwd homeDirectory    msSFU30HomeDirectory
+#map    passwd homeDirectory    msSFUHomeDirectory
+#filter shadow (objectClass=User)
+#map    shadow uid              msSFU30Name
+#map    shadow userPassword     msSFU30Password
+#filter group  (objectClass=Group)
+#map    group  member           msSFU30PosixMember
+
+# Mappings for Services for UNIX 2.0
+#filter passwd (objectClass=User)
+#map    passwd uid              msSFUName
+#map    passwd userPassword     msSFUPassword
+#map    passwd homeDirectory    msSFUHomeDirectory
+#map    passwd gecos            msSFUName
+#filter shadow (objectClass=User)
+#map    shadow uid              msSFUName
+#map    shadow userPassword     msSFUPassword
+#map    shadow shadowLastChange pwdLastSet
+#filter group  (objectClass=Group)
+#map    group  member           posixMember
+
+# Mappings for Active Directory
+#pagesize 1000
+#referrals off
+#idle_timelimit 800
+#filter passwd (&(objectClass=user)(!(objectClass=computer))(uidNumber=*)(unixHomeDirectory=*))
+#map    passwd uid              sAMAccountName
+#map    passwd homeDirectory    unixHomeDirectory
+#map    passwd gecos            displayName
+#filter shadow (&(objectClass=user)(!(objectClass=computer))(uidNumber=*)(unixHomeDirectory=*))
+#map    shadow uid              sAMAccountName
+#map    shadow shadowLastChange pwdLastSet
+#filter group  (objectClass=group)
+
+# Alternative mappings for Active Directory
+# (replace the SIDs in the objectSid mappings with the value for your domain)
+#pagesize 1000
+#referrals off
+#idle_timelimit 800
+#filter passwd (&(objectClass=user)(objectClass=person)(!(objectClass=computer)))
+#map    passwd uid           cn
+#map    passwd uidNumber     objectSid:S-1-5-21-3623811015-3361044348-30300820
+#map    passwd gidNumber     objectSid:S-1-5-21-3623811015-3361044348-30300820
+#map    passwd homeDirectory "/home/$cn"
+#map    passwd gecos         displayName
+#map    passwd loginShell    "/bin/bash"
+#filter group (|(objectClass=group)(objectClass=person))
+#map    group gidNumber      objectSid:S-1-5-21-3623811015-3361044348-30300820
+
+# Mappings for AIX SecureWay
+#filter passwd (objectClass=aixAccount)
+#map    passwd uid              userName
+#map    passwd userPassword     passwordChar
+#map    passwd uidNumber        uid
+#map    passwd gidNumber        gid
+#filter group  (objectClass=aixAccessGroup)
+#map    group  cn               groupName
+#map    group  gidNumber        gid
diff --git a/files/ldap/nsswitch.conf b/files/ldap/nsswitch.conf
new file mode 100644
index 0000000000000000000000000000000000000000..821b4f38a1252b07561ba851c73b851bead1204c
--- /dev/null
+++ b/files/ldap/nsswitch.conf
@@ -0,0 +1,16 @@
+#
+# nsswitch.conf(5) - name service switch configuration file
+# $FreeBSD: releng/12.1/lib/libc/net/nsswitch.conf 338729 2018-09-17 18:56:47Z brd $
+#
+group: files ldap
+group_compat: nis
+hosts: files dns
+netgroup: compat
+networks: files
+passwd: files ldap
+passwd_compat: nis
+shells: files
+services: compat
+services_compat: nis
+protocols: files
+rpc: files
diff --git a/files/ldap/openldap/ldap.conf b/files/ldap/openldap/ldap.conf
new file mode 100644
index 0000000000000000000000000000000000000000..70e364949bb08f9f1263ed8bb7f3ff7a7f4d3b40
--- /dev/null
+++ b/files/ldap/openldap/ldap.conf
@@ -0,0 +1,18 @@
+#
+# LDAP Defaults
+#
+
+# See ldap.conf(5) for details
+# This file should be world readable but not world writable.
+
+#BASE	dc=example,dc=com
+#URI	ldap://ldap.example.com ldap://ldap-provider.example.com:666
+
+#SIZELIMIT	12
+#TIMELIMIT	15
+#DEREF		never
+
+URI ldaps://trocca.ad.lysator.liu.se
+BASE dc=ad,dc=lysator,dc=liu,dc=se
+TLS_CACERT /usr/local/etc/ipa/ca.crt
+SASL_MECH GSSAPI
diff --git a/files/ldap/pam.d/sshd b/files/ldap/pam.d/sshd
new file mode 100644
index 0000000000000000000000000000000000000000..c5befa85deb26a9b4b183c6c3c6d8125228bc6a6
--- /dev/null
+++ b/files/ldap/pam.d/sshd
@@ -0,0 +1,28 @@
+#
+# $FreeBSD: releng/12.1/lib/libpam/pam.d/sshd 197769 2009-10-05 09:28:54Z des $
+#
+# PAM configuration for the "sshd" service
+#
+
+# auth
+auth		sufficient	pam_opie.so		no_warn no_fake_prompts
+auth		requisite	pam_opieaccess.so	no_warn allow_local
+auth		sufficient	pam_krb5.so		no_warn try_first_pass
+#auth		sufficient	pam_ssh.so		no_warn try_first_pass
+auth		required	pam_unix.so		no_warn try_first_pass
+
+# account
+account		required	pam_nologin.so
+account		required	pam_login_access.so
+account		sufficient	/usr/local/lib/pam_ldap.so      no_warn ignore_authinfo_unavail ignore_unknown_user
+#account		required	pam_krb5.so
+account		required	pam_login_access.so
+account		required	pam_unix.so
+
+# session
+#session	optional	pam_ssh.so		want_agent
+session		required	pam_permit.so
+
+# password
+password	sufficient	pam_krb5.so		no_warn try_first_pass
+password	required	pam_unix.so		no_warn try_first_pass
diff --git a/files/ldap/pam.d/su b/files/ldap/pam.d/su
new file mode 100644
index 0000000000000000000000000000000000000000..c29826951a65deee30e29403d758d6a9ccb12b18
--- /dev/null
+++ b/files/ldap/pam.d/su
@@ -0,0 +1,17 @@
+#
+# $FreeBSD: releng/12.1/lib/libpam/pam.d/su 219663 2011-03-15 10:13:35Z des $
+#
+# PAM configuration for the "su" service
+#
+
+# auth
+auth		sufficient	pam_rootok.so		no_warn
+auth		sufficient	pam_self.so		no_warn
+auth		requisite	pam_group.so		no_warn group=root root_only fail_safe ruser
+auth		include		system
+
+# account
+account		include		system
+
+# session
+session		required	pam_permit.so
diff --git a/files/ldap/pam.d/system b/files/ldap/pam.d/system
new file mode 100644
index 0000000000000000000000000000000000000000..7c734e9f01cad91acfc52c21aa0f471e5039484e
--- /dev/null
+++ b/files/ldap/pam.d/system
@@ -0,0 +1,26 @@
+#
+# $FreeBSD: releng/12.1/lib/libpam/pam.d/system 197769 2009-10-05 09:28:54Z des $
+#
+# System-wide defaults
+#
+
+# auth
+auth		sufficient	pam_opie.so		no_warn no_fake_prompts
+auth		requisite	pam_opieaccess.so	no_warn allow_local
+auth		sufficient	pam_krb5.so		no_warn try_first_pass
+#auth		sufficient	pam_ssh.so		no_warn try_first_pass
+auth		required	pam_unix.so		no_warn try_first_pass nullok
+
+# account
+#account	required	pam_krb5.so
+account		required	pam_login_access.so
+account		sufficient	/usr/local/lib/pam_ldap.so	no_warn ignore_authinfo_unavail ignore_unknown_user
+account		required	pam_unix.so
+
+# session
+#session	optional	pam_ssh.so		want_agent
+session		required	pam_lastlog.so		no_fail
+
+# password
+password	sufficient	pam_krb5.so		no_warn try_first_pass
+password	required	pam_unix.so		no_warn try_first_pass
diff --git a/manifests/ldap.pp b/manifests/ldap.pp
new file mode 100644
index 0000000000000000000000000000000000000000..b0daecb995c301674e8107b7a9fb71ccaaad8081
--- /dev/null
+++ b/manifests/ldap.pp
@@ -0,0 +1,108 @@
+class freebsd::ldap {
+  package {
+    [
+      'nss-pam-ldapd',
+      'openldap-client',
+    ]:
+      ensure => installed,
+  }
+
+  file { '/etc/nsswitch.conf':
+    ensure => file,
+    source => 'puppet:///modules/freebsd/ldap/nsswitch.conf',
+    owner  => 'root',
+    group  => 'wheel',
+    mode   => '0644',
+  }
+
+  file { '/etc/krb5.conf':
+    ensure => file,
+    source => 'puppet:///modules/freebsd/ldap/krb5.conf',
+    owner  => 'root',
+    group  => 'wheel',
+    mode   => '0644',
+  }
+
+  file { '/etc/pam.d/sshd':
+    ensure => file,
+    source => 'puppet:///modules/freebsd/ldap/pam.d/sshd',
+    owner  => 'root',
+    group  => 'wheel',
+    mode   => '0644',
+  }
+
+  file { '/etc/pam.d/system':
+    ensure => file,
+    source => 'puppet:///modules/freebsd/ldap/pam.d/system',
+    owner  => 'root',
+    group  => 'wheel',
+    mode   => '0644',
+  }
+
+  file { '/etc/pam.d/su':
+    ensure => file,
+    source => 'puppet:///modules/freebsd/ldap/pam.d/su',
+    owner  => 'root',
+    group  => 'wheel',
+    mode   => '0644',
+  }
+
+  file { '/etc/auto_master':
+    ensure => file,
+    source => 'puppet:///modules/freebsd/ldap/autofs/auto_master',
+    owner  => 'root',
+    group  => 'wheel',
+    mode   => '0644',
+  }
+
+  file { '/etc/autofs/include_ldap':
+    ensure => file,
+    source => 'puppet:///modules/freebsd/ldap/autofs/include_ldap',
+    owner  => 'root',
+    group  => 'wheel',
+    mode   => '0755',
+  }
+
+  file { '/etc/autofs/include':
+    ensure => 'link',
+    target => '/etc/autofs/include_ldap',
+  }
+
+  file_line { 'Enable autofs':
+    path => '/etc/rc.conf',
+    line => 'autofs_enable="YES"',
+  }
+
+  file { '/usr/local/etc/nslcd.conf':
+    ensure => file,
+    source => 'puppet:///modules/freebsd/ldap/nslcd.conf',
+    owner  => 'root',
+    group  => 'wheel',
+    mode   => '0644',
+  }
+
+  file_line { 'Enable nslcd':
+    path => '/etc/rc.conf',
+    line => 'nslcd_enable="YES"',
+  }
+
+  file { '/usr/local/etc/openldap/ldap.conf':
+    ensure => file,
+    source => 'puppet:///modules/freebsd/ldap/openldap/ldap.conf',
+    owner  => 'root',
+    group  => 'wheel',
+    mode   => '0644',
+  }
+
+  file { '/usr/local/etc/ipa':
+    ensure => directory,
+  }
+
+  file { '/usr/local/etc/ipa/ca.crt':
+    ensure => file,
+    source => 'puppet:///modules/freebsd/ldap/ipa/ca.crt',
+    owner  => 'root',
+    group  => 'wheel',
+    mode   => '0644',
+  }
+}