mirror of
https://github.com/mail-in-a-box/mailinabox.git
synced 2024-11-22 02:17:26 +00:00
make the system SSL certificate a symlink so we never have to replace a certificate file, and flatten the directory structure of user-installed certificates
This commit is contained in:
parent
cf33be4596
commit
c422543fdd
@ -351,21 +351,18 @@ def install_cert(domain, ssl_cert, ssl_chain, env):
|
|||||||
return cert_status
|
return cert_status
|
||||||
|
|
||||||
# Where to put it?
|
# Where to put it?
|
||||||
if domain == env['PRIMARY_HOSTNAME']:
|
# Make a unique path for the certificate.
|
||||||
ssl_certificate = os.path.join(os.path.join(env["STORAGE_ROOT"], 'ssl', 'ssl_certificate.pem'))
|
from status_checks import load_cert_chain, load_pem, get_certificate_domains
|
||||||
else:
|
from cryptography.hazmat.primitives import hashes
|
||||||
# Make a unique path for the certificate.
|
from binascii import hexlify
|
||||||
from status_checks import load_cert_chain, load_pem, get_certificate_domains
|
cert = load_pem(load_cert_chain(fn)[0])
|
||||||
from cryptography.hazmat.primitives import hashes
|
all_domains, cn = get_certificate_domains(cert)
|
||||||
from binascii import hexlify
|
path = "%s-%s-%s.pem" % (
|
||||||
cert = load_pem(load_cert_chain(fn)[0])
|
cn, # common name
|
||||||
all_domains, cn = get_certificate_domains(cert)
|
cert.not_valid_after.date().isoformat().replace("-", ""), # expiration date
|
||||||
path = "%s-%s-%s" % (
|
hexlify(cert.fingerprint(hashes.SHA256())).decode("ascii")[0:8], # fingerprint prefix
|
||||||
cn, # common name
|
)
|
||||||
cert.not_valid_after.date().isoformat().replace("-", ""), # expiration date
|
ssl_certificate = os.path.join(os.path.join(env["STORAGE_ROOT"], 'ssl', path))
|
||||||
hexlify(cert.fingerprint(hashes.SHA256())).decode("ascii")[0:8], # fingerprint prefix
|
|
||||||
)
|
|
||||||
ssl_certificate = os.path.join(os.path.join(env["STORAGE_ROOT"], 'ssl', path, 'ssl_certificate.pem'))
|
|
||||||
|
|
||||||
# Install the certificate.
|
# Install the certificate.
|
||||||
os.makedirs(os.path.dirname(ssl_certificate), exist_ok=True)
|
os.makedirs(os.path.dirname(ssl_certificate), exist_ok=True)
|
||||||
@ -373,17 +370,23 @@ def install_cert(domain, ssl_cert, ssl_chain, env):
|
|||||||
|
|
||||||
ret = ["OK"]
|
ret = ["OK"]
|
||||||
|
|
||||||
# When updating the cert for PRIMARY_HOSTNAME, also update DNS because it is
|
# When updating the cert for PRIMARY_HOSTNAME, symlink it from the system
|
||||||
# used in the DANE TLSA record and restart postfix and dovecot which use
|
# certificate path, which is hard-coded for various purposes, and then
|
||||||
# that certificate.
|
# update DNS (because of the DANE TLSA record), postfix, and dovecot,
|
||||||
|
# which all use the file.
|
||||||
if domain == env['PRIMARY_HOSTNAME']:
|
if domain == env['PRIMARY_HOSTNAME']:
|
||||||
ret.append( do_dns_update(env) )
|
# Update symlink.
|
||||||
|
system_ssl_certificate = os.path.join(os.path.join(env["STORAGE_ROOT"], 'ssl', 'ssl_certificate.pem'))
|
||||||
|
os.unlink(system_ssl_certificate)
|
||||||
|
os.symlink(ssl_certificate, system_ssl_certificate)
|
||||||
|
|
||||||
|
# Update DNS & restart postfix and dovecot so they pick up the new file.
|
||||||
|
ret.append( do_dns_update(env) )
|
||||||
shell('check_call', ["/usr/sbin/service", "postfix", "restart"])
|
shell('check_call', ["/usr/sbin/service", "postfix", "restart"])
|
||||||
shell('check_call', ["/usr/sbin/service", "dovecot", "restart"])
|
shell('check_call', ["/usr/sbin/service", "dovecot", "restart"])
|
||||||
ret.append("mail services restarted")
|
ret.append("mail services restarted")
|
||||||
|
|
||||||
# Kick nginx so it sees the cert.
|
# Update the web configuration so nginx picks up the new certificate file.
|
||||||
ret.append( do_web_update(env) )
|
ret.append( do_web_update(env) )
|
||||||
return "\n".join(ret)
|
return "\n".join(ret)
|
||||||
|
|
||||||
|
@ -111,6 +111,32 @@ def migration_9(env):
|
|||||||
db = os.path.join(env["STORAGE_ROOT"], 'mail/users.sqlite')
|
db = os.path.join(env["STORAGE_ROOT"], 'mail/users.sqlite')
|
||||||
shell("check_call", ["sqlite3", db, "ALTER TABLE aliases ADD permitted_senders TEXT"])
|
shell("check_call", ["sqlite3", db, "ALTER TABLE aliases ADD permitted_senders TEXT"])
|
||||||
|
|
||||||
|
def migration_10(env):
|
||||||
|
# Clean up the SSL certificates directory.
|
||||||
|
|
||||||
|
# Move the primary certificate to a new name and then
|
||||||
|
# symlink it to the system certificate path.
|
||||||
|
import datetime
|
||||||
|
system_certificate = os.path.join(env["STORAGE_ROOT"], 'ssl/ssl_certificate.pem')
|
||||||
|
if not os.path.islink(system_certificate): # not already a symlink
|
||||||
|
new_path = os.path.join(env["STORAGE_ROOT"], 'ssl', env['PRIMARY_HOSTNAME'] + "-" + datetime.datetime.now().date().isoformat().replace("-", "") + ".pem")
|
||||||
|
print("Renamed", system_certificate, "to", new_path, "and created a symlink for the original location.")
|
||||||
|
shutil.move(system_certificate, new_path)
|
||||||
|
os.symlink(new_path, system_certificate)
|
||||||
|
|
||||||
|
# Flatten the directory structure. For any directory
|
||||||
|
# that contains a single file named ssl_certificate.pem,
|
||||||
|
# move the file out and name it the same as the directory,
|
||||||
|
# and remove the directory.
|
||||||
|
for sslcert in glob.glob(os.path.join( env["STORAGE_ROOT"], 'ssl/*/ssl_certificate.pem' )):
|
||||||
|
d = os.path.dirname(sslcert)
|
||||||
|
if len(os.listdir(d)) == 1:
|
||||||
|
# This certificate is the only file in that directory.
|
||||||
|
newname = os.path.join(env["STORAGE_ROOT"], 'ssl', os.path.basename(d) + '.pem')
|
||||||
|
if not os.path.exists(newname):
|
||||||
|
shutil.move(sslcert, newname)
|
||||||
|
os.rmdir(d)
|
||||||
|
|
||||||
def get_current_migration():
|
def get_current_migration():
|
||||||
ver = 0
|
ver = 0
|
||||||
while True:
|
while True:
|
||||||
|
11
setup/ssl.sh
11
setup/ssl.sh
@ -77,12 +77,17 @@ if [ ! -f $STORAGE_ROOT/ssl/ssl_certificate.pem ]; then
|
|||||||
-sha256 -subj "/C=$CSR_COUNTRY/ST=/L=/O=/CN=$PRIMARY_HOSTNAME"
|
-sha256 -subj "/C=$CSR_COUNTRY/ST=/L=/O=/CN=$PRIMARY_HOSTNAME"
|
||||||
|
|
||||||
# Generate the self-signed certificate.
|
# Generate the self-signed certificate.
|
||||||
|
CERT=$STORAGE_ROOT/ssl/$PRIMARY_HOSTNAME-selfsigned-$(date --rfc-3339=date | sed s/-//g).pem
|
||||||
hide_output \
|
hide_output \
|
||||||
openssl x509 -req -days 365 \
|
openssl x509 -req -days 365 \
|
||||||
-in $CSR -signkey $STORAGE_ROOT/ssl/ssl_private_key.pem -out $STORAGE_ROOT/ssl/ssl_certificate.pem
|
-in $CSR -signkey $STORAGE_ROOT/ssl/ssl_private_key.pem -out $CERT
|
||||||
|
|
||||||
# Delete the certificate signing request because it has no other purpose.
|
# Delete the certificate signing request because it has no other purpose.
|
||||||
rm -f $CSR
|
rm -f $CSR
|
||||||
|
|
||||||
|
# Symlink the certificate into the system certificate path, so system services
|
||||||
|
# can find it.
|
||||||
|
ln -s $CERT $STORAGE_ROOT/ssl/ssl_certificate.pem
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Generate some Diffie-Hellman cipher bits.
|
# Generate some Diffie-Hellman cipher bits.
|
||||||
|
Loading…
Reference in New Issue
Block a user