"You have a basic access, and then you can restrict and build on restrictions. And then that allows for fine grained authorization, with a lot of flexibility."
We all know about cookies. And while they have their uses, cookies cant be shared. That can create obstacles, for example when working with a team on a project. It's rare that each person on a team needs the exact same access as every other member. What usually happens is that tasks are split up, and different people need different privileges to allow them to carry out their individual tasks.
Macaroons are, as the name suggests like web cookies, but embed caveats; the embedded caveats attenuate and contextually confine the way services should authorize requests. For example, you can decide when or where a target should authorize requests. And you can also decide who can authorize request, and for what purpose. And I should also mention, one key thing is that the caveats are indelible and cant be overturned.
The idea here is that you can embed these access restrictions all from the client side - and the satellite knows how to interpret those restrictions. You effectively are able to delegate access management entirely to a client, but again, because you’re using macaroons, you can restrict the starting point.
It might help to use an example.
Use cases always make things more interesting. My friend and colleague Paul Cannon wrote a really great blog with a family photo album as the use case. I highly recommend reading it, and I'll borrow his example as some convenient scaffolding. (Psst -- read the Google whitepaper for some fun as well)
Let's say we want to decide things like Person A can see it whenever they want, and Person B can access a file but only on a certain date. And Person C can't see it at all unless they meet certain other conditions.
In this example, we’d start with a root API key with an all access pass to all the data in your buckets; and we get that from the satellite. Then all from the client side (using our Uplink client) we can create child API Keys
- Person A gets a child API key with a path restriction in the caveat;
- Person B gets a child API key with a path restriction and a date restriction in the caveat; it’s actually a child API key of the person A API Key
- Person C gets a child API key with a different set of restrictions altogether
One key thing about the hierarchy of restrictions is when you get an API key, you can further restrict access by adding more caveats, but you can't add caveats that expand access. New macaroons can be derived from existing macaroons without involving the service they target. What that means in practice is macaroons can become increasingly restrictive if you want.
With Tardigrade, you may want to do something similar to sticking files on Dropbox, but in a more secure way. The question then becomes "how do I share this?" You can create a share-link if you know the person, but you may also want to do something more robust, or handle cases where you actually don't even know who your end user is -- for example, customers you have not acquired yet. Or viewers of your great Oscar-nominated film!
Let's imagine a family album scenario. Say you have a wedding picture and want to share it with aunts and uncles. When you create a new project on the Storj network the satellite gives you a token, which governs access to the project. you can imagine yourself bearing a certificate - the token bearer can access anything in the project.
Think of this like a general access thing. And if you were to make a copy of that certificate and share it, then you would be handing over the exact same access to the next person . They would see what you see.
Unfortunately we all have selfies that go wrong sometime. You're squinting at the sun, you've got spinach on your teeth, a pterodactyl is photobombing you from behind.
So here you are with a photo you want to conceal. You may be wondering, Do I have to create a new token? Well, you wouldn't need to make an API call for a new token. What you could instead do, is make a copy of the existing token that you're happy with but enact a few changes. You'd copy the existing token, cut off the signature, and add on a proviso.
Let's make it a little more interesting and also say that in addition to disallowing access to a file, you also don't want people outside of your immediate family to delete or change anything they see.
Let's talk provisos. (At this point we're not talking about the original caveat, but a new and bigger one.) You can take the new caveat and hand it out. People who want to see the family photos will have the digital signature verified by the Satellite, and thereby verify the added proviso is satisfied.
Is there a way that someone could bypass the proviso? Can they just cut out the original caveat that granted wider access and use that to look around? No, because the original signature is gone. And since they don't know what the original signature did look like, they also couldn't create a new caveat to mimic the original one.The original signature that would make it useful to you has been removed beforehand.
The satellite is the part of our platform that knows where all the pieces of your file are. It cant see whats being stored though, since the file is encrypted by you clientside.
The satellite verifies the digital signature, and that the signer knew what the signature on the intermediate certificate looked like, verifies the intermediate signature was also valid. Then it checks that all the provisos there are satisfied before granting access.
The same safeties still apply.
There's no way for a new person (we'll call them Bob) to use either the original root project token or the intermediate family-sharing token on their own. The only thing they can use this certificate for is to fetch the specific file within the allowed time period. And since one of the proviso that was added is "BEARER IS BOB", they cannot pass it on to anybody else. The reason for that is provisos are indelibly added. You can't take one away, you can only apply additional restrictions.
There are different ways to conceptualize this, but what helped me to get my head around it was to imagine a lego set.
With a Lego set, you can have this basic piece and snap on other pieces which make it larger, but also more specialized at the same time. But in this example you're not just snapping pieces together, you're Super Glue-ing them. You can never take away, you can only add.
You definitely wouldn’t want long lived or immortal bearer tokens floating around without a way to revoke specific permissions.
So let's revisit the pterodactyl scenario. What if a friend of yours shared an unflattering photo with someone they thought they could trust, and that third person started sharing that token around? It’s a bearer token and it’s generated client side...that’s a concern with a delegated authorization model. With an Access Control List you modify the ACL to get the result. We have a simple way with one command that you can revoke the API Key at the Satellite.
Access management on the Tardigrade Platform requires coordination of those two parallel constructs —encryption and authorization.
While both of these constructs are managed client-side, it’s important to point out that only the API keys are sent to the Satellite. The Satellite interprets the restrictions set by the client in the form of caveats, then controls what operations are allowed based on those restrictions. Encryption keys are never sent to the Satellite.
Sharing access to objects stored on the Tardigrade Platform requires sending encryption and authorization information about that object from one client to another.
The information is sent in a construct called an Access. An Access is a security envelope that contains a restricted HD API key and an HD encryption key—everything an application needs to locate an object on the network, access that object, and decrypt it.
We have a simple share command that encapsulates both an encryption key and a macaroon into something called an Access in the format of an encoded string that can be easily imported into an Uplink client.
Essentially, you specify a path or object. The share command creates:
- an HD encryption key to just that path or object
- and an API key with a Caveat restricting access to just that path or object
Then encodes it in a string that can be passed between two uplink clients. In our photo album example, the photo sharing app would create an Access specifically for a photo or folder of photos and pass that to another family member via the photo album app.
When that family member accesses a photo, what happens is the uplink client in the app sends just the macaroon to the satellite to request the photo, but it keeps the encryption key and decryption happens client-side. Even sharing access, the network (satellite and storage nodes) never has access to the encryption key.