Merge pull request #1062 from YunoHost/move-local-ca-mangement-to-regenconf

Refactor local CA management for more consistency and simpler postinstall
This commit is contained in:
Alexandre Aubin 2021-01-31 16:17:20 +01:00 committed by GitHub
commit 68e24c986a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 70 additions and 116 deletions

View file

@ -3,71 +3,81 @@
set -e set -e
ssl_dir="/usr/share/yunohost/yunohost-config/ssl/yunoCA" ssl_dir="/usr/share/yunohost/yunohost-config/ssl/yunoCA"
ynh_ca="/etc/yunohost/certs/yunohost.org/ca.pem"
ynh_crt="/etc/yunohost/certs/yunohost.org/crt.pem"
ynh_key="/etc/yunohost/certs/yunohost.org/key.pem"
openssl_conf="/usr/share/yunohost/templates/ssl/openssl.cnf"
do_init_regen() { regen_local_ca() {
if [[ $EUID -ne 0 ]]; then
echo "You must be root to run this script" 1>&2
exit 1
fi
LOGFILE="/tmp/yunohost-ssl-init" domain="$1"
echo "Initializing a local SSL certification authority ..." echo -e "\n# Creating local certification authority with domain=$domain\n"
echo "(logs available in $LOGFILE)"
rm -f $LOGFILE
touch $LOGFILE
# create certs and SSL directories # create certs and SSL directories
mkdir -p "/etc/yunohost/certs/yunohost.org" mkdir -p "/etc/yunohost/certs/yunohost.org"
mkdir -p "${ssl_dir}/"{ca,certs,crl,newcerts} mkdir -p "${ssl_dir}/"{ca,certs,crl,newcerts}
# initialize some files pushd ${ssl_dir}
# (Update the serial so that it's specific to this very instance)
# N.B. : the weird RANDFILE thing comes from: # N.B. : the weird RANDFILE thing comes from:
# https://stackoverflow.com/questions/94445/using-openssl-what-does-unable-to-write-random-state-mean # https://stackoverflow.com/questions/94445/using-openssl-what-does-unable-to-write-random-state-mean
[[ -f "${ssl_dir}/serial" ]] \ RANDFILE=.rnd openssl rand -hex 19 > serial
|| RANDFILE=.rnd openssl rand -hex 19 > "${ssl_dir}/serial" rm -f index.txt
[[ -f "${ssl_dir}/index.txt" ]] \ touch index.txt
|| touch "${ssl_dir}/index.txt" cp /usr/share/yunohost/templates/ssl/openssl.cnf openssl.ca.cnf
sed -i s/yunohost.org/${domain}/g openssl.ca.cnf
openssl req -x509 \
-new \
-config openssl.ca.cnf \
-days 3650 \
-out ca/cacert.pem \
-keyout ca/cakey.pem \
-nodes \
-batch \
-subj /CN=${domain}/O=${domain%.*} 2>&1
openssl_conf="/usr/share/yunohost/templates/ssl/openssl.cnf" chmod 640 ca/cacert.pem
ynh_ca="/etc/yunohost/certs/yunohost.org/ca.pem" chmod 640 ca/cakey.pem
ynh_crt="/etc/yunohost/certs/yunohost.org/crt.pem"
ynh_key="/etc/yunohost/certs/yunohost.org/key.pem" cp ca/cacert.pem $ynh_ca
ln -sf "$ynh_ca" /etc/ssl/certs/ca-yunohost_crt.pem
update-ca-certificates
popd
}
do_init_regen() {
LOGFILE=/tmp/yunohost-ssl-init
echo "" > $LOGFILE
chown root:root $LOGFILE
chmod 640 $LOGFILE
# create default certificates # create default certificates
if [[ ! -f "$ynh_ca" ]]; then if [[ ! -f "$ynh_ca" ]]; then
echo -e "\n# Creating the CA key (?)\n" >>$LOGFILE regen_local_ca yunohost.org >>$LOGFILE
openssl req -x509 \
-new \
-config "$openssl_conf" \
-days 3650 \
-out "${ssl_dir}/ca/cacert.pem" \
-keyout "${ssl_dir}/ca/cakey.pem" \
-nodes -batch >>$LOGFILE 2>&1
cp "${ssl_dir}/ca/cacert.pem" "$ynh_ca"
ln -sf "$ynh_ca" /etc/ssl/certs/ca-yunohost_crt.pem
update-ca-certificates
fi fi
if [[ ! -f "$ynh_crt" ]]; then if [[ ! -f "$ynh_crt" ]]; then
echo -e "\n# Creating initial key and certificate (?)\n" >>$LOGFILE echo -e "\n# Creating initial key and certificate \n" >>$LOGFILE
openssl req -new \ openssl req -new \
-config "$openssl_conf" \ -config "$openssl_conf" \
-days 730 \ -days 730 \
-out "${ssl_dir}/certs/yunohost_csr.pem" \ -out "${ssl_dir}/certs/yunohost_csr.pem" \
-keyout "${ssl_dir}/certs/yunohost_key.pem" \ -keyout "${ssl_dir}/certs/yunohost_key.pem" \
-nodes -batch >>$LOGFILE 2>&1 -nodes -batch &>>$LOGFILE
openssl ca \ openssl ca \
-config "$openssl_conf" \ -config "$openssl_conf" \
-days 730 \ -days 730 \
-in "${ssl_dir}/certs/yunohost_csr.pem" \ -in "${ssl_dir}/certs/yunohost_csr.pem" \
-out "${ssl_dir}/certs/yunohost_crt.pem" \ -out "${ssl_dir}/certs/yunohost_crt.pem" \
-batch >>$LOGFILE 2>&1 -batch &>>$LOGFILE
chmod 640 "${ssl_dir}/certs/yunohost_key.pem" chmod 640 "${ssl_dir}/certs/yunohost_key.pem"
chmod 640 "${ssl_dir}/certs/yunohost_crt.pem" chmod 640 "${ssl_dir}/certs/yunohost_crt.pem"
@ -80,6 +90,8 @@ do_init_regen() {
chown -R root:ssl-cert /etc/yunohost/certs/yunohost.org/ chown -R root:ssl-cert /etc/yunohost/certs/yunohost.org/
chmod o-rwx /etc/yunohost/certs/yunohost.org/ chmod o-rwx /etc/yunohost/certs/yunohost.org/
install -D -m 644 $openssl_conf "${ssl_dir}/openssl.cnf"
} }
do_pre_regen() { do_pre_regen() {
@ -93,22 +105,16 @@ do_pre_regen() {
do_post_regen() { do_post_regen() {
regen_conf_files=$1 regen_conf_files=$1
# Ensure that index.txt exists current_local_ca_domain=$(openssl x509 -in $ynh_ca -text | tr ',' '\n' | grep Issuer | awk '{print $4}')
index_txt=/usr/share/yunohost/yunohost-config/ssl/yunoCA/index.txt main_domain=$(cat /etc/yunohost/current_host)
[[ -f "${index_txt}" ]] || {
if [[ -f "${index_txt}.saved" ]]; then
# use saved database from 2.2
cp "${index_txt}.saved" "${index_txt}"
elif [[ -f "${index_txt}.old" ]]; then
# ... or use the state-1 database
cp "${index_txt}.old" "${index_txt}"
else
# ... or create an empty one
touch "${index_txt}"
fi
}
# TODO: regenerate certificates if conf changed? if [[ "$current_local_ca_domain" != "$main_domain" ]]
then
regen_local_ca $main_domain
# Idk how useful this is, but this was in the previous python code (domain.main_domain())
ln -sf /etc/yunohost/certs/$domain/crt.pem /etc/ssl/certs/yunohost_crt.pem
ln -sf /etc/yunohost/certs/$domain/key.pem /etc/ssl/private/yunohost_key.pem
fi
} }
FORCE=${2:-0} FORCE=${2:-0}

View file

@ -627,8 +627,6 @@
"user_update_failed": "Could not update user {user}: {error}", "user_update_failed": "Could not update user {user}: {error}",
"user_updated": "User info changed", "user_updated": "User info changed",
"yunohost_already_installed": "YunoHost is already installed", "yunohost_already_installed": "YunoHost is already installed",
"yunohost_ca_creation_failed": "Could not create certificate authority",
"yunohost_ca_creation_success": "Local certification authority created.",
"yunohost_configured": "YunoHost is now configured", "yunohost_configured": "YunoHost is now configured",
"yunohost_installing": "Installing YunoHost...", "yunohost_installing": "Installing YunoHost...",
"yunohost_not_installed": "YunoHost is not correctly installed. Please run 'yunohost tools postinstall'", "yunohost_not_installed": "YunoHost is not correctly installed. Please run 'yunohost tools postinstall'",

View file

@ -30,6 +30,7 @@ from moulinette import m18n, msettings
from moulinette.core import MoulinetteError from moulinette.core import MoulinetteError
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import write_to_file
from yunohost.app import app_ssowatconf, _installed_apps, _get_app_settings, _get_conflicting_apps from yunohost.app import app_ssowatconf, _installed_apps, _get_app_settings, _get_conflicting_apps
from yunohost.regenconf import regen_conf, _force_clear_hashes, _process_regen_conf from yunohost.regenconf import regen_conf, _force_clear_hashes, _process_regen_conf
@ -318,36 +319,20 @@ def domain_main_domain(operation_logger, new_main_domain=None):
operation_logger.start() operation_logger.start()
# Apply changes to ssl certs # Apply changes to ssl certs
ssl_key = "/etc/ssl/private/yunohost_key.pem"
ssl_crt = "/etc/ssl/private/yunohost_crt.pem"
new_ssl_key = "/etc/yunohost/certs/%s/key.pem" % new_main_domain
new_ssl_crt = "/etc/yunohost/certs/%s/crt.pem" % new_main_domain
try: try:
if os.path.exists(ssl_key) or os.path.lexists(ssl_key): write_to_file('/etc/yunohost/current_host', new_main_domain)
os.remove(ssl_key)
if os.path.exists(ssl_crt) or os.path.lexists(ssl_crt):
os.remove(ssl_crt)
os.symlink(new_ssl_key, ssl_key) _set_hostname(new_main_domain)
os.symlink(new_ssl_crt, ssl_crt)
_set_maindomain(new_main_domain)
except Exception as e: except Exception as e:
logger.warning("%s" % e, exc_info=1) logger.warning("%s" % e, exc_info=1)
raise YunohostError('main_domain_change_failed') raise YunohostError('main_domain_change_failed')
_set_hostname(new_main_domain)
# Generate SSOwat configuration file # Generate SSOwat configuration file
app_ssowatconf() app_ssowatconf()
# Regen configurations # Regen configurations
try: if os.path.exists('/etc/yunohost/installed'):
with open('/etc/yunohost/installed', 'r'):
regen_conf() regen_conf()
except IOError:
pass
logger.success(m18n.n('main_domain_changed')) logger.success(m18n.n('main_domain_changed'))
@ -385,11 +370,6 @@ def _get_maindomain():
return maindomain return maindomain
def _set_maindomain(domain):
with open('/etc/yunohost/current_host', 'w') as f:
f.write(domain)
def _build_dns_conf(domain, ttl=3600, include_empty_AAAA_if_no_ipv6=False): def _build_dns_conf(domain, ttl=3600, include_empty_AAAA_if_no_ipv6=False):
""" """
Internal function that will returns a data structure containing the needed Internal function that will returns a data structure containing the needed

View file

@ -327,37 +327,7 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
os.system('chmod 644 /etc/ssowat/conf.json.persistent') os.system('chmod 644 /etc/ssowat/conf.json.persistent')
# Create SSL CA
regen_conf(['ssl'], force=True)
ssl_dir = '/usr/share/yunohost/yunohost-config/ssl/yunoCA'
# (Update the serial so that it's specific to this very instance)
os.system("openssl rand -hex 19 > %s/serial" % ssl_dir)
commands = [
'rm %s/index.txt' % ssl_dir,
'touch %s/index.txt' % ssl_dir,
'cp %s/openssl.cnf %s/openssl.ca.cnf' % (ssl_dir, ssl_dir),
'sed -i s/yunohost.org/%s/g %s/openssl.ca.cnf ' % (domain, ssl_dir),
'openssl req -x509 -new -config %s/openssl.ca.cnf -days 3650 -out %s/ca/cacert.pem -keyout %s/ca/cakey.pem -nodes -batch -subj /CN=%s/O=%s' % (ssl_dir, ssl_dir, ssl_dir, domain, os.path.splitext(domain)[0]),
'cp %s/ca/cacert.pem /etc/ssl/certs/ca-yunohost_crt.pem' % ssl_dir,
'update-ca-certificates'
]
for command in commands:
p = subprocess.Popen(
command.split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
out, _ = p.communicate()
if p.returncode != 0:
logger.warning(out)
raise YunohostError('yunohost_ca_creation_failed')
else:
logger.debug(out)
logger.success(m18n.n('yunohost_ca_creation_success'))
# New domain config # New domain config
regen_conf(['nsswitch'], force=True)
domain_add(domain, dyndns) domain_add(domain, dyndns)
domain_main_domain(domain) domain_main_domain(domain)