Package: neutron-api
Version: 2:26.0.0-1~bpo12+1
Severity: wishlist

Dear Maintainer,

The init.d script controlling neutron-api would benefit from extending options related to HTTPS config.

1. Current configuration option looks under /etc/${PROJECT_NAME}/ssl/public and /etc/${PROJECT_NAME}/ssl/private:

 66 if [ -n "${UWSGI_PORT}" ] && [ -n "${UWSGI_INI_PATH}" ] && [ -n "${UWSGI_INI_APP}" ] ; then
 67     if ! [ -f "${UWSGI_INI_APP}" ] ; then
 68         ·exit 0
 69     fi
 70     if [ -d /etc/${PROJECT_NAME}/ssl/private ] ; then
 71         KEY_FILE=$(find /etc/${PROJECT_NAME}/ssl/private -type f -iname '*.pem' 2>/dev/null | head -n 1)
 72     fi
 73
 74     if [ -e /usr/local/share/ca-certificates/puppet_openstack.crt ] ; then
 75         # This is needed for puppet...
 76 CERT_FILE=/usr/local/share/ca-certificates/puppet_openstack.crt
 77     else
 78         if [ -d /etc/${PROJECT_NAME}/ssl/public ] ; then
 79            ·CERT_FILE=$(find /etc/${PROJECT_NAME}/ssl/public -type f -iname '*.crt' 2>/dev/null | head -n 1)
 80         fi
 81     fi

2. Later in the script the parameters for https or http are decided:

128         if [ -n "${BIND_PARAMS}" ] ; then
129                 DAEMON_ARGS="${BIND_PARAMS}${UWSGI_PROCESSES}"
130         else
131                 if [ -n "${KEY_FILE}" ] && [ -n "${CERT_FILE}" ] ; then
132                         DAEMON_ARGS="--https-socket ${UWSGI_BIND_IP}:${UWSGI_PORT},${CERT_FILE},${KEY_FILE}${UWSGI_PROCESSES}"
133                 else
134                         DAEMON_ARGS="--http-socket ${UWSGI_BIND_IP}:${UWSGI_PORT}${UWSGI_PROCESSES}"
135                 fi
136         fi

1. It would be beneficial if one could add arbitrary path for the key and certificate files and specify the file names instead of using find. Or have somewhere a configuration file where one could write the values.

2. When using  client certificate authentication, it is required to be able to pass more parameters to uwsgi.

Then the DAEMON_ARGS should be something like following:

DAEMON_ARGS="--https-socket ${UWSGI_BIND_IP}:${UWSGI_PORT},${CERT_FILE},${KEY_FILE},${TLS_CIPHER},${CA_FILE}${UWSGI_PROCESSES}"

where TLS_CIPHER in this case would be 'HIGH' indicating highest possible ciphers for TLS [1] and CA_FILE path to CA file.

Attached is the modified neutron-api script which allows us to run api
over https with the native uwsgi script.

This issue has been around already in Dalmation with Debian 12.9.

So far we could circumvent with using apache2 to serve api with wsgi
module and TLS. However now neutron requires native uwsgi to be used to
serve the APIs.

Best, Jani

[1] https://uwsgi-docs.readthedocs.io/en/latest/HTTPS.html

-- System Information:
Debian Release: trixie/sid
  APT prefers stable-updates
  APT policy: (500, 'stable-updates'), (500, 'stable-security'), (500, 'stable')
Architecture: amd64 (x86_64)

Kernel: Linux 6.10.6-progress7.99-amd64 (SMP w/64 CPU threads; PREEMPT)
Locale: LANG=C.UTF-8, LC_CTYPE=C.UTF-8 (charmap=UTF-8) (ignored: LC_ALL set to C.UTF-8), LANGUAGE not set
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)

Versions of packages neutron-api depends on:
ii  adduser                                  3.134
ii  debconf [debconf-2.0]                    1.5.82
ii  neutron-common                           2:26.0.0-1~bpo12+1
ii  python3-keystoneclient                   1:5.6.0-2~bpo12+1
ii  python3-openstackclient                  7.4.0-3~bpo12+1
ii  python3-pastescript                      3.2.1-1
ii  python3-q-text-as-data [q-text-as-data]  3.1.6-5~bpo12+1
ii  uwsgi-plugin-python3                     2.0.21-5.1

neutron-api recommends no packages.

neutron-api suggests no packages.

