I have worked on too-many-to-count threat models over the last twenty or so years and invariably I have to explain, “Who is authenticating whom?”
Let me explain the issue with a simple example.
In this scenario, a user communicates through an API App on Azure which in turn communicates with a CosmosDB instance.
When I ask the question, “How do you authenticate the API App?” The response is often, “We use a username and password” and here’s where the confusion lies: the answer (uid and pwd) is the user’s credential.
What I do at this point is hop up to the whiteboard to explain that both communicating parties should authenticate one another.
First, when the user connects to the API App, how does the user know that the API App is the correct API App and not a rogue? The answer is to use server authentication and the correct answer most of the time is to use TLS.
That’s what I meant when I asked, “How do you authenticate the API App?”
Next, how does the API App know the user is a valid user of the system?
That depends on what the server, in this case API Apps, supports.
Different server technologies offer various ways to authenticate incoming connections from users. Examples include client TLS, username and password (with 2FA!) and delegating to a federated identity provider, such as Google, Facebook, Twitter or Microsoft ID.
A common way to authenticate a valid user is through the use of access keys, which are often implemented as a long, random series of bytes that are passed in the client request. Here’s an example from an Azure Storage Account:
Another method to authenticate and authorize a client is to use Shared Access Signatures. Here’s an example from the same Storage Account:
…and a resulting SAS token:
This page and this page explain the client authentication (not authorization) policies supported by Azure API Apps.
Let’s be super secure and in our solution we’re going to use TLS at both ends: TLS is used to authenticate the server and TLS is used to authenticate the client.
Let me state this another way.
When the user connects to a server, the user’s software (browser) authenticates the server is the correct server. This is SERVER authentication.
On accepting a user’s connection, the server verifies the user is who they are. This is CLIENT authentication.
But it gets a little more complex. When the API App connects to CosmosDB, how does CosmosDB know the connection is from a valid source and how does the API App know it is talking to the correct CosmosDB?
In this scenario, the API App is now the client, and CosmosDB is the server. When building the threat model, you might decide that you don’t need to authenticate the two to each other. That’s fine, so long as is it’s the threat model and the rationale for that decision.
API App authenticating CosmosDB, the server, is easy: use TLS, which is enabled by default anyway in CosmosDB.
When the API App connects to ComsosDB, it can provide and key to do so. This key should be stored in Key Vault and use a Managed Identity for the API App to access Key Vault.
Now I think about this, I might do a Proof of Concept for the entire solution to show how it’s done and build the threat model while I am at it. There’re many more ways to restrict access at the backend, such as only allowing CosmosDB to listen on specific IP addresses or ranges, and in this scenario, we can use the backend IP address of API Apps. This way CosmosDB will ONLY allow traffic from our API App. Let me know what you think!
Anyway, to wrap up. When working with a threat model, or looking at the security of any architecture, you must always consider:
“Who is authenticating whom”
or… how is the client authenticating the server (server authentication) and how is the server authenticating the client (client authentication)?