Commit 02d0b225618503ff14ef20d769a3f3983b24b43a
1 parent
5df78460
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)
Showing
3 changed files
with
189 additions
and
2 deletions
README.md
... | ... | @@ -24,6 +24,9 @@ This repository contains the following scripts: |
24 | 24 | * [freeipa-dns.py](#freeipadns) |
25 | 25 | is a script providing functionality not available in FreeIPA itself to |
26 | 26 | migrate/synchronize and maintain DNS zones in FreeIPA |
27 | + * [freeipa-letsencrypt.sh](#freeipaletsencrypt) | |
28 | + is a script to setup and configure Certbot and FreeIPA to request and renew | |
29 | + use publicly verifiable Let's Encrypt certificate(s) | |
27 | 30 | |
28 | 31 | |
29 | 32 | <a name=users2freeipa>users2freeipa.py</a> |
... | ... | @@ -60,6 +63,14 @@ This will also install the OpenDirectory-specific schema customization, create |
60 | 63 | groups and copy group memberships, copy usuable passwords and ensure that all |
61 | 64 | users have a password (storing generated passwords to ```passwords.txt```) |
62 | 65 | |
66 | +Please note that migrating existing passwords from LDAP has limitations, see | |
67 | +[this](https://www.freeipa.org/page/NIS_accounts_migration_preserving_Passwords) | |
68 | +page on migrating NIS passwords and [this](https://pagure.io/freeipa/issue/4732) | |
69 | +issue reported with it. Bottom line is that (at this moment) password migration | |
70 | +is flawed and always will require manual action from the user. For this reason | |
71 | +the better alternative to set a random password and ask the user to reset the | |
72 | +password using the FreeIPA portal makes more sense. | |
73 | + | |
63 | 74 | Before running a production user migration, it is important to have FreeIPA |
64 | 75 | setup and configured correctly so that the right defaults are used for new |
65 | 76 | 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 |
160 | 171 | the available options for each commmand run ```freeipa-dns.py <command> -h``` |
161 | 172 | |
162 | 173 | |
174 | +<a name=freeipaletsencrypt>freeipa-letsencrypt.sh</a> | |
175 | +---------------------------------------------------------------- | |
176 | +This script will ensure the necessary setup is in place so that Certbot (EFF's | |
177 | +certificate request script for Let's Encrypt) will work with FreeIPA for DNS | |
178 | +challenges and and instructs it to deploy new certificates for FreeIPA's web | |
179 | +interface. Before writing this script I looked at available options, especially | |
180 | +[freeipa-letsencrypt](https://github.com/freeipa/freeipa-letsencrypt) and [antevens'](https://github.com/antevens/letsencrypt-freeipa) implementation but | |
181 | +decided to take a slightly different approach where Certbot does all the work | |
182 | +and the setup script will only ensure that the environment is prepared and that | |
183 | +Certbot is initially instructed correctly. This allows to fully tie-in with how | |
184 | +Certbot handles renews and use the Certbot package's provided method to schedule | |
185 | +these. | |
186 | + | |
187 | +The following changes will be made for this: | |
188 | + 1. Add Let's Encrypt Root and Intermediate CAs as trusted CAs | |
189 | + 2. Create DNS Administrator role in FreeIPA that can edit any DNS Record | |
190 | + 3. Create host service: ${SERVICE} | |
191 | + 4. Allow letsencrypt host service to manage DNS entries | |
192 | + 5. Register with Let's encrypt as: ${EMAIL} | |
193 | + 6. Request a Let's Encrypt SSL certificate for: ${CERTNAME} | |
194 | + with DNS Alternative names: ${DNSALTNAMES} | |
195 | + 7. install the Let's Encrypt certificate in apache as host SSL certificate, | |
196 | + storing renewal config in: /etc/letsencrypt/renewal/$HOSTNAME.conf | |
197 | + 8. configure the Fedora Certbot renew timer so that certbot is run daily to | |
198 | + renew the certificate when needed. | |
199 | + | |
200 | +The script is built to auto-configure but many of the defaults can be overridden | |
201 | +by setting one of the following environment variables: | |
202 | + | |
203 | +| Variable | Description | Default value | | |
204 | +|-------------|------------------------------------|---------------------------| | |
205 | +| CERTNAME | certificate hostname, | host's canonicalname (*) | | |
206 | +| DNSALTNAMES | certificate DNS names | host's principalnames (*) | | |
207 | +| DOMAIN | Let's Encrypt challenge DNS zone | {DNS name's domain} (**) | | |
208 | +| EMAIL | administrator's e-mail address | hostmaster@{domain} | | |
209 | +| HOSTNAME | FreeIPA server's hostname | `hostname --fqdn` | | |
210 | +| KEYTAB | Let'sEncrypt service's keytab file | /etc/letsencrypt/keytab | | |
211 | +| KRB5CCNAME | Kerberos5 cache to use for tickets | automatically determined | | |
212 | +| REPLY | when 'y' skip user confirmation | "" | | |
213 | +| SERVICE | FreeIPA service for Certbot to use | letsencrypt/canonicalname | | |
214 | +| SUDO | command to become root (if needed) | sudo | | |
215 | +| TMPDIR | Directory for temporary files | /tmp | | |
216 | + | |
217 | +(*) obtained from the FreeIPA server record looked up based on ${HOSTNAME} | |
218 | +(**) this allows to enforce the DNS zone, e.g. host.subdomain in mydomain.tld | |
219 | + | |
220 | +When things change, the script can simply be run again. | |
221 | + | |
163 | 222 | <a name="license">License</a> |
164 | 223 | ----------------------------- |
165 | 224 | These scripts, documentation & configration examples are free software: you can |
... | ... |
freeipa-dns.py
... | ... | @@ -378,7 +378,7 @@ def reverseptr(api, args): |
378 | 378 | if currrev == recordname: |
379 | 379 | logger.debug('no update for %s (%s) in %s', |
380 | 380 | reventry, recordname, revzone) |
381 | - elif currrev and not args.overwrite: | |
381 | + elif currrev and not args.override: | |
382 | 382 | logger.warn('not updating %s (%s) in %s pointing to' |
383 | 383 | ' %s', reventry, recordname, revzone, currrev) |
384 | 384 | else: |
... | ... | @@ -588,7 +588,7 @@ if __name__ == '__main__': |
588 | 588 | args.func(api, args) |
589 | 589 | exit(0) |
590 | 590 | except DNSException as e: |
591 | - logger.critical("Domain %s cannot be downloaded,%s", domain, e) | |
591 | + logger.critical("Domain cannot be downloaded: %s", e) | |
592 | 592 | except AuthenticationError: |
593 | 593 | logger.critical("Unable to authenticate to FreeIPA, make sure you have a valid Kerberos ticket!") |
594 | 594 | except PublicError as e: |
... | ... |
freeipa-letsencrypt.sh
0 โ 100755
1 | +#!/bin/bash -e | |
2 | +# | |
3 | +# freeipa-letsencrypt.sh - script to setup Let's Encrypt's Certbot for FreeIPA | |
4 | +# | |
5 | +# Version 1.0, latest version, documentation and bugtracker available at: | |
6 | +# https://gitlab.lindenaar.net/scripts/freeipa | |
7 | +# | |
8 | +# Copyright (c) 2018 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 | +# Sanity checks, ensure we have a valid Kerberos ticket, current host is a | |
22 | +# FreeIPA server, certbot is installed and that we can run priviliged commands | |
23 | +die() { echo $* >&2; exit 1; } | |
24 | +if ! klist -s; then | |
25 | + die no valid Kerberos ticket, please login to FreeIPA using kinit first | |
26 | +elif ! ipa server-show ${HOSTNAME:=$(hostname --fqdn)} > /dev/null; then | |
27 | + die this script should be run on an active IPA server | |
28 | +elif ! which certbot > /dev/null; then | |
29 | + die this script requires Certbot to be installed, please install that first | |
30 | +elif [ $(id -u) == 0 ]; then | |
31 | + unset SUDO | |
32 | +elif ! ${SUDO:=sudo} -v; then | |
33 | + die Error: this script must be run by root and $SUDO does not seem to work | |
34 | +else | |
35 | + $SUDO kinit -k | |
36 | +fi | |
37 | + | |
38 | +# Set KRB5CCNAME to ensure the current ticket cache will be used | |
39 | +KRB5CCNAME=${KRB5CCNAME:-$(klist -l | head -3 | tail -1 | cut -d\ -f2-)} | |
40 | + | |
41 | +# Ensure the user consents with changing his system. | |
42 | +if tty > /dev/null; then | |
43 | + cat << EOT | |
44 | +This script modifies this host's FreeIPA setup so that its web interface will | |
45 | +use a Let's Encrypt certificate and will automatically renew that when needed. | |
46 | +The following changes will be made for this: | |
47 | + 1. Add Let's Encrypt Root and Intermediate CAs as trusted CAs | |
48 | + 2. Create DNS Administrator role in FreeIPA that can edit any DNS Record | |
49 | + 3. Create host service: ${SERVICE:=letsencrypt/$( | |
50 | +ipa host-show $HOSTNAME --raw | fgrep "krbcanonicalname: host/" | cut -d/ -f2)} | |
51 | + 4. Allow letsencrypt host service to manage DNS entries | |
52 | + 5. Register with Let's encrypt as: ${EMAIL:=hostmaster@${HOSTNAME#*.}} | |
53 | + 6. Request a Let's Encrypt SSL certificate for: ${CERTNAME:=$(ipa host-show $HOSTNAME --raw | fgrep "krbcanonicalname: host/" | cut -d/ -f2 | cut -d@ -f1)} | |
54 | + with DNS Alternative names: ${DNSALTNAMES:=$(ipa host-show $HOSTNAME --raw | fgrep "krbprincipalname: host/" | cut -d/ -f2 | cut -d@ -f1 | paste -sd,)} | |
55 | + 7. install the Let's Encrypt certificate in apache as host SSL certificate, | |
56 | + storing renewal config in: /etc/letsencrypt/renewal/$HOSTNAME.conf | |
57 | + 8. configure the Fedora Certbot renew timer so that certbot is run daily to | |
58 | + renew the certificate when needed. | |
59 | +EOT | |
60 | + while ! [[ "${REPLY:-}" =~ ^[YyNn]$ ]]; do | |
61 | + echo | |
62 | + read -rp "Please confirm these changes should be applied (y/n): " -n 1 | |
63 | + done | |
64 | + echo | |
65 | + [[ "${REPLY}" =~ ^[Nn]$ ]] && die aborted | |
66 | +fi | |
67 | + | |
68 | +echo | |
69 | +echo Download and importing Let\'s Encrypt certificates, this may take a while | |
70 | +declare -A LETSENCRYPTCERTS=( | |
71 | + [ISRGRootCAX1]=https://letsencrypt.org/certs/isrgrootx1.pem | |
72 | + [LetsEncryptX3]=https://letsencrypt.org/certs/letsencryptauthorityx3.pem | |
73 | +) | |
74 | +for certname in ${!LETSENCRYPTCERTS[@]}; do | |
75 | + certfile=$(mktemp -u ${TMPDIR:-/tmp}/$0.XXXXXXX.cert) | |
76 | + curl -s "${LETSENCRYPTCERTS[$certname]}" -o $certfile | |
77 | + $SUDO ipa-cacert-manage install $certfile -n "$certname" -t C,, | |
78 | + rm -f $certfile | |
79 | +done | |
80 | +$SUDO ipa-certupdate | |
81 | + | |
82 | +echo | |
83 | +if ! ipa role-show "DNS Administrator" > /dev/null 2>&1; then | |
84 | + echo Creating DNS Administrator role | |
85 | + ipa role-add "DNS Administrator" | |
86 | + ipa role-add-privilege "DNS Administrator" --privileges="DNS Administrators" | |
87 | +else | |
88 | + echo DNS Administrator role already exists | |
89 | +fi | |
90 | + | |
91 | +echo | |
92 | +if ! ipa service-show "$SERVICE" > /dev/null 2>&1; then | |
93 | + echo Add service user $SERVICE | |
94 | + ipa service-add "$SERVICE" | |
95 | + ipa role-add-member "DNS Administrator" --services="$SERVICE" | |
96 | +else | |
97 | + echo Service user $SERVICE already exists | |
98 | +fi | |
99 | + | |
100 | +echo | |
101 | +if [ ! -f "${KEYTAB:=/etc/letsencrypt/keytab}" ]; then | |
102 | + echo creating keytab file $KEYTAB | |
103 | + $SUDO ipa-getkeytab -p "$SERVICE" -k "$KEYTAB" | |
104 | +else | |
105 | + echo not touching existing keytab file $KEYTAB | |
106 | +fi | |
107 | + | |
108 | +echo | |
109 | +echo Requesting Let\'s Encrypt SSL certificate and setup renewals | |
110 | +$SUDO certbot certonly --expand --manual --preferred-challenges dns \ | |
111 | + --manual-public-ip-logging-ok --agree-tos --email "${EMAIL}" \ | |
112 | + --cert-name ${HOSTNAME} --domains "${DNSALTNAMES}" \ | |
113 | + --pre-hook "kinit -k -t $KEYTAB \"$SERVICE\"" --post-hook "kdestroy" \ | |
114 | + --manual-auth-hook "ipa dnsrecord-add ${DOMAIN:-\${CERTBOT_DOMAIN#*.\}}. _acme-challenge.\${CERTBOT_DOMAIN}. \"--txt-rec=\${CERTBOT_VALIDATION}\"; sleep 3" \ | |
115 | + --manual-cleanup-hook "ipa dnsrecord-del ${DOMAIN:-\${CERTBOT_DOMAIN#*.\}}. _acme-challenge.\${CERTBOT_DOMAIN}. --del-all" \ | |
116 | + --deploy-hook 'echo | ipa-server-certinstall --http "${RENEWED_LINEAGE}/fullchain.pem" "${RENEWED_LINEAGE}/privkey.pem" --dirman-password="" --pin="" && service httpd restart' | |
117 | + | |
118 | +echo | |
119 | +echo Enabling Certbot package\'s renewal timer | |
120 | +$SUDO systemctl enable --now certbot-renew.timer | |
121 | + | |
122 | +cat << EOT | |
123 | + | |
124 | +FreeIPA was successfully setup to use a Let\'s Encrypt certificate for its web | |
125 | +interface. This certificate will be renewed automatically when needed. | |
126 | + | |
127 | +EOT | |
128 | + | |
... | ... |