-- Configuration Files:
/etc/init.d/neutron-api changed:
DESC="OpenStack Neutron API (neutron-api)"
PROJECT_NAME=neutron
NAME=${PROJECT_NAME}-server
UWSGI_PORT=9696
UWSGI_INI_PATH=/etc/neutron/neutron-api-uwsgi.ini
UWSGI_INI_APP=/usr/bin/neutron-api
PYARGV="--config-file=/etc/neutron/neutron.conf"
[ -r /usr/share/neutron-common/plugin_guess_func ] || exit 0
. /usr/share/neutron-common/plugin_guess_func
if ! [ -r /etc/neutron/neutron.conf ] ; then
        echo "Cloud not read /etc/neutron/neutron.conf: exiting"
        exit 0
fi
CURRENT_PLUGIN=`grep "^[ \t]*core_plugin[ \t]*=[ \t]*[._a-zA-Z0-9]*\$" /etc/neutron/neutron.conf | sed -e 's/^[ \t]*core_plugin[ \t]*=[ \t]*//'`
if [ -z "${CURRENT_PLUGIN}" ] ; then
        echo "No core_plugin= value found: please set it and try again"
        exit 0
fi
neutron_core_plugin_to_plugin_name ${CURRENT_PLUGIN}
neutron_plugin_ini_path ${NEUTRON_PLUGIN_NAME}

if [ -z "${NEUTRON_PLUGIN_CONFIG}" ] ; then
        echo "Plugin not recognized: please edit /etc/init.d/neutron-api to select the correct .ini file to load for your plugin"
else
        PYARGV="${PYARGV} --config-file=${NEUTRON_PLUGIN_CONFIG}"
        DESC="${DESC} with ${NEUTRON_PLUGIN_NAME} plugin"
fi
if [ -e /etc/neutron/server.conf.d ] ; then
        PYARGV="--config-dir=/etc/neutron/server.conf.d ${PYARGV}"
fi
mkdir -p /var/lib/neutron/tmp
chown neutron:neutron /var/lib/neutron/tmp
export TMPDIR=/var/lib/neutron/tmp
PATH=/sbin:/usr/sbin:/bin:/usr/bin
if [ -n "${UWSGI_PORT}" ] && [ -n "${UWSGI_INI_PATH}" ] && [ -n "${UWSGI_INI_APP}" ] ; then
        if ! [ -f "${UWSGI_INI_APP}" ] ; then
                exit 0
        fi
        if [ -d /etc/${PROJECT_NAME}/ssl/private ] ; then
                KEY_FILE=$(find /etc/${PROJECT_NAME}/ssl/private -type f -iname '*.pem' 2>/dev/null | head -n 1)
        fi
        if [ -e /usr/local/share/ca-certificates/puppet_openstack.crt ] ; then
                # This is needed for puppet...
CERT_FILE=/usr/local/share/ca-certificates/puppet_openstack.crt
        else
                if [ -d /etc/${PROJECT_NAME}/ssl/public ] ; then
                        CERT_FILE=$(find /etc/${PROJECT_NAME}/ssl/public -type f -iname '*.crt' 2>/dev/null | head -n 1)
                fi
        fi
        # Sid doesn't have /usr/bin/uwsgi_python3, so we need
        # to search for a more specific daemon name. For stretch
        # /usr/bin/uwsgi_python3 is fine.
        for i in 3 35 36 37 38 39 310 311 312 313 314 315 316 317 318 319 ; do
                if [ -x /usr/bin/uwsgi_python${i} ] ; then
                        DAEMON=/usr/bin/uwsgi_python${i}
                fi
        done
        if [ -n "${UWSGI_BIND_CONFIG_FILE}" ] && [ -r "${UWSGI_BIND_CONFIG_FILE}" ] && [ -n "${UWSGI_BIND_CONFIG_SECTION}" ] && [ -n "${UWSGI_BIND_CONFIG_IP_DIRECTIVE}" ] && [ -n "${UWSGI_BIND_CONFIG_PORT_DIRECTIVE}" ] && [ -r /usr/share/openstack-pkg-tools/pkgos_func ] ; then
                . /usr/share/openstack-pkg-tools/pkgos_func
                pkgos_inifile get ${UWSGI_BIND_CONFIG_FILE} ${UWSGI_BIND_CONFIG_SECTION} ${UWSGI_BIND_CONFIG_IP_DIRECTIVE}
                if [ -n "${RET}" ] && [ ! "${RET}" = "NOT_FOUND" ] ; then
                        UWSGI_BIND_IP=${RET}
                fi
                pkgos_inifile get ${UWSGI_BIND_CONFIG_FILE} ${UWSGI_BIND_CONFIG_SECTION} ${UWSGI_BIND_CONFIG_PORT_DIRECTIVE}
                if [ -n "${RET}" ] && [ ! "${RET}" = "NOT_FOUND" ] ; then
                        UWSGI_PORT=${RET}
                fi
                if [ -n "${UWSGI_BIND_CONFIG_WORKERS_DIRECTIVE}" ] ; then
                        pkgos_inifile get ${UWSGI_BIND_CONFIG_FILE} ${UWSGI_BIND_CONFIG_SECTION} ${UWSGI_BIND_CONFIG_WORKERS_DIRECTIVE}                         if [ -n "${RET}" ] && [ ! "${RET}" = "NOT_FOUND" ] ; then
                                UWSGI_PROCESSES=" --processes ${RET}"
                        else
                                # If we can't find the directive in the config file,
                                # we fallback to the number of thread / 2.
                                UWSGI_PROCESSES=" --processes "$(( $(nproc) / 2 ))
                        fi
                fi
                if [ "${UWSGI_BIND_CONFIG_FILE}" = "/etc/swift/object-server.conf" ] ; then                         pkgos_inifile get ${UWSGI_BIND_CONFIG_FILE} ${UWSGI_BIND_CONFIG_SECTION} devices                         if [ -n "${RET}" ] && [ ! "${RET}" = "NOT_FOUND" ] ; then
                                DEVICES_PATH=${RET}
                                NUM_DEVICES=$(ls ${DEVICES_PATH} | wc -l)
                                COUNT=0
                                while [ "${COUNT}" != "${NUM_DEVICES}" ] ; do                                         CUR_PORT=$(( ${UWSGI_PORT} + ${COUNT} ))
