Sysadmin by day, developer by night
Why I don't like maven, setup.py, and all the rest

Disclaimer: I am pretty new to all of this, I could be doing it wrong, and would love to be set straight.

I’m pretty new to Python, a little over a year developing with it, and most of that on Appengine. Java/Scala I’ve barely touched, but there are some barriers that keep me from really wanting to look further into it, and one of those is the deployment methods used.

Python, as I’m moving towards a more traditional run it on my own server approach, is starting to frustrate me too. I don’t want to rely on fancy tools that go and get everything for me, distributes it all over my filesystem, and it “just works!”. Ugh.

This approach is great for developers working on dev boxes. For production systems, not so much. The systems I maintain, apache is built from source, python is built from source… you get the point. Everything lives in /usr/local, usually in version named directories with symlinks to them (ie: /usr/local/apache2 => /usr/local/apache2-2.2.13). We have nice fancy scripts that let us build and deploy on stage, and copy to production hardware that doesn’t have compilers running on it. And, that /usr/local is more often than not /CHROOT/system/usr/local with us running a chroot system to further protect out systems (root exploit apache? You don’t even have ping buddy).

Now, maybe there are easy ways to have maven install itself is specific directories, and tell setup.py to do the same. I mean, I use ./configure prefix=/usr/local/app all the time. However, I’m not sure I want to have to learn a new deployment system as well as a new language, when configure and make have been serving me well for over a decade.

For my own project, I think I’m ok. Tornado can run off of a version of python I compile. Memcached and Cassandra can be deployed easily enough. I wish the c version of memcached client for python worked, but, whatever. However, as I considered learning Scala/Lift/Akka to use instead for this project, all of the above just kept me from even really getting into the language. Just food for thought.

Why Memcached

This will probably be the shortest of the articles about why I’ve chosen what I’ve chosen for my systems architecture. Memcached really was an easy choice. It’s proven time and time again, and honestly I’ve yet to see anything that competes for it.

As I said in my previous post, Cassandra will be used for persistent data. Memcached is for all the other data. That data being temporary sessions and cache data. Memcached provides the horizontal scaling necessary for the infrastructure design I am trying to implement, and with 0 disk access provides the performance necessary to for the performance I am trying to get.

I did look for alternatives, but really couldn’t find anything that fit. Playing with memcached, the only complaint I have so far is the fact it appears I can’t have keys in a unicode format. I don’t believe this will be a problem to start with, I’ve in fact already got a simple sessions library written for it. But it would be nice if it could support it.

Why Cassandra

So, after choosing Rackspace Cloud for initial hosting, I need to start piecing together my application. First, I’m taking a look at where, how, and what to store data in. I’m actually going to store data in two places, depending on the type of data it is. This entry will cover where I’m storing what I call, persistent data.

Persistent data is data the will remain relatively unchanged, and is something I will need to keep indefinitely. I’ll actually be using another datastore for things like cache, session tokens, and the like. Another entry will be written to detail my choice for that. Persistent data is things like user accounts, comments, and other application data that I’m not ready to divulge yet, but you should get the point.

Individual data items are not expected to be large. No media, just unicode text. However, the application I’m working on is something that could potentially scale to support large amounts of users. So while individual items may be small, there may be a lot of them. The comments feature especially could explode with data… or never be used at all. It’s one of those things.

So with the above in mind, and remembering some technology articles Digg released a while back about their infrastructure, I pretty much ruled out any RDBMS. Having developed on Appengine, I knew a little about key/value systems, but was spoiled by their own query capabilities within BigTable. As I started looking for altenatives, I stumbled across Facebook’s Opensource Page. There Cassandra caught my interest, and I started reading about it.

The things that interested me was the fact it’s built to scale across machines and even data centers, using a customizable replication topology. I prefer the eventually consistent approach, it’s a good fit for my application as I want to make sure I never lose data, and that reads/write operations succeed every request. For the few cases I need to write and have the data immediately available, I can workaround using the other datastore I’ll write about later. The fact Facebook was using it for it’s messaging system was another thing that caught my eye.

