Capistrano security fun

Capistrano (formerly switchtower) is the ‘ruby on rails’ way to deploy your code out onto your fleet of production/test servers. I’ve previously written my own ‘deploy’ script which had similar goals to capistrano, but I’ve only recently tried capistrano itself.

Having now used it, I think it makes a poor design decision. Capistrano runs a “svn co” operation on the deploy host itself. I think it’d be much better to grab a clean set of sources on your local development box, and then rsync/scp that to each deploy host.

The capistrano way is poor for the following reasons. Firstly, since I access my svn respository over ssh I need to have my private key on my deploy host. This is non-optimal for security reasons. I want to keep close tabs on my private keys, and I don’t want it living on a (potentially) compromisable public-facing host. Why not do all the svn stuff locally and keep your private key local?

But it gets worse. Your deployed rails app ends up (by default) being a ‘live’ checked out copy, complete with .svn directories. Additionally, the default rails setup unfortunately exposes the very top level .svn directory in your deployment. This leaks some information: nothing critical, but in security terms any leakage is bad. To find examples, look no further than the list of apps on the RoR site. Examples include 37signals [fixed] and penny arcade and strongspace and iconbuffer [fixed] etc.

Like I say, the information leaked in this way is not too critical. But, if you were into social engineering, knowing the hostname of their internal svn server in addition to login names for several developers could be just the info you need.

What’s the moral to this story? It’s the old lesson of minimal privileges. There’s no real need for the deployment hosts to have ssh access to the svn repository. Nor is there any need to have your deployment version be a ‘live’ checked out version of your source code. I think I will be sticking to a deployment method where I check out locally and rsync to the production hosts …

Update: This method also reveals the contents of some .htaccess files … append .svn/text-base/.htaccess.svn-base to your favourite rails app URL.


17 Responses to “Capistrano security fun”

  1. Tom says:

    Can one solve the first problem with agent forwarding?

    Also: glad to see you’re using Rails!

  2. Andrew says:

    Hey Tom, nice to hear from you again! What are you up to these days? :-)

    My searches for ‘capistrano agent forward’ only showed up people saying ‘not supported’. But I rechecked and Capistrano uses the ruby Net::SSH module which _does_ appear to support agent forwarding. So I’ll have another go sometime and see if I can make capistrano talk to my ssh-agent like you suggest. The other niggle is that Net::SSH ignores your .ssh/config file totally, so any port/agent-forward/username options which you’ve already got working there need to be restated.

  3. Rob Sanheim says:

    You can setup Capistrano to use svn export instead of co, which eliminates the svn metadata issue. And if you check the capistrano list, there are some folks working on getting rsync support right now.

  4. James H says:

    Interesting thoughts. Have you thought about writing a patch to alter how Capistrano to act in the way you suggested above?

  5. topfunky says:

    See also Dan Benjamin’s article on this from May 2006:

    http://hivelogic.com/narrative/articles/preventing_svn_exposure

  6. Alan says:

    These are issues but they can be worked around without compromising security. Not serving up .svn files is as simple as a few lines in your .htaccess file. See http://lovetastic.com/.svn/entries. Or as someone said earlier, a few capistrano tweaks.

    As for your private key: use a DIFFERENT key for your server. Don’t use the same private key you use locally on your machine. Create a key that only gets access to the svn repository and only put that key on your production servers. That way, all that is exposed is the repository.

    This shouldn’t be a problem since the repository is checked out on the production server anyway, so if that is compromised, your source code already is too.

  7. This is just sloppy deployment – svn export is the easy way to get a clean set of files, or you can do svn up into a local directory and rsync, excluding .svn (avoiding the overhead of checking out the same files over and over if only .001% of them change).

    Please tell me nobody is running svn up from their production server, pointed at their svn repo… I can almost hear someone saying “but it’s a read only user, that means it’s secure!”

    Seriously, the production server shouldn’t even have subversion on it, nor gcc, and it should have files magically appear via rsync over ssh when the deployment script runs. Anything pull-oriented is asking for trouble. Ditto with logs and backups – things just get yanked off of there over ssh; it should not be possible for a hacker to root your production server and from there blow away your backups, download your whole svn repo and all of your logs etc.

  8. Roland says:

    You don’t need svn on the remote server if you don’t mind writing custom tasks.

    See Rob Orsini’s Rails Cookbook, Chapter 13-11 for an example. The code example by itself is available online: http://examples.oreilly.com/9780596527310/

  9. Anon says:

    Why not just uncomment this line in deploy.rb?

    set :checkout, “export”

    Why would you want a .svn at all? You won’t change anything or ever do a diff on the deployment server.

  10. Philip Hallstrom says:

    If using apache, you can do this to have it return 404 not found results for anything in the .svn directory:

    <Directory “/home/philip/cpr/forums/public”>
    Options FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all
    </Directory>

  11. Andrew says:

    Thanks for all the comments, particularly the link to the rsync recipe which seems almost exactly what I need. Yes, it’s possible to do workarounds to stop the .svn files being served. But the root problem (as Jamie said above) is that the production servers have rights/apps/data on them which are not absolutely required for performing their role. For public-facing machines, this is a risky situation.

  12. Erik Karulf says:

    Just as a follow up, I patched Penny Arcade to block at the server level any .svn entries. This is a relic from our old Capistrano deployment model. Humorously, we found the model to involve too many holes to be punched in our firewall so we started working on an in house solution. Our new deployment model is in the testing stage and involves FreeBSD’s jailing and some nullfs voodoo.

    All the passwords and hostnames have long since expired so for us the worst part is people probably saw some of the old PHP code I inherited, which I don’t really want myself or PA associated with.

    Anyway thanks for the heads up.

  13. So nice to see a software blogger, that’s even using Ruby and that is also a bass player! Am I right? Then we are at least two! Have a look at http://www.vesterberg.se.

    All the best,
    Anders Vesterberg

  14. Off subject matter – Thanks for adding our company to your Edinburgh software companies page.

    Jamie

  15. Andrew, thank you so much for writing such a detailed post, it was no 1 in my google search on “capistrano svn security”

    http://www.google.com/search?q=capistrano+svn+security&ie=utf-8&oe=utf-8&aq=t&rls=com.ubuntu:en-US:official&client=firefox-a

    I’ve only started using Capistrano this morning and was already worried by the “svn checkout on a live server” issue.

    I’ll go and read the other links in the comments now.

    I know it’s been a few months now since your post, what is your current “best practice” way of deploying via Capistrano?

  16. Capistrano 2.0 fixes this. You can do:

    set :deploy_via, :copy
    set :copy_strategy, :export

    And it will only send a tarball of your exported sources up.

Leave a Reply