- freeipa-samba-user.sh - freeipa-service-ntlm.sh - freeipa-service-password.sh
398 lines
20 KiB
Markdown
398 lines
20 KiB
Markdown
FreeIPA Scripts
|
||
===============
|
||
This repository contains a small collection of scripts written to migrate my
|
||
existing LDAP/DNS setup (MacOS Server) to [FreeIPA](https://www.freeipa.org)
|
||
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](https://gitlab.lindenaar.net/scripts/freeipa)
|
||
|
||
Copyright (c) 2018 - 2019 Frederik Lindenaar. free for distribution under the
|
||
GNU General Public License, see [below](#license)
|
||
|
||
Contents
|
||
========
|
||
This repository contains the following scripts:
|
||
* [freeipa-dns.py](#freeipadns)
|
||
is a script providing functionality not available in FreeIPA itself to
|
||
migrate/synchronize and maintain DNS zones in FreeIPA
|
||
* [freeipa-letsencrypt.sh](#freeipaletsencrypt)
|
||
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](#setdnssource)
|
||
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](#users2freeipa)
|
||
is a migration script to transfer/synchronize LDAP users to/with FreeIPA
|
||
* [freeipa-service-password.sh](#freeipaservicepassword)
|
||
is a script to create a service account and (re)set it's password
|
||
* [freeipa-service-ntlm.sh](#freeipaservicentlm)
|
||
is a script to grant a service account access to NTLM password attributes
|
||
* [freeipa-samba-user.sh](freeipasambauser)
|
||
is a script to extend users to a sambaSAMAccount for Samba compatibility
|
||
|
||
|
||
<a name=freeipadns>freeipa-dns.py</a>
|
||
-------------------------------------
|
||
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](https://docs.pagure.org/bind-dyndb-ldap/Migration.html)
|
||
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```
|
||
|
||
|
||
<a name=freeipaletsencrypt>freeipa-letsencrypt.sh</a>
|
||
-----------------------------------------------------
|
||
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](https://github.com/freeipa/freeipa-letsencrypt) and
|
||
[antevens'](https://github.com/antevens/letsencrypt-freeipa) 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.
|
||
|
||
|
||
<a name=setdnssource>set-dns-source.sh</a>
|
||
------------------------------------------
|
||
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```
|
||
|
||
|
||
|
||
<a name=users2freeipa>users2freeipa.py</a>
|
||
------------------------------------------
|
||
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](https://www.freeipa.org/page/NIS_accounts_migration_preserving_Passwords)
|
||
page on migrating NIS passwords and [this](https://pagure.io/freeipa/issue/4732)
|
||
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```
|
||
|
||
|
||
<a name=freeipaservicepassword>freeipa-service-password.sh</a>
|
||
--------------------------------------------------------------
|
||
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.
|
||
|
||
|
||
<a name=freeipaservicentlm>freeipa-service-ntlm.sh</a>
|
||
------------------------------------------------------
|
||
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](freeipasambauser). 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](#freeipaservicepassword) 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|
|
||
|
||
|
||
<a name=freeipasambauser>freeipa-samba-user.sh</a>
|
||
--------------------------------------------------
|
||
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](#freeipaservicepassword)) with access to the NTLM
|
||
password attributes (setup with [freeipa-service-ntlm.sh](#freeipaservicentlm)).
|
||
This script was written to support integration with Synology DSM (see also this
|
||
[blog post](https://frederik.lindenaar.nl/2019/07/14/integrating-synology-ds-with-freeipa.html))
|
||
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 |
|
||
|
||
|
||
<a name="license">License</a>
|
||
-----------------------------
|
||
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/>.
|
||
|