The "First Secret" Problem

Trust is an important property. Actually, it is the single most important property of them all. With trust we can bootstrap security, as security cannot be fabricated out of thin air. However, trust has an inherited problem, it requires you to assume that something is true, verified, confidential, integral or, simply, secure. This is why, as a rule of thumb, a system, to be secure, should be built so that it doesn’t make many trust assumptions.

A very good example of such trust issue is the so-called “first secret problem”. There is not a formal definition of the “first secret problem” but we could refer to it as the problem of bootstrapping a system which requires some confidential information (e.g., a password or an authentication token) in order to work. Imagine you have a bash script that runs as a cron job and queries an API using an authentication token. The authentication token is our secret and we need the script to use it. The problems that you might have to face when handling such secret are:

I’ve seen many times the suggestion of having the secret stored in an encrypted file so that the cron job can read it from there. Let’s see what would happen in that case:

This is, in a nutshell, the first secret problem.

How do we solve it? Unfortunately, we cannot solve it with a definite solution that would work in all situations, there’s no “one size fits all” solution (otherwise we would probably be able to fabricate security out of thin air). In the remainder of this post I will describe a scenario and I shall attempt at describing a number of solutions that could be used to solve the “first secret problem”. Note that I will most likely not provide an exhaustive list of solutions but rather a general overview of the most common ones (or at least the ones that popped into my brain).

Scenario

Let’s describe a simple scenario and the attacker we want to protect ourselves from. You have a standalone application running that takes a backup of a folder and stores the backup on a network folder that is already mounted on the system. The backup you want to take is encrypted and therefore the backup application requires a password. In this example, the “first secret problem” is the password used to encrypt the backup. As for the attacker, say you want to protect from a remote attacker that might want to attempt at compromising the machine where the backup script is running, e.i. the attacker does not have physical access to the machine itself.
How shall we handle it?

However, before getting into the juice part, allow me to make a quick remark: please, please, please 🙏, before picking up a solution (any solution) to any security issue, make sure you fully understand the problem you are trying to solve, the attack scenario you want to prevent and you want to achieve. Do not pick the most complicated solution just because it’s considered to be the “safest one”. You might end up implementing an incredible complicated mechanism to solve a problem you probably didn’t even have.

Command parameter

Imagine the case where the password is passed to the application via command line parameter.

Environment Variables

Imagine the case where the password is feed to the application via environment variables.

Local file-system

Imagine the case where the password is stored on the local file-system where the application is running and the application reads the file to obtain the password. The file is stored in plaintext.

What about if we want to encrypt the file that contains the password? As we’ve seen before, we end up in the recursive dilemma of the “first secret problem”, where now we are back at square one and should find a way to provide another password to our application.

Database

Imagine the case where your password is stored within a database and your application has to access the database. This solution is actually not too different from the “local file-system” solution and most of the considerations that we have already explored applies here too, especially if the database is installed on the same machine where the backup application is running.

To make things interesting, let’s consider the case where the database is provided as a service running on a separate machine. For the backup application to access the database, it has to use a network protocol. The network protocol must provide integrity and confidentiality so that an attacker cannot eavesdrop on the network channel, and should also provide authentication, so that only the backup application can access the backup password. We can consider two solutions for allowing only the backup application to access the database:

  1. Taking advantage of the network topology so that the machine running the backup application is the only one allowed to access the machine running the database i.e. the backup machine has a physical wired connected to the database machine and the database machine is not physically connected to anything else. 
This case falls right back into the “local file-system” scenario, the presence of a physical wire that connected the two machines is negligible from a security point of view (remember the assumption on the attacker).
  2. The machine running the database is located somewhere on the network and the backup application has credentials to access the database. This means that the backup application requires a pair username\password to access the database to retrieve the backup password.
This case makes us loop back again in the recursive dilemma of the “first secret problem”: what are we supposed to do with the pair username\password?

Vault

We can think of vaults as an envolved database. A vault is essentially a database that provides helpful functionalities for storing secrets, providing features such as encryption at rest and encryption in transit out of the box along with many others. A vault is also very helpful to developers for lifting the burden of handling secrets. However, the way they integrate into your application is still very close to what we have seen above with databases:

So here we are again, how to we make the application to authenticate to a vault? We still need to bootstrap security between the two entities. You might think that there’s another option, since the concept of Vault is often associated with the Cloud, which in turn is often associated with the concept of Identity and Access Management (or IAM for short).

Does IAM solve the first secret problem?

TL;DR: “I’m afraid not Billy”.

What IAM does is essentially allowing us to specify, given an identity, to which resources or services that identity has access to. The way IAM actually provides access to a resource or service, is still by providing some kind of credentials (typically temporary) so that the identity can access the resource. If we go back to our example, it would work something like this:

iam-workflow

The backup application has an IAM policy stating that it can access the vault.

  1. The backup application requests access for the Vault service to the IAM system;
  2. The IAM system has the list of policies and identities and checks if the identity making the request has a policy that allows it access to the Vault;
  3. If the check is positive, the IAM system provides temporary credentials to backup application;
  4. The backup application can use the temporary credentials to access the vault;
  5. The vault answers with the backup password for encrypting the backups.

Now the question should be obvious, how do we actually perform step 1-2? How does the BackupApp entity identify itself to the IAM system? This is where, once again, we loop back to the first secret problem. When you implement the BackupApp entity to access the IAM system you are using a library or SDK provided by the Cloud provider of your choice. The SDK is working some magic under the hood you don’t see, and is retrieving some other secret that can be used to prove its identity to the IAM system. (The SDK only simplifies access to the credentials which are instantiated, for instance, as environment variables or metadata endpoint and are temporary and rotate frequently.)

What is this? A cat and mouse game?

Indeed it is. As you might have noticed from the brief excursuses of the solutions above, the basic idea behind solving the first secret problem is to put the initial secret far away as possible from the attacker reach, so that we can make the attacker’s life more complicated. As I said at the beginning, there is no one-size-fit-all solution to the “first secret problem” and you have to choose which is the better solution for your case. To choose the better solution you should use our favourite thing in security: a threat model. A brief list of things to consider in this case are:

For example: let’s consider the case above of the backup script that takes a backup of your local NAS and stores it into a network storage in the cloud. In this case you want to encrypt the backup because it’s sent into the cloud and you want to ensure confidentiality, but you might be ok at storing the backup password in plaintext in a cron job because your NAS is running in your local network and does not have a wide attack surface that can be abused by a remote attacker. On the other hand, if you are running a kubernetes cluster at scale, and have many people working on it, you might want to use a Vault to store secrets since it will provide with:

I highly recommend exploring and testing these solutions, try to understand how they work and how they can integrate into your use case.

Stay safe, cheers!