Merge "Docker Registry Keystone Authentication"

This commit is contained in:
Zuul 2019-03-08 15:34:46 +00:00 committed by Gerrit Code Review
commit f56056cffc
14 changed files with 468 additions and 24 deletions

View File

@ -262,6 +262,43 @@ start()
fi
fi
if [ -e $CONFIG_DIR/registry-cert-pkcs1.key ]
then
cp $CONFIG_DIR/registry-cert-pkcs1.key /etc/ssl/private/registry-cert-pkcs1.key
if [ $? -ne 0 ]
then
fatal_error "Unable to copy $CONFIG_DIR/registry-cert-pkcs1.key"
fi
fi
if [ -e $CONFIG_DIR/registry-cert.key ]
then
cp $CONFIG_DIR/registry-cert.key /etc/ssl/private/registry-cert.key
if [ $? -ne 0 ]
then
fatal_error "Unable to copy $CONFIG_DIR/registry-cert.key"
fi
fi
if [ -e $CONFIG_DIR/registry-cert.crt ]
then
cp $CONFIG_DIR/registry-cert.crt /etc/ssl/private/registry-cert.crt
if [ $? -ne 0 ]
then
fatal_error "Unable to copy $CONFIG_DIR/registry-cert.crt to certificates dir"
fi
# this is management network for now
REGISTRY_IP=$(get_ip controller)
mkdir -p /etc/docker/certs.d/$REGISTRY_IP:9001/
chmod 700 /etc/docker/certs.d/$REGISTRY_IP:9001/
cp $CONFIG_DIR/registry-cert.crt /etc/docker/certs.d/$REGISTRY_IP:9001/registry-cert.crt
if [ $? -ne 0 ]
then
fatal_error "Unable to copy $CONFIG_DIR/registry-cert.crt to docker dir"
fi
fi
if [ -e $CONFIG_DIR/iptables.rules ]
then
cp $CONFIG_DIR/iptables.rules /etc/platform/iptables.rules

View File

@ -0,0 +1,90 @@
#!/bin/bash
#
# SPDX-License-Identifier: Apache-2.0
#
# Startup script for registry-token-server
#
DESC="Docker Registry Token Server"
SERVICE="registry-token-server.service"
PIDFILE="/var/run/registry-token-server.pid"
status()
{
if [ "`systemctl is-active registry-token-server.service`" = "active" ]; then
RETVAL=0
echo "$DESC is running"
return
else
echo "$DESC is Not running"
RETVAL=1
fi
}
start()
{
if [ -e $PIDFILE ]; then
PIDDIR=/proc/$(cat $PIDFILE)
if [ -d $PIDDIR ]; then
echo "$DESC already running."
return
else
echo "Removing stale PID file $PIDFILE"
rm -f $PIDFILE
fi
fi
echo "Starting $SERVICE..."
systemctl start $SERVICE
if [ $? -eq 0 ]; then
echo "Started $SERVICE successfully"
RETVAL=0
else
echo "$SERVICE failed!"
RETVAL=1
fi
}
stop()
{
echo -n "Stopping $SERVICE..."
systemctl stop $SERVICE
if [ $? -eq 0 ]; then
echo "$SERVICE stopped."
else
echo "failed to stop $SERVICE!"
fi
if [ -e $PIDFILE ]; then
echo "Removing stale PID file $PIDFILE"
rm -f $PIDFILE
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
stop
start
;;
*)
echo "Usage: $0 {start|stop|status|restart}"
exit 1
;;
esac
exit $RETVAL

View File

