Commit 3470ed2dcf8c31dc3103a271e828522a36a85b61

Authored by Frederik Lindenaar
1 parent 63e71697

Added 3 additional scripts (refer to README.md for what they do)

- freeipa-samba-user.sh
  - freeipa-service-ntlm.sh
  - freeipa-service-password.sh
README.md
@@ -10,11 +10,17 @@ between an existing situation and FreeIPA and are safe to run multiple times. @@ -10,11 +10,17 @@ between an existing situation and FreeIPA and are safe to run multiple times.
10 As side-effect, this also makes them suitable to support a gradual migration 10 As side-effect, this also makes them suitable to support a gradual migration
11 over time (where a source system is still in production until final cut-over) 11 over time (where a source system is still in production until final cut-over)
12 12
  13 +Please note that these scripts are intended to run on the FreeIPA server and
  14 +require a valid (admin) kerberos ticket, which can be obtained with:
  15 +```
  16 +kinit admin
  17 +```
  18 +
13 The latest versions, documentation and a bug tracker are available on my 19 The latest versions, documentation and a bug tracker are available on my
14 [GitLab instance](https://gitlab.lindenaar.net/scripts/freeipa) 20 [GitLab instance](https://gitlab.lindenaar.net/scripts/freeipa)
15 21
16 -Copyright (c) 2018 Frederik Lindenaar. free for distribution under the GNU  
17 -General Public License, see [below](#license) 22 +Copyright (c) 2018 - 2019 Frederik Lindenaar. free for distribution under the
  23 +GNU General Public License, see [below](#license)
18 24
19 Contents 25 Contents
20 ======== 26 ========
@@ -30,6 +36,12 @@ This repository contains the following scripts: @@ -30,6 +36,12 @@ This repository contains the following scripts:
30 around for bind-dyndb-ldap plugin not supporting bind's ```notify-source``` 36 around for bind-dyndb-ldap plugin not supporting bind's ```notify-source```
31 * [users2freeipa.py](#users2freeipa) 37 * [users2freeipa.py](#users2freeipa)
32 is a migration script to transfer/synchronize LDAP users to/with FreeIPA 38 is a migration script to transfer/synchronize LDAP users to/with FreeIPA
  39 + * [freeipa-service-password.sh](#freeipaservicepassword)
  40 + is a script to create a service account and (re)set it's password
  41 + * [freeipa-service-ntlm.sh](#freeipaservicentlm)
  42 + is a script to grant a service account access to NTLM password attributes
  43 + * [freeipa-samba-user.sh](freeipasambauser)
  44 + is a script to extend users to a sambaSAMAccount for Samba compatibility
33 45
34 46
35 <a name=freeipadns>freeipa-dns.py</a> 47 <a name=freeipadns>freeipa-dns.py</a>
@@ -133,7 +145,8 @@ This script will ensure the necessary setup is in place so that Certbot (EFF&#39;s @@ -133,7 +145,8 @@ This script will ensure the necessary setup is in place so that Certbot (EFF&#39;s
133 certificate request script for Let's Encrypt) will work with FreeIPA for DNS 145 certificate request script for Let's Encrypt) will work with FreeIPA for DNS
134 challenges and and instructs it to deploy new certificates for FreeIPA's web 146 challenges and and instructs it to deploy new certificates for FreeIPA's web
135 interface. Before writing this script I looked at available options, especially 147 interface. Before writing this script I looked at available options, especially
136 -[freeipa-letsencrypt](https://github.com/freeipa/freeipa-letsencrypt) and [antevens'](https://github.com/antevens/letsencrypt-freeipa) implementation but 148 +[freeipa-letsencrypt](https://github.com/freeipa/freeipa-letsencrypt) and
  149 +[antevens'](https://github.com/antevens/letsencrypt-freeipa) implementation but
137 decided to take a slightly different approach where Certbot does all the work 150 decided to take a slightly different approach where Certbot does all the work
138 and the setup script will only ensure that the environment is prepared and that 151 and the setup script will only ensure that the environment is prepared and that
139 Certbot is initially instructed correctly. This allows to fully tie-in with how 152 Certbot is initially instructed correctly. This allows to fully tie-in with how
@@ -160,7 +173,7 @@ by setting one of the following environment variables: @@ -160,7 +173,7 @@ by setting one of the following environment variables:
160 |-------------|------------------------------------|---------------------------| 173 |-------------|------------------------------------|---------------------------|
161 | CERTNAME | certificate hostname, | host's canonicalname (1) | 174 | CERTNAME | certificate hostname, | host's canonicalname (1) |
162 | DNSALTNAMES | certificate DNS names | host's principalnames (1) | 175 | DNSALTNAMES | certificate DNS names | host's principalnames (1) |
163 -| DOMAIN | Let's Encrypt challenge DNS zone | {DNS name's domain} (2) | 176 +| DOMAIN | Let's Encrypt challenge DNS zone | {DNS name's domain} (2) |
164 | EMAIL | administrator's e-mail address | hostmaster@{domain} | 177 | EMAIL | administrator's e-mail address | hostmaster@{domain} |
165 | HOSTNAME | FreeIPA server's hostname | `hostname --fqdn` | 178 | HOSTNAME | FreeIPA server's hostname | `hostname --fqdn` |
166 | KEYTAB | Let'sEncrypt service's keytab file | /etc/letsencrypt/keytab | 179 | KEYTAB | Let'sEncrypt service's keytab file | /etc/letsencrypt/keytab |
@@ -250,6 +263,123 @@ as FreeIPA does not yet support that) and use an ID View to store legacy data. @@ -250,6 +263,123 @@ as FreeIPA does not yet support that) and use an ID View to store legacy data.
250 For all available command-line options, run ```users2freeipa.py -h``` 263 For all available command-line options, run ```users2freeipa.py -h```
251 264
252 265
  266 +<a name=freeipaservicepassword>freeipa-service-password.sh</a>
  267 +--------------------------------------------------------------
  268 +This script sets up a service under a host (creating both if needed) so that it
  269 +can use an LDAP simple bind for authentication. Although it is straightforward
  270 +to setup a host and service account in FreeIPA using the web interface, this
  271 +will not allow it to perform an LDAP simple bind (without requiring Kerberos).
  272 +For this, a direct change to the LDAP database is required to extend the service
  273 +principal object and make it an ```simpleSecurityObject``` with a password. This
  274 +script accepts a hostname and one or more services and should be run like:
  275 +~~~
  276 +./freeipa-service-password.sh <hostname> <service> [<service>]
  277 +~~~
  278 +
  279 +As it always sets the password this script can be used for initial setup as well
  280 +as a reset of a service password. It performs the following actions:
  281 + * Creates the host in FreeIPA (if it does not exists)
  282 + When creating a new host it scans its SSH key and stores this in FreeIPA
  283 + * Creates each service under the host in FreeIPA (if it does not exists)
  284 + * (Re)sets each serviceโ€™s LDAP password to a long generated random password
  285 +
  286 +When done it prints the services bind DN and generated password for later use.
  287 +
  288 +
  289 +<a name=freeipaservicentlm>freeipa-service-ntlm.sh</a>
  290 +------------------------------------------------------
  291 +This script grants a service under a host access to the LDAP attributes required
  292 +to perform NLTM authentication. It sets up the necessary privilege, permission
  293 +and a role to grant the rights (if necessary) and then assigns the role to the
  294 +service on the host as specified on the command line. for this to work, Active
  295 +Directory domain trust support must have been enabled with the command:
  296 +~~~
  297 +sudo ipa-adtrust-install --add-sid
  298 +~~~
  299 +(the ```--addsid``` parameter is required to convert existing users).
  300 +
  301 +Please note that for the necessary attributes to become available, users *must*
  302 +change their password after enabling Active Directoy domain support as FreeIPA
  303 +only maintains the necessary attributes after the user object has been modified.
  304 +
  305 +Running this command will make the ```ipNTHash``` attribute available with the
  306 +necessary hash to perform NTLM authentication. Depending on whether the client
  307 +implementation supports mapping the attribute it is sufficient to configure it
  308 +to use this attribute or require to migrate users to the Samba schema with
  309 +[freeipa-samba-user.sh](freeipasambauser). To use the script execute:
  310 +~~~
  311 +./freeipa-service-ntlm.sh <hostname> <service> [<service>]
  312 +~~~
  313 +The specified service principals must already exist (they can be created using
  314 +[freeipa-service-password.sh](#freeipaservicepassword) or manually).
  315 +
  316 +The script is built to auto-configure though some settings can be overridden by
  317 +setting one of the following environment variables:
  318 +
  319 +| Variable | Description | Default value |
  320 +|-----------|-------------------------|----------------------------------------|
  321 +| HOST | Service host hostname | 1st command line parameter |
  322 +| HOSTNAME | FreeIPA server hostname | `hostname --fqdn` |
  323 +| PERM_NAME | Name of permission | Read Samba NTLM RC4 Password Hash attribute |
  324 +| PRIV_NAME | Name of privilege | Samba (NTLM) RC4 Password Hash Access |
  325 +| ROLE_NAME | Name of role | Samba/NTLM Authenticator |
  326 +
  327 +The description of the privilege / role creates can be changed through:
  328 +| Variable | Default value |
  329 +|----------------|-------------------------------------------------------------|
  330 +|PRIV_DESCRIPTION|Perform Samba NTLM authentication using the RC4 password Hash|
  331 +|ROLE_DESCRIPTION|Perform Samba (NTLM) Authentication using the RC4 Password hash|
  332 +
  333 +
  334 +<a name=freeipasambauser>freeipa-samba-user.sh</a>
  335 +--------------------------------------------------
  336 +This script adds the ```sambaSAMAccount``` objectclass to specified users so
  337 +that they can with Samba / NTLM. For everything to work, the Samba server must
  338 +login with a service account that has a simple password (setup with
  339 +[freeipa-service-password.sh](#freeipaservicepassword)) with access to the NTLM
  340 +password attributes (setup with [freeipa-service-ntlm.sh](#freeipaservicentlm)).
  341 +This script was written to support integration with Synology DSM (see also this
  342 +[blog post](https://frederik.lindenaar.nl/2019/07/14/integrating-synology-ds-with-freeipa.html))
  343 +but should also work for other Samba servers (please raise an issue in case it
  344 +doesn't work). I found that FreeIPA will maintain and expose required attributes
  345 +for NTLM authentication (```sambaNTPassword``` and ```sambaPwdLastSet```) when
  346 +Active Directory domain trust support has been enabled with the command:
  347 +~~~
  348 +sudo ipa-adtrust-install --add-sid
  349 +~~~
  350 +(the ```--addsid``` parameter is required to convert existing users).
  351 +
  352 +To use the script to migrate all users (except admin) run (the backslash is
  353 +needed to avoid shell expansion of * as parameter):
  354 +~~~
  355 +./freeipa-service-password.sh \*
  356 +~~~
  357 +
  358 +Besides a single * the script also accepts the login of one or more users to
  359 +migrate as parameter. To explicitly migrate admin - excluded with * - run:
  360 +~~~
  361 +./freeipa-samba-user.sh admin
  362 +~~~
  363 +
  364 +The script will only migrate users that are not yet a ```sambaSAMAccount``` so
  365 +it can be run safely multiple times or at set intervals from cron (additional
  366 +work is required to make that work though as it will need a valid Kerberos
  367 +ticket from a keytab file for that).
  368 +
  369 +Please note that for the necessary attributes to become available, users *must*
  370 +change their password after being converted ```sambaSAMAccount``` as FreeIPA
  371 +only maintains the necessary attributes after the user object has been modified.
  372 +
  373 +The script is built to auto-configure though some settings can be overridden by
  374 +setting one of the following environment variables:
  375 +
  376 +| Variable | Description | Default value |
  377 +|-------------|------------------------------------|---------------------------|
  378 +| HOST | Service host hostname | 1st command line parameter|
  379 +| HOSTNAME | FreeIPA server's hostname | `hostname --fqdn` |
  380 +| SAMBADOMAIN | Samba (Windows) domain name | FreeIPA Kerberos realm |
  381 +
  382 +
253 <a name="license">License</a> 383 <a name="license">License</a>
254 ----------------------------- 384 -----------------------------
255 These scripts, documentation & configration examples are free software: you can 385 These scripts, documentation & configration examples are free software: you can
freeipa-samba-user.sh 0 โ†’ 100755
  1 +#!/bin/bash -e
  2 +#
  3 +# freeipa-samba-user.sh - extend existing user(s) with sambaSAMAccount
  4 +#
  5 +# Version 1.0, latest version, documentation and bugtracker available at:
  6 +# https://gitlab.lindenaar.net/scripts/freeipa
  7 +#
  8 +# Copyright (c) 2019 Frederik Lindenaar
  9 +#
  10 +# This script is free software: you can redistribute and/or modify it under the
  11 +# terms of version 3 of the GNU General Public License as published by the Free
  12 +# Software Foundation, or (at your option) any later version of the license.
  13 +#
  14 +# This script is distributed in the hope that it will be useful but WITHOUT ANY
  15 +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  16 +# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  17 +#
  18 +# You should have received a copy of the GNU General Public License along with
  19 +# this program. If not, visit <http://www.gnu.org/licenses/> to download it.
  20 +
  21 +die() { echo $* >&2; exit 1; }
  22 +
  23 +# Exit if hostname not provided
  24 +if [ $# -lt 1 ]; then
  25 + die "Usage: `basename $0` <user> [<user> ...]"
  26 +fi
  27 +
  28 +# Sanity checks, ensure we have a valid Kerberos ticket and run on FreeIPA server
  29 +if ! klist -s; then
  30 + die "no valid Kerberos ticket, please login to FreeIPA using kinit first"
  31 +elif ! ipa server-show ${HOSTNAME:=$(hostname --fqdn)} > /dev/null; then
  32 + die "this script should be run on an active IPA server"
  33 +fi
  34 +
  35 +# Generate the LDAP User filter, !admin if parameter is * else a list of users
  36 +if [ $# == 1 -a "$1" == "*" ]; then
  37 + USERFILTER='(!(uid=admin))'
  38 +else
  39 + USERS="$*"
  40 + USERFILTER="(|(uid=${USERS// /)(uid=}))"
  41 +fi
  42 +
  43 +# Lookup the Samba Domain - equal to the Kerberos REALM by default
  44 +: ${SAMBADOMAIN:=$(ipa host-show $HOSTNAME --raw | fgrep "krbcanonicalname: host/" | cut -d@ -f2)}
  45 +
  46 +# Lookup the users not yet converted and process each of them
  47 +declare -A params=( )
  48 +ldapsearch -QLLL "(&${USERFILTER}(objectClass=ipantuserattrs)(!(objectClass=sambaSamAccount)))" dn uid ipaNTSecurityIdentifier | while read key value; do
  49 + # If we're at an empty line it's the end of the record, perform the change
  50 + if [ -z "$key" ]; then
  51 + if ldapmodify -Q > /dev/null 2>&1 <<EOLDIF; then
  52 +dn: ${params[dn]}
  53 +changetype: modify
  54 +add: objectClass
  55 +objectClass: sambaSamAccount
  56 +-
  57 +add: sambaSID
  58 +sambaSID: ${params[ipaNTSecurityIdentifier]}
  59 +-
  60 +add: sambaAcctFlags
  61 +sambaAcctFlags: [U ]
  62 +-
  63 +add: sambaDomainName
  64 +sambaDomainName: ${SAMBADOMAIN}
  65 +EOLDIF
  66 + echo "successfully updated user ${params[uid]}"
  67 + else
  68 + die "failed to update user ${params[uid]}, aborting!"
  69 + fi
  70 + declare -A params=( )
  71 + else # we got another attibute, store it for later processing
  72 + params[${key/:/}]="$value"
  73 + fi
  74 +done
  75 +
freeipa-service-ntlm.sh 0 โ†’ 100755
  1 +#!/bin/bash -e
  2 +#
  3 +# freeipa-service-ntlm.sh - grant host service access to NTLM Password Hash
  4 +#
  5 +# Version 1.0, latest version, documentation and bugtracker available at:
  6 +# https://gitlab.lindenaar.net/scripts/freeipa
  7 +#
  8 +# Copyright (c) 2019 Frederik Lindenaar
  9 +#
  10 +# This script is free software: you can redistribute and/or modify it under the
  11 +# terms of version 3 of the GNU General Public License as published by the Free
  12 +# Software Foundation, or (at your option) any later version of the license.
  13 +#
  14 +# This script is distributed in the hope that it will be useful but WITHOUT ANY
  15 +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  16 +# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  17 +#
  18 +# You should have received a copy of the GNU General Public License along with
  19 +# this program. If not, visit <http://www.gnu.org/licenses/> to download it.
  20 +
  21 +die() { echo $* >&2; exit 1; }
  22 +
  23 +# Exit if hostname not provided
  24 +if [ $# -lt 2 ]; then
  25 + die "Usage: `basename $0` <hostname> <service> [<service> ...]"
  26 +fi
  27 +
  28 +# Sanity checks, ensure we have a valid Kerberos ticket and run on FreeIPA server
  29 +if ! klist -s; then
  30 + die "no valid Kerberos ticket, please login to FreeIPA using kinit first"
  31 +elif ! ipa server-show ${HOSTNAME:=$(hostname --fqdn)} > /dev/null; then
  32 + die "this script should be run on an active IPA server"
  33 +fi
  34 +
  35 +# Set parameters
  36 +: ${HOST:=$1}
  37 +shift
  38 +: ${ROLE_NAME:=Samba/NTLM Authenticator}
  39 +: ${ROLE_DESCRIPTION:=Perform Samba (NTLM) Authentication using the RC4 Password hash}
  40 +: ${PRIV_NAME:=Samba (NTLM) RC4 Password Hash Access}
  41 +: ${PRIV_DESCRIPTION:=Perform Samba NTLM authentication using the RC4 password Hash}
  42 +: ${PERM_NAME:=Read Samba NTLM RC4 Password Hash attribute}
  43 +
  44 +
  45 +if ! ipa host-show "$HOST" > /dev/null 2>&1; then
  46 + die "host $HOST does not exist, aborting!"
  47 +fi
  48 +
  49 +
  50 +if ipa role-add "$ROLE_NAME" --desc="$ROLE_DESCRIPTION" > /dev/null 2>&1; then
  51 + echo created role $ROLE_NAME
  52 + if ipa privilege-add "$PRIV_NAME" --desc="$PRIV_DESCRIPTION" > /dev/null 2>&1; then
  53 + echo created privilege $PRIV_NAME
  54 + if ipa permission-add "$PERM_NAME" --attrs=sambaNTPassword --attrs=sambaPwdLastSet --attrs=sambaSID --attrs=sambaAcctFlags --attrs=sambaDomainName --type=user --right=read --right=compare > /dev/null 2>&1; then
  55 + echo created permission $PERM_NAME
  56 + else
  57 + echo permission $PERM_NAME exists
  58 + fi
  59 + if ! ipa privilege-add-permission "$PRIV_NAME" --permissions="$PERM_NAME" > /dev/null 2>&1; then
  60 + die "adding permission to privileges failed, aborting!"
  61 + fi
  62 + else
  63 + echo privilege $PRIV_NAME exists
  64 + fi
  65 + if ! ipa role-add-privilege "$ROLE_NAME" --privileges="$PRIV_NAME" > /dev/null 2>&1; then
  66 + die "adding privilege to role failed, aborting!"
  67 + fi
  68 +fi
  69 +
  70 +
  71 +for service in $*
  72 +do
  73 + if ipa service-show "$service/$HOST" > /dev/null 2>&1; then
  74 + if ipa role-add-member "$ROLE_NAME" --services="$service/$HOST" > /dev/null 2>&1; then
  75 + echo granted service $service/$HOST the role $ROLE_NAME
  76 + else
  77 + echo service $service/$HOST already had role $ROLE_NAME
  78 + fi
  79 + else
  80 + echo "service $service/$HOST does not exist, skipping"
  81 + fi
  82 +done
  83 +
freeipa-service-password.sh 0 โ†’ 100755
  1 +#!/bin/bash -e
  2 +#
  3 +# freeipa-service-password.sh - add/set host service login password
  4 +#
  5 +# Version 1.0, latest version, documentation and bugtracker available at:
  6 +# https://gitlab.lindenaar.net/scripts/freeipa
  7 +#
  8 +# Copyright (c) 2019 Frederik Lindenaar
  9 +#
  10 +# This script is free software: you can redistribute and/or modify it under the
  11 +# terms of version 3 of the GNU General Public License as published by the Free
  12 +# Software Foundation, or (at your option) any later version of the license.
  13 +#
  14 +# This script is distributed in the hope that it will be useful but WITHOUT ANY
  15 +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  16 +# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  17 +#
  18 +# You should have received a copy of the GNU General Public License along with
  19 +# this program. If not, visit <http://www.gnu.org/licenses/> to download it.
  20 +
  21 +die() { echo $* >&2; exit 1; }
  22 +
  23 +# Exit if hostname not provided
  24 +if [ $# -lt 2 ]; then
  25 + die "Usage: `basename $0` <hostname> <service> [<service> ...]"
  26 +fi
  27 +
  28 +# Sanity checks, ensure we have a valid Kerberos ticket and run on FreeIPA server
  29 +if ! klist -s; then
  30 + die "no valid Kerberos ticket, please login to FreeIPA using kinit first"
  31 +elif ! ipa server-show ${HOSTNAME:=$(hostname --fqdn)} > /dev/null; then
  32 + die "this script should be run on an active IPA server"
  33 +fi
  34 +
  35 +# Set parameters from command line
  36 +: ${HOST:=$1}
  37 +shift
  38 +
  39 +if ! ipa host-show "$HOST" > /dev/null 2>&1; then
  40 + echo Fetching information for $HOST
  41 + SSHKEYS=($(ssh-keyscan $HOST 2>/dev/null | cut -f2- -d\ | sed "s/\(.*\)/--sshpubkey='\1'/"))
  42 + echo Creating host $HOST
  43 + eval ipa host-add "$HOST" ${SSHKEYS[@]}
  44 + eval ipa host-add-principal "$HOST" $HOSTALIASES
  45 +else
  46 + echo host $HOST exists
  47 +fi
  48 +
  49 +
  50 +for service in $*
  51 +do
  52 + if ipa service-add "$service/$HOST" > /dev/null 2>&1; then
  53 + echo Created service $service/$HOST
  54 + else
  55 + echo service $service/$HOST exists
  56 + fi
  57 + service_binddn=$(ipa service-show "$service/$HOST" --raw --all | fgrep " dn: " | cut -f2 -d: | tr -d \ )
  58 + echo Service Bind DN: $service_binddn
  59 + service_bindpw=$(pwmake 128)
  60 + if ipa service-show "$service/$HOST" --all --raw | fgrep "objectClass:" | fgrep -q "simpleSecurityObject" > /dev/null 2>&1; then
  61 + echo resetting password to generated password: $service_bindpw
  62 + ldapmodify -Q > /dev/null 2>&1 <<EOLDIF
  63 +dn: $service_binddn
  64 +changetype: modify
  65 +replace: userPassword
  66 +userPassword: $service_bindpw
  67 +EOLDIF
  68 + else
  69 + echo Enabled login with generated password: $service_bindpw
  70 + ldapmodify -Q > /dev/null 2>&1 <<EOLDIF
  71 +dn: $service_binddn
  72 +changetype: modify
  73 +add: objectClass
  74 +objectClass: simpleSecurityObject
  75 +-
  76 +add: userPassword
  77 +userPassword: $service_bindpw
  78 +EOLDIF
  79 + fi
  80 +done
  81 +