If you're anything like me, you think everything should be free. Lunch, beer, access to data. Unfortunately our bosses and customers probably wouldn't agree with that last one.
In this article I'm going to explain the concepts of permissions in Azure Cosmos DB. Giving you enough information so you can protect access to your data - all the way down to specifying which individual users can read which individual documents - freeing you up to enjoy all the free beer at our free lunches as you want!
Types of Users
When dealing with permissions in Azure Cosmos DB, you first have to understand the two (with sub-types!) different types of users that are present: Admin and Application. While the distinction may sound trivial, there are some subtleties involved.
The most straightforward of the user types is the account user type. This user type applies to the entire Azure Cosmos DB account - across all databases (and everything a database can contain) defined within it.
Despite the name Account these users do not necessarily have full-on superuser rights. They can be limited to various capabilities, down to read-only. Of course, the ability to manage everything is possible too!
Note however the level of permission this user type is granted is pretty coarse grained. It's not for a particular collection within a database, not even for a particular database - it's for everything in the account.
How account users get defined is where things get interesting however. These users correspond to users, groups, or applications within your Azure Active Directory. They're real live things that you know about ahead of time when setting up the Azure Cosmos DB account. And you create them through the Access Control (IAM) blade of your Azure Cosmos DB account.
The Other Type of Account User
We're going to have to earn our free beer and lunch, so of course there is another type of account user. It's very similar to the account users described above, except it only has 2 roles - owner (or master) and read-only.
And here's the kicker - this type of account user does not correspond to an Active Directory object. Rather whatever or whomever is connecting to the Azure Cosmos DB database is doing so with a connection string.
The connection strings are defined within the Connection String blade of the portal.
It's great for things that need control of the entire database, but aren't within your Active Directory ... something like Azure Storage Explorer.
Account Users - What Are The Good For?
Just kidding ... generally an account level user will be used to perform admin type functions on the Azure Cosmos DB. So whether you're logging in interactively through the portal with Azure AD, or with an application that has the master key - you'll generally be creating databases or users with this type of user.
Creating users? What type of users would you create? Glad you asked...
This brings us to database users - or probably why you read 15 paragraphs of this article.
To understand database users, it helps to understand how Cosmos DB structures the resources within a database.
The first level of Cosmos DB hierarchy is the account. This is what gets created when you do a Create a Resource -> Azure Cosmos DB in the portal. Everything that contains the actual data and objects related to the data is a part of this. (Which of course, is where the users in the above section come into play.)
You can have one or more databases in your Azure Cosmos DB account. For the rest of the article - the database resource is going to be our starting point.
So then next up in the hierarchy are collections. It's a bit outside the scope of this article to explain collections - but think of collections as a way to organize and hold your data... which are in documents.
Collections also hold stored procedures, triggers, and user defined functions. And documents can also have what are known as attachments that hang off of them.
Cool - so that's the hierarchy of objects... almost. There are 2 more. Users and user permissions.
These are database users because they are defined at the... well... database level (as opposed to the account users who have account level access).
Then each user has a set of permissions attached to it. These permissions are either read or write but they can be applied to any resource within the database. So a user could have a permission to read only a single document ... OR ... the user could have permission to read the entire collection.
It's important to note is that they are associated with the individual user.
The database user cannot do anything useful without having some sort of permission assigned to it.
The database user is a construct of the database - and does not correspond to an Azure AD object (unless you decide to manually keep track of the relationship in a meta-document within a collection).
So the upshot of all of this is that when you create database users, you need to assign permissions to that new database user in order for it to be useful.
Think of a database user as an abstraction for a set of permissions for resources in a database.
Gimme the Data!!
We have users - we have permissions ... let's read some data!!
Oh yeah... there's one more thing about database users. When you create one, you don't specify a username and password - and then use that later on to sign-in with.
If it was only that easy...
What happens is that when a user gets a permission assigned to it, that permission will be assigned a resource token (which isn't permanent, but is generated on demand). That resource token is then used to sign-in with.
The only way to generate that resource token for an individual database user's permission is to have another user - one with master rights to the database - do the generation.
You know where this is going ... there's going to be a middleware application involved somewhere that serves as a resource token broker.
The general work flow looks like this:
- Client application needs a particular database user's permissions to do something.
- Client application asks a resource token broker (it's gonna be a web service) to pass back a resource token (that corresponds to the necessary permissions needed) that the Azure Cosmos DB will recognize.
- The client application will also pass along some other identifying aspect of itself so the resource token broker knows it's not just sending the keys to the Azure Cosmos DB database to any random Joe.
- The resource token broker verifies the client application, then using it's master user powers, generates tokens for the correct permission(s) being asked for and returns them.
- The client app uses those token to then make direct requests to the Azure Cosmos DB database - and the database knows via the token passed in - what operations can be completed.
Check out the server-side samples on this page for a working demo.
Despite all the steps and the moving parts, this is a well established pattern and it works.
It keeps the master key out of any client applications that the general public uses.
Summing It Up
We covered a lot of ground in the article - and it was all conceptual - so you definitely owe yourself some lunch and your beverage of choice!
We looked at how Azure Cosmos DB has two different types of users. One that applies at the account level - and this type of user is usually responsible admin type work like creating databases and users.
The account level users can be done either manually through the portal with Azure AD, or with an application using a connection string.
Then there are database users. These users apply to only a single database and they represent an abstraction of permissions.
The permissions assigned to a database user can vary from being able to create collections, to only being able to read a single document.
Database users do not sign-in to a database with a traditional username/password. Rather we need to user a resource broker web service, which uses a user with admin rights, to requests permissions for individual operations.
That's it - you know have a total conceptual handle on Azure Cosmos DB permissions! Go grab that lunch!