mirror of
https://pagure.io/fedora-infra/ansible.git
synced 2026-07-27 00:51:39 +08:00
copr: rework letsencrypt
We need two-phase configuration for Let's Encrypt: 1. initialize; the letsencrypt automation, this is happening only once per VM (when it is spawned) 2. periodic; using certbot-renew.timer. Both those phases are now wrapped into copr/certbot role. Phase 1. needs to be done before the web-server is started (so include the role on appropriate place in the playbook), so we can do 'certbot --standalone' (bounds to port 80). Phase 2. is accomplished using the running web-server, using 'certbot renew --webroot'. If (and only if) the certificate is renewed, web server needs to be restarted (and lighttpd needs to have post-processed certificate format). So we also need the deploy hook script in hand (two actually, lighttpd/httpd) so 'certbot renew' automatically does what we expect it to do.
This commit is contained in:
@@ -29,3 +29,13 @@ csi_security_category: Moderate
|
||||
csi_primary_contact: "msuchy (mirek), frostyx, dturecek, praiskup IRC #fedora-admin, #fedora-buildsys"
|
||||
csi_purpose: Provide the testing environment of copr's backend
|
||||
csi_relationship: This host is the testing environment for the cloud infrastructure of copr's backend
|
||||
|
||||
# consumed by roles/copr/certbot
|
||||
letsencrypt:
|
||||
predefined_deploy_script: lighttpd
|
||||
certificates:
|
||||
copr-be-dev.cloud.fedoraproject.org:
|
||||
domains:
|
||||
- copr-be-dev.cloud.fedoraproject.org
|
||||
challenge_dir: /var/lib/copr/public_html
|
||||
mail: copr-devel@lists.fedorahosted.org
|
||||
|
||||
@@ -18,3 +18,13 @@ frontend_base_url: "https://copr-fe-dev.cloud.fedoraproject.org"
|
||||
dist_git_base_url: "copr-dist-git-dev.fedorainfracloud.org"
|
||||
|
||||
ansible_ifcfg_blacklist: true
|
||||
|
||||
# consumed by roles/copr/certbot
|
||||
letsencrypt:
|
||||
predefined_deploy_script: httpd
|
||||
certificates:
|
||||
copr-fe-dev.cloud.fedoraproject.org:
|
||||
domains:
|
||||
- copr-fe-dev.cloud.fedoraproject.org
|
||||
challenge_dir: /var/www/html
|
||||
mail: copr-devel@lists.fedorahosted.org
|
||||
|
||||
@@ -2,3 +2,13 @@
|
||||
tcp_ports: [22, 80, 443]
|
||||
datacenter: cloud
|
||||
freezes: false
|
||||
|
||||
# consumed by roles/copr/certbot
|
||||
letsencrypt:
|
||||
predefined_deploy_script: httpd
|
||||
certificates:
|
||||
copr-dist-git.fedorainfracloud.org:
|
||||
domains:
|
||||
- copr-dist-git.fedorainfracloud.org
|
||||
challenge_dir: /var/www/html
|
||||
mail: copr-devel@lists.fedorahosted.org
|
||||
|
||||
@@ -3,3 +3,13 @@ tcp_ports: [22, 80, 443]
|
||||
datacenter: cloud
|
||||
freezes: false
|
||||
devel: true
|
||||
|
||||
# consumed by roles/copr/certbot
|
||||
letsencrypt:
|
||||
predefined_deploy_script: httpd
|
||||
certificates:
|
||||
copr-dist-git-dev.fedorainfracloud.org:
|
||||
domains:
|
||||
- copr-dist-git-dev.fedorainfracloud.org
|
||||
challenge_dir: /var/www/html
|
||||
mail: copr-devel@lists.fedorahosted.org
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
# This playbook is inspired by
|
||||
# https://mikeshultz.com/setting-up-lets-encrypt-with-lighttpd-and-certbot.html
|
||||
# Particularly it follows "(Option B) The Hard Way"
|
||||
|
||||
- name: Install required packages
|
||||
dnf:
|
||||
state: latest
|
||||
name: certbot
|
||||
|
||||
- name: Create The Web Root
|
||||
file:
|
||||
path: /var/certbot/public_html/.well-known/
|
||||
state: directory
|
||||
owner: lighttpd
|
||||
group: lighttpd
|
||||
mode: g+s
|
||||
|
||||
- name: certbot, correct fcontext mapping the web root
|
||||
sefcontext:
|
||||
target: '/var/certbot/public_html/.well-known(/.*)'
|
||||
setype: httpd_sys_content_t
|
||||
state: present
|
||||
|
||||
- name: certbot, restorecon the web root
|
||||
file:
|
||||
path: /var/certbot/public_html/.well-know
|
||||
state: directory
|
||||
setype: httpd_sys_content_t
|
||||
|
||||
- name: Check that cert file exists
|
||||
stat:
|
||||
path: "/etc/letsencrypt/live/copr-be-dev.cloud.fedoraproject.org/cert.pem"
|
||||
register: stat_cert
|
||||
|
||||
# This is only for initial setup
|
||||
# In such case, lighttpd config expects certificate files in /etc/letsencrypt/live,
|
||||
# but it doesn't exist yet and therefore lighttpd refuses to start at all.
|
||||
# We will use certbot standalone server to get certificates and then let the playbook to
|
||||
# parse them and start the lighttpd again.
|
||||
# Once we have at least some existing certificate files, this step will be skipped.
|
||||
- name: Should admin run certbot?
|
||||
fail:
|
||||
msg:
|
||||
- "There are no certificates yet"
|
||||
- "Please temporarily stop lighttpd and run:"
|
||||
- " certbot certonly --standalone --manual-public-ip-logging-ok -d copr-be-dev.cloud.fedoraproject.org"
|
||||
- "Let it stopped and re-run the playbook."
|
||||
when:
|
||||
- stat_cert.stat.exists == False
|
||||
|
||||
- name: Reformat Cert Files For Lighttpd
|
||||
shell: cat /etc/letsencrypt/live/copr-be-dev.cloud.fedoraproject.org/privkey.pem /etc/letsencrypt/live/copr-be-dev.cloud.fedoraproject.org/cert.pem > /etc/letsencrypt/live/copr-be-dev.cloud.fedoraproject.org/combined.pem
|
||||
|
||||
- name: Give Lighty Permissions
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
group: lighttpd
|
||||
mode: g+x
|
||||
with_items:
|
||||
- /etc/letsencrypt
|
||||
- /etc/letsencrypt/live
|
||||
|
||||
- name: Service lighttpd should be running
|
||||
service:
|
||||
name: lighttpd
|
||||
state: started
|
||||
|
||||
- name: Install config for cert renewal
|
||||
template: src="sysconfig/certbot" dest="/etc/sysconfig/certbot" owner=root group=root
|
||||
|
||||
- name: Automatize cert renewal
|
||||
service:
|
||||
name: certbot-renew.timer
|
||||
state: started
|
||||
enabled: yes
|
||||
@@ -93,12 +93,13 @@
|
||||
notify:
|
||||
- restart lighttpd
|
||||
|
||||
# TODO: move production to Let's Encrypt as well as devel
|
||||
- name: install certificates for production
|
||||
when: not devel
|
||||
import_tasks: "install_certs.yml"
|
||||
|
||||
- name: letsencrypt cert
|
||||
import_tasks: "letsencrypt.yml"
|
||||
include_role: name=copr/certbot
|
||||
when: devel
|
||||
tags:
|
||||
- config
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
## NOTE ##
|
||||
# If a hook is set here then it will be used for all
|
||||
# certificates and will override any per certificate
|
||||
# hook configuration in place.
|
||||
|
||||
# Command to be run in a shell before obtaining any
|
||||
# certificates. Intended primarily for renewal, where it
|
||||
# can be used to temporarily shut down a webserver that
|
||||
# might conflict with the standalone plugin. This will
|
||||
# only be called if a certificate is actually to be
|
||||
# obtained/renewed. When renewing several certificates
|
||||
# that have identical pre-hooks, only the first will be
|
||||
# executed.
|
||||
#
|
||||
# An example to stop the MTA before updating certs would be
|
||||
# PRE_HOOK="--pre-hook 'systemctl stop postfix'"
|
||||
PRE_HOOK=""
|
||||
|
||||
# Command to be run in a shell after attempting to
|
||||
# obtain/renew certificates. Can be used to deploy
|
||||
# renewed certificates, or to restart any servers that
|
||||
# were stopped by --pre-hook. This is only run if an
|
||||
# attempt was made to obtain/renew a certificate. If
|
||||
# multiple renewed certificates have identical post-
|
||||
# hooks, only one will be run.
|
||||
#
|
||||
# An example to restart httpd would be:
|
||||
# POST_HOOK="--post-hook 'systemctl restart httpd'"
|
||||
POST_HOOK=""
|
||||
|
||||
# Command to be run in a shell once for each
|
||||
# successfully renewed certificate. For this command,
|
||||
# the shell variable $RENEWED_LINEAGE will point to the
|
||||
# config live subdirectory containing the new certs and
|
||||
# keys; the shell variable $RENEWED_DOMAINS will contain
|
||||
# a space-delimited list of renewed cert domains
|
||||
#
|
||||
# An example to run a script to alert each cert would be:
|
||||
# RENEW_HOOK="--renew-hook /usr/local/bin/cert-notifier.sh"
|
||||
RENEW_HOOK=""
|
||||
|
||||
# Any other misc arguments for the renewal
|
||||
# See certbot -h renew for full list
|
||||
#
|
||||
# An example to force renewal for certificates not due yet
|
||||
# CERTBOT_ARGS="--force-renewal"
|
||||
#
|
||||
# The following command is produced
|
||||
# certbot renew **CERTBOT_ARGS
|
||||
{% if devel %}
|
||||
CERTBOT_ARGS="--webroot -w /var/certbot/public_html --cert-name copr-be-dev.cloud.fedoraproject.org"
|
||||
{% else %}
|
||||
CERTBOT_ARGS=""
|
||||
{% endif %}
|
||||
60
roles/copr/certbot/tasks/letsencrypt.yml
Normal file
60
roles/copr/certbot/tasks/letsencrypt.yml
Normal file
@@ -0,0 +1,60 @@
|
||||
- name: install certbot package
|
||||
package: name=certbot state=present
|
||||
|
||||
- name: install certbot config
|
||||
template: src=certbot.j2 dest=/etc/sysconfig/certbot
|
||||
mode=0644
|
||||
|
||||
- name: install certbot deploy script
|
||||
template: src={{ letsencrypt.predefined_deploy_script }}
|
||||
dest=/usr/libexec/auto-certbot-deploy
|
||||
mode=0755
|
||||
when: letsencrypt.predefined_deploy_script is defined
|
||||
|
||||
- name: check whether we need to initialize letsencrypt first
|
||||
stat: path="/etc/letsencrypt/live/{{ item.key }}"
|
||||
register: le_stat_checks
|
||||
with_dict: "{{ letsencrypt.certificates }}"
|
||||
|
||||
- name: initialize certbot configuration
|
||||
shell: |
|
||||
certbot certonly --standalone \
|
||||
-w {{ item.item.value.challenge_dir }} \
|
||||
-d {{ item.item.value.domains | join(' -d ') }} \
|
||||
--cert-name {{ item.item.key }} \
|
||||
-m {{ item.item.value.mail }} \
|
||||
--agree-tos \
|
||||
-n >> /tmp/call
|
||||
when:
|
||||
- not item.stat.exists
|
||||
with_items: "{{ le_stat_checks.results }}"
|
||||
|
||||
|
||||
- name: configure certbot to use webroot next time
|
||||
ini_file: dest="/etc/letsencrypt/renewal/{{ item.item.key }}.conf"
|
||||
section=renewalparams
|
||||
option=authenticator
|
||||
value=webroot
|
||||
with_items: "{{ le_stat_checks.results }}"
|
||||
|
||||
- name: configure certbot to use webroot next time
|
||||
ini_file: dest="/etc/letsencrypt/renewal/{{ item.item.key }}.conf"
|
||||
section=renewalparams
|
||||
option=webroot_path
|
||||
value="{{ item.item.value.challenge_dir }},"
|
||||
with_items: "{{ le_stat_checks.results }}"
|
||||
|
||||
- name: post init script
|
||||
shell: |
|
||||
/usr/libexec/auto-certbot-deploy \
|
||||
--init {{ item.item.key }}
|
||||
when:
|
||||
- letsencrypt.predefined_deploy_script is defined
|
||||
- not item.stat.exists
|
||||
with_items: "{{ le_stat_checks.results }}"
|
||||
|
||||
- name: Automatize cert renewal
|
||||
service:
|
||||
name: certbot-renew.timer
|
||||
state: started
|
||||
enabled: yes
|
||||
3
roles/copr/certbot/tasks/main.yml
Normal file
3
roles/copr/certbot/tasks/main.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
- include_tasks: letsencrypt.yml
|
||||
when:
|
||||
- letsencrypt is defined
|
||||
13
roles/copr/certbot/templates/certbot.j2
Normal file
13
roles/copr/certbot/templates/certbot.j2
Normal file
@@ -0,0 +1,13 @@
|
||||
# Usually it is enough to do `certbot renew --dry-run` to check that certbot is
|
||||
# configured correctly (anytime, without rate limits). You can though (up to 5x
|
||||
# a week) try force renewal. It is both affecting your letsencrypt quota, and
|
||||
# it requires web server restart. But if you still want to try, please
|
||||
# uncomment the following config option, and hit `systemctl start
|
||||
# certbot-renew.service`. WARNING WARNING Don't forget to comment it again!
|
||||
#CERTBOT_ARGS="--force-renewal"
|
||||
{% if letsencrypt.predefined_deploy_script %}
|
||||
|
||||
# Execute the script after certificate renewal, usually this is needed to
|
||||
# restart web server, etc.
|
||||
DEPLOY_HOOK="--deploy-hook /usr/libexec/auto-certbot-deploy"
|
||||
{% endif %}
|
||||
5
roles/copr/certbot/templates/httpd
Normal file
5
roles/copr/certbot/templates/httpd
Normal file
@@ -0,0 +1,5 @@
|
||||
#! /bin/sh
|
||||
|
||||
case $1 in --init) exit 0 ;; esac
|
||||
|
||||
systemctl restart httpd
|
||||
26
roles/copr/certbot/templates/lighttpd
Normal file
26
roles/copr/certbot/templates/lighttpd
Normal file
@@ -0,0 +1,26 @@
|
||||
#! /bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
pem_fixup()
|
||||
{
|
||||
cat "/etc/letsencrypt/live/$1/cert.pem" \
|
||||
"/etc/letsencrypt/live/$1/privkey.pem" \
|
||||
> "/etc/letsencrypt/live/$1/combined.pem"
|
||||
}
|
||||
|
||||
case $1 in
|
||||
--init)
|
||||
pem_fixup "$2"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# Automatically called by certbot.
|
||||
test -z "$RENEWED_DOMAINS" && echo "you are not certbot" && exit 1
|
||||
|
||||
for domain in $RENEWED_DOMAINS; do
|
||||
pem_fixup "$domain"
|
||||
done
|
||||
|
||||
systemctl restart lighttpd
|
||||
@@ -56,6 +56,9 @@
|
||||
notify:
|
||||
- reload httpd
|
||||
|
||||
- name: letsencrypt for copr-dist-git
|
||||
include_role: name=copr/certbot
|
||||
|
||||
- name: install copr-dist-git httpd config
|
||||
copy: src="httpd/{{ item }}" dest="/etc/httpd/conf.d/{{ item }}"
|
||||
with_items:
|
||||
@@ -65,34 +68,10 @@
|
||||
notify:
|
||||
- reload httpd
|
||||
|
||||
- name: letsencrypt cert
|
||||
include_role: name=certbot
|
||||
|
||||
- template: src="ssl.conf.j2" dest="/etc/httpd/conf.d/ssl.conf" owner=root group=root mode=0644
|
||||
notify:
|
||||
- reload httpd
|
||||
|
||||
- name: certbot, correct fcontext mapping the web root
|
||||
sefcontext:
|
||||
target: '/srv/web/acme-challenge/.well-known(/.*)'
|
||||
setype: httpd_sys_content_t
|
||||
state: present
|
||||
|
||||
- name: certbot, restorecon the web root
|
||||
file:
|
||||
path: /srv/web/acme-challenge/.well-known
|
||||
state: directory
|
||||
setype: httpd_sys_content_t
|
||||
|
||||
- name: Install config for cert renewal
|
||||
template: src="sysconfig/certbot" dest="/etc/sysconfig/certbot" owner=root group=root
|
||||
|
||||
- name: Automatize cert renewal
|
||||
service:
|
||||
name: certbot-renew.timer
|
||||
state: started
|
||||
enabled: yes
|
||||
|
||||
- name: temporary logrotation fix until copr-dist-git 0.26 is released & deployed
|
||||
copy: src="logrotate.d/copr-dist-git" dest="/etc/logrotate.d/copr-dist-git"
|
||||
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
<VirtualHost *:80>
|
||||
RewriteEngine on
|
||||
RewriteRule ^/\.well-known/(.*) /srv/web/acme-challenge/.well-known/$1 [L]
|
||||
RewriteRule "^/?(.*)" "https://%{HTTP_HOST}/$1" [L,R=301,NE]
|
||||
</VirtualHost>
|
||||
|
||||
Listen 443 https
|
||||
|
||||
SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
## NOTE ##
|
||||
# If a hook is set here then it will be used for all
|
||||
# certificates and will override any per certificate
|
||||
# hook configuration in place.
|
||||
|
||||
# Command to be run in a shell before obtaining any
|
||||
# certificates. Intended primarily for renewal, where it
|
||||
# can be used to temporarily shut down a webserver that
|
||||
# might conflict with the standalone plugin. This will
|
||||
# only be called if a certificate is actually to be
|
||||
# obtained/renewed. When renewing several certificates
|
||||
# that have identical pre-hooks, only the first will be
|
||||
# executed.
|
||||
#
|
||||
# An example to stop the MTA before updating certs would be
|
||||
# PRE_HOOK="--pre-hook 'systemctl stop postfix'"
|
||||
PRE_HOOK=""
|
||||
|
||||
# Command to be run in a shell after attempting to
|
||||
# obtain/renew certificates. Can be used to deploy
|
||||
# renewed certificates, or to restart any servers that
|
||||
# were stopped by --pre-hook. This is only run if an
|
||||
# attempt was made to obtain/renew a certificate. If
|
||||
# multiple renewed certificates have identical post-
|
||||
# hooks, only one will be run.
|
||||
#
|
||||
# An example to restart httpd would be:
|
||||
# POST_HOOK="--post-hook 'systemctl restart httpd'"
|
||||
POST_HOOK=""
|
||||
|
||||
# Command to be run in a shell once for each
|
||||
# successfully renewed certificate. For this command,
|
||||
# the shell variable $RENEWED_LINEAGE will point to the
|
||||
# config live subdirectory containing the new certs and
|
||||
# keys; the shell variable $RENEWED_DOMAINS will contain
|
||||
# a space-delimited list of renewed cert domains
|
||||
#
|
||||
# An example to run a script to alert each cert would be:
|
||||
# RENEW_HOOK="--renew-hook /usr/local/bin/cert-notifier.sh"
|
||||
RENEW_HOOK=""
|
||||
|
||||
# Any other misc arguments for the renewal
|
||||
# See certbot -h renew for full list
|
||||
#
|
||||
# An example to force renewal for certificates not due yet
|
||||
# CERTBOT_ARGS="--force-renewal"
|
||||
#
|
||||
# The following command is produced
|
||||
# certbot renew **CERTBOT_ARGS
|
||||
{% if devel %}
|
||||
CERTBOT_ARGS="--webroot -w /srv/web/acme-challenge --cert-name copr-dist-git-dev.fedorainfracloud.org"
|
||||
{% else %}
|
||||
CERTBOT_ARGS="--webroot -w /srv/web/acme-challenge --cert-name copr-dist-git.fedorainfracloud.org"
|
||||
{% endif %}
|
||||
@@ -1,38 +0,0 @@
|
||||
- name: letsencrypt cert
|
||||
include_role: name=certbot
|
||||
when: devel
|
||||
tags:
|
||||
- config
|
||||
|
||||
- name: Check that cert file exists
|
||||
stat:
|
||||
path: "/etc/letsencrypt/live/{{ copr_frontend_public_hostname }}/cert.pem"
|
||||
register: stat_cert
|
||||
|
||||
- name: Should admin run certbot?
|
||||
fail:
|
||||
msg: Please see roles/certbot/README step (2) and manually run certbot
|
||||
when:
|
||||
- stat_cert.stat.exists == False
|
||||
- devel
|
||||
|
||||
- name: certbot, correct fcontext mapping the web root
|
||||
sefcontext:
|
||||
target: '/srv/web/acme-challenge/.well-known(/.*)'
|
||||
setype: httpd_sys_content_t
|
||||
state: present
|
||||
|
||||
- name: certbot, restorecon the web root
|
||||
file:
|
||||
path: /srv/web/acme-challenge/.well-known
|
||||
state: directory
|
||||
setype: httpd_sys_content_t
|
||||
|
||||
- name: Install config for cert renewal
|
||||
template: src="sysconfig/certbot" dest="/etc/sysconfig/certbot" owner=root group=root
|
||||
|
||||
- name: Automatize cert renewal
|
||||
service:
|
||||
name: certbot-renew.timer
|
||||
state: started
|
||||
enabled: yes
|
||||
@@ -98,14 +98,16 @@
|
||||
- nb
|
||||
- kevin
|
||||
|
||||
# TODO: move production to lets-encrypt as well
|
||||
- name: install ssl certificates for production
|
||||
import_tasks: "install_certs.yml"
|
||||
when: not devel
|
||||
tags:
|
||||
- config
|
||||
|
||||
# development servers use Let's Encrypt
|
||||
- name: install letsencrypt ssl certificates for dev
|
||||
import_tasks: "letsencrypt.yml"
|
||||
include_role: name=copr/certbot
|
||||
when: devel
|
||||
tags:
|
||||
- config
|
||||
|
||||
@@ -27,11 +27,11 @@ WSGIScriptAlias / /usr/share/copr/coprs_frontend/application
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
{% if devel %}
|
||||
{% if letsencrypt -%}
|
||||
RewriteEngine on
|
||||
RewriteRule ^/\.well-known/(.*) /srv/web/acme-challenge/.well-known/$1 [L]
|
||||
RewriteRule ^/\.well-known/(.*) /var/www/html/.well-known/$1 [L]
|
||||
RewriteRule "^/?(.*)" "https://%{HTTP_HOST}/$1" [L,R=301,NE]
|
||||
{% endif %}
|
||||
{%- endif %}
|
||||
</VirtualHost>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user