Skip to content

Docker Image for Apache Subversion with http:// and svn:// access plus LDAP and local passdb auth as well as WebSVN

License

Notifications You must be signed in to change notification settings

iaean/docker-subversion

Repository files navigation

docker-subversion

Docker container for Subversion with WebSVN.

Features

Installation

  • Get it from docker hub: docker pull iaean/subversion
  • -or- build the image as you normally would: docker build --tag=subversion ./
  • Setting your environment...
  • ...Yee-haw!

Configuration

Persistent storage

Repositories are stored inside "repository groups" or "SVN parent paths" under /data/svn. This directory is published. To enable persistence, run your docker container via:

  • named volume: -v svn_repos:/data/svn
  • bind mount: -v /path/to/svn_repos:/data/svn

The following three files under /data/svn needs special attention, too: .htpasswd, .svn.sasldb and .svn.access. This could become important, if you want to backup your environment. Backup your repositories as usual, but keep a copy of this files when indicated, because your authentication and authorization configuration is stored here.

Repository groups

Repositories are grouped and managed within so-called "repository groups" or "SVN parent paths". In fact that are simple directories inside /data/svn wherein the proper repositories are residing. You can provide a description for these directories which is used by WebSVN.
You specify all repositories via SUBVERSION_REPOS. A repository is described by the SVN parent path and the repo name separated by a slash. Specify several repos separated by semicolon. They are created, if they does not exist. The environment variable for the description is built by prefixing the repository group name with DESCRIPTION_. Spaces in group or repo name are not allowed. See the examples below.

Autoconfiguration via environment

Variable Scope Default Example
SUBVERSION_REPOS recommended sandbox/test legacy/code;legacy/conf;dev/apps;prod/apps
DESCRIPTION_legacy recommended Legacy stuff
DESCRIPTION_prod recommended Production app code & config
DESCRIPTION_dev recommended Development app code & config
SVN_LOCAL_ADMIN_USER recommended admin
SVN_LOCAL_ADMIN_PASS recommended password
LDAP_BindDN optional | LDAP mandatory uid=root,cn=users,dc=example,dc=com
LDAP_BindPW optional | LDAP mandatory password
SASL_LDAP_SERVER optional | LDAP mandatory ldaps://synology
SASL_LDAP_SEARCHBASE optional | LDAP mandatory cn=users,dc=example,dc=com
SASL_LDAP_FILTER optional | LDAP mandatory (uid=%U)
APACHE_LDAP_URL optional | LDAP mandatory ldaps://synology/cn=users,dc=example,dc=com?uid?sub
APACHE_LDAP_ALIAS optional directory synology
LDAP_Use_TLS optional no yes | no
LDAP_TLS_Ciphers optional
LDAP_TLS_VerifyCert optional allow never | allow | try | demand

Running

Beside svn:// http://is exposed only. To provide adequate security and handle your certificate bale, you are highly encouraged to run the http:// part behind a SSL enabled reverse proxy and publishing https:// only.

# All your SSL and virtual host stuff...

<Location />
  SSLRequireSSL
</Location>

ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https"

ProxyPass / http://subversion:4711/ connectiontimeout=5 timeout=300
ProxyPassReverse / http://subversion:4711/

Keep in mind that your passwords are not encrypted via svn://.

Running the docker image

Use docker to run the container as you normally would.

Production:

docker run -p 80:80 -p 3690:3690 --env-file env --rm --name subversion subversion

Devolopment:

docker run -it -p 80:80 -p 3690:3690 --env-file env --rm --name subversion subversion /bin/sh

docker exec -it subversion /bin/sh

docker exec -u apache -it subversion /bin/sh

Accessing your repositories

Assume your docker exposes to localhost:

  • Browse via SVN DAV: http://localhost/
  • Browse via WebSVN: http://localhost/websvn/
  • SVN access via http: svn info --username=admin http://localhost/svn/sandbox/test
  • SVN access via svn: svn info --username=admin svn://localhost/sandbox/test

