Archived
1
0

fixed small issue in freeipa-dns (override check not working)

updated README - added clarification on password migration being limited
adding first version of freeipa-letsencrypt.sh (fixes #1)
This commit is contained in:
2018-09-30 00:43:02 +02:00
parent 5df784602e
commit 02d0b22561
3 changed files with 189 additions and 2 deletions

View File

@@ -24,6 +24,9 @@ This repository contains the following scripts:
* [freeipa-dns.py](#freeipadns) * [freeipa-dns.py](#freeipadns)
is a script providing functionality not available in FreeIPA itself to is a script providing functionality not available in FreeIPA itself to
migrate/synchronize and maintain DNS zones in FreeIPA 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)
<a name=users2freeipa>users2freeipa.py</a> <a name=users2freeipa>users2freeipa.py</a>
@@ -60,6 +63,14 @@ This will also install the OpenDirectory-specific schema customization, create
groups and copy group memberships, copy usuable passwords and ensure that all groups and copy group memberships, copy usuable passwords and ensure that all
users have a password (storing generated passwords to ```passwords.txt```) 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 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 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 users. Best is to start with a single user and add that as a stage user (please
@@ -160,6 +171,54 @@ 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``` 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 (*) |
| DNSALTNAMES | certificate DNS names | host's principalnames (*) |
| DOMAIN | Let's Encrypt challenge DNS zone | {DNS name's domain} (**) |
| 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 |
(*) obtained from the FreeIPA server record looked up based on ${HOSTNAME}
(**) 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="license">License</a> <a name="license">License</a>
----------------------------- -----------------------------
These scripts, documentation & configration examples are free software: you can These scripts, documentation & configration examples are free software: you can

View File

@@ -378,7 +378,7 @@ def reverseptr(api, args):
if currrev == recordname: if currrev == recordname:
logger.debug('no update for %s (%s) in %s', logger.debug('no update for %s (%s) in %s',
reventry, recordname, revzone) reventry, recordname, revzone)
elif currrev and not args.overwrite: elif currrev and not args.override:
logger.warn('not updating %s (%s) in %s pointing to' logger.warn('not updating %s (%s) in %s pointing to'
' %s', reventry, recordname, revzone, currrev) ' %s', reventry, recordname, revzone, currrev)
else: else:
@@ -588,7 +588,7 @@ if __name__ == '__main__':
args.func(api, args) args.func(api, args)
exit(0) exit(0)
except DNSException as e: except DNSException as e:
logger.critical("Domain %s cannot be downloaded,%s", domain, e) logger.critical("Domain cannot be downloaded: %s", e)
except AuthenticationError: except AuthenticationError:
logger.critical("Unable to authenticate to FreeIPA, make sure you have a valid Kerberos ticket!") logger.critical("Unable to authenticate to FreeIPA, make sure you have a valid Kerberos ticket!")
except PublicError as e: except PublicError as e:

128
freeipa-letsencrypt.sh Executable file
View File

@@ -0,0 +1,128 @@
#!/bin/bash -e
#
# freeipa-letsencrypt.sh - script to setup Let's Encrypt's Certbot for FreeIPA
#
# Version 1.0, latest version, documentation and bugtracker available at:
# https://gitlab.lindenaar.net/scripts/freeipa
#
# Copyright (c) 2018 Frederik Lindenaar
#
# This script is free software: you can redistribute and/or modify it under the
# terms of version 3 of the GNU General Public License as published by the Free
# Software Foundation, or (at your option) any later version of the license.
#
# This script is 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, visit <http://www.gnu.org/licenses/> to download it.
# Sanity checks, ensure we have a valid Kerberos ticket, current host is a
# FreeIPA server, certbot is installed and that we can run priviliged commands
die() { echo $* >&2; exit 1; }
if ! klist -s; then
die no valid Kerberos ticket, please login to FreeIPA using kinit first
elif ! ipa server-show ${HOSTNAME:=$(hostname --fqdn)} > /dev/null; then
die this script should be run on an active IPA server
elif ! which certbot > /dev/null; then
die this script requires Certbot to be installed, please install that first
elif [ $(id -u) == 0 ]; then
unset SUDO
elif ! ${SUDO:=sudo} -v; then
die Error: this script must be run by root and $SUDO does not seem to work
else
$SUDO kinit -k
fi
# Set KRB5CCNAME to ensure the current ticket cache will be used
KRB5CCNAME=${KRB5CCNAME:-$(klist -l | head -3 | tail -1 | cut -d\ -f2-)}
# Ensure the user consents with changing his system.
if tty > /dev/null; then
cat << EOT
This script modifies this host's FreeIPA setup so that its web interface will
use a Let's Encrypt certificate and will automatically renew that when needed.
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:=letsencrypt/$(
ipa host-show $HOSTNAME --raw | fgrep "krbcanonicalname: host/" | cut -d/ -f2)}
4. Allow letsencrypt host service to manage DNS entries
5. Register with Let's encrypt as: ${EMAIL:=hostmaster@${HOSTNAME#*.}}
6. Request a Let's Encrypt SSL certificate for: ${CERTNAME:=$(ipa host-show $HOSTNAME --raw | fgrep "krbcanonicalname: host/" | cut -d/ -f2 | cut -d@ -f1)}
with DNS Alternative names: ${DNSALTNAMES:=$(ipa host-show $HOSTNAME --raw | fgrep "krbprincipalname: host/" | cut -d/ -f2 | cut -d@ -f1 | paste -sd,)}
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.
EOT
while ! [[ "${REPLY:-}" =~ ^[YyNn]$ ]]; do
echo
read -rp "Please confirm these changes should be applied (y/n): " -n 1
done
echo
[[ "${REPLY}" =~ ^[Nn]$ ]] && die aborted
fi
echo
echo Download and importing Let\'s Encrypt certificates, this may take a while
declare -A LETSENCRYPTCERTS=(
[ISRGRootCAX1]=https://letsencrypt.org/certs/isrgrootx1.pem
[LetsEncryptX3]=https://letsencrypt.org/certs/letsencryptauthorityx3.pem
)
for certname in ${!LETSENCRYPTCERTS[@]}; do
certfile=$(mktemp -u ${TMPDIR:-/tmp}/$0.XXXXXXX.cert)
curl -s "${LETSENCRYPTCERTS[$certname]}" -o $certfile
$SUDO ipa-cacert-manage install $certfile -n "$certname" -t C,,
rm -f $certfile
done
$SUDO ipa-certupdate
echo
if ! ipa role-show "DNS Administrator" > /dev/null 2>&1; then
echo Creating DNS Administrator role
ipa role-add "DNS Administrator"
ipa role-add-privilege "DNS Administrator" --privileges="DNS Administrators"
else
echo DNS Administrator role already exists
fi
echo
if ! ipa service-show "$SERVICE" > /dev/null 2>&1; then
echo Add service user $SERVICE
ipa service-add "$SERVICE"
ipa role-add-member "DNS Administrator" --services="$SERVICE"
else
echo Service user $SERVICE already exists
fi
echo
if [ ! -f "${KEYTAB:=/etc/letsencrypt/keytab}" ]; then
echo creating keytab file $KEYTAB
$SUDO ipa-getkeytab -p "$SERVICE" -k "$KEYTAB"
else
echo not touching existing keytab file $KEYTAB
fi
echo
echo Requesting Let\'s Encrypt SSL certificate and setup renewals
$SUDO certbot certonly --expand --manual --preferred-challenges dns \
--manual-public-ip-logging-ok --agree-tos --email "${EMAIL}" \
--cert-name ${HOSTNAME} --domains "${DNSALTNAMES}" \
--pre-hook "kinit -k -t $KEYTAB \"$SERVICE\"" --post-hook "kdestroy" \
--manual-auth-hook "ipa dnsrecord-add ${DOMAIN:-\${CERTBOT_DOMAIN#*.\}}. _acme-challenge.\${CERTBOT_DOMAIN}. \"--txt-rec=\${CERTBOT_VALIDATION}\"; sleep 3" \
--manual-cleanup-hook "ipa dnsrecord-del ${DOMAIN:-\${CERTBOT_DOMAIN#*.\}}. _acme-challenge.\${CERTBOT_DOMAIN}. --del-all" \
--deploy-hook 'echo | ipa-server-certinstall --http "${RENEWED_LINEAGE}/fullchain.pem" "${RENEWED_LINEAGE}/privkey.pem" --dirman-password="" --pin="" && service httpd restart'
echo
echo Enabling Certbot package\'s renewal timer
$SUDO systemctl enable --now certbot-renew.timer
cat << EOT
FreeIPA was successfully setup to use a Let\'s Encrypt certificate for its web
interface. This certificate will be renewed automatically when needed.
EOT