Enterprise Level Access Control with Keys and Entitlements

entitlements200x190

“Private repositories”, “Teams and Organizations”, “Permissions”…, sounds like that’s all you need to provide secure private downloads. Well, not quite. Those are great features that fit the bill if your consumer is a Bintray user. But what if she isn’t? Well, then there are signed URLs. Those should do the trick. Just sign your file and send your consumer the URL. But what if you want to share an entire repository, package or version with a group of people, but need to give each of them different privileges. Some can only view or download your files, but others should be able to delete your files or upload new ones. Signed URLs don’t cover that kind of control. They are great for single files, but for more fine-grained access control, you need a more sophisticated feature. That’s where entitlements and keys come in.

“Entitlements,” you said? What are those?

Entitlements are privileges you can give anyone…yes anyone, not only Bintray users, to entities in your private repositories. “Entities” means anything that can contain files – a whole repository, a path within the repository, a specific package or a specific version. “Privileges” means “rw”  – download, upload and delete, or “r” – download only. If you didn’t notice, the combination of entities and privileges gives you any level of granularity that you need for providing access.

But how do you unlock entitlements?

I guess you get the hint. Keys unlock entitlements. You generate a key along with its password (or Bintray can generate one for you automatically). Your user will have to provide the username and password to enable the key that unlocks the entitlement. That’s where the security lies. Only users who have both the username and the password of the key that you provide to them can access your repository entities according to the entitlements you created.

So how does it all work?

Two simple steps using Bintray’s REST API:

  1. Create keys. You can supply a password for each key you create, or Bintray can generate one for you.

  2. Create entitlements. When you create entitlements, you specify which keys to apply to them.

Now all you need to do is provide your user with the username and password for one of those keys. Your user now applies a REST API to access your private Bintray resource while including the key and password you provided as parameters to the API call. Bintray will check if there is an entitlement that allows access to that resource, and if that entitlement has the key that the user specified associated with it.

Let’s see an example at work

Let’s say user “ACMECorp” has a private repository called “acme”.

This private repo contains several versions of acprod under the “acmecorprod” directory that are protected from public access.

ACMECorp wants to authorize a “platinum customer” to download the different versions. Needless to say, “Ms. Platinum” does not have a Bintray account.

First, ACMECorp needs to create a key. Bintray offers two ways to maintain control over keys that are distributed to outside users. The easy way is to just put an expiry date on the key. A more advanced method is to set up an internal server that is used to validate and authenticate keys, and provide the server URL to Bintray when a key is created. Every time a user tries to access ACMECorp’s repositories, Bintray will validate the key using  the URL that ACMECorp provided when creating it. Since ACMECorp is very careful with its key, let’s assume they want to validate keys with their own systems:

curl -XPOST -uacmecorp:APIKEY “https://api.bintray.com/users/acmecorp/download_keys
{
“id”: “key1″,
“expiry”: 7956915742000
“existence_check”:{
      “url”: “https://callbacks.myci.org/username=:username,password=:password”,
      “cache_for_secs”: 60
      }
}

Bintray creates a key and its associated password

Status: 201 Created
{
"username": "key1@acmecorp",
"password": "8fdf84d2a814783f0fc2ce869b5e7f6ce9f286a0"
}

ACMECorp now creates an entitlement that provides download privileges to the acmecorprod directory, while assigning key1 that was just created

curl -XPOST -uacmecorp:APIKEY "https://api.bintray.com/packages/acmecorp/acme/acprod/entitlements
{
"access": "r",
"download_keys": ["key1"]
}

Bintray responds:

Status: 201 Created
{
"id": "7f8d57b16c1046e38062ea3db91838ff77758eca",
"access": "r",
"download_keys": ["key1"]
}

Basically, that’s it. ACMECorp can now just provide the username “key1@acmecorp” and its password to Ms. Platinum who can now use them to access the acmecorprod directory in ACMECorp’s repository.

For example, to download version 1.0 of acprod, Ms. Platinum would use:

curl -XGET “https://dl.bintray.com/acmecorp/acme/acmecorprod/1.0/acprod.exe” -ukey1@acmecorp -p”8fdf84d2a814783f0fc2ce869b5e7f6ce9f286a0”

But what happens now if ACMECorp and Ms. Platinum have a falling out. When that happens, ACMECorp can just delete the download key from their validation server and “Hey presto”, Ms. Platinum is now locked out of ACMECorp’s repositories.

Try doing that on Docker Hub, RubyGems.org, NuGet Gallery, Maven Central or any other repository or download center out there. Bintray is the only one that provides you with this level of control over access to your private resources.