README.md 20 KB

FreeIPA Scripts

This repository contains a small collection of scripts written to migrate my existing LDAP/DNS setup (MacOS Server) to FreeIPA and manage my setup afterwards. These scripts provide functionality unavailable in the FreeIPA command line tools. They use the FreeIPA API as much as possible as I didn't like the provided alternatives for migration to directly update the FreeIPA LDAP database. Most of these script / commands are meant to synchronize between an existing situation and FreeIPA and are safe to run multiple times. As side-effect, this also makes them suitable to support a gradual migration over time (where a source system is still in production until final cut-over)

Please note that these scripts are intended to run on the FreeIPA server and require a valid (admin) kerberos ticket, which can be obtained with:

kinit admin

The latest versions, documentation and a bug tracker are available on my GitLab instance

Copyright (c) 2018 - 2019 Frederik Lindenaar. free for distribution under the GNU General Public License, see below

Contents

This repository contains the following scripts:

  • freeipa-dns.py is a script providing functionality not available in FreeIPA itself to migrate/synchronize and maintain DNS zones in FreeIPA
  • freeipa-letsencrypt.sh is a script to setup and configure Certbot and FreeIPA to request and renew use publicly verifiable Let's Encrypt certificate(s)
  • set-dns-source.sh enforce the source address of outgoing DNS messages using firewalld as work around for bind-dyndb-ldap plugin not supporting bind's notify-source
  • users2freeipa.py is a migration script to transfer/synchronize LDAP users to/with FreeIPA
  • freeipa-service-password.sh is a script to create a service account and (re)set it's password
  • freeipa-service-ntlm.sh is a script to grant a service account access to NTLM password attributes
  • freeipa-samba-user.sh is a script to extend users to a sambaSAMAccount for Samba compatibility

freeipa-dns.py

This script provides functionality not provided by FreeIPA to migrate and/or synchronize / maintain DNS data in FreeIPA. Currently the following commands are implemented:

  • axfr - synchronize DNS zone(s) using a zone-xfer. Contrary to the suggested migration approach this uses the FreeIPA API to migrate or synchronize DNS zones with FreeIPA so it can also be used for running things in parallel or gradual migrations.

    for example, to migrate / synchronize fromain domain.tld from DNS server 192.168.1.53 without checking DNS overlap, issue the command:

    ./freeipa-dns.py -v axfr -T 172.1.2.53 -n -f none 192.168.1.53 domain.tld

    in addition, this will ensure zone-xfers are allowed from 172.1.2.53 and disable forwarding in FreeIPA.

  • copy - copy a DNS record in FreeIPA within or between zones for example, to copy A and AAAA from host wwww.domain.tld to the domain domain.tld itself, issue the command:

    ./freeipa-dns.py -v copy -l A AAAA wwww.domain.tld -T domain.tld
  • move - move a DNS record in FreeIPA from one one to another for example, to move host1.int in zone domain.tld to host in zone int.domain.tld issue the command:

    ./freeipa-dns.py -v move -z domain.tld host.int host.int.domain.tld
  • serial - update (set) zone serial(s) in FreeIPA, supporting both RFC1912 style serials (YYYYMMDD##) based on current date and setting the serial to a specific value. To set the serial of a zone to revision 2 of today for zones zone1.mydomain.tld and zone2.mydomain.tld, run:

    ./freeipa-dns.py -v serial -t 2 zone1.mydomain.tld zone2.mydomain.tld

    by default this command will set the serial to a larger value (which can be overridden with the -f/--force flag)

  • generate - generate number-range DNS records/attributes in FreeIPA This is meant to generate series of hosts or attributes, for example, to generate hosts dhcp-01 to dhcp-10 in zone int.mydomain.tld with ip addresses starting from 192.168.2.100 issue to command:

    ./freeipa-dns.py -v generate int.mydomain.tld dhcp-%02d -4 192.168.2.100 \
                     --auto-increment-a -n 5

    it can also be used to generate a farm of web servers in different subnets with the command:

    ./freeipa-dns.py -v generate int.mydomain.tld www -4 192.168.%d.80 -n 5
  • reverse-ptr - create/update reverse DNS (PTR) entries in FreeIPA With this command reverse-zones can be automatically maintained. it scans the zones in FreeIPA for A and AAAA records and creates the corresponding records in the in-addr.arpa and ip6.arpa zones. The reverse zones must exist, and can also be created with this command by:

    ./freeipa-dns.py -v reverse-ptr -n -p -c 10. 10.100 192.168 2001:0db8:85a3

    which will create the reverse zones for prefixes 10.* 10.100.* 192.168.* and ipv6 prefix 2001:0db8:85a3. Reverse (PTR) records will automatically be created in the correct zone with the following command:

    ./freeipa-dns.py -v reverse-ptr -a

    by default, the command will not overwrite existing records, (which can be overridden with the -o/--override flag). To force a PTR record to point to a specific host, e.g. www.mydomain.tld run the command:

    ./freeipa-dns.py -v reverse-ptr -o -z mydomain.tld -H www

for available commands run freeipa-dns.py -h and to get an overview of the available options for each commmand run freeipa-dns.py <command> -h

freeipa-letsencrypt.sh

This script will ensure the necessary setup is in place so that Certbot (EFF's certificate request script for Let's Encrypt) will work with FreeIPA for DNS challenges and and instructs it to deploy new certificates for FreeIPA's web interface. Before writing this script I looked at available options, especially freeipa-letsencrypt and antevens' implementation but decided to take a slightly different approach where Certbot does all the work and the setup script will only ensure that the environment is prepared and that Certbot is initially instructed correctly. This allows to fully tie-in with how Certbot handles renews and use the Certbot package's provided method to schedule these.

The following changes will be made for this:

  1. Add Let's Encrypt Root and Intermediate CAs as trusted CAs
  2. Create DNS Administrator role in FreeIPA that can edit any DNS Record
  3. Create host service: ${SERVICE}
  4. Allow letsencrypt host service to manage DNS entries
  5. Register with Let's encrypt as: ${EMAIL}
  6. Request a Let's Encrypt SSL certificate for: ${CERTNAME} with DNS Alternative names: ${DNSALTNAMES}
  7. install the Let's Encrypt certificate in apache as host SSL certificate, storing renewal config in: /etc/letsencrypt/renewal/$HOSTNAME.conf
  8. configure the Fedora Certbot renew timer so that certbot is run daily to renew the certificate when needed.

The script is built to auto-configure but many of the defaults can be overridden by setting one of the following environment variables:

Variable Description Default value
CERTNAME certificate hostname, host's canonicalname (1)
DNSALTNAMES certificate DNS names host's principalnames (1)
DOMAIN Let's Encrypt challenge DNS zone {DNS name's domain} (2)
EMAIL administrator's e-mail address hostmaster@{domain}
HOSTNAME FreeIPA server's hostname hostname --fqdn
KEYTAB Let'sEncrypt service's keytab file /etc/letsencrypt/keytab
KRB5CCNAME Kerberos5 cache to use for tickets automatically determined
REPLY when 'y' skip user confirmation ""
SERVICE FreeIPA service for Certbot to use letsencrypt/canonicalname
SUDO command to become root (if needed) sudo
TMPDIR Directory for temporary files /tmp