@ -1,8 +1,11 @@
class platform::dockerdistribution::params (
$registry_ks_endpoint = undef,
) {}
class platform::dockerdistribution::config
inherits ::platform::dockerdistribution::params {
include ::platform::params
include ::platform::kubernetes::params
include ::platform::network::mgmt::params
include ::platform::docker::params
@ -12,13 +15,12 @@ class platform::dockerdistribution::config
# check insecure registries
if $::platform::docker::params::insecure_registry {
# insecure registry is true means unified registry was set
$insecure_registries = "\"${::platform::docker::params::k8s_registry}\", \"${docker_registry_ip}:9001\""
$insecure_registries = "\"${::platform::docker::params::k8s_registry}\""
} else {
$insecure_registries = "\"${docker_registry_ip}:9001\""
$insecure_registries = ''
}
# currently docker registry is running insecure mode
# when proper authentication is implemented, this would go away
# for external docker registry running insecure mode
file { '/etc/docker':
ensure => 'directory',
owner => 'root',
@ -33,7 +35,7 @@ class platform::dockerdistribution::config
content => template('platform/insecuredockerregistry.conf.erb'),
}
-> file { '/etc/docker-distribution/registry/config.yml':
file { '/etc/docker-distribution/registry/config.yml':
ensure => present,
owner => 'root',
group => 'root',
@ -41,6 +43,14 @@ class platform::dockerdistribution::config
content => template('platform/dockerdistribution.conf.erb'),
}
file { '/etc/docker-distribution/registry/token_server.conf':
ensure => present,
owner => 'root',
group => 'root',
mode => '0644',
content => template('platform/registry-token-server.conf.erb'),
}
# copy the startup script to where it is supposed to be
file {'docker_distribution_initd_script':
ensure => 'present',
@ -48,27 +58,146 @@ class platform::dockerdistribution::config
mode => '0755',
source => "puppet:///modules/${module_name}/docker-distribution"
}
file {'registry_token_server_initd_script':
ensure => 'present',
path => '/etc/init.d/registry-token-server',
mode => '0755',
source => "puppet:///modules/${module_name}/registry-token-server"
}
# self-signed certificate for registry use
# this needs to be generated here because the certificate
# need to know the registry ip address for SANs
if str2bool($::is_initial_config_primary) {
$shared_dir = $::platform::params::config_path
$certs_dir = '/etc/ssl/private'
# create the certificate files
file { "${certs_dir}/registry-cert-extfile.cnf":
ensure => present,
owner => 'root',
group => 'root',
mode => '0400',
content => template('platform/registry-cert-extfile.erb'),
}
-> exec { 'docker-registry-generate-cert':
command => "openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 \
-keyout ${certs_dir}/registry-cert.key \
-out ${certs_dir}/registry-cert.crt \
-config ${certs_dir}/registry-cert-extfile.cnf",
logoutput => true
}
-> exec { 'docker-registry-generate-pkcs1-cert-from-pkcs8':
command => "openssl rsa -in ${certs_dir}/registry-cert.key \
-out ${certs_dir}/registry-cert-pkcs1.key",
logoutput => true
}
# ensure permissions are set correctly
-> file { "${certs_dir}/registry-cert-pkcs1.key":
ensure => 'file',
owner => 'root',
group => 'root',
mode => '0400',
}
-> file { "${certs_dir}/registry-cert.key":
ensure => 'file',
owner => 'root',
group => 'root',
mode => '0400',
}
-> file { "${certs_dir}/registry-cert.crt":
ensure => 'file',
owner => 'root',
group => 'root',
mode => '0400',
}
# delete the extfile used in certificate generation
-> exec { 'remove-registry-cert-extfile':
command => "rm ${certs_dir}/registry-cert-extfile.cnf"
}
# copy certificates and keys to shared directory for second controller
# we do not need to worry about second controller being up at this point,
# since we have a is_initial_config_primary check
-> file { "${shared_dir}/registry-cert-pkcs1.key":
ensure => 'file',
owner => 'root',
group => 'root',
mode => '0400',
source => "${certs_dir}/registry-cert-pkcs1.key",
}
-> file { "${shared_dir}/registry-cert.key":
ensure => 'file',
owner => 'root',
group => 'root',
mode => '0400',
source => "${certs_dir}/registry-cert.key",
}
-> file { "${shared_dir}/registry-cert.crt":
ensure => 'file',
owner => 'root',
group => 'root',
mode => '0400',
source => "${certs_dir}/registry-cert.crt",
}
# copy the certificate to docker certificates directory,
# which makes docker trust that specific certificate
# this is required for self-signed and also if the user does
# not have a certificate signed by a "default" CA
-> file { '/etc/docker/certs.d':
ensure => 'directory',
owner => 'root',
group => 'root',
mode => '0700',
}
-> file { "/etc/docker/certs.d/${docker_registry_ip}:9001":
ensure => 'directory',
owner => 'root',
group => 'root',
mode => '0700',
}
-> file { "/etc/docker/certs.d/${docker_registry_ip}:9001/registry-cert.crt":
ensure => 'file',
owner => 'root',
group => 'root',
mode => '0400',
source => "${certs_dir}/registry-cert.crt",
}
}
}
# compute also needs the "insecure" flag in order to deploy images from
# the registry. This will go away when proper authentication is implemented
# the registry. This is needed for insecure external registry
class platform::dockerdistribution::compute
inherits ::platform::dockerdistribution::params {
include ::platform::kubernetes::params
include ::platform::network::mgmt::params
include ::platform::docker::params
$docker_registry_ip = $::platform::network::mgmt::params::controller_address
# check insecure registries
if $::platform::docker::params::insecure_registry {
# insecure registry is true means unified registry was set
$insecure_registries = "\"${::platform::docker::params::k8s_registry}\", \"${docker_registry_ip}:9001\""
$insecure_registries = "\"${::platform::docker::params::k8s_registry}\""
} else {
$insecure_registries = "\"${docker_registry_ip}:9001\""
$insecure_registries = ''
}
# currently docker registry is running insecure mode
# when proper authentication is implemented, this would go away
# for external docker registry running insecure mode
file { '/etc/docker':
ensure => 'directory',
owner => 'root',
@ -86,8 +215,23 @@ class platform::dockerdistribution::compute
class platform::dockerdistribution
inherits ::platform::dockerdistribution::params {
include ::platform::kubernetes::params
include platform::dockerdistribution::config
Class['::platform::docker::config'] -> Class[$name]
}
class platform::dockerdistribution::reload {
platform::sm::restart {'registry-token-server': }
platform::sm::restart {'docker-distribution': }
}
# this does not update the config right now
# the run time is only used to restart the token server and registry
class platform::dockerdistribution::runtime {
class {'::platform::dockerdistribution::reload':
stage => post
}
}

View File

@ -1046,6 +1046,11 @@ class platform::sm
command => "sm-configure service_instance docker-distribution docker-distribution \"\"",
}
# Docker Registry Token Server
exec { 'Configure Docker Registry Token Server':
command => "sm-configure service_instance registry-token-server registry-token-server \"\"",
}
if $system_mode == 'duplex-direct' or $system_mode == 'simplex' {
exec { 'Configure Platform NFS':
command => "sm-configure service_instance platform-nfs-ip platform-nfs-ip \"ip=${platform_nfs_ip_param_ip},cidr_netmask=${platform_nfs_ip_param_mask},nic=${mgmt_ip_interface},arp_count=7,dc=yes\"",
@ -1188,6 +1193,14 @@ class platform::sm
command => 'sm-provision service docker-distribution',
}
# Configure Docker Registry Token Server
exec { 'Provision Docker Registry Token Server (service-group-member)':
command => 'sm-provision service-group-member controller-services registry-token-server',
}
-> exec { 'Provision Docker Registry Token Server (service)':
command => 'sm-provision service registry-token-server',
}
# Barbican
if $barbican_enabled {
exec { 'Provision OpenStack - Barbican API (service-group-member)':

View File

@ -10,8 +10,8 @@ storage:
http:
addr: <%= @docker_registry_ip %>:9001
tls:
certificate: /etc/ssl/private/self-signed-server-cert.pem
key: /etc/ssl/private/self-signed-server-cert.pem
certificate: /etc/ssl/private/registry-cert.crt
key: /etc/ssl/private/registry-cert.key
headers:
X-Content-Type-Options: [nosniff]
health:
@ -19,3 +19,9 @@ health:
enabled: true
interval: 10s
threshold: 3
auth:
token:
realm: https://<%= @docker_registry_ip %>:9002/token/
service: <%= @docker_registry_ip %>:9001
issuer: bird-token-server
rootcertbundle: /etc/ssl/private/registry-cert.crt

View File

@ -0,0 +1,10 @@
[req]
prompt = no
x509_extensions = v3_req
distinguished_name = dn
[dn]
CN = <%= @docker_registry_ip %>
[v3_req]
subjectAltName = @alt_names
[alt_names]
IP = <%= @docker_registry_ip %>

View File

@ -0,0 +1,7 @@
REGISTRY_TOKEN_SERVER_ADDR=<%= @docker_registry_ip %>:9002
REGISTRY_TOKEN_SERVER_ISSUER=bird-token-server
REGISTRY_TOKEN_SERVER_KS_ENDPOINT=<%= @registry_ks_endpoint %>
REGISTRY_TOKEN_SERVER_TLSCERT=/etc/ssl/private/registry-cert.crt
REGISTRY_TOKEN_SERVER_TLSKEY=/etc/ssl/private/registry-cert.key
REGISTRY_TOKEN_SERVER_REALM=https://<%= @docker_registry_ip %>:9002/token/
REGISTRY_TOKEN_SERVER_KEY=/etc/ssl/private/registry-cert-pkcs1.key

View File

@ -69,7 +69,8 @@ def do_certificate_list(cc, args):
help='The passphrase for the PEM file')
@utils.arg('-m', '--mode',
metavar='<mode>',
help="optional mode: 'tpm_mode', 'murano', 'murano_ca'. "
help="optional mode: 'tpm_mode', 'murano', 'murano_ca',"
"'docker_registry'. "
"Default is 'ssl'.")
def do_certificate_install(cc, args):
"""Install certificate."""

View File

@ -70,8 +70,9 @@ systemconfig.puppet_plugins =
030_smapi = sysinv.puppet.smapi:SmPuppet
031_fm = sysinv.puppet.fm:FmPuppet
032_swift = sysinv.puppet.swift:SwiftPuppet
033_service_parameter = sysinv.puppet.service_parameter:ServiceParamPuppet
034_barbican = sysinv.puppet.barbican:BarbicanPuppet
033_barbican = sysinv.puppet.barbican:BarbicanPuppet
034_dockerdistribution = sysinv.puppet.dockerdistribution:DockerDistributionPuppet
099_service_parameter = sysinv.puppet.service_parameter:ServiceParamPuppet
systemconfig.helm_plugins =
aodh = sysinv.helm.aodh:AodhHelm

View File

@ -268,6 +268,7 @@ class CertificateController(rest.RestController):
tpm_mode: install certificate to tpm devices for ssl
murano: install certificate for rabbit-murano
murano_ca: install ca certificate for rabbit-murano
docker_registry: install certificate for docker registry
"""
log_start = cutils.timestamped("certificate_do_post_start")
@ -297,7 +298,8 @@ class CertificateController(rest.RestController):
system = pecan.request.dbapi.isystem_get_one()
capabilities = system.capabilities
if not mode.startswith(constants.CERT_MODE_MURANO):
if not mode.startswith(constants.CERT_MODE_MURANO) and \
mode != constants.CERT_MODE_DOCKER_REGISTRY:
system_https_enabled = capabilities.get('https_enabled', False)
if system_https_enabled is False or system_https_enabled == 'n':
msg = "No certificates have been added, https is not enabled."

View File

@ -1329,6 +1329,17 @@ MURANO_CERT_KEY_FILE = os.path.join(CERT_MURANO_DIR, CERT_KEY_FILE)
MURANO_CERT_FILE = os.path.join(CERT_MURANO_DIR, CERT_FILE)
MURANO_CERT_CA_FILE = os.path.join(CERT_MURANO_DIR, CERT_CA_FILE)
DOCKER_REGISTRY_CERT_FILE = os.path.join(SSL_CERT_DIR, "registry-cert.crt")
DOCKER_REGISTRY_KEY_FILE = os.path.join(SSL_CERT_DIR, "registry-cert.key")
DOCKER_REGISTRY_PKCS1_KEY_FILE = os.path.join(SSL_CERT_DIR,
"registry-cert-pkcs1.key")
DOCKER_REGISTRY_CERT_FILE_SHARED = os.path.join(tsc.CONFIG_PATH,
"registry-cert.crt")
DOCKER_REGISTRY_KEY_FILE_SHARED = os.path.join(tsc.CONFIG_PATH,
"registry-cert.key")
DOCKER_REGISTRY_PKCS1_KEY_FILE_SHARED = os.path.join(tsc.CONFIG_PATH,
"registry-cert-pkcs1.key")
SSL_CERT_CA_DIR = "/etc/ssl/certs/"
SSL_CERT_CA_FILE = os.path.join(SSL_CERT_CA_DIR, CERT_CA_FILE)
SSL_CERT_CA_FILE_SHARED = os.path.join(tsc.CONFIG_PATH, CERT_CA_FILE)
@ -1338,11 +1349,13 @@ CERT_MODE_SSL_CA = 'ssl_ca'
CERT_MODE_TPM = 'tpm_mode'
CERT_MODE_MURANO = 'murano'
CERT_MODE_MURANO_CA = 'murano_ca'
CERT_MODE_DOCKER_REGISTRY = 'docker_registry'
CERT_MODES_SUPPORTED = [CERT_MODE_SSL,
CERT_MODE_SSL_CA,
CERT_MODE_TPM,
CERT_MODE_MURANO,
CERT_MODE_MURANO_CA]
CERT_MODE_MURANO_CA,
CERT_MODE_DOCKER_REGISTRY]
# CONFIG file permissions
CONFIG_FILE_PERMISSION_ROOT_READ_ONLY = 0o400

View File

@ -94,6 +94,7 @@ from sysinv.openstack.common.gettextutils import _
from sysinv.puppet import common as puppet_common
from sysinv.puppet import puppet
from sysinv.helm import helm
from sysinv.helm import common as helm_common
MANAGER_TOPIC = 'sysinv.conductor_manager'
@ -10178,11 +10179,14 @@ class ConductorManager(service.PeriodicService):
alarm.entity_instance_id)
@staticmethod
def _extract_keys_from_pem(mode, pem_contents, passphrase=None):
def _extract_keys_from_pem(mode, pem_contents, cert_format,
passphrase=None):
"""Extract keys from the pem contents
:param mode: mode one of: ssl, tpm_mode, murano, murano_ca
:param mode: mode one of: ssl, tpm_mode, murano, murano_ca,
docker_registry
:param pem_contents: pem_contents
:param cert_format: serialization.PrivateFormat
:param passphrase: passphrase for PEM file
:returns: private_bytes, public_bytes, signature
@ -10202,6 +10206,7 @@ class ConductorManager(service.PeriodicService):
if mode in [constants.CERT_MODE_SSL,
constants.CERT_MODE_TPM,
constants.CERT_MODE_MURANO,
constants.CERT_MODE_DOCKER_REGISTRY,
]:
private_mode = True
@ -10229,7 +10234,7 @@ class ConductorManager(service.PeriodicService):
private_bytes = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
format=cert_format,
encryption_algorithm=serialization.NoEncryption())
signature = mode + '_' + str(cert.serial_number)
@ -10289,6 +10294,16 @@ class ConductorManager(service.PeriodicService):
except OSError:
pass
def _get_registry_floating_address(self):
"""gets the registry floating address. Currently this is mgmt
"""
registry_network = self.dbapi.network_get_by_type(
constants.NETWORK_TYPE_MGMT)
registry_network_addr_pool = self.dbapi.address_pool_get(
registry_network.pool_uuid)
addr = registry_network_addr_pool.floating_address
return addr
def config_certificate(self, context, pem_contents, config_dict):
"""Configure certificate with the supplied data.
@ -10309,7 +10324,9 @@ class ConductorManager(service.PeriodicService):
LOG.info("config_certificate mode=%s file=%s" % (mode, certificate_file))
private_bytes, public_bytes, signature = \
self._extract_keys_from_pem(mode, pem_contents, passphrase)
self._extract_keys_from_pem(mode, pem_contents,
serialization.PrivateFormat.PKCS8,
passphrase)
personalities = [constants.CONTROLLER]
tpm = None
@ -10420,6 +10437,77 @@ class ConductorManager(service.PeriodicService):
'permissions': constants.CONFIG_FILE_PERMISSION_DEFAULT,
}
self._config_update_file(context, config_uuid, config_dict)
elif mode == constants.CERT_MODE_DOCKER_REGISTRY:
LOG.info("Docker registry certificate install")
# docker registry requires a PKCS1 key for the token server
pkcs1_private_bytes, pkcs1_public_bytes, pkcs1_signature = \
self._extract_keys_from_pem(mode, pem_contents,
serialization.PrivateFormat
.TraditionalOpenSSL, passphrase)
# install certificate, key, and pkcs1 key to controllers
config_uuid = self._config_update_hosts(context, personalities)
key_path = constants.DOCKER_REGISTRY_KEY_FILE
cert_path = constants.DOCKER_REGISTRY_CERT_FILE
pkcs1_key_path = constants.DOCKER_REGISTRY_PKCS1_KEY_FILE
config_dict = {
'personalities': personalities,
'file_names': [key_path, cert_path, pkcs1_key_path],
'file_content': {key_path: private_bytes,
cert_path: public_bytes,
pkcs1_key_path: pkcs1_private_bytes},
'nobackup': True,
'permissions': constants.CONFIG_FILE_PERMISSION_ROOT_READ_ONLY,
}
self._config_update_file(context, config_uuid, config_dict)
# copy certificate to shared directory
with os.fdopen(os.open(constants.DOCKER_REGISTRY_CERT_FILE_SHARED,
os.O_CREAT | os.O_WRONLY,
constants.CONFIG_FILE_PERMISSION_ROOT_READ_ONLY),
'wb') as f:
f.write(public_bytes)
with os.fdopen(os.open(constants.DOCKER_REGISTRY_KEY_FILE_SHARED,
os.O_CREAT | os.O_WRONLY,
constants.CONFIG_FILE_PERMISSION_ROOT_READ_ONLY),
'wb') as f:
f.write(private_bytes)
with os.fdopen(os.open(constants.DOCKER_REGISTRY_PKCS1_KEY_FILE_SHARED,
os.O_CREAT | os.O_WRONLY,
constants.CONFIG_FILE_PERMISSION_ROOT_READ_ONLY),
'wb') as f:
f.write(pkcs1_private_bytes)
config_uuid = self._config_update_hosts(context, personalities)
config_dict = {
"personalities": personalities,
"classes": ['platform::dockerdistribution::runtime']
}
self._config_apply_runtime_manifest(context,
config_uuid,
config_dict)
self._remove_certificate_file(mode, certificate_file)
# install docker certificate on controllers and workers
registry_full_address = self._get_registry_floating_address() + ":" + helm_common.REGISTRY_PORT
docker_cert_path = os.path.join("/etc/docker/certs.d",
registry_full_address,
"registry-cert.crt")
personalities = [constants.CONTROLLER,
constants.WORKER]
config_uuid = self._config_update_hosts(context,
personalities)
config_dict = {
'personalities': personalities,
'file_names': [docker_cert_path],
'file_content': public_bytes,
'nobackup': True,
'permissions': constants.CONFIG_FILE_PERMISSION_ROOT_READ_ONLY,
}
self._config_update_file(context, config_uuid, config_dict)
else:
msg = "config_certificate unexpected mode=%s" % mode
LOG.warn(msg)
@ -10446,7 +10534,9 @@ class ConductorManager(service.PeriodicService):
LOG.info("_config_selfsigned_certificate mode=%s file=%s" % (mode, certificate_file))
private_bytes, public_bytes, signature = \
self._extract_keys_from_pem(mode, pem_contents, passphrase)
self._extract_keys_from_pem(mode, pem_contents,
serialization.PrivateFormat.PKCS8,
passphrase)
personalities = [constants.CONTROLLER]

View File

@ -0,0 +1,19 @@
#
# Copyright (c) 2019 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from sysinv.puppet import base
class DockerDistributionPuppet(base.BasePuppet):
"""Class to encapsulate puppet operations for docker distribution"""
def get_system_config(self):
config = {
'platform::dockerdistribution::params::registry_ks_endpoint':
self._operator.keystone.get_auth_uri() + '/v3',
}
return config

View File

@ -249,6 +249,17 @@ start()
then
fatal_error "This node is running a different load than the active controller and must be reinstalled"
fi
# Install docker certificate if required
# this is management network for now
REGISTRY_IP=$(get_ip controller)
mkdir -p /etc/docker/certs.d/$REGISTRY_IP:9001/
chmod 700 /etc/docker/certs.d/$REGISTRY_IP:9001/
cp $CONFIG_DIR/registry-cert.crt /etc/docker/certs.d/$REGISTRY_IP:9001/registry-cert.crt
if [ $? -ne 0 ]
then
fatal_error "Unable to copy $CONFIG_DIR/registry-cert.crt to docker dir"
fi
fi
# banner customization always returns 0, success: