SVN+SSH-path-based-authorisation, version 1
parent
9bd1fe132b
commit
8129749aa9
374
SVN+SSH-path-based-authorisation.md
Normal file
374
SVN+SSH-path-based-authorisation.md
Normal file
@ -0,0 +1,374 @@
|
|||||||
|
SVN+SSH path-based authorisation
|
||||||
|
================================
|
||||||
|
|
||||||
|
This is an article about using SVN as a secure replacement for FTP to
|
||||||
|
facilitate partners collaborations. If you are not interested in the
|
||||||
|
rationale/testing part you ca go straight to the
|
||||||
|
[SVN+SSH
|
||||||
|
path-based authorisation How-to](SVN+SSH-path-based-authorisation\#\#4-Implementation).
|
||||||
|
|
||||||
|
1. Problem
|
||||||
|
----------
|
||||||
|
|
||||||
|
### 1.1. Rationale
|
||||||
|
|
||||||
|
As we are hosting plenty of websites, we have to work with different
|
||||||
|
partners (web designer, integrators, website developers etc.). All using
|
||||||
|
different operating systems and browsers and all demanding a plain old
|
||||||
|
FTP access to upload their work. We tried to get them to use chrooted
|
||||||
|
SFTP access but it seems they couldn’t get their head around it.
|
||||||
|
|
||||||
|
Internally we were using SVN for all our projects. It’s running on a
|
||||||
|
webdav enabled Apache with SSL linked with a password based LDAP
|
||||||
|
authentication. This server was only accessible through our VPN (yes we
|
||||||
|
are a bit paranoid).
|
||||||
|
|
||||||
|
The idea was to allow our partners/customers to have read/write access
|
||||||
|
to our web servers without the need for an insecure password based FTP
|
||||||
|
access (yes even if it is running through SSL). A solution we are
|
||||||
|
contemplating is to give a secure access to our SVN server. Our web
|
||||||
|
servers would then have working copies of the part of the repository
|
||||||
|
they are concerned. Auto-update can be done through a cron jobs that
|
||||||
|
calls a simple svn update. Partners would then be able to work on same
|
||||||
|
files instead of having lengthy discussion of whose turns it is to
|
||||||
|
upload to the FTP.
|
||||||
|
|
||||||
|
In short the goal was :
|
||||||
|
|
||||||
|
- non-password authentication
|
||||||
|
- encrypted
|
||||||
|
- path-based authorisation (to avoid to have to create a SSH
|
||||||
|
repository per-project)
|
||||||
|
- if possible try to avoid another Apache instance (all our servers
|
||||||
|
are openVZ containers and I don’t want to add yet another Apache
|
||||||
|
server)
|
||||||
|
|
||||||
|
### 1.2. Existing methods
|
||||||
|
|
||||||
|
There is 3 way of running a SVN server :
|
||||||
|
|
||||||
|
- On a Webdav share. It is only available for Apache with
|
||||||
|
mod\_dav\_svn. Lighttpd’s webdav does not support SVN’s specifics.
|
||||||
|
Nginx and lighttpd advise to only use them as caching/proxy
|
||||||
|
mechanism for an Apache webdav server.
|
||||||
|
- svnserve as a daemon. There is no encryption available for svnserve
|
||||||
|
which means that all data are transiting in clear except the
|
||||||
|
authentication that can be through SASL. SASL provides lots of
|
||||||
|
authentication methods and notably LDAP.
|
||||||
|
- svnserve ran standalone from a SSH connection.
|
||||||
|
|
||||||
|
According to the [SVN book](http://svnbook.red-bean.com/) it is only
|
||||||
|
possible to do path based authorisation with Apache and svnserve daemon
|
||||||
|
(See [Table
|
||||||
|
6.1](http://svnbook.red-bean.com/nightly/en/svn.serverconfig.overview.html#svn.serverconfig.overview.tbl-1))
|
||||||
|
>svnserve over SSH : Read/write access only grant-able over the
|
||||||
|
whole repository
|
||||||
|
|
||||||
|
### 1.3. Requirements
|
||||||
|
|
||||||
|
Path base authorisation is necessary if we want to provide access to
|
||||||
|
partners on website devs. The best solution would be to keep the current
|
||||||
|
repository structure :
|
||||||
|
|
||||||
|
- Websites
|
||||||
|
|-trunk
|
||||||
|
|-html
|
||||||
|
|-customer1website1.com
|
||||||
|
|-customer2website2.fr
|
||||||
|
|-drupal6
|
||||||
|
|-customer1website3.net
|
||||||
|
|-customer1website4.com
|
||||||
|
|...
|
||||||
|
|
||||||
|
|
||||||
|
and give only access to the customer’s website folder. Else we would
|
||||||
|
have to completely re-structure the SVN and do some script magic to
|
||||||
|
create/delete/link lots of separate SVN to redmine.
|
||||||
|
|
||||||
|
### 1.4. Choice
|
||||||
|
|
||||||
|
- We cannot use webdav as only Apache has a webdav SVN module and we
|
||||||
|
do not want to waste resources on it.
|
||||||
|
- svnserve is not an option as data won’t be crypted (even if login
|
||||||
|
can be)
|
||||||
|
- SSH is a great option except that when connecting to the SVN server
|
||||||
|
through SSH, it spawns a svnserve standalone process which doesn’t
|
||||||
|
support path based authorisation, according to the documentation.
|
||||||
|
|
||||||
|
2. Testing
|
||||||
|
----------
|
||||||
|
|
||||||
|
### 2.1. Initialise a SVN repository :
|
||||||
|
|
||||||
|
mkdir /var/lib/svn
|
||||||
|
cd /var/lib/svn/
|
||||||
|
svnadmin create test
|
||||||
|
|
||||||
|
### 2.2. Set up basic authorisation
|
||||||
|
|
||||||
|
vi /var/lib/svn/test/conf/svnserve.conf
|
||||||
|
-> [general]
|
||||||
|
anon-access = none
|
||||||
|
auth-access = write
|
||||||
|
|
||||||
|
password-db = passwd
|
||||||
|
|
||||||
|
authz-db = authz
|
||||||
|
vi /var/lib/svn/test/conf/authz
|
||||||
|
-> [groups]
|
||||||
|
testwrite = user1
|
||||||
|
testread = svn
|
||||||
|
|
||||||
|
[test:/]
|
||||||
|
@testwrite = rw
|
||||||
|
@testread = r
|
||||||
|
|
||||||
|
[test:/public]
|
||||||
|
@testread = rw
|
||||||
|
# passwd is only required for the svnserve daemon
|
||||||
|
vi /var/lib/svn/test/conf/passwd
|
||||||
|
-> [users]
|
||||||
|
user1 = test
|
||||||
|
svn = test
|
||||||
|
svnserve -d -r /var/lib/svn
|
||||||
|
svn co --no-auth-cache svn://127.0.0.1/test
|
||||||
|
|
||||||
|
|
||||||
|
Committing things with user svn only works in the ‘public’ folder.
|
||||||
|
whereas user1 can commit everywhere.
|
||||||
|
|
||||||
|
### 2.3. SVN+SSH configuration :
|
||||||
|
|
||||||
|
adduser svn --disabled-password
|
||||||
|
cp -ax /root/.ssh/ /home/svn/
|
||||||
|
chown -R svn:svn /home/svn/
|
||||||
|
chown -R svn:svn /var/lib/svn/
|
||||||
|
vi /home/svn/.ssh/authorized_keys
|
||||||
|
-> command="svnserve -t -r /var/lib/svn --config-file=/var/lib/svn/haven/conf/svnserve.conf --log-file=/tmp/svnserver.log --tunnel-user=USERNAME",no-port-forwarding,no-agent-forwarding,no-X11-forwarding,no-pty USERKEY
|
||||||
|
# On Client
|
||||||
|
svn co svn+ssh://svn@svnserver/test
|
||||||
|
|
||||||
|
According to the [SVN book’s SSH
|
||||||
|
tricks](http://svnbook.red-bean.com/nightly/en/svn.serverconfig.svnserve.html#svn.serverconfig.svnserve.sshtricks.fixedcmd).
|
||||||
|
This configuration is very secure but does not respect above
|
||||||
|
configuration regarding path based authorisation.
|
||||||
|
|
||||||
|
As said in the [SSHauth
|
||||||
|
section](http://svnbook.red-bean.com/nightly/en/svn.serverconfig.svnserve.html#svn.serverconfig.svnserve.sshauth)
|
||||||
|
of the SVN book :
|
||||||
|
>When running over a tunnel, authorization is primarily controlled
|
||||||
|
by operating system permissions to the repository’s database files; it’s
|
||||||
|
very much the same as if Harry were accessing the repository directly
|
||||||
|
via a file:// URL. If multiple system users are going to be accessing
|
||||||
|
the repository directly, you may want to place them into a common group,
|
||||||
|
and you’ll need to be careful about umasks (be sure to read the section
|
||||||
|
called “Supporting Multiple Repository Access Methods” later in this
|
||||||
|
chapter). But even in the case of tunneling, you can still use the
|
||||||
|
svnserve.conf file to block access, by simply setting auth-access = read
|
||||||
|
or auth-access = none.
|
||||||
|
|
||||||
|
3. Solution
|
||||||
|
-----------
|
||||||
|
|
||||||
|
After some testing/debugging I manage to come up with 2 solutions that
|
||||||
|
should work with our set goals :
|
||||||
|
|
||||||
|
### 3.1. svnserve daemon
|
||||||
|
|
||||||
|
We can simply override SVN+SSH behaviour by using netcat in the
|
||||||
|
commands= section of the authorized\_keys file. So for example we can do
|
||||||
|
the following :
|
||||||
|
|
||||||
|
vi /home/svn/.ssh/authorized_keys
|
||||||
|
-> command="netcat localhost 3690"
|
||||||
|
svnserve -d -r /var/lib/svn/
|
||||||
|
# On the client
|
||||||
|
svn co svn+ssh://svn@svnserver/test
|
||||||
|
|
||||||
|
|
||||||
|
This will use 2 authentications process. First it will use the SSH keys,
|
||||||
|
then it will ask for a regular username/password. That’s where you could
|
||||||
|
use SASL to link this with your authentication of choice (LDAP or
|
||||||
|
others). This isn’t ideal but according to the SVN documentation this is
|
||||||
|
the only way of having path based authorisation with SSH, which as you
|
||||||
|
will see below is NOT TRUE.
|
||||||
|
|
||||||
|
### 3.2. svnserve tunnel
|
||||||
|
|
||||||
|
- From the start of my debugging I found out that svnserve.conf, authz
|
||||||
|
and passwd ARE indeed loaded by svnserve (even in tunnel mode -t).
|
||||||
|
So I was pretty sure that path based authorisation should work with
|
||||||
|
little tinkering.
|
||||||
|
- After debugging the whole application I found that path based
|
||||||
|
authorisation SHOULD work by modifying the configuration. Simply
|
||||||
|
revoking all authorisation in the authz file before allowing them
|
||||||
|
works like a charm !
|
||||||
|
vi /var/lib/svn/test/conf/authz
|
||||||
|
-> [groups]
|
||||||
|
testwrite = user1
|
||||||
|
testread = svn
|
||||||
|
|
||||||
|
#Revoke all rights to the SVN folder
|
||||||
|
[/]
|
||||||
|
* =
|
||||||
|
|
||||||
|
[test:/]
|
||||||
|
@testwrite = rw
|
||||||
|
|
||||||
|
[test:/public]
|
||||||
|
@testread = rw
|
||||||
|
|
||||||
|
|
||||||
|
In that case svn can’t check out /test but has full permissions in
|
||||||
|
/test/public !
|
||||||
|
|
||||||
|
<!-- -->
|
||||||
|
|
||||||
|
- Beware of the default permissions in the svnserve.conf that cannot
|
||||||
|
be overridden. Setting auth-access to read will prevent EVERY user
|
||||||
|
from writing despite anything that can be written in the authz file,
|
||||||
|
as stated above :
|
||||||
|
>But even in the case of tunneling, you can still use the
|
||||||
|
svnserve.conf file to block access, by simply setting auth-access =
|
||||||
|
read or auth-access = none.\_
|
||||||
|
|
||||||
|
4. Implementation
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Now that we found out that the SVN documentation is misleading (probably
|
||||||
|
from lack of update), here is a simple procedure to setup path based
|
||||||
|
authorisation with SVN+SSH.
|
||||||
|
|
||||||
|
### 4.1. Give all permissions to svn users :
|
||||||
|
|
||||||
|
chown -R svn:svn /var/lib/svn/
|
||||||
|
|
||||||
|
### 4.2. Add public SVN user keys to its authorized\_keys following the below format :
|
||||||
|
|
||||||
|
vi /home/svn/.ssh/authorized_keys
|
||||||
|
-> command="svnserve -t -r /var/lib/svn --log-file=/tmp/svnserver.log --tunnel-user=USERNAME",no-port-forwarding,no-agent-forwarding,no-X11-forwarding,no-pty ssh-dss USERKEY
|
||||||
|
|
||||||
|
### 4.3. Configure a generic svnserve.conf
|
||||||
|
|
||||||
|
/var/lib/svn/svnserve.conf
|
||||||
|
-> [general]
|
||||||
|
anon-access = none
|
||||||
|
auth-access = write
|
||||||
|
# password-db = passwd
|
||||||
|
authz-db = authz
|
||||||
|
rm */conf/svnserve.conf .
|
||||||
|
# Our example repository for all websites :
|
||||||
|
ln -s /var/lib/svn/svnserve.conf websites/conf/
|
||||||
|
# All you other projects
|
||||||
|
ln -s /var/lib/svn/svnserve.conf project2/conf/
|
||||||
|
...
|
||||||
|
ln -s /var/lib/svn/svnserve.conf projectn/conf/
|
||||||
|
|
||||||
|
### 4.4. Per repository permissions :
|
||||||
|
|
||||||
|
vi /var/lib/svn/websites/conf/authz
|
||||||
|
-> [aliases]
|
||||||
|
# Could be used with LDAP i.e. :
|
||||||
|
# joe = /C=XZ/ST=Dessert/L=Snake City/O=Snake Oil, Ltd./OU=Research Institute/CN=Joe Average
|
||||||
|
|
||||||
|
[groups]
|
||||||
|
websitesread = webserver1, webserver2
|
||||||
|
websiteswrite = adminuser
|
||||||
|
customer1site1read = customer1
|
||||||
|
customer1site1write = designer1, webdeveloper1
|
||||||
|
|
||||||
|
# VERY IMPORTANT
|
||||||
|
[/]
|
||||||
|
* =
|
||||||
|
|
||||||
|
[websites:/]
|
||||||
|
@websitesread = r
|
||||||
|
@websiteswrite = rw
|
||||||
|
|
||||||
|
[websites:/trunk/html/customer1/site1.com]
|
||||||
|
@customer1site1read = r
|
||||||
|
@customer1site1write = rw
|
||||||
|
|
||||||
|
### 4.5. User checkouts
|
||||||
|
|
||||||
|
SVN+SSH makes it very easy to test permissions of your repository. You
|
||||||
|
just have to change your USERNAME in SVN’s authorized\_keys.
|
||||||
|
|
||||||
|
As customer1 :
|
||||||
|
|
||||||
|
svn co svn+ssh://svn@svnserver/websites
|
||||||
|
svn: Authorization failed
|
||||||
|
svn co svn+ssh://svn@svnserver/websites/trunk/html/customer1/site1.com
|
||||||
|
At revision 5.
|
||||||
|
|
||||||
|
As adminuser :
|
||||||
|
|
||||||
|
svn co svn+ssh://svn@svnserver/websites
|
||||||
|
At revision 5.
|
||||||
|
|
||||||
|
### 4.6. Deploy website on web server
|
||||||
|
|
||||||
|
- Generate ssh key for webserver1
|
||||||
|
su - www-data
|
||||||
|
ssh-keygen -t rsa -b 2048
|
||||||
|
|
||||||
|
<!-- -->
|
||||||
|
|
||||||
|
- On the SVN server add webserver1’s public key to svn’s
|
||||||
|
authorized\_keys and give it the username webserver1
|
||||||
|
- Back on webserver1
|
||||||
|
cd /var/www/customer1/site1/web/
|
||||||
|
svn co svn+ssh://svn@svnserver/websites/trunk/html/customer1/site1.com
|
||||||
|
crontab -e
|
||||||
|
*/5 * * * * /usr/bin/svn --non-interactive update /var/www/customer1/site1.com/web 2>&1 > /dev/null
|
||||||
|
|
||||||
|
5. Related topics
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
### 5.1. SVN migration
|
||||||
|
|
||||||
|
See [Migration-trac-redmine\#6-SVN-migration](Migration-trac-redmine\#6-SVN-migration).
|
||||||
|
|
||||||
|
### 5.2. Clean up a SVN repository from bogus commits
|
||||||
|
|
||||||
|
While migrating our SVN to a new server we jump on the occasion to clean
|
||||||
|
up some bogus commits. Here is an example on how to modify the author
|
||||||
|
property, that can be used for any revision properties.
|
||||||
|
|
||||||
|
- List all committer
|
||||||
|
svn log --quiet file:///var/lib/svn/project1/ | awk '/^r/ {print $3}' | sort -u
|
||||||
|
|
||||||
|
- Change bogus committer (requires the
|
||||||
|
[pre-revprop-change
|
||||||
|
script](Migration-trac-redmine\#71-Add-pre-revprop-change-hooks-to-allow-revision-modifications))
|
||||||
|
for rev in `svn log --quiet file:///var/lib/svn/project1/ | awk '/bogususer/ {print substr($1,2)}'`; do
|
||||||
|
svn propset --revprop -r $rev svn:author correctuser file:///var/lib/svn/project1/ ;
|
||||||
|
done
|
||||||
|
# If done after the import in redmine we need to modify this in Redmine's DB as well :
|
||||||
|
sqlite3 /var/lib/dbconfig-common/sqlite3/redmine/instances/default/redmine_default
|
||||||
|
-> update changesets set user_id = X where committer="bogususer" and user_id is null;
|
||||||
|
update changesets set committer="correctuser" where committer = "bogususer";
|
||||||
|
|
||||||
|
### 5.3. Reference for Debugging
|
||||||
|
|
||||||
|
Here are some links to tools and documentation that were useful for my
|
||||||
|
debugging :
|
||||||
|
|
||||||
|
- The [SVN daemon
|
||||||
|
protocol](http://svn.apache.org/repos/asf/subversion/trunk/subversion/libsvn_ra_svn/protocol).
|
||||||
|
- If you require to sniff the full SVN protocol you can use the
|
||||||
|
following :
|
||||||
|
aptitude install simpleproxy
|
||||||
|
simpleproxy -L 3333 -R 127.0.0.1:3690 -t trace
|
||||||
|
# Locally do
|
||||||
|
svn co svn://127.0.0.1:3333/test
|
||||||
|
|
||||||
|
- For svnserve step by step debugging, I compiled from source and used
|
||||||
|
gdb, nemiver and netbeans.
|
||||||
|
|
||||||
|
See Also
|
||||||
|
--------
|
||||||
|
|
||||||
|
- The [migration from trac to Redmine](Migration-trac-redmine)
|
||||||
|
that was performed in conjunction with the above.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user