What concerned me was that it didn’t look like a lot was going on with the project. The project page was pretty sparse. Apache incubator project was nice, but… I was initially feeling that this was something Facebook threw over the wall and no one really picked up. The reason I’m saying all this is because if this is the impression I got, I imagine others my have had the same impression.

However, I’m pretty stubborn, hey I’ve been using Slackware since version 3, and remember when increasing the amount of available http sockets with apache was a source code change. Lack of documentation doesn’t scare me, so I kept digging. Well, turns out Digg, Rackspace, and to some degree Twitter are getting behind the project. The IRC channel (#cassandra on irc.freenode.net) is pretty active, and they appear to have an interest in prettying things up, as they have had a contest on 99designs.com to create a new logo. (At the time of writing this, the contest has 3 hours, so not posting the link as I’m not sure what happens to contest links after they are over.) In fact, while researching the project. 0.4 was released.

There are a lot of projects out there that provide similar functionality. Some more mature than Cassandra. As I said in my last article, this series will not compare what I’ve chosen to other software choices. I will only detail why I chose the product I am going with. I am fully open to hearing more information about other projects, as I have not begun building, and just making infrastructure choices. One reason for this series is I want the feedback to confirm my choices, or to provide me with information about why I might look elsewhere.

So why Cassandra? It provide horizontal scalability for the persistent data layer of my application. The horizontal clustering approach, with it’s replication topology also provides redundancy. This redundancy includes geographical redundancy support. It was originally built by Facebook, who is a prime example of an organization with data reliability and scalability requirements that match my own. After being opensourced, it has been picked up by Rackspace, Digg, and Twitter, more organizations with scalability requirements similar to my own. Sometimes you have to look at the bells and whistles, but sometimes it’s more important to look at who is standing behind a project. The latter, combined with the fact out the gate Cassandra meets my data requirements, made this choice a no brainer.

Looking forward to how I’ll use Cassandra… Based off of a conversation I had with jbellis in the Cassandra irc channel, I’ll be standing up 3 Rackspace Cloud machines, instead of 1, when I’m ready to move off of working on my home dev machine. The reason for this I want to have the clustering concepts down, long before I need them.

I’ll also have to look at how I want to layout my data. As I understand how Cassandra works, there is no querying, you get by key. So, for example, my user system which allows login from multiple sources will need to be denormalized. So, something like

User:
    twitter_id
    facebook_id

Where on login, I’d query the user table for the appropriate id, or create a new account if it doesn’t exist. Instead I’ll need something like

{username: {
  twitter_id: 123456789,
  facebook_id: abcdefg
  }
}

{twitter:
  {
  123456789: username
  }
}

{facebook:
  {
  abcdefg: username
  }
}

On login, from say Twitter, I get the key twitter.123456789 and know my account is username. It means my application has more places to update information, but as far as speed goes, should be pretty zippy.

Now, I do have LOTS to still learn about Cassandra. The clustering concepts and how to order my data on disk using functionality Cassandra provides to optimize it is going to take time. The project also is pretty active, and I’m probably months away from even doing my first install. So, some things may change before I even get to that point. What I really like about this is it’s going to be a chance to learn a whole new way of managing data. Professionally, I support installation of MySQL, Microsoft SQL Server, and to a small extent Oracle and their clients for the applications our developers use to interact with them. I have direct experience with MySQL from various side projects, and of course I learned a lot about BigTable working on gaeutilities. Cassandra is going to be a whole new depth of managing data that DBA’s or Google has usually handled for me. This is something I really look forward to.

Why Rackspace Cloud
This is the first in a series of posts I’ll be making about the choices I’ve made for the hosting and infrastructure for an application I’ve been developing for a while on another environment, and will be rewriting. This will be a bottoms up approach, and I’m starting with my decision on hosting provider, as the bare metal (or virtual metal) is about as bottom as you go. These articles are why I’ve made my choices, but it should be noted that design has not begun yet, and no dollars spent. I am more than open to comments, suggestions, and questions that may influence me to make other decisions. I’m also discussing what my choices are, and why I made those choices based off of product merit. No comparisons to other products detailing why I did not choose them.

So to start with, I’m looking at hosting. My requirements, based on already building a proof of concept for my application, are as follows:
  • Virtual Server-esque deployment.
    Basically I want my own operating system, preferably a flavor of Linux, on which I can deploy my application. I am not interested in application platforms.
  • Low cost for entrance, with vertical scaling.
    My application will be designed to be horizontally scalable, but as I’m covering all costs on my own initially (and I don’t have much money) I’m looking for something I can enter into with a low cost, and can scale without a lot of work.
  • Reliability.
    I need to know that when I am showing off the application in beta, and eventually trying to get people to buy into it, that the application will be available. If I’m trying to convince someone how great it is and they go to look at it and it doesn’t work, well…
  • Opportunity to form a long term hosting relationship.
    I really think the application I am building has the potential to become a major spot on the internet. I’m looking for some place that not only can I start small with, but I can move to dedicated server hosting, and eventually get geographical redundancy. Migrations are painful, so minimizing the complexity of those by finding a vendor who can provide the full range of hosting will be helpful.
So, after a lot of deliberation, and changing my mind several times, I’ve decided that once I’m done building on my development box, Rackspace Cloud will be the first host for my app. It meets every one of the requirements above.

Their cloud servers support multiple Linux flavors, basically I’ll just have to pick one. $10.95 a month entry point for a small VPS in their cloud is cheaper than most providers. The Bandwidth costs are somewhat of a concern, many other providers do offer a base level of bandwidth in/out, from what I can see Rack Space you immediately pay extra for bandwidth consumption. The reason this is a concern up front is that my application will be making multiple http requests of it’s own, as it works with various APIs. However, the entry level $10.95 option will not support the load where bandwidth costs will be an option, so it’s really not too big of a concern.

Their machines also scale to higher priced pacakges, and if I read the marketing literature right, they scale in place. I’m guessing they do the initial OS deployment and configure an lvm to scale the filesystem. I can also deploy more machines (at more cost) when horizontal scaling is more appropriate than vertical scaling. They give you an IP on their private network for the machines, basically your own little backbone to work on. Very nice.

I’ve been a Sysadmin for over a decade now. I’ve never heard a single bad thing about Rackspace. I’ve heard they were expensive, and it is true they are more expensive than other proivders. However, I’ve never a single bad thing about Rackspace. You get what you pay for, and if I’m trying to launch a business, I want a hosting provider with that reputation. Rackspace cloud is new. Rackspace has been doing datacenter hosting for years, and they have multiple datacenters. People move to Rackspace when they grow to big for other hosting providers and they have to make the choice between building their own datacenter, or getting a big provider. For example, Github is migrating to Rackspace.

So overall, Rackspace Cloud gives me a low cost entry point to building a relationship with a hosting provider that can support just about any scale of hosting my application may require. I really don’t see how any other provider can meet the requirements I have better. As a bonus, Rackspace are contributors to the Cassandra project, which will be the topic for the next post in this series.
Why Cookie Only Sessions Are Not Secure, Not Matter What Encryption You Use

So, after my entry on why I’m leaving Appengine, due to the lack of reliability of the datastore for something like a sessions api, someone asked about encrypted sessions. I admit at first I wasn’t very willing to look at how encryption could be used to manage the sessions, but after a bit of thought I started trying to work on an encryption scheme for cookie only sessions in an attempt to provide a solid solution for Appengine.

After several days of working on it, I returned to working on trying to make the datastore more reliable. The reason is, encryption of the cookies only protects the data. Checksum validation only validates the data is unchanged. However, the issue is that when you’re using cookies for sessions, you also need to validate identity. Not matter what encryption scheme you build, or checksum solution you implement, all it takes is for someone to sniff and copy the cookie to hijack the session itself. And once you’ve hijacked the session you have access to everything.

Now, GAEUtiltiies approach isn’t a fool proof solution for this. So before I talk about it’s implementation, I want to state the best solution is to ssl wrap the cookie. This is something I’m going to look at implementing at some point. The catch on appengine being you’d need to set the cookie domain to your .appspot.com domain, rather than any CNAME domain you’re using, because at this time Google can’t support SSL connections on your domains.

GAEUtilities approach is to keep tokens that rapidly rotate. Chances are, you’re probably getting a new token each request with it’s default settings. It was rapid enough that some AJAX enabled sites found that sessions couldn’t support them, so I turned the token into a 3 element list in order to provide support for them. This does lengthen the time that the session is valid for. I believe a single token is good for about 15 seconds.

If someone does hijack your session, that’s how long you have until the tokens on the browsers diverge enough that one of you will be logged out. As each request will assign a new token to the browser based on the timestamp of their current token. Now that I think about it, I suppose a good idea would be to make sure a token is written out to a browser only once to make sure this is the case. So either the attacker is logged out, or the user is. I believe the tendency would be for the user to try to log back in again, which would initiate a new session. You’d want your authentication system to only support a user logged in on one session to provide the best security.

This is why I always suggest someone use sessions that are backed with server side data only. Encryption of the data isn’t necessary, as it never makes it across the wire, and identity can be preserved by rapidly changing tokens.

Working Towards a More Stable Datastore On Appengine

I’ve just finished the first version of a new Model class for Appengine, ROTModel (Retry On Timeout Model) for gaeutilities. What it does is superclass db.Model, implementing most models with a wrapper which retries when a timeout exception is raised. It will retry 3 times, adding a 1 second pause exponentially (first retry 0 seconds, second 1 second, last 2 seconds).

The purpose is to try and make sure your reads and writes happen, and your requests don’t error out as often.

I got the idea from this post in the Google Appengine group - http://groups.google.com/group/google-appengine/browse_thread/thread/ac51cc32196d62f8/aa6ccd47f217cb9a?lnk=gst&q=timeout#aa6ccd47f217cb9a

I may actually just turn around release a decorator, as the model still isn’t working as I’d like. get_or_insert and get_by_key_name both are not included at the moment, as the attempt I made at wrapping them failed.

Trying to Secure Cookie Only Sessions, Without HTTPS

So, I’ve started breaking ground on the new cookie only sessions for gaeutilities. However, I’m only working on raw read/write functionality as I still determine how I’m going to secure them. I’m also trying to do it in a way that can exist on appengine without https, as that’s a paid resource on Appengine. Also, https for your domain doesn’t exist, only for the .appspot.com subdomain for your application.

Originally, I thought I’d just do two cookies, the data cookie, and then a checksum of the data cookie. The checksum creation would be configured with a salt. However, after a night of sleeping on it, I realized that an attacker would just need to copy those two cookies, and resend them and they’d have the victims session as their own.

So, now I’m trying to think of a way to include more information in the cookie to protect it. I could use the expires header and use it as part of the salt, however someone may want to have the session persist longer than the seconds it would take to script sniffing the cookie and resending it to start a session hijack.

User-agent and IP checking can help, but are easily spoofed and with the prevalence of shared outbound ips, and proxies that change user agents, can create more accessibility problems for a website than the marginal security gains.

It’s actually kind of frustrating that the browser and web server projects haven’t come up with a way to handle this problem already.

So, still trying to think of a way to manage the session hijack issue, and if/when I’ll come up with a solution I’ll post a follow up. If anyone has any ideas, as I’m sure this has been solved by someone already, please feel free to use the comments.

Better Sessions For Appengine?

I’ve always hated the idea of only using cookies for session data. Even when you encrypt them, there’s a chance that the encryption can be broken. The thing is, I’ve been thinking about it wrong, and a result I wrote gaeutilities session class to be entirely too resource intensive and also unreliable because of it’s dependence on the datastore, which is also unreliable.

Yes, any encrypted string, even if it’s one-way encrypted, can eventually be decrypted. The key word there is “eventually”. Once you know the algorithm and the hash, it becomes trivial. The algorithm can be figured out reasonably quickly just be looking at the string, the hash takes more work. Now, if you can determine a way to obfuscate the hash, and change it often, it makes it more difficult to steal the session.

I’m not ready to rewrite session for gaeutilities yet, as I want to think about this a bit. Also, I think I should take a look at what other session libraries exist for Python already, as someone less stubborn about persisting data server side may have already written something that does what I am thinking now.

A rough draft of how I’d go about doing it is…
Cookie would be a single cookie, it’s payload being a json string encrypted.
Server side, I’d have to maintain a hash to decrypt that cookie.
That hash would need to change periodically, with a max interval before change of x seconds

The challenge is the last part. I wouldn’t want to store the hash in the datastore or memcache, because quite frankly neither is reliable enough. So, the trick will be coming up with a way to manage the hash constantly changing and being able to keep it’s state so I can decrypt the cookies. Can’t store the hash in a cookie, because then you’ve given away half your encryption, and the important half at that.

Need to think on this more. After looking to see what else out there.

Tornado URLs

All my previous experience with web development using Python has been with Django. One nice about Django is it’s url mapping. It automatically handles adding the final / to a url. So if on a Django site you go to http://mysite.com/test you automatically get sent to http://mysite.com/test/. Tornado doesn’t do this for you.

If no one else does, I’ll probably figure out how to get Tornado to do this, shouldn’t be too difficult as it is the webserver as well as the application framework. For now though I’m figured out bandaid. You’d probably think to do your url mappings like this:

application = tornado.web.Application([
    (r"/", MainHandler),
    (r"/test", views.TestHandler),
])

That will work for http://mysite.com/test but not http://mysite.com/test/. Instead try

application = tornado.web.Application([
    (r"/", MainHandler),
    (r"/test/*", views.TestHandler),
])

This will now match both cases.

Taking a look at Tornado

So, a big announcement today. Facebook has released an opensource project called Tornado, which is a framework derived from the application that powers FriendFeed. What is it? It’s a web server and development framework written in Python. Some of the features that interested me was the built in asynchronous http client, and support for authentication against various 3rd party sources including Twitter, Facebook, Yahoo! and Google. Facebook has stated they’ll stand behind this framework, supporting it.

From the Tornado website -

The framework is distinct from most mainstream web server frameworks (and certainly most Python frameworks) because it is non-blocking and reasonably fast. Because it is non-blocking and uses epoll, it can handle thousands of simultaneous standing connections, which means it is ideal for real-time web services. We built the web server specifically to handle FriendFeed’s real-time features — every active user of FriendFeed maintains an open connection to the FriendFeed servers. (For more information on scaling servers to support thousands of clients, see The C10K problem.)

So, how does it work?

I guess I’m new to Python still. I downloaded it, and installed it per the instructions. Lo and behold, there’s no binary to run the server. However, if you read the documentation, you find a sample script that uses the httpserver module to run as a server. I’ve modified it slightly, adding a command line argument to set the port.

So, as a minimal quick getting started tutorial.

Download the project from Tornado Website.

I have several versions of python installed on my development machine, 2.6 installed by ubuntu, and a custom compiled 2.5 version I used for Google Appengine development. So, I took the approach of not running the install, I did build it though.

mkdir WORK; cd WORK
mkdir project
# copy the file from your download location into WORK
tar zxvf tornado-0.1.tar.gz
cd tornado-0.1
python setup.py build
cp -Rp build/lib.linux-i686-2.6/tornado ../project
cd ../project
cat <<EOF > server.py
#!/usr/bin/python
import sys
import tornado.httpserver
import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

application = tornado.web.Application([
    (r"/", MainHandler),
])

if __name__ == "__main__":
    port = 8888
    if len(sys.argv) > 1:
        port = int(sys.argv[1])
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(port)
    tornado.ioloop.IOLoop.instance().start()

EOF
chmod 755 server.py
./server.py

You can now connect to http://localhost:8888 to see your server running.

The only modification I made the same server was to make it so you can set the port when you run the script from the command line.

./server 8887

Will run the server on port 8887 for example. Now this is just a pure minimal get you started tutorial. This is about as far as I can go because I put that together and wrote this while my daughter was watching Dora, and it’s just about over.

Technorati Profile