The tailing part of the URL is group/repo, for HTTP prefixed with svn/.

Importing your repositories

zcat backup.svn.gz | svnrdump [--username=admin --password=...] load http://localhost/svn/sandbox/test

Keep in mind that pre-revprop-change hook is enabled for any via SUBVERSION_REPOS autocreated repo to support svnrdump. Because this is not the Subversion default, you want to disable this hook manually after importing.

Setting local user passwords

We are using Apache htpasswd for httpd local auth and SASL for svnserve local auth. Unfortunately we had to maintain both auth sources until now.

docker exec -u apache -it subversion sasldblistusers2 -f .svn.sasldb

docker exec -u apache -it subversion saslpasswd2 -f .svn.sasldb -u "Local or LDAP Account" foobar

docker exec -u apache -it subversion htpasswd -mb .htpasswd foobar password

TODO

  • Apache publishes XML for repository indexing. This is transformed to HTML via XSLT. Make the XSLT looks smooth like the group listing HTML to avoid the visual break at SVN DAV browsing.
  • Bind mount volumes under Docker for Windows should not be used actually, because they are problematic due to chmod and chown. Files are created as user root and this cannot be changed. Just there is no workaround for this behaviour. Maybe an configurable solution could be to run httpd and svnserve as root, if this becomes an issue.
  • It's annoying to maintain two local password databases actually. The solution is to enable Apache to use SASL too. Because there is no SASL auth feature in the official vanilla distribution, we could try to make mod-authn-sasl running.
  • Add an additional WebSVN instance with MultiViews enabled.

Towards SSL/TLS and Alpine

Alpine Linux is linking almost all packages against LibreSSL. LibreSSL should be compatible to OpenSSL. But it isn't. I fought against a bug in LibreSSL a couple of days. There are servers with certificates from well-known CA's and OpenSSL works like a charm. But LibreSSL doesn't. This is because of a bug in LibreSSL with TLSv1.2 and elliptic curve handshaking. (1)(2)

In my opinion, this is a major drawback for Alpine Linux, because it can break SSL/TLS security for any package. In our case OpenLDAP via SASL and Apache. Beside nginx I don't know about an application that support feeding Elliptic curve groups to their TLS stack. The workaround for our case was a forced downgrade to AES128-SHA cipher. And feeding ciphers is supported by OpenLDAP. But feeding Elliptic curve groups isn't. It could have been worse.

If you run into this issue, try to use LDAP_TLS_Ciphers and hoping your server supports some working fallback.

# Uhmpf... BROKEN!!
#
echo | openssl s_client -connect sec.srv.tld:636 -tls1_2 | egrep 'Cipher|Protocol'
140182729145292:error:140040E5:SSL routines:CONNECT_CR_SRVR_HELLO:ssl handshake failure:ssl_pkt.c:585:
New, (NONE), Cipher is (NONE)
    Protocol  : TLSv1.2
    Cipher    : 0000

# Works. But negotiates to AES128-SHA only.
#
echo | openssl s_client -connect sec.srv.tld:636 -tls1_2 -groups secp256k1:secp224r1 2>/dev/null | egrep 'Cipher|Protocol'
New, TLSv1/SSLv3, Cipher is AES128-SHA
    Protocol  : TLSv1.2
    Cipher    : AES128-SHA

# Works. But needs forced cipher.
#
echo | openssl s_client -connect sec.srv.tld:636 -tls1_2 -cipher AES128-SHA 2>/dev/null | egrep 'Cipher|Protocol'
New, TLSv1/SSLv3, Cipher is AES128-SHA
    Protocol  : TLSv1.2
    Cipher    : AES128-SHA

# TLSv1.1 works fine.
#
echo | openssl s_client -connect sec.srv.tld:636 -tls1_1 2>/dev/null | egrep 'Cipher|Protocol'
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-SHA
    Protocol  : TLSv1.1
    Cipher    : ECDHE-RSA-AES128-SHA

1) https://bugs.alpinelinux.org/issues/8199
2) libressl/openbsd#79