BIND_PARAMS="${BIND_PARAMS} --http-socket ${UWSGI_BIND_IP}:${CUR_PORT}"
                                        COUNT=$(( ${COUNT} + 1 ))
                                done
                        fi
                fi
        else
                UWSGI_BIND_IP="[::]"
        fi
        if [ -n "${BIND_PARAMS}" ] ; then
                DAEMON_ARGS="${BIND_PARAMS}${UWSGI_PROCESSES}"
        else
                KEY_FILE="/srv/path/to/ssl/privkey.pem"
                CERT_FILE="/srv/path/to/ssl/cert.pem"
CA_FILE="/srv/path/to/ssl/root_intermediate_cert.pem"
                if [ -n "${KEY_FILE}" ] && [ -n "${CERT_FILE}" ] ; then
                        DAEMON_ARGS="--https-socket ${UWSGI_BIND_IP}:${UWSGI_PORT},${CERT_FILE},${KEY_FILE},HIGH,${CA_FILE}${UWSGI_PROCESSES}"
                else
                        DAEMON_ARGS="--http-socket ${UWSGI_BIND_IP}:${UWSGI_PORT}${UWSGI_PROCESSES}"
                fi
        fi
        DAEMON_ARGS="${DAEMON_ARGS} --ini ${UWSGI_INI_PATH}"
        NO_OPENSTACK_CONFIG_FILE_DAEMON_ARG=yes
        NO_OPENSTACK_LOGFILE_DAEMON_ARG=yes
fi
if [ -z "${DAEMON}" ] ; then
        DAEMON=/usr/bin/${NAME}
fi
PIDFILE=/var/run/${PROJECT_NAME}/${NAME}.pid
if [ -z "${SCRIPTNAME}" ] ; then
        SCRIPTNAME=/etc/init.d/${NAME}
fi
if [ -z "${SYSTEM_USER}" ] ; then
        SYSTEM_USER=${PROJECT_NAME}
fi
if [ -z "${SYSTEM_GROUP}" ] ; then
        SYSTEM_GROUP=${PROJECT_NAME}
fi
if [ "${SYSTEM_USER}" != "root" ] ; then
        STARTDAEMON_CHUID="--chuid ${SYSTEM_USER}:${SYSTEM_GROUP}"
fi
if [ -z "${CONFIG_FILE}" ] ; then
        CONFIG_FILE=/etc/${PROJECT_NAME}/${PROJECT_NAME}.conf
fi
LOGFILE=/var/log/${PROJECT_NAME}/${NAME}.log
if [ -z "${NO_OPENSTACK_CONFIG_FILE_DAEMON_ARG}" ] ; then
        DAEMON_ARGS="--config-file=${CONFIG_FILE} ${DAEMON_ARGS}"
fi
[ -x $DAEMON ] || exit 0
if [ `whoami` = "root" ] ; then
        for i in lock run cache ; do
                mkdir -p /var/$i/${PROJECT_NAME}
                chown ${SYSTEM_USER}:${SYSTEM_GROUP} /var/$i/${PROJECT_NAME}
        done