(1) obtained from the FreeIPA server record looked up based on ${HOSTNAME} (2) this allows to enforce the DNS zone, e.g. host.subdomain in mydomain.tld

When things change, the script can simply be run again.

set-dns-source.sh

FreeIPA's bind-dyndb-ldap plugin does not support bind's notify-source settings and simply uses the main address when sending DNS notifications. This breaks multi-homed setups and, in case of IPv6, even causes bind to send NOTIFY messages from the temporary IPv6 address, causing slave servers to reject them. This script will setup Source NAT in firewalld to enforce the IPv4/IPv6 address of outgoing DNS packets to ensure that DNS NOTIFYs messages will use the correct source IPv4/IPv6 address. The IPv4/IPv6 address(es) to enforce should either be provided in the environment or changed at the top of the script. In case an IPv4 address is provided, the script can figure out itself which device to use when running it, if not this should be provided as well. To install run:

sudo IPV4ADDR=192.168.0.100 IPV6ADDR=none ./set-dns-source.sh install

to remove installed rules, run with the same parameters and parameter 'remove':

sudo IPV4ADDR=192.168.0.100 IPV6ADDR=none ./set-dns-source.sh remove

and to see custom rules run: sudo firewall-cmd --direct --get-all-rules

users2freeipa.py

This script uses LDAP to obtain users from a MacOS Server (or other LDAP) server and synchronizes the results with the users registered in FreeIPA. Since it synchronizes data it is safe to run multiple times and users can be imported also as stage users initially.

The intent is to migrate user data and to not drag on a legacy setup. For this reason, the script will create new user and group IDs and not copy homedir and shell information by default. For the IDs, the legacy information can be stored in an FreeIPA ID View so it remains available, other items can be copied over using command line options. Passwords can be copied-over (if available in a usable format), and the script also supports having FreeIPA generate random passwords and store these in a file for further processing/sharing with users.

