diff --git a/apache/README.rst b/apache/README.rst new file mode 100644 index 0000000..7eedb25 --- /dev/null +++ b/apache/README.rst @@ -0,0 +1,29 @@ + + +SSH Tunnel +---------- + +On the server side, you can configure your compose file:: + + apache: + options: + ssh-tunnel: + domain: ssh.domain.com ## required + #ssh: ... ## required, but automatically setup if you + ## provide a ``cert-provider`` to ``apache``. + + +On the client side you should add this to your ``~/.ssh/config``:: + + Host ssh.domain.com + Port 443 + ProxyCommand proxytunnel -q -E -p ssh.domain.com:443 -d ssh.domain.com:22 + DynamicForward 1080 + ServerAliveInterval 60 + +If it doesn't work, you can do some checks thanks to this command:: + + $ proxytunnel -E -p ssh.domain.com:443 -d ssh.domain.com:22 -v \ + -H "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Win32)\n" + + diff --git a/apache/build/Dockerfile b/apache/build/Dockerfile index 02618ff..b7f078b 100644 --- a/apache/build/Dockerfile +++ b/apache/build/Dockerfile @@ -20,7 +20,7 @@ FROM docker.0k.io/php:7.3-apache ## XXXvlab: could load these in 'entrypoint.sh' to be more dynamic -RUN a2enmod headers proxy_http rewrite ssl proxy_wstunnel http2 +RUN a2enmod headers proxy_http rewrite ssl proxy_wstunnel http2 proxy_connect ## Can remove this when SSL certificate are all valid ones RUN apt-get update && apt-get install -y --force-yes ssl-cert diff --git a/apache/hooks/init b/apache/hooks/init index a490518..2809ebc 100755 --- a/apache/hooks/init +++ b/apache/hooks/init @@ -10,10 +10,11 @@ ## - SERVICE_DATASTORE Location on host of the DATASTORE of this service ## - SERVICE_CONFIGSTORE Location on host of the CONFIGSTORE of this service +. lib/common APACHE_LOG_DIR=/var/log/apache2 +set -e -set -u cat < @@ -49,3 +50,9 @@ cat < EOF + +ssh_tunnel_cfg=$(options-get ssh-tunnel 2>/dev/null) || true +if [ "$ssh_tunnel_cfg" ]; then + apache_ssh_tunnel "$ssh_tunnel_cfg" +fi + diff --git a/apache/lib/common b/apache/lib/common index b9ebdc4..0204f9d 100644 --- a/apache/lib/common +++ b/apache/lib/common @@ -14,7 +14,7 @@ get_domain() { elif [[ "$BASE_SERVICE_NAME" =~ ^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$ ]]; then echo "$BASE_SERVICE_NAME" | tee "$cache_file" else - err "You must specify a ${WHITE}domain$NORMAL option in relation. (${FUNCNAME[@]})" + err "You must specify a ${WHITE}domain$NORMAL option. (${FUNCNAME[@]})" return 1 fi } @@ -40,6 +40,21 @@ apache_publish_dir() { export -f apache_publish_dir +apache_ssh_tunnel() { + local cfg="$1" domain ssh_tunnel + domain=$(e "$cfg" | cfg-get-value domain) || { + err "${WHITE}domain${NORMAL} must be valued in ${WHITE}ssh-tunnel${NORMAL} config." + return 1 + } + protocols=$(__vhost_cfg_normalize_protocol "$cfg") || return 1 + if ! is_protocol_enabled https "$protocols"; then + err "${WHITE}ssl${NORMAL} must be valued in ${WHITE}ssh-tunnel${NORMAL} config." + return 1 + fi + apache_vhost_create ssh_tunnel "$cfg" ",https," "000-$domain" || return 1 +} +export -f apache_publish_dir + ## ## Simple functions @@ -218,14 +233,16 @@ __vhost_cfg_normalize_protocol() { ssl_get_plugin_fun() { # from ssl conf, return the function that should manage SSL code creation local master_cfg="$1" cfg type keys - cfg=$(_get_ssl_option_value "$master_cfg") || return 1 + cfg=$(_get_ssl_option_value "$master_cfg") || { + err "No ssl options available." + return 1 + } local cache_file="$state_tmpdir/$FUNCNAME.cache.$(H "$SERVICE_NAME" "$cfg")" if [ -e "$cache_file" ]; then cat "$cache_file" return 0 fi - [ "$cfg" ] || { touch "$cache_file" return 0 @@ -667,6 +684,9 @@ __vhost_content_statement() { "publish_dir") __vhost_publish_dir_statement "$@" || return 1 ;; + "ssh_tunnel") + __vhost_tunnel_ssh_statement "$@" || return 1 + ;; esac } @@ -791,6 +811,38 @@ EOF } +__vhost_tunnel_ssh_statement() { + local protocol="$1" cfg="$2" dest="$3" custom_rules content_statement + cat < + Order deny,allow + Deny from all + + +### Accept redirect only to same domain + + + Order deny,allow +$(__vhost_creds_statement "$cfg" "$dest" | prefix " ") + + +EOF +} + + apache_config_hash() { debug "Adding config hash to enable recreating upon config change." config_hash=$({ diff --git a/apache/test/ssl_plugin b/apache/test/ssl_plugin index 200ce12..7552bdb 100644 --- a/apache/test/ssl_plugin +++ b/apache/test/ssl_plugin @@ -50,7 +50,8 @@ ssl_get_plugin_fun ' domain: www.example.com '" is errlvl 1 -is err '' +is err 'Error: No ssl options available. +' is out '' diff --git a/apache/test/vhost b/apache/test/vhost index d5d50dd..8e812e0 100644 --- a/apache/test/vhost +++ b/apache/test/vhost @@ -399,3 +399,81 @@ is out ' #Header set Access-Control-Allow-Headers "origin, content-type, accept" ' RTRIM + + +try " +apache_vhost_statement ssh_tunnel ,https, ' +ssl: true +apache-custom-rules: | + RewriteEngine On + RewriteCond %{QUERY_STRING} !skin=formanoo + RewriteRule ^(/web/webclient/home.*)$ $1?skin=formanoo [L,QSA,R=302] +target: popo:3333 +' 'ssh.example.com' +" "ssh tunnel" +noerror +is out ' + + + + ServerAdmin contact@ssh.example.com + ServerName ssh.example.com + + ServerSignature Off + CustomLog /var/log/apache2/s-ssh.example.com_access.log combined + ErrorLog /var/log/apache2/s-ssh.example.com_error.log + ErrorLog syslog:local2 + + + ## + ## Custom rules + ## + + RewriteEngine On + RewriteCond %{QUERY_STRING} !skin=formanoo + RewriteRule ^(/web/webclient/home.*)$ ?skin=formanoo [L,QSA,R=302] + + + ## + ## SSH Tunnel + ## + + #HostnameLookups On + ProxyRequests On + AllowConnect 22 + #ProxyVia on + + ### Deny everything by default + + + Order deny,allow + Deny from all + + + ### Accept redirect only to same domain + + + Order deny,allow + Allow from all + + + ## Forbid any cache, this is only usefull on dev server. + #Header set Cache-Control "no-cache" + #Header set Access-Control-Allow-Origin "*" + #Header set Access-Control-Allow-Methods "POST, GET, OPTIONS" + #Header set Access-Control-Allow-Headers "origin, content-type, accept" + + ## + ## SSL Configuration + ## + + SSLEngine On + + SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem + SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key + + + SSLVerifyClient None + + +' RTRIM diff --git a/apache/test/vhost_files b/apache/test/vhost_files index ff43e2a..4d268ac 100644 --- a/apache/test/vhost_files +++ b/apache/test/vhost_files @@ -318,3 +318,74 @@ is out part ' | $MASTER_BASE_SERVICE_NAME: | - /opt/apps/newlocation:/var/www/www.example.com' + + +try " +export DATASTORE='\$DATASTORE' +export DOCKER_BASE_IMAGE=docker/apache +export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' +export CONFIGSTORE='\$CONFIGSTORE' +export BASE_SERVICE_NAME='\$BASE_SERVICE_NAME' +export MASTER_BASE_SERVICE_NAME='\$MASTER_BASE_SERVICE_NAME' +export MASTER_TARGET_SERVICE_NAME='\$MASTER_TARGET_SERVICE_NAME' +apache_ssh_tunnel ' +domain: www.example.com +creds: + toto: xxx +' +" "ssh tunnel without ssl" +is errlvl 1 +is err 'Error: ssl must be valued in ssh-tunnel config. +' +is out '' + + +try " +export DATASTORE='\$DATASTORE' +export DOCKER_BASE_IMAGE=docker/apache +export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' +export CONFIGSTORE='\$CONFIGSTORE' +export BASE_SERVICE_NAME='\$BASE_SERVICE_NAME' +export MASTER_BASE_SERVICE_NAME='\$MASTER_BASE_SERVICE_NAME' +export MASTER_TARGET_SERVICE_NAME='\$MASTER_TARGET_SERVICE_NAME' +apache_ssh_tunnel ' +ssl: true +creds: + toto: xxx +' +" "ssh tunnel without domain" +is errlvl 1 +is err 'Error: domain must be valued in ssh-tunnel config. +' +is out '' + + +try " +export DATASTORE='\$DATASTORE' +export DOCKER_BASE_IMAGE=docker/apache +export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' +export CONFIGSTORE='\$CONFIGSTORE' +export BASE_SERVICE_NAME='\$BASE_SERVICE_NAME' +export MASTER_BASE_SERVICE_NAME='\$MASTER_BASE_SERVICE_NAME' +export MASTER_TARGET_SERVICE_NAME='\$MASTER_TARGET_SERVICE_NAME' +apache_ssh_tunnel ' +domain: ssh.example.com +ssl: + key: a + ca-cert: b +creds: + toto: xxx +' +" "ssh tunnel" +is errlvl 0 +is err reg 'relation-set domain: + | ssh.example.com' +is out reg 'file_put \$SERVICE_CONFIGSTORE/etc/apache2/sites-enabled/000-ssh.example.com.conf' +is out reg 'file_put \$CONFIGSTORE/\$BASE_SERVICE_NAME/etc/ssl/private/ssh.example.com.key' +is out reg 'file_put \$CONFIGSTORE/\$BASE_SERVICE_NAME/etc/ssl/certs/ssh.example.com-ca.pem' +is out reg 'AuthUserFile /etc/apache2/sites-enabled/ssh.example.com.passwd' +is out reg "htpasswd -bc '/etc/apache2/sites-enabled/000-ssh.example.com.passwd' 'toto' 'xxx'" + + + +