fi
. /lib/lsb/init-functions
RET=0
[ -r /etc/default/openstack ] && . /etc/default/openstack
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
[ "x$USE_SYSLOG" = "xyes" ] && DAEMON_ARGS="$DAEMON_ARGS --use-syslog"
if [ -z "${NO_OPENSTACK_LOGFILE_DAEMON_ARG}" ] ; then
        [ "x$USE_LOGFILE" != "xno" ] && DAEMON_ARGS="$DAEMON_ARGS --log-file=$LOGFILE"
fi
do_start() {
        start-stop-daemon \
                --start \
                --quiet \
                --background ${STARTDAEMON_CHUID} \
                --make-pidfile --pidfile ${PIDFILE} \
                --chdir /var/lib/${PROJECT_NAME} \
                --startas $DAEMON \
                --test > /dev/null \
                || return 1
        if [ -n "${PYARGV}" ] ; then
                start-stop-daemon \
                        --start \
                        --quiet \
                        --background ${STARTDAEMON_CHUID} \
                        --make-pidfile --pidfile ${PIDFILE} \
                        --chdir /var/lib/${PROJECT_NAME} \
                        --startas $DAEMON \
                        -- $DAEMON_ARGS --pyargv "${PYARGV}" \
                        || return 2
        else
                start-stop-daemon \
                        --start \
                        --quiet \
                        --background ${STARTDAEMON_CHUID} \
                        --make-pidfile --pidfile ${PIDFILE} \
                        --chdir /var/lib/${PROJECT_NAME} \
                        --startas $DAEMON \
                        -- $DAEMON_ARGS \
                        || return 2
        fi
}
do_stop() {
        start-stop-daemon \
                --stop \
                --quiet \
                --retry=TERM/30/KILL/5 \
                --pidfile $PIDFILE
        RETVAL=$?
        rm -f $PIDFILE
        return "$RETVAL"
}
do_systemd_start() {
        # Set umask to ensure log files are created with 0644 mode bits
        # Note we can't set 0026 to have files 0640, because that's going
        # to be in use in for example neutron-dhcp-agent, which makes it
        # so it wont be able to read /var/lib/neutron/external/pids/*.pid.haproxy
        # and then fail hardly. However, 0022 is enough, since the log
        # folders are owned by <project>:adm, so users don't have access
        # to it unless they are on the adm group, which is what we want.
        umask 0022
        if [ -n "${PYARGV}" ] ; then
                exec $DAEMON $DAEMON_ARGS --pyargv "${PYARGV}"
        else
                exec $DAEMON $DAEMON_ARGS
        fi
}
case "$1" in
start)
        log_daemon_msg "Starting $DESC" "$NAME"
        do_start
        case $? in
                0|1) log_end_msg 0 ; RET=$? ;;
                2)   log_end_msg 1 ; RET=$? ;;
        esac
;;
stop)
        log_daemon_msg "Stopping $DESC" "$NAME"
        do_stop
        case $? in
                0|1) log_end_msg 0 ; RET=$? ;;
                2)   log_end_msg 1 ; RET=$? ;;
        esac
;;
status)
        status_of_proc "$DAEMON" "$NAME"
        RET=$?
;;
systemd-start)
        do_systemd_start
;;
show-args)
        if [ -n "${PYARGV}" ] ; then
                echo $DAEMON $DAEMON_ARGS --pyargv \"${PYARGV}\"
        else
                echo $DAEMON $DAEMON_ARGS
        fi
;;
restart|force-reload)
        log_daemon_msg "Restarting $DESC" "$NAME"
        do_stop
        case $? in
                0|1)
                        do_start
                        case $? in
                                0) log_end_msg 0 ; RET=$? ;;
                                1) log_end_msg 1 ; RET=$? ;; # Old process is still running                                 *) log_end_msg 1 ; RET=$? ;; # Failed to start
                        esac
                ;;
                *) log_end_msg 1 ; RET=$? ;; # Failed to stop
        esac
;;
*)
        echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload|systemd-start}" >&2
        RET=3
;;
esac
exit $RET


-- debconf information:
  neutron/configure_api-endpoint: false
  neutron/api-keystone-address:
  neutron/api-keystone-proto: http
  neutron/api-endpoint-proto: http
  neutron/api-endpoint-address:
  neutron/api-keystone-admin-project-name: admin
  neutron/api-keystone-admin-username: admin
  neutron/api-endpoint-region-name: regionOne


--
Berner Fachhochschule / Bern University of Applied Sciences
IT-Services / Team Linux & Infrastructure Services
Jani Heikkinen
IT Linux Engineer
___________________________________________________________
Dammweg 3, CH-3013 Bern
Telefon direkt +41 31 848 68 14
Telefon Servicedesk +41 31 848 48 48
[email protected]

Reply via email to