Users can be copied from an existing (generic) LDAP database and a MacOS Server OpenDirectory-flavor LDAP server. In this case, additional information (e.g. Apple's generatedUID) will be copied over as well. Please note that this does require customizing the FreeIPA LDAP schema, which the script will check for and can install (option -U). As the setup is modular it should be easy to tweak or add other migrations.

By default all users will be migrated/synchronized, but it is also possible to limit this to specific user(s) or group(s) or specifically exclude specific users or groups. An example to copy all users in the group workgroup except admin from an Apple MacOS OpenDirectory server:

./users2freeipa.py -v -O -U -c "Legacy LDAP" -g workgroup -x admin -G \
                   -P -p passwords.txt ldap://ldap.mydomain.tld

This will also install the OpenDirectory-specific schema customization, create groups and copy group memberships, copy usuable passwords and ensure that all users have a password (storing generated passwords to passwords.txt)

Please note that migrating existing passwords from LDAP has limitations, see this page on migrating NIS passwords and this issue reported with it. Bottom line is that (at this moment) password migration is flawed and always will require manual action from the user. For this reason the better alternative to set a random password and ask the user to reset the password using the FreeIPA portal makes more sense.

Before running a production user migration, it is important to have FreeIPA setup and configured correctly so that the right defaults are used for new users. Best is to start with a single user and add that as a stage user (please note that this will not yet assign userIDs, group memberships and a password as FreeIPA does not yet support that) and use an ID View to store legacy data.

For all available command-line options, run users2freeipa.py -h

freeipa-service-password.sh

This script sets up a service under a host (creating both if needed) so that it can use an LDAP simple bind for authentication. Although it is straightforward to setup a host and service account in FreeIPA using the web interface, this will not allow it to perform an LDAP simple bind (without requiring Kerberos). For this, a direct change to the LDAP database is required to extend the service principal object and make it an simpleSecurityObject with a password. This script accepts a hostname and one or more services and should be run like:

./freeipa-service-password.sh <hostname> <service> [<service>]

As it always sets the password this script can be used for initial setup as well as a reset of a service password. It performs the following actions:

  • Creates the host in FreeIPA (if it does not exists) When creating a new host it scans its SSH key and stores this in FreeIPA
  • Creates each service under the host in FreeIPA (if it does not exists)
  • (Re)sets each service’s LDAP password to a long generated random password

When done it prints the services bind DN and generated password for later use.

freeipa-service-ntlm.sh

This script grants a service under a host access to the LDAP attributes required to perform NLTM authentication. It sets up the necessary privilege, permission and a role to grant the rights (if necessary) and then assigns the role to the service on the host as specified on the command line. for this to work, Active Directory domain trust support must have been enabled with the command:

sudo ipa-adtrust-install --add-sid

(the --addsid parameter is required to convert existing users).

Please note that for the necessary attributes to become available, users must change their password after enabling Active Directoy domain support as FreeIPA only maintains the necessary attributes after the user object has been modified.

Running this command will make the ipNTHash attribute available with the necessary hash to perform NTLM authentication. Depending on whether the client implementation supports mapping the attribute it is sufficient to configure it to use this attribute or require to migrate users to the Samba schema with freeipa-samba-user.sh. To use the script execute:

./freeipa-service-ntlm.sh <hostname> <service> [<service>]

The specified service principals must already exist (they can be created using freeipa-service-password.sh or manually).

The script is built to auto-configure though some settings can be overridden by setting one of the following environment variables:

Variable Description Default value
HOST Service host hostname 1st command line parameter
HOSTNAME FreeIPA server hostname hostname --fqdn
PERM_NAME Name of permission Read Samba NTLM RC4 Password Hash attribute
PRIV_NAME Name of privilege Samba (NTLM) RC4 Password Hash Access
ROLE_NAME Name of role Samba/NTLM Authenticator

The description of the privilege / role creates can be changed through: | Variable | Default value | |----------------|-------------------------------------------------------------| |PRIV_DESCRIPTION|Perform Samba NTLM authentication using the RC4 password Hash| |ROLE_DESCRIPTION|Perform Samba (NTLM) Authentication using the RC4 Password hash|

freeipa-samba-user.sh

This script adds the sambaSAMAccount objectclass to specified users so that they can with Samba / NTLM. For everything to work, the Samba server must login with a service account that has a simple password (setup with freeipa-service-password.sh) with access to the NTLM password attributes (setup with freeipa-service-ntlm.sh). This script was written to support integration with Synology DSM (see also this blog post) but should also work for other Samba servers (please raise an issue in case it doesn't work). I found that FreeIPA will maintain and expose required attributes for NTLM authentication (sambaNTPassword and sambaPwdLastSet) when Active Directory domain trust support has been enabled with the command:

sudo ipa-adtrust-install --add-sid

(the --addsid parameter is required to convert existing users).

To use the script to migrate all users (except admin) run (the backslash is needed to avoid shell expansion of * as parameter):

./freeipa-service-password.sh \*

Besides a single * the script also accepts the login of one or more users to migrate as parameter. To explicitly migrate admin - excluded with * - run:

./freeipa-samba-user.sh admin

The script will only migrate users that are not yet a sambaSAMAccount so it can be run safely multiple times or at set intervals from cron (additional work is required to make that work though as it will need a valid Kerberos ticket from a keytab file for that).

Please note that for the necessary attributes to become available, users must change their password after being converted sambaSAMAccount as FreeIPA only maintains the necessary attributes after the user object has been modified.

The script is built to auto-configure though some settings can be overridden by setting one of the following environment variables:

Variable Description Default value
HOST Service host hostname 1st command line parameter
HOSTNAME FreeIPA server's hostname hostname --fqdn
SAMBADOMAIN Samba (Windows) domain name FreeIPA Kerberos realm

License

These scripts, documentation & configration examples are free software: you can redistribute and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This script, documenatation and configuration examples are distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, download it from http://www.gnu.org/licenses/.