Compare commits
38 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb5965263c | ||
|
|
a96fdb7828 | ||
|
|
e2cc44637e | ||
|
|
c41bfb7f57 | ||
|
|
91e84d7225 | ||
|
|
ac00c1c43e | ||
|
|
f66dd5959a | ||
|
|
11b4bc888d | ||
|
|
d0da9ba348 | ||
|
|
c0325ba991 | ||
|
|
5614e7fd15 | ||
|
|
a24ade1723 | ||
|
|
51195094a8 | ||
|
|
6196b1a0ed | ||
|
|
4c3d6134a6 | ||
|
|
4ec0479c68 | ||
|
|
a9d75e6644 | ||
|
|
e84794303a | ||
|
|
8ae612179c | ||
|
|
6606afa0cd | ||
|
|
e96af0a3c9 | ||
|
|
6a6a98e3c3 | ||
|
|
de07a8cc67 | ||
|
|
766eae26ed | ||
|
|
23a0e06149 | ||
|
|
6859d7092c | ||
|
|
1d4a4aa823 | ||
|
|
e62eb5289d | ||
|
|
640fa49ef9 | ||
|
|
5c6956e7cc | ||
|
|
592fc09fb7 | ||
|
|
28ca09289c | ||
|
|
5bf9ac63df | ||
|
|
2cc9f0adbf | ||
|
|
c9d3920f74 | ||
|
|
bfa7928076 | ||
|
|
038d15cdf3 | ||
|
|
651e6647bb |
13 changed files with 222 additions and 360 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -4,3 +4,6 @@
|
|||
/*.src.rpm
|
||||
/.build-*
|
||||
/acme-tiny-4.1.0.tar.gz
|
||||
/results_acme-tiny
|
||||
/acme-tiny-4.1.1.tar.gz
|
||||
/acme-tiny-5.0.1.tar.gz
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
# acme-tiny-core Fedora package
|
||||
|
||||
This package contains only the upstream python script - for those
|
||||
who prefer their own framework for cert maintenance.
|
||||
|
||||
# acme-tiny Fedora package
|
||||
|
||||
The Fedora package for acme-tiny adds a tiny framework to make issuing
|
||||
|
|
@ -74,7 +79,7 @@ Use
|
|||
systemctl start acme-tiny
|
||||
```
|
||||
to run the service now. The certificate should appear in `/var/lib/acme/certs`,
|
||||
and errors will be in journalctl. Alternatively (and on EL6), run
|
||||
and errors will be in journalctl. Alternatively, run
|
||||
`/usr/libexec/acme-tiny/sign` as the acme user, and errors will go
|
||||
to your terminal.
|
||||
|
||||
|
|
@ -99,34 +104,38 @@ and other apps.
|
|||
Sendmail is a special problem - it insists that any certificates it loads be
|
||||
only writable by root. This is at odds with the privilege separation of the
|
||||
acme user. (Obviously, the private key must be accessible only by root.) You
|
||||
can, of course, copy the crt file to /etc/pki/tls/certs as root and change the
|
||||
mode. But this has to be done every time the cert is renewed. You can
|
||||
install `incron` to do this. After installing, create `/etc/incron.d/acme`
|
||||
with the line
|
||||
```
|
||||
/var/lib/acme/certs/mail.crt IN_MOVED_TO cp $@ /etc/pki/tls/certs
|
||||
```
|
||||
where `mail.crt` is the certificate sendmail will use. Sendmail
|
||||
can then load it from /etc/pki/tls/certs and be happy. This also
|
||||
solves the file context problem if you add lines for other certificates.
|
||||
You might wonder why we don't simply supply an acme incrontab as part
|
||||
of the package with a wildcard, for example:
|
||||
```
|
||||
/var/lib/acme/certs/*.crt IN_MOVED_TO cp $@ /etc/pki/tls/certs
|
||||
```
|
||||
The answer is that incron is insecure, and very nasty things can be
|
||||
done by putting shell meta characters (including semicolon and quote!) in
|
||||
filenames that then become part of a command run as root. The first example
|
||||
above uses a fixed filename, so that is safe. Complain to incron
|
||||
upstream - they need an option to use a simple execvpe instead of
|
||||
using the shell. Then it would at least be possible to carefully
|
||||
handle [malicious names](https://www.xkcd.com/327/).
|
||||
can, of course, copy the crt file to `/etc/pki/tls/certs` as root and change
|
||||
the mode. But this has to be done every time the cert is renewed.
|
||||
The systemd `acme-tiny.service` runs `acme-tiny-notify.service`
|
||||
afterward which executes as root. It calls
|
||||
`/usr/libexec/acme-tiny/notify` for each nenewed cert. (This used
|
||||
to be `/etc/acme-tiny/notify.sh` - which is now a symlink.)
|
||||
|
||||
Suppose `/var/lib/acme/certs/mail.crt` is renewed, where `mail.crt` is the
|
||||
certificate sendmail will use. The notify script
|
||||
sees the reference to `/etc/pki/tls/certs/mail.crt` in `/etc/mail/*.cf`, and
|
||||
copies the renewed cert to `/etc/pki/tls/certs`. Sendmail can then load it
|
||||
from there and be happy. This also solves the file context problem.
|
||||
|
||||
The notify script has built in support for the httpd, sendmail, and dovecot
|
||||
packages for Fedora. To avoid restarting services multiple times,
|
||||
the notify script records in `/var/lib/acme/.notify`
|
||||
when it last restarted each service.
|
||||
|
||||
By dropping scripts with names ending in `.sh` in `/etc/acme-tiny/notify.d`,
|
||||
additional packages (e.g. nginx) can be supported.
|
||||
|
||||
This new system should be compatible with older incrond configs,
|
||||
but the additional `/etc/acme-tiny/notify.sh` calls from incrond are redundant.
|
||||
Making them redundant, incidentally fixes
|
||||
[BZ#1839904](https://bugzilla.redhat.com/show_bug.cgi?id=1839904). There
|
||||
could still be a race condition missed in testing, so I would disable your old
|
||||
acme incrontab.
|
||||
|
||||
## Logging and Error Reporting
|
||||
|
||||
On EL6, cron will email the acme user when certs are signed or errors
|
||||
are encountered. Under systemd, errors and certs signed are logged
|
||||
with the acme-tiny syslog identifier.
|
||||
Under systemd, errors and certs signed are logged with the acme-tiny
|
||||
syslog identifier.
|
||||
|
||||
## Virtual Hosts
|
||||
|
||||
|
|
@ -134,6 +143,10 @@ Most web servers can handle multiple logical web hosts - configuring that is
|
|||
beyond the scope of this document. Each virtual host may need to have its own
|
||||
certificate for SSL. They can all share the same key file (see above for
|
||||
how to use an existing key for certificate requests), or use different keys.
|
||||
Put all the CSRs in /var/lib/acme/csr and the acme-tiny service will keep them
|
||||
all renewed. This also works for certificates used by other SSL applications,
|
||||
such as dovecot, sendmail, jabberd, or znc.
|
||||
Note that apache can load certs directly from `/var/lib/acme/certs`, and
|
||||
so notify.sh simply does `apachectl graceful`.
|
||||
|
||||
Put all the CSRs in `/var/lib/acme/csr` and the acme-tiny service will keep
|
||||
them all renewed. This also works for certificates used by other SSL
|
||||
applications, such as dovecot, sendmail, jabberd, or znc.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,118 +0,0 @@
|
|||
diff -up ./acme_tiny.py.chain ./acme_tiny.py
|
||||
--- ./acme_tiny.py.chain 2017-05-16 03:57:46.000000000 -0400
|
||||
+++ ./acme_tiny.py 2017-11-22 12:18:56.963653336 -0500
|
||||
@@ -1,4 +1,4 @@
|
||||
-#!/usr/bin/env python
|
||||
+#!/usr/bin/python
|
||||
import argparse, subprocess, json, os, sys, base64, binascii, time, hashlib, re, copy, textwrap, logging
|
||||
try:
|
||||
from urllib.request import urlopen # Python 3
|
||||
@@ -12,7 +12,7 @@ LOGGER = logging.getLogger(__name__)
|
||||
LOGGER.addHandler(logging.StreamHandler())
|
||||
LOGGER.setLevel(logging.INFO)
|
||||
|
||||
-def get_crt(account_key, csr, acme_dir, log=LOGGER, CA=DEFAULT_CA):
|
||||
+def get_crt(account_key, csr, acme_dir, log=LOGGER, CA=DEFAULT_CA, chain=False):
|
||||
# helper function base64 encode for jose spec
|
||||
def _b64(b):
|
||||
return base64.urlsafe_b64encode(b).decode('utf8').replace("=", "")
|
||||
@@ -57,9 +57,9 @@ def get_crt(account_key, csr, acme_dir,
|
||||
})
|
||||
try:
|
||||
resp = urlopen(url, data.encode('utf8'))
|
||||
- return resp.getcode(), resp.read()
|
||||
+ return resp.getcode(), resp.read(), resp.info()
|
||||
except IOError as e:
|
||||
- return getattr(e, "code", None), getattr(e, "read", e.__str__)()
|
||||
+ return getattr(e, "code", None), getattr(e, "read", e.__str__)(), None
|
||||
|
||||
# find domains
|
||||
log.info("Parsing CSR...")
|
||||
@@ -80,9 +80,9 @@ def get_crt(account_key, csr, acme_dir,
|
||||
|
||||
# get the certificate domains and expiration
|
||||
log.info("Registering account...")
|
||||
- code, result = _send_signed_request(CA + "/acme/new-reg", {
|
||||
+ code, result, headers = _send_signed_request(CA + "/acme/new-reg", {
|
||||
"resource": "new-reg",
|
||||
- "agreement": "https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf",
|
||||
+ "agreement": "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf",
|
||||
})
|
||||
if code == 201:
|
||||
log.info("Registered!")
|
||||
@@ -96,7 +96,7 @@ def get_crt(account_key, csr, acme_dir,
|
||||
log.info("Verifying {0}...".format(domain))
|
||||
|
||||
# get new challenge
|
||||
- code, result = _send_signed_request(CA + "/acme/new-authz", {
|
||||
+ code, result, headers = _send_signed_request(CA + "/acme/new-authz", {
|
||||
"resource": "new-authz",
|
||||
"identifier": {"type": "dns", "value": domain},
|
||||
})
|
||||
@@ -123,7 +123,7 @@ def get_crt(account_key, csr, acme_dir,
|
||||
wellknown_path, wellknown_url))
|
||||
|
||||
# notify challenge are met
|
||||
- code, result = _send_signed_request(challenge['uri'], {
|
||||
+ code, result, headers = _send_signed_request(challenge['uri'], {
|
||||
"resource": "challenge",
|
||||
"keyAuthorization": keyauthorization,
|
||||
})
|
||||
@@ -153,17 +153,32 @@ def get_crt(account_key, csr, acme_dir,
|
||||
proc = subprocess.Popen(["openssl", "req", "-in", csr, "-outform", "DER"],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
csr_der, err = proc.communicate()
|
||||
- code, result = _send_signed_request(CA + "/acme/new-cert", {
|
||||
+ code, result, headers = _send_signed_request(CA + "/acme/new-cert", {
|
||||
"resource": "new-cert",
|
||||
"csr": _b64(csr_der),
|
||||
})
|
||||
if code != 201:
|
||||
raise ValueError("Error signing certificate: {0} {1}".format(code, result))
|
||||
|
||||
+ certchain = [result]
|
||||
+ if chain:
|
||||
+ def parse_link_header(line):
|
||||
+ m = re.search(r"^<([^>]*)>(?:\s*;\s*(.*))?$", line)
|
||||
+ return (m.group(1), dict([(a[0],a[1].strip('"'))
|
||||
+ for a in [attr.split("=")
|
||||
+ for attr in m.group(2).split("\s*;\s*")]]))
|
||||
+
|
||||
+ up = [
|
||||
+ link for link, attr in [
|
||||
+ parse_link_header(l) for l in headers.get_all("Link")
|
||||
+ ] if attr['rel'] == 'up'
|
||||
+ ]
|
||||
+ certchain += [urlopen(url).read() for url in up]
|
||||
+
|
||||
# return signed certificate!
|
||||
log.info("Certificate signed!")
|
||||
- return """-----BEGIN CERTIFICATE-----\n{0}\n-----END CERTIFICATE-----\n""".format(
|
||||
- "\n".join(textwrap.wrap(base64.b64encode(result).decode('utf8'), 64)))
|
||||
+ return "".join(["""-----BEGIN CERTIFICATE-----\n{0}\n-----END CERTIFICATE-----\n""".format(
|
||||
+ "\n".join(textwrap.wrap(base64.b64encode(cert).decode('utf8'), 64))) for cert in certchain])
|
||||
|
||||
def main(argv):
|
||||
parser = argparse.ArgumentParser(
|
||||
@@ -188,11 +203,19 @@ def main(argv):
|
||||
parser.add_argument("--acme-dir", required=True, help="path to the .well-known/acme-challenge/ directory")
|
||||
parser.add_argument("--quiet", action="store_const", const=logging.ERROR, help="suppress output except for errors")
|
||||
parser.add_argument("--ca", default=DEFAULT_CA, help="certificate authority, default is Let's Encrypt")
|
||||
+ parser.add_argument("--chain", action="store_true",
|
||||
+ help="fetch and append intermediate certs to output")
|
||||
|
||||
args = parser.parse_args(argv)
|
||||
LOGGER.setLevel(args.quiet or LOGGER.level)
|
||||
- signed_crt = get_crt(args.account_key, args.csr, args.acme_dir, log=LOGGER, CA=args.ca)
|
||||
- sys.stdout.write(signed_crt)
|
||||
+ try:
|
||||
+ signed_crt = get_crt(args.account_key, args.csr, args.acme_dir,
|
||||
+ log=LOGGER, CA=args.ca, chain=args.chain)
|
||||
+ sys.stdout.write(signed_crt)
|
||||
+ except Exception as e:
|
||||
+ #if not args.quiet: raise e
|
||||
+ LOGGER.error(e)
|
||||
+ sys.exit(1)
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
main(sys.argv[1:])
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
diff -up ./acme_tiny.py.chain ./acme_tiny.py
|
||||
--- ./acme_tiny.py.chain 2017-05-16 03:57:46.000000000 -0400
|
||||
+++ ./acme_tiny.py 2017-11-22 15:14:19.270485351 -0500
|
||||
@@ -1,4 +1,4 @@
|
||||
-#!/usr/bin/env python
|
||||
+#!/usr/bin/python
|
||||
import argparse, subprocess, json, os, sys, base64, binascii, time, hashlib, re, copy, textwrap, logging
|
||||
try:
|
||||
from urllib.request import urlopen # Python 3
|
||||
@@ -12,7 +12,7 @@ LOGGER = logging.getLogger(__name__)
|
||||
LOGGER.addHandler(logging.StreamHandler())
|
||||
LOGGER.setLevel(logging.INFO)
|
||||
|
||||
-def get_crt(account_key, csr, acme_dir, log=LOGGER, CA=DEFAULT_CA):
|
||||
+def get_crt(account_key, csr, acme_dir, log=LOGGER, CA=DEFAULT_CA, chain=False):
|
||||
# helper function base64 encode for jose spec
|
||||
def _b64(b):
|
||||
return base64.urlsafe_b64encode(b).decode('utf8').replace("=", "")
|
||||
@@ -57,9 +57,9 @@ def get_crt(account_key, csr, acme_dir,
|
||||
})
|
||||
try:
|
||||
resp = urlopen(url, data.encode('utf8'))
|
||||
- return resp.getcode(), resp.read()
|
||||
+ return resp.getcode(), resp.read(), resp.info()
|
||||
except IOError as e:
|
||||
- return getattr(e, "code", None), getattr(e, "read", e.__str__)()
|
||||
+ return getattr(e, "code", None), getattr(e, "read", e.__str__)(), None
|
||||
|
||||
# find domains
|
||||
log.info("Parsing CSR...")
|
||||
@@ -80,9 +80,9 @@ def get_crt(account_key, csr, acme_dir,
|
||||
|
||||
# get the certificate domains and expiration
|
||||
log.info("Registering account...")
|
||||
- code, result = _send_signed_request(CA + "/acme/new-reg", {
|
||||
+ code, result, headers = _send_signed_request(CA + "/acme/new-reg", {
|
||||
"resource": "new-reg",
|
||||
- "agreement": "https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf",
|
||||
+ "agreement": "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf",
|
||||
})
|
||||
if code == 201:
|
||||
log.info("Registered!")
|
||||
@@ -96,7 +96,7 @@ def get_crt(account_key, csr, acme_dir,
|
||||
log.info("Verifying {0}...".format(domain))
|
||||
|
||||
# get new challenge
|
||||
- code, result = _send_signed_request(CA + "/acme/new-authz", {
|
||||
+ code, result, headers = _send_signed_request(CA + "/acme/new-authz", {
|
||||
"resource": "new-authz",
|
||||
"identifier": {"type": "dns", "value": domain},
|
||||
})
|
||||
@@ -123,7 +123,7 @@ def get_crt(account_key, csr, acme_dir,
|
||||
wellknown_path, wellknown_url))
|
||||
|
||||
# notify challenge are met
|
||||
- code, result = _send_signed_request(challenge['uri'], {
|
||||
+ code, result, headers = _send_signed_request(challenge['uri'], {
|
||||
"resource": "challenge",
|
||||
"keyAuthorization": keyauthorization,
|
||||
})
|
||||
@@ -153,17 +153,32 @@ def get_crt(account_key, csr, acme_dir,
|
||||
proc = subprocess.Popen(["openssl", "req", "-in", csr, "-outform", "DER"],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
csr_der, err = proc.communicate()
|
||||
- code, result = _send_signed_request(CA + "/acme/new-cert", {
|
||||
+ code, result, headers = _send_signed_request(CA + "/acme/new-cert", {
|
||||
"resource": "new-cert",
|
||||
"csr": _b64(csr_der),
|
||||
})
|
||||
if code != 201:
|
||||
raise ValueError("Error signing certificate: {0} {1}".format(code, result))
|
||||
|
||||
+ certchain = [result]
|
||||
+ if chain:
|
||||
+ def parse_link_header(line):
|
||||
+ m = re.search(r"^Link:\s*<([^>]*)>(?:\s*;\s*(.*))?\r\n$", line)
|
||||
+ return (m.group(1), dict([(a[0],a[1].strip('"'))
|
||||
+ for a in [attr.split("=")
|
||||
+ for attr in m.group(2).split("\s*;\s*")]]))
|
||||
+
|
||||
+ up = [
|
||||
+ link for link, attr in [
|
||||
+ parse_link_header(l) for l in headers.getallmatchingheaders("Link")
|
||||
+ ] if attr['rel'] == 'up'
|
||||
+ ]
|
||||
+ certchain += [urlopen(url).read() for url in up]
|
||||
+
|
||||
# return signed certificate!
|
||||
log.info("Certificate signed!")
|
||||
- return """-----BEGIN CERTIFICATE-----\n{0}\n-----END CERTIFICATE-----\n""".format(
|
||||
- "\n".join(textwrap.wrap(base64.b64encode(result).decode('utf8'), 64)))
|
||||
+ return "".join(["""-----BEGIN CERTIFICATE-----\n{0}\n-----END CERTIFICATE-----\n""".format(
|
||||
+ "\n".join(textwrap.wrap(base64.b64encode(cert).decode('utf8'), 64))) for cert in certchain])
|
||||
|
||||
def main(argv):
|
||||
parser = argparse.ArgumentParser(
|
||||
@@ -188,11 +203,19 @@ def main(argv):
|
||||
parser.add_argument("--acme-dir", required=True, help="path to the .well-known/acme-challenge/ directory")
|
||||
parser.add_argument("--quiet", action="store_const", const=logging.ERROR, help="suppress output except for errors")
|
||||
parser.add_argument("--ca", default=DEFAULT_CA, help="certificate authority, default is Let's Encrypt")
|
||||
+ parser.add_argument("--chain", action="store_true",
|
||||
+ help="fetch and append intermediate certs to output")
|
||||
|
||||
args = parser.parse_args(argv)
|
||||
LOGGER.setLevel(args.quiet or LOGGER.level)
|
||||
- signed_crt = get_crt(args.account_key, args.csr, args.acme_dir, log=LOGGER, CA=args.ca)
|
||||
- sys.stdout.write(signed_crt)
|
||||
+ try:
|
||||
+ signed_crt = get_crt(args.account_key, args.csr, args.acme_dir,
|
||||
+ log=LOGGER, CA=args.ca, chain=args.chain)
|
||||
+ sys.stdout.write(signed_crt)
|
||||
+ except Exception as e:
|
||||
+ #if not args.quiet: raise e
|
||||
+ LOGGER.error(e)
|
||||
+ sys.exit(1)
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
main(sys.argv[1:])
|
||||
8
acme-tiny-notify.service
Normal file
8
acme-tiny-notify.service
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[Unit]
|
||||
Description=Notify services of updates to acme certs
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
Nice=19
|
||||
SyslogIdentifier=acme-tiny
|
||||
ExecStart=/usr/libexec/acme-tiny/notify --scan
|
||||
15
acme-tiny-sign.sh
Normal file → Executable file
15
acme-tiny-sign.sh
Normal file → Executable file
|
|
@ -1,11 +1,20 @@
|
|||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
|
||||
if test "$(id -u)" -eq 0; then
|
||||
echo "Do not run as root!"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
DAYS="${1:-7}"
|
||||
. /etc/sysconfig/acme-tiny
|
||||
DAYS="${1:-$DAYS}"
|
||||
test -n "$DAYS" || DAYS="7"
|
||||
if [[ "$DAYS" =~ ^[0-9]+$ ]]; then
|
||||
echo "Days before expiration: $DAYS"
|
||||
secs=$(( $DAYS * 24 * 60 * 60 ))
|
||||
else
|
||||
echo "Invalid number of days: $DAYS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd /var/lib/acme
|
||||
|
||||
|
|
@ -22,7 +31,7 @@ for csr in csr/*.csr; do
|
|||
crt="${csr%%.csr}"
|
||||
tmp="certs/${crt##csr/}.tmp"
|
||||
crt="certs/${crt##csr/}.crt"
|
||||
if test -s "$crt" && /usr/sbin/cert-check --days="$DAYS" "$crt"; then
|
||||
if test -s "$crt" && openssl x509 -in "$crt" -noout -checkend "$secs"; then
|
||||
continue
|
||||
fi
|
||||
if test -w "$crt" || test ! -e "$crt"; then
|
||||
|
|
|
|||
4
acme-tiny.conf
Normal file
4
acme-tiny.conf
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# Default settings for acme-tiny wrapper script
|
||||
|
||||
# Number of days before expiration to renew a certificate
|
||||
DAYS=7
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
# Check daily for csrs in /var/lib/acme/csr that need signing or renewing
|
||||
# within 7 days.
|
||||
31 2 * * * acme /usr/libexec/acme-tiny/sign 7
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
[Unit]
|
||||
Description=Check for acme certs about to expire
|
||||
Wants=acme-tiny-notify.service
|
||||
Before=acme-tiny-notify.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
|
|
@ -9,7 +11,7 @@ ProtectSystem=true
|
|||
User=acme
|
||||
Group=acme
|
||||
SyslogIdentifier=acme-tiny
|
||||
ExecStart=/usr/libexec/acme-tiny/sign 7
|
||||
ExecStart=/usr/libexec/acme-tiny/sign
|
||||
|
||||
[Install]
|
||||
Also=acme-tiny.timer
|
||||
|
|
|
|||
138
acme-tiny.spec
138
acme-tiny.spec
|
|
@ -1,10 +1,4 @@
|
|||
|
||||
%if 0%{?rhel} >= 5 && 0%{?rhel} < 7
|
||||
%global use_systemd 0
|
||||
%else
|
||||
%global use_systemd 1
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} || 0%{?rhel} > 7
|
||||
# Explicity require python3 on Fedora to help track which packages
|
||||
# no longer need python2.
|
||||
|
|
@ -14,8 +8,8 @@
|
|||
%endif
|
||||
|
||||
Name: acme-tiny
|
||||
Version: 4.1.0
|
||||
Release: 1%{?dist}
|
||||
Version: 5.0.1
|
||||
Release: 13%{?dist}
|
||||
Summary: Tiny auditable script to issue, renew Let's Encrypt certificates
|
||||
|
||||
License: MIT
|
||||
|
|
@ -24,26 +18,17 @@ Source0: https://github.com/diafygi/%{name}/archive/%{version}.tar.gz#/%{name}-%
|
|||
Source1: acme-tiny-sign.sh
|
||||
Source2: cert-check.py
|
||||
Source3: acme.conf
|
||||
Source4: lets-encrypt-x3-cross-signed.pem
|
||||
Source5: acme-tiny.cron
|
||||
Source6: acme-tiny.timer
|
||||
Source7: acme-tiny.service
|
||||
Source8: README-fedora.md
|
||||
# simple script hook to kick services when cert is updated
|
||||
Source9: notify.sh
|
||||
# Fetch and include intermediate cert(s), too.
|
||||
Patch0: acme-tiny-chain.patch
|
||||
# Python3 broke getallmatchingheaders() and the fix breaks python2
|
||||
Patch1: acme-tiny-chain2.patch
|
||||
Source10: acme-tiny-notify.service
|
||||
Source11: acme-tiny.conf
|
||||
|
||||
Requires(pre): shadow-utils
|
||||
%if %{use_systemd}
|
||||
# systemd macros are not defined unless systemd is present
|
||||
BuildRequires: systemd
|
||||
BuildRequires: systemd-rpm-macros
|
||||
%{?systemd_requires}
|
||||
%else
|
||||
Requires: cronie
|
||||
%endif
|
||||
Requires: %{name}-core = %{version}-%{release}
|
||||
BuildArch: noarch
|
||||
%if 0%{?fedora}
|
||||
|
|
@ -63,7 +48,7 @@ This package adds a simple directory layout and timer service that runs
|
|||
acme_tiny on installed CSRs as the acme user for privilege separation.
|
||||
|
||||
%package core
|
||||
Summary: core python module of acme-tiny
|
||||
Summary: Core python module of acme-tiny
|
||||
Requires: openssl
|
||||
%if 0%{?rhel} >= 5 && 0%{?rhel} < 7
|
||||
# EL6 uses python2.6, which does not include argparse
|
||||
|
|
@ -81,12 +66,11 @@ unneeded packages.
|
|||
cp -p %{SOURCE1} %{SOURCE2} %{SOURCE8} .
|
||||
sed -i.orig -e '1,1 s,^.*python$,#!/usr/bin/python,' acme_tiny.py
|
||||
%if %{use_python3}
|
||||
#patch0 -p1 -b .chain
|
||||
sed -i.old -e '1,1 s/python$/python3/' *.py
|
||||
#else
|
||||
#patch1 -p1 -b .chain2
|
||||
%endif
|
||||
|
||||
echo 'u acme - "Tiny Auditable ACME Client" %{_sharedstatedir}/acme' >acme.sysusers.conf
|
||||
|
||||
%build
|
||||
|
||||
%install
|
||||
|
|
@ -94,26 +78,25 @@ mkdir -p %{buildroot}/var/www/challenges
|
|||
mkdir -p %{buildroot}%{_sysconfdir}/httpd/conf.d
|
||||
mkdir -p %{buildroot}%{_sbindir}
|
||||
mkdir -p %{buildroot}%{_libexecdir}/%{name}
|
||||
mkdir -p %{buildroot}%{_sharedstatedir}/acme/{private,csr,certs}
|
||||
mkdir -p %{buildroot}%{_sharedstatedir}/acme/{private,csr,certs,.notify}
|
||||
mkdir -p %{buildroot}%{_sysconfdir}/%{name}/notify.d
|
||||
mkdir -p %{buildroot}%{_sysconfdir}/sysconfig
|
||||
chmod 0700 %{buildroot}%{_sharedstatedir}/acme/private
|
||||
|
||||
install -m 0755 acme-tiny-sign.sh %{buildroot}%{_libexecdir}/%{name}/sign
|
||||
install -m 0755 %{SOURCE9} %{buildroot}%{_libexecdir}/%{name}/notify
|
||||
install -m 0755 acme_tiny.py %{buildroot}%{_sbindir}/acme_tiny
|
||||
ln -sf acme_tiny %{buildroot}%{_sbindir}/%{name}
|
||||
ln -sf %{_libexecdir}/%{name}/sign %{buildroot}%{_sbindir}/acme-tiny-sign
|
||||
ln -sf %{_libexecdir}/%{name}/notify %{buildroot}%{_sysconfdir}/%{name}/notify.sh
|
||||
install -m 0755 cert-check.py %{buildroot}%{_sbindir}/cert-check
|
||||
install -m 0644 %{SOURCE3} %{buildroot}%{_sysconfdir}/httpd/conf.d
|
||||
install -m 0644 %{SOURCE4} %{buildroot}%{_sharedstatedir}/acme
|
||||
install -m 0755 %{SOURCE9} %{buildroot}%{_sysconfdir}/%{name}
|
||||
%if %{use_systemd}
|
||||
mkdir -p %{buildroot}%{_unitdir}
|
||||
install -pm 644 %{SOURCE6} %{buildroot}%{_unitdir}
|
||||
install -pm 644 %{SOURCE7} %{buildroot}%{_unitdir}
|
||||
%else
|
||||
mkdir -p %{buildroot}%{_sysconfdir}/cron.d
|
||||
install -m 0644 %{SOURCE5} %{buildroot}%{_sysconfdir}/cron.d/acme-tiny
|
||||
%endif
|
||||
install -pm 644 %{SOURCE10} %{buildroot}%{_unitdir}
|
||||
install -m 0644 %{SOURCE11} %{buildroot}%{_sysconfdir}/sysconfig/%{name}
|
||||
install -m 0644 -D acme.sysusers.conf %{buildroot}%{_sysusersdir}/acme.conf
|
||||
|
||||
%pre
|
||||
getent group acme > /dev/null || groupadd -r acme
|
||||
|
|
@ -122,18 +105,14 @@ getent passwd acme > /dev/null || /usr/sbin/useradd -g acme \
|
|||
-r -d %{_sharedstatedir}/acme -s /sbin/nologin acme
|
||||
exit 0
|
||||
|
||||
%if %{use_systemd}
|
||||
|
||||
%post
|
||||
%systemd_post acme-tiny.service acme-tiny.timer
|
||||
%systemd_post acme-tiny.service acme-tiny-notice.service acme-tiny.timer
|
||||
|
||||
%postun
|
||||
%systemd_postun_with_restart acme-tiny.service acme-tiny.timer
|
||||
%systemd_postun_with_restart acme-tiny.service acme-tiny-notice.service acme-tiny.timer
|
||||
|
||||
%preun
|
||||
%systemd_preun acme-tiny.service acme-tiny.timer
|
||||
|
||||
%endif
|
||||
%systemd_preun acme-tiny.service acme-tiny-notice.service acme-tiny.timer
|
||||
|
||||
%files
|
||||
%{!?_licensedir:%global license %%doc}
|
||||
|
|
@ -143,15 +122,13 @@ exit 0
|
|||
%attr(-,acme,acme) %{_sharedstatedir}/acme
|
||||
%{_libexecdir}/%{name}
|
||||
%config(noreplace) %{_sysconfdir}/httpd/conf.d/acme.conf
|
||||
%if %{use_systemd}
|
||||
%config(noreplace) %{_sysconfdir}/sysconfig/%{name}
|
||||
%{_unitdir}/*
|
||||
%else
|
||||
%config(noreplace) %{_sysconfdir}/cron.d/%{name}
|
||||
%endif
|
||||
%{_sbindir}/acme-tiny-sign
|
||||
%{_sbindir}/cert-check
|
||||
%{_sbindir}/%{name}
|
||||
%{_sysconfdir}/%{name}
|
||||
%{_sysusersdir}/acme.conf
|
||||
|
||||
%files core
|
||||
%license LICENSE
|
||||
|
|
@ -159,7 +136,80 @@ exit 0
|
|||
%{_sbindir}/acme_tiny
|
||||
|
||||
%changelog
|
||||
* Fri Oct 11 2019 Tim Jackson <rpm@timj.co.uK - 4.1.0-1
|
||||
* Fri Jan 16 2026 Fedora Release Engineering <releng@fedoraproject.org> - 5.0.1-13
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild
|
||||
|
||||
* Wed Jul 23 2025 Fedora Release Engineering <releng@fedoraproject.org> - 5.0.1-12
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild
|
||||
|
||||
* Thu Jan 16 2025 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> - 5.0.1-11
|
||||
- Add sysusers.d config file
|
||||
|
||||
* Thu Jan 16 2025 Fedora Release Engineering <releng@fedoraproject.org> - 5.0.1-10
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild
|
||||
|
||||
* Wed Jul 17 2024 Fedora Release Engineering <releng@fedoraproject.org> - 5.0.1-9
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild
|
||||
|
||||
* Mon Jan 22 2024 Fedora Release Engineering <releng@fedoraproject.org> - 5.0.1-8
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
|
||||
|
||||
* Fri Jan 19 2024 Fedora Release Engineering <releng@fedoraproject.org> - 5.0.1-7
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
|
||||
|
||||
* Wed Jul 19 2023 Fedora Release Engineering <releng@fedoraproject.org> - 5.0.1-6
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
|
||||
|
||||
* Tue Mar 28 2023 Stuart D. Gathman <stuart@gathman.org> - 5.0.1-5
|
||||
- Verified SPDX license
|
||||
|
||||
* Wed Jan 18 2023 Fedora Release Engineering <releng@fedoraproject.org> - 5.0.1-4
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild
|
||||
|
||||
* Wed Jul 20 2022 Fedora Release Engineering <releng@fedoraproject.org> - 5.0.1-3
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild
|
||||
|
||||
* Wed Jan 19 2022 Fedora Release Engineering <releng@fedoraproject.org> - 5.0.1-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild
|
||||
|
||||
* Thu Oct 28 2021 Stuart D. Gathman <stuart@gathman.org> 5.0.1-1
|
||||
- New upstream release
|
||||
|
||||
* Wed Sep 8 2021 Stuart D. Gathman <stuart@gathman.org> 4.1.1-2
|
||||
- Remove CLI override in acme-tiny.service (uses /etc/sysconfig/acme-tiny now)
|
||||
|
||||
* Tue Sep 7 2021 Stuart D. Gathman <stuart@gathman.org> 4.1.1-1
|
||||
- New upstream release
|
||||
- Set days before expiration in /etc/sysconfig
|
||||
|
||||
* Wed Jul 21 2021 Fedora Release Engineering <releng@fedoraproject.org> - 4.1.0-8
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild
|
||||
|
||||
* Thu May 27 2021 Stuart D. Gathman <stuart@gathman.org> 4.1.0-7
|
||||
- Fix BZ#1839904
|
||||
- enhance notify after cert update, incrond no longer needed
|
||||
|
||||
* Tue Mar 02 2021 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> - 4.1.0-6
|
||||
- Rebuilt for updated systemd-rpm-macros
|
||||
See https://pagure.io/fesco/issue/2583.
|
||||
|
||||
* Mon Jan 25 2021 Fedora Release Engineering <releng@fedoraproject.org> - 4.1.0-5
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
|
||||
|
||||
* Mon Jul 27 2020 Fedora Release Engineering <releng@fedoraproject.org> - 4.1.0-4
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
|
||||
|
||||
* Thu Apr 9 2020 Stuart D. Gathman <stuart@gathman.org> 4.1.0-3
|
||||
- Update README-fedora.md to describe notify.sh
|
||||
- Apply selected changes from Marcel Metz <mmetz@adrian-broher.net>:
|
||||
- Use openssl x509 -checkend parameter to determine certificate expiration
|
||||
- Remove Let's Encrypt intermediate certificate
|
||||
- Remove cron job used on non systemd systems
|
||||
|
||||
* Tue Jan 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 4.1.0-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
|
||||
|
||||
* Fri Oct 11 2019 Tim Jackson <rpm@timj.co.uk> - 4.1.0-1
|
||||
- Update to 4.1.0
|
||||
|
||||
* Fri Oct 11 2019 Stuart D. Gathman <stuart@gathman.org> 4.0.4-5
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
|
||||
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
|
||||
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
|
||||
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
|
||||
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
|
||||
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
|
||||
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
|
||||
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
|
||||
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
|
||||
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
|
||||
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
|
||||
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
|
||||
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
|
||||
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
|
||||
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
|
||||
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
|
||||
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
|
||||
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
|
||||
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
|
||||
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
|
||||
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
|
||||
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
|
||||
-----END CERTIFICATE-----
|
||||
70
notify.sh
70
notify.sh
|
|
@ -1,20 +1,58 @@
|
|||
#!/bin/sh
|
||||
#!/usr/bin/sh
|
||||
|
||||
cert="$1"
|
||||
name="${cert##*/}"
|
||||
script="/etc/acme-tiny/notify.d/${name%.crt}.sh"
|
||||
acmedir="/var/lib/acme"
|
||||
#acmedir="test"
|
||||
notify="${acmedir}/.notify"
|
||||
verbose="n"
|
||||
mkdir -p "$notify"
|
||||
|
||||
# kick apache if cert is mentioned
|
||||
if grep "$cert" /etc/httpd/conf.d/*.conf >/dev/null 2>&1; then
|
||||
apachectl graceful
|
||||
fi
|
||||
scancerts() {
|
||||
if test -e "${notify}/notify"; then
|
||||
find "${acmedir}/certs" -name '*.crt' -newer "${notify}/notify" -print0
|
||||
else
|
||||
find "${acmedir}/certs" -name '*.crt' -print0
|
||||
fi | xargs -0 /usr/libexec/acme-tiny/notify -v
|
||||
touch "${notify}/notify"
|
||||
}
|
||||
|
||||
# kick sendmail if cert is mentioned
|
||||
if grep "/etc/pki/tls/certs/$name" /etc/mail/*.cf >/dev/null 2>&1; then
|
||||
cp "$cert" /etc/pki/tls/certs && systemctl restart sendmail
|
||||
fi
|
||||
for cert in "$@"; do
|
||||
case "$cert" in
|
||||
-v|--verbose) verbose="y"; continue;;
|
||||
-s|--scan) scancerts; continue;;
|
||||
-*) echo "Invalid option $cert"; exit 2;;
|
||||
esac
|
||||
name="${cert##*/}"
|
||||
script="/etc/acme-tiny/notify.d/${name%.crt}.sh"
|
||||
|
||||
# run any dropin extension
|
||||
if test -x "$script"; then
|
||||
"$script" "$cert"
|
||||
fi
|
||||
# kick apache if cert is mentioned
|
||||
if test "$cert" -nt "${notify}/httpd"; then
|
||||
if grep "$cert" /etc/httpd/conf.d/*.conf >/dev/null 2>&1; then
|
||||
apachectl graceful && touch "${notify}/httpd" && \
|
||||
[ "$verbose" = "y" ] && echo "Httpd reloaded"
|
||||
fi
|
||||
fi
|
||||
|
||||
# kick sendmail if cert is mentioned
|
||||
if test "$cert" -nt "${notify}/sendmail"; then
|
||||
if grep "/etc/pki/tls/certs/$name" /etc/mail/*.cf >/dev/null 2>&1; then
|
||||
cp "$cert" /etc/pki/tls/certs && systemctl restart sendmail \
|
||||
&& touch "${notify}/sendmail" && \
|
||||
[ "$verbose" = "y" ] && echo "Sendmail reloaded"
|
||||
fi
|
||||
fi
|
||||
|
||||
# kick dovecot if cert is mentioned
|
||||
if test "$cert" -nt "${notify}/dovecot"; then
|
||||
if grep "/etc/pki/dovecot/certs/$name" /etc/dovecot/conf.d/10-ssl.conf >/dev/null 2>&1; then
|
||||
cp "$cert" /etc/pki/dovecot/certs && systemctl restart dovecot \
|
||||
&& touch "${notify}/dovecot" && \
|
||||
[ "$verbose" = "y" ] && echo "Dovecot reloaded"
|
||||
fi
|
||||
fi
|
||||
|
||||
# run any dropin extension
|
||||
if test -x "$script"; then
|
||||
[ "$verbose" = "y" ] && echo "Running $script $cert"
|
||||
ACMEDIR="$acmedir" NOTIFY="$notify" VERBOSE="$verbose" "$script" "$cert"
|
||||
fi
|
||||
done
|
||||
|
|
|
|||
3
sources
3
sources
|
|
@ -1 +1,2 @@
|
|||
SHA512 (acme-tiny-4.1.0.tar.gz) = 31d69a5031c019acbc23b3f06041eae8e261766396d4a7420fd70a71cfa16de953bea4c0c2ad0c6a6e793ed61ab5331f40145352ffce69f4f062f35dd0db7519
|
||||
SHA512 (acme-tiny-4.1.1.tar.gz) = 9e1aac03f3aa744061b8b03bb7bb6ede52ccf1a72d729775f106eb0fef786ee495dedd4f44c672e4ee2a8fc385477366bf164ab5e78d85e0a031558cde68f4b1
|
||||
SHA512 (acme-tiny-5.0.1.tar.gz) = 6e0619917b31a5795c2c7d8aa811b46231b81fc6b57227f611f7f4b9f73eb3de669676482563c33d935a4a0812498677bcbe974663a561af61abb441a880947e
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue