Samba AD Smart Card Login for macOS clients
Introduction
This page covers a basic configuration for PIV smart Card login with a macOS client domain member of a Samba domain. The intended use is in a lab environment for experimentation, i.e. it works but is not necessarily best practices, which surely would be a lot longer as the three main areas that it covers (Domain controllers, Public Key Infrastructure and PIV smart cards) are vast in their own right, without even getting into the interrelations between them.
These instructions attempt to be PIV smart card hardware-agnostic, so user key pairs are created with the Certificate Authority (CA). Instructions on how to transfer the key pairs and certificate to the smart card will vary depending on the smart card's manufacturer. Generally speaking, it involves creating a key pair and certificate for the smart card's 9a slot (authentication).
This page is largely based on the Samba AD Smart Card Login page.
Prerequisites
These instructions have only been tested using the configuration below.
macOS
Smart card logon was added in macOS Sierra 10.12 and Directory logon in macOS High Sierra 10.13.
PIV smart card
Any macOS compatible PIV smart card should work.
Samba AD DC
The Samba AD DC was set up following the instructions on the Setting up Samba as an Active Directory Domain Controller page using Debian.
CRL Distribution Point
To make the .crl
file available to clients, a CRL distribution point will be configured. These instructions will use lighttpd on FreeBSD as a web server, although different methods (FTP, LDAP) may also work.
If intending to follow the Configure CRL Distribution Point section's instructions, a fresh FreeBSD installation is required. Details on the configuration for the FreeBSD installation are given in the corresponding section.
Tested configuration
- Samba AD DC: version 4.13.13 on Debian 11 bullseye
- macOS client: macOS Monterey 12.6.6 (21G646)
- PIV smart card: Yubikey 5 NFC (Firmware 5.1.2)
- CRL distribution point: lighttpd-1.4.71 on FreeBSD 12.4-RELEASE
Instructions
Configure OpenSSL
In depth file permissions are not covered in these instructions. Generally speaking, the principal of least privilege should be applied. Private keys should be kept private. For example, on a system with a root user, private keys could have read only permissions just for root. As a side note, ideally, CA private keys would be stored with specialised air-gapped hardware.
Open a shell on your Samba AD DC and proceed with the instructions. All commands are for Debian, run as the root user.
Get Samba AD DC GUID in hex
Get your Samba AD DC GUID in hex:
If not done already, install ldb-tools
:
# apt-get install ldb-tools
Adapt the following command for your domain to get your DC's GUID in hex and note it for later. Example for dc1.samdom.example.com
:
GUID=$(/usr/bin/ldbsearch -H /var/lib/samba/private/sam.ldb --basedn="OU=Domain Controllers,DC=samdom,DC=example,DC=com" "CN=DC1" objectGUID | grep "objectGUID:" | sed 's/objectGUID: //g' | sed 's/-//g'); HEX="${GUID:6:2}"; HEX="${HEX}${GUID:4:2}"; HEX="${HEX}${GUID:2:2}"; HEX="${HEX}${GUID:0:2}"; HEX="${HEX}${GUID:10:2}"; HEX="${HEX}${GUID:8:2}"; HEX="${HEX}${GUID:14:2}"; HEX="${HEX}${GUID:12:2}"; len=${#HEX}; HEX="${HEX}${GUID:16:${len}}"; printf '%s\n' "${HEX}"
Create OpenSSL Root CA directory structure
Create the directory structure for the CA:
# mkdir /root/CA /root/CA/certs /root/CA/crl /root/CA/private /root/CA/newcerts
Create the serial
file:
# echo 00 > /root/CA/serial
Create the crlnumber
file:
# echo 00 > /root/CA/crlnumber
Create the index.txt
file:
# touch /root/CA/index.txt
Configure openssl.cnf
Adapt the following openssl.cnf
to suit your needs. Use your DC's FQDN for the set_dns
option. Use the Samba AD DC GUID in hex previously obtained, for the set_dc_guid
option.
Later in the instructions, a CRL Distribution Point will be configured. This consists of copying the .crl
file to a web server to make it accessible to clients. The .crl
file's URL used here, for the set_crp_default
option, needs to be the same as the one used when configuring the CRL Distribution Point.
######################################################################################### EDIT BELOW THIS LINE set_countryName_default = My Country (2 letter code) set_stateOrProvinceName_default = My State or Province set_localityName_default = My Locality set_organizationName_default = My Organisation set_organizationalUnitName_default = My Department set_crp_default = http://crl.samdom.example.com/samdom.crl set_dns = dc1.samdom.example.com set_dc_guid = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ######################################################################################### DO NOT EDIT BELOW THIS LINE CRLDISTPT = $set_crp_default # Variable used for CRL URL oid_section = new_oids # Extra OBJECT IDENTIFIER info [ new_oids ] # New OIDs msADGUID = 1.3.6.1.4.1.311.25.1 # Identifies AD GUID [ ca ] # Default CA section default_ca = CA_default # Default CA name [ CA_default ] # Default settings for CA dir = /root/CA # CA directory certs = $dir/certs # Certificates directory crl_dir = $dir/crl # CRL directory new_certs_dir = $dir/newcerts # New certificates directory database = $dir/index.txt # Certificate index file serial = $dir/serial # Serial number file RANDFILE = $dir/private/.rand # Random number file private_key = $dir/private/ca.key.pem # Root CA private key certificate = $dir/certs/ca.cert.pem # Root CA certificate crl = $dir/crl/ca.crl.pem # Root CA CRL crlnumber = $dir/crlnumber # Root CA CRL number crl_extensions = crl_ext # CRL extensions unique_subject = yes # Prevent creation of multiple certificates with same subject name_opt = ca_default # Subject Name options cert_opt = ca_default # Certificate field options copy_extensions = copy # Extension copying use with caution default_days = 730 # How long to certify for default_crl_days = 30 # How long before next CRL default_md = sha256 # Use public key default MD preserve = no # Keep passed DN ordering policy = policy_match # Certificate policy [ policy_match ] # For CA policy countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional [ policy_anything ] # For anything policy countryName = match stateOrProvinceName = match localityName = match organizationName = match organizationalUnitName = match commonName = supplied emailAddress = supplied [ req ] # Request settings default_bits = 2048 # Default key size default_keyfile = priv.key.pem distinguished_name = req_distinguished_name # Default DN template attributes = req_attributes x509_extensions = v3_ca # Extensions added to self signed cert string_mask = utf8only # UTF-8 encoding [ req_distinguished_name ] # Template for DN in CSR countryName = Country Name (2 letter code) countryName_default = $set_countryName_default countryName_min = 2 countryName_max = 2 stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = $set_stateOrProvinceName_default localityName = Locality Name (eg, city) localityName_default = $set_localityName_default organizationName = Organization Name (eg, company) organizationName_default = $set_organizationName_default organizationalUnitName = Organizational Unit Name (eg, section) organizationalUnitName_default = $set_organizationalUnitName_default commonName = Common Name (eg, YOUR name) commonName_max = 64 emailAddress = Email Address emailAddress_max = 64 [ req_attributes ] challengePassword = A challenge password challengePassword_min = 4 challengePassword_max = 20 unstructuredName = An optional company name [ v3_req ] # Extensions added to certificate requests basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment [ v3_ca ] # Root CA certificate extensions subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = CA:true keyUsage = cRLSign, keyCertSign crlDistributionPoints = URI:$CRLDISTPT nsCertType = sslCA, emailCA issuerAltName = issuer:copy [ crl_ext ] # CRL extensions issuerAltName = issuer:copy authorityKeyIdentifier = keyid:always [ usr_cert_mskdc ] # Domain Controller Certificate basicConstraints = CA:FALSE crlDistributionPoints = URI:$CRLDISTPT nsCertType = server keyUsage = nonRepudiation, digitalSignature, keyEncipherment nsComment = "Domain Controller Certificate" # Displayed in Netscape's comment listbox subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer subjectAltName = @dc_subjalt issuerAltName = issuer:copy nsCaRevocationUrl = $CRLDISTPT extendedKeyUsage = clientAuth,serverAuth,pkInitKDC # serverAuth cert identifies ssl server, pkInitKDC cert identifies Kerberos DC [dc_subjalt] # Further Domain Controller Certificate DNS = $set_dns otherName = msADGUID;FORMAT:HEX,OCTETSTRING:$set_dc_guid [ usr_cert_scarduser ] # User Certificates basicConstraints = CA:FALSE crlDistributionPoints = URI:$CRLDISTPT nsCertType = client, email keyUsage = nonRepudiation, digitalSignature, keyEncipherment nsComment = "Smart Card Login Certificate" # Displayed in Netscape's comment listbox subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer issuerAltName = issuer:copy nsCaRevocationUrl = $CRLDISTPT extendedKeyUsage = clientAuth,msSmartcardLogin # Extended Key requirements for client certs #subjectAltName = email:copy,otherName:msUPN;UTF8:UserPrincipalName # Can be used for CSR from smart card
Create the openssl.cnf
file:
# touch /root/CA/openssl.cnf
Add your modified openssl.cnf
to the newly created file.
Side note: CSR from smart card
This section is a side note that can be skipped, it concerns generating a CSR with a smart card.
Although outside the scope of these instructions, if generating the user key pair with a smart card, the last line of the openssl.cnf
can be modified for a Certificate Signing Request (CSR) from a smart card.
Go through these instructions and modify where required. Transfer the CSR to the CA. Uncomment the last line of the openssl.cnf
and add the user's UPN for the user requesting the certificate. For example, subjectAltName = email:copy,otherName:msUPN;UTF8:sambauser@samdom.example.com
.
Modify the command below to suit your needs, when prompted use the CA root key's password:
# openssl ca -config /root/CA/openssl.cnf -subj "/emailAddress=sambauser@samdom.example.com/CN=samba user/OU=My Departement/O=My Departement/L=My Locality/ST=My State or Province/C=My Country 2 letter code" -extensions usr_cert_scarduser -in /root/CA/crl/sambauser.csr -out /root/CA/certs/sambauser.crt
Comment out the previously uncommented line and transfer the certificate to the smart card.
Generate key pair and certificate for root CA
Generate a key pair and certificate for the root CA:
# openssl req -new -x509 -days 3650 -sha256 -extensions v3_ca -addext 'subjectAltName = email:copy' -keyout /root/CA/private/ca.key.pem -out /root/CA/certs/ca.cert.pem -config /root/CA/openssl.cnf
Go through the interactive session. Example:
… Common Name (eg, YOUR name) []:samdom.example.com Certificate Authority Email Address []:ca@samdom.example.com …
Set read only permissions for root on the private key:
# chmod 400 /root/CA/private/ca.key.pem
Generate key pair and certificate for Domain Controller
Generate a key pair and certificate for the Domain Controller:
# openssl req -new -addext 'subjectAltName = email:copy' -newkey rsa:2048 -keyout /root/CA/private/dc.key.pem -out /root/CA/certs/dc.csr.pem -config /root/CA/openssl.cnf
Go through the interactive session, using the Domain Controller's DNS name as the Common Name. The Email can be left blank. Example:
… Common Name (eg, YOUR name) []:dc1.samdom.example.com …
Set read only permissions for root on the private key:
# chmod 400 /root/CA/private/dc.key.pem
Issue the certificate, when prompted, use the CA root key's password:
# openssl ca -config /root/CA/openssl.cnf -extensions usr_cert_mskdc -in /root/CA/certs/dc.csr.pem -out /root/CA/certs/dc.cert.pem
Create user that will login with smart card
Create the user that will log in using the smart card:
# samba-tool user add sambauser
Get the UserPrincipalName for the user
Get the UserPrincipalName
for the user that will log in using a Smart Cart. Example for a user named sambauser
:
# samba-tool user show sambauser | grep userPrincipalName
Here the UserPrincipalName
is sambauser@samdom.example.com
.
Generate key pair and certificate for user
Create a certificate request and a private key. Example for a user with the UserPrincipalName
sambauser@samdom.example.com
:
# openssl req -new -addext 'subjectAltName = otherName:msUPN;UTF8:sambauser@samdom.example.com,email:copy' -newkey rsa:2048 -keyout /root/CA/private/sambauser.key.pem -out /root/CA/certs/sambauser.csr.pem -config /root/CA/openssl.cnf
Go through the interactive session, using the UserPrincipalName
for the Email Address. Example:
… Email Address []:sambauser@samdom.example.com …
Set read only permissions for root on the private key:
# chmod 400 /root/CA/private/sambauser.key.pem
Sign the certificate request:
# openssl ca -config /root/CA/openssl.cnf -extensions usr_cert_scarduser -in /root/CA/certs/sambauser.csr.pem -out /root/CA/certs/sambauser.cert.pem
Generate a CRL
Generate a CRL:
# openssl ca -config /root/CA/openssl.cnf -gencrl -out /root/CA/crl/samdom.crl
Generate a DH parameter file
Create DH parameter file:
# openssl dhparam -outform PEM -out /root/CA/dcdhparams.pem 2048
Configure Samba AD DC
Stop Samba:
# systemctl stop samba-ad-dc smbd
Archive Samba generated Certificates and CA Files, just in case:
# tar -czvf /root/samba.tls.tar.gz /var/lib/samba/private/tls
Delete Samba generated Certificates and CA Files:
# rm /var/lib/samba/private/tls/ca.pem /var/lib/samba/private/tls/cert.pem /var/lib/samba/private/tls/key.pem
Copy files to Samba Provision Directory:
# cp -p /root/CA/certs/dc.cert.pem /root/CA/certs/ca.cert.pem /root/CA/crl/samdom.crl /root/CA/dcdhparams.pem /root/CA/private/dc.key.pem /var/lib/samba/private/tls/
Decrypt the Domain Controller Private Key:
# openssl rsa -in /var/lib/samba/private/tls/dc.key.pem -inform PEM -out /var/lib/samba/private/tls/dc.priv.key.pem -outform PEM
Add the following to the global section of your /etc/samba/smb.conf
:
tls enabled = yes tls certfile = /var/lib/samba/private/tls/dc.cert.pem tls keyfile = /var/lib/samba/private/tls/dc.priv.key.pem tls cafile = /var/lib/samba/private/tls/ca.cert.pem tls crlfile = /var/lib/samba/private/tls/samdom.crl tls dhparams file = /var/lib/samba/private/tls/dcdhparams.pem
Start Samba:
# systemctl start samba-ad-dc
Check that were no errors loading certificates or associated files:
# systemctl status samba-ad-dc
Stop Samba:
# systemctl stop samba-ad-dc
Adapt your /var/lib/samba/private/krb5.conf
to suit your needs. Example for DC1.SAMDOM.EXAMPLE.COM
:
[libdefaults] default_realm = SAMDOM.EXAMPLE.COM dns_lookup_realm = false dns_lookup_kdc = true pkinit_anchors = FILE:/var/lib/samba/private/tls/ca.cert.pem [appdefaults] pkinit_anchors = FILE:/var/lib/samba/private/tls/ca.cert.pem [realms] SAMDOM.EXAMPLE.COM = { pkinit_require_eku = true } [kdc] enable-pkinit = yes pkinit_identity = FILE:/var/lib/samba/private/tls/dc.cert.pem,/var/lib/samba/private/tls/dc.priv.key.pem pkinit_anchors = FILE:/var/lib/samba/private/tls/ca.cert.pem pkinit_principal_in_certificate = yes pkinit_win2k = no pkinit_win2k_require_binding = yes [domain_realm] DC1 = SAMDOM.EXAMPLE.COM
Note: the dash in enable-pkinit
is not a typo.
Archive current /etc/krb5.conf
just in case:
# mv /etc/krb5.conf /etc/krb5.conf.old
Copy Samba's krb5.conf
file to your operating system's Kerberos configuration:
# cp /var/lib/samba/private/krb5.conf /etc/krb5.conf
![]() | Do not create a symbolic link to Samba's krb5.conf file. In Samba 4.7 and later, the /var/lib/samba/private/ directory is no longer accessible by other users than the root user. If the file is a symbolic link, other users cannot read the file and, for example, dynamic DNS updates fail if you use the BIND_DLZ DNS back end. |
Start Samba:
# systemctl start samba-ad-dc
Check status:
# systemctl status samba-ad-dc
Configure CRL Distribution Point
Here, the previously generated .crl
file in the Generate a CRL section will be copied to a web server. The URL for the .crl
file should be the same as the one used in the openssl.cnf
set_crp_default
option configured in the Configure openssl.cnf section.
The following instructions use lighttpd on FreeBSD as a web server, but any web server could probably be used or other types of server such as FTP or LDAP may also work.
The following is for a fresh FreeBSD installation with the following configuration that needs to be adapted to suit your needs:
- Hostname: crl
- No optional system components installed
- IPv4 Static Configuration:
- IP Address: 192.168.1.6
- Subnet Mask: 255.255.255.0
- Default Router: 192.168.1.1
- DNS Configuration:
- Search: samdom.example.com
- IPv4 DNS: 192.168.1.2 (Samba AD DC's IPv4)
Open a shell on your FreeBSD and proceed with the instructions. All commands are for FreeBSD 12.4-RELEASE-amd64, run as the root user.
Install git:
# pkg install git
# git clone https://git.FreeBSD.org/ports.git /usr/ports
Install lib32:
# pkg install wget
# wget https://download.freebsd.org/ftp/releases/amd64/12.4-RELEASE/lib32.txz
# tar -C / -xpf lib32.txz
# freebsd-update fetch
# freebsd-update install
Install lighttpd:
# cd /usr/ports/www/lighttpd
Run the following command, default options are acceptable:
# make config-recursive
Keep running make config-recursive
until all dependent ports options have been defined, and ports options screens no longer appear, as options may create new dependencies.
# make install clean
# mkdir /usr/local/www/data
Copy the .crl
file generated in the Generate a CRL section to the /usr/local/www/data
directory on the web server.
Make the .crl
file world readable, example for samdom.crl
:
# chmod 444 /usr/local/www/data/samdom.crl
Add the following line to /etc/rc.conf
:
lighttpd_enable="YES"
Adapt the following line to suit your needs and add it /usr/local/etc/lighttpd/lighttpd.conf
:
server.bind = "192.168.1.6"
Start lighttpd:
# /usr/local/etc/rc.d/lighttpd start
Open a shell on your Samba AD DC and proceed with the instructions. All commands are for Debian, run as the root user.
Create a A
DNS record for the web server by adapting the following command to suit your needs, example for dc1.samdom.example.com
with 192.168.1.6
as the web server's IP address and crl
as its name:
# samba-tool dns add dc1.samdom.example.com samdom.example.com crl A 192.168.1.6 -U administrator
Check that the A
DNS record is working:
# host -t A crl.samdom.example.com
Optional, requires having created a reverse zone beforehand, as indicated on the Setting up Samba as an Active Directory Domain Controller page. Create a PTR
DNS record for the web server by adapting the following command to suit your needs, example for dc1.samdom.example.com
with 192.168.1.6
as the web server's IP address and crl.samdom.example.com
as its FQDN:
# samba-tool dns add dc1.samdom.example.com 1.168.192.in-addr.arpa 6 PTR crl.samdom.example.com -U administrator
Check that the PTR
DNS record is working:
# host 192.168.1.6
With a web browser on a client with the Samba AD DC as its DNS server, check that the .crl
file downloads, for example, go to crl.samdom.example.com/samdom.crl
.
macOS client configuration
Modify SmartcardLogin.plist
Add the following to /private/etc/SmartcardLogin.plist
and make it word readable:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>AttributeMapping</key> <dict> <key>fields</key> <array> <string>NT Principal Name</string> </array> <key>formatString</key> <string>$1</string> <key>dsAttributeString</key> <string>dsAttrTypeNative:userPrincipalName</string> </dict> </dict> </plist>
Join macOS client to domain
The macOS client needs to be joined to the domain. For instructions, see the Joining a macOS Client to a Domain page.
Turn on mobile accounts
The mobile account feature allows using a network account when the client is disconnected from the network. As these instructions don't cover the configuration for setting up user's home folders on a file server, this feature allows us to login without setting up user's home folders on a network share.
- Open
System Preferences
, then click onUsers & Groups
.
- macOS security settings may require clicking on the padlock in the bottom left of the window and entering a local administrator account's credentials, before being able to make changes.
- On the left pane, click on
Login Options
, then click on theEdit…
button.
- Click on the
Open Directory Utility…
button.
- Click on the padlock in the bottom left of the
Directory Utility
window and enter a local administrator account's credentials, then click on theModify Configuration
button.
- On the
Services
tab, select theActive Directory
service and click the pen icon on the bottom left of the window. If required, enter a local administrator account's credentials, then click on theModify Configuration
button.
- In the window that opens, expand the
Show Options
section by clicking the arrow to its left. Check theCreate mobile account at login
checkbox then clickOK
. If required, enter a local administrator account's credentials, then click on theModify Configuration
button.
- Click on the padlock in the bottom left of the
Directory Utility
window to lock the preferences, then quitDirectory Utility
.
- If your security settings initially required you to click on the padlock for
System Preferences
, click on it again to lock the preferences.
- Close
System Preferences
.
Import certificates to smart card
The user's key pair and certificate need to be transferred to the smart card's 9a slot (authentication). See your smart card's manufacturer documentation on how to do this.
For the Yubikey 5 NFC used to test these instructions, the following was done:
Open a shell on your Samba AD DC and proceed with the instructions. The command is for Debian, run as the root user.
# openssl pkcs12 -in /root/CA/certs/sambauser.cert.pem -inkey /root/CA/private/sambauser.key.pem -export -out sambauser.p12
Transfer the sambauser.p12
file to a computer with YubiKey Manager (ykman) CLI installed and the smart card connected.
Get the smart card's serial number. This isn't necessary, but it makes sure that the correct YubiKey is being addressed:
# ykman list --serials
In the following commands the serial number 0000000
is used and needs to be substituted. The -P
switch defines the smart card's PIN, here the default 123456
is used.
# ykman --device 0000000 piv keys import -P 123456 9a /path/to/sambauser.p12
# ykman --device 0000000 piv certificates import -P 123456 -v 9a /path/to/sambauser.p12
Login with smart card
Occasionally, there can be some delay before macOS is ready to use network accounts, in which case, at the login screen, a red light appears in the top-right corner of the screen, and will go away when macOS is ready. Additionally, sometimes the Smart Card needs to be removed and reconnected to be recognised.
At the login screen, connect the smart card to the macOS client.
Your user should be recognised, allowing for the entry of the smart card's PIN to log in to the domain.
Enter your smart card's PIN, a dialog box will appear asking to create a mobile account, click the Create Now
button.
Done!
Side note: Further configuration options
Several options exist both for smart card login and for domain login on macOS clients, such as domain password policies or automatically enabling the screen saver on smart card removal.
For more information, see the following Apple guides:
- Directory Utility User Guide
- Apple Platform Deployment: Smart card integration
- Apple Platform Deployment: Directory Service MDM payload settings