Monday, August 16, 2021

Explorations of a wannabe security programmer

 Right now I am in that state where I am trying to make sense of different security building blocks, and feeling for the true use cases they help solve. This has been an interesting journey because it builds understanding of problems as well as perspective. The uber-perspective is that security is never really a fully-solved problem. Getting the basic interactions and workflows right is merely the beginning. There are many scenarios and edge cases to take care of when dealing with real production deployments, and there are a ton of concerns around hardening the security of such a deployment. It's a game of probabilities, and therefore of prioritization.

HashiCorp Vault

HashiCorp Vault has been at the top of my list of technologies to understand for a while now. That's not only because it seems like a particularly good component to build a cloud-agnostic architecture around, which it is. It's also because of how well it helps address security concerns that often do not figure in the architect's priority list till the security team comes back and either vetoes the release or does some hard-talking to extract commitment for a vulnerability fix patch.

What I figured while trying to learn Vault is that it isn't straightforward, and while there is plenty of documentation, what is lacking is a good cohesive introduction that shows the big picture well. I thought I'd jot down, still rather tersely, my understanding of what Vault essentially is and does.

HashiCorp Vault is a service that you run in your deployment, and which stores and protects your secrets from unauthorized access, credential theft, and proliferation of secrets.

  1. It stores secrets securely, ensuring secrets are always encrypted, whether at rest or in transit.
  2. It allows only authorized access to these secrets.
  3. Easy access management through policies
  4. Integrates with a wide number of applications, databases, continuous integration systems, container orchestrators, etc.
  5. Recommends ways to secure deployments from the outset.
The last point, which HashiCorp calls the Secure Introduction problem is significant. Essentially, it tries to answer the following question.

When a new component (a service, container, VM, etc.) is introduced into a system, how do existing components authenticate it? In essence, it is the problem of establishing trust where none exists to begin with, and needless to say, it relies on some best practices rather than any innovative technique to get the job done.

How does Vault work

Vault works through a set of abstractions for creation, retrieval and management of secrets. Here are the key abstractions.
  1. Storage engine: The storage backend used to store the secrets securely. This could be local disk, a cloud-based key management system such as Azure Vault or AWS KMS, HashiCorp Consul, etcd, etc. This is part of the server start-up configuration.
  2. Secrets engine: The secrets engine defines the type of secret that is protected, as well as the kind of metadata associated with a secret, and the operations that can be performed on it. For example, these could be static key-value pairs, database credentials, etc. Secrets and their associated metadata can be stored and retrieved using a path-based naming scheme of the form: <engine>/<path>/<secret-id>.
  3. Sealing and unsealing: When a Vault server bootstraps, it does so in a sealed mode (except when you run it in dev mode which is obviously only for development). Sealed mode means that the Vault server has no way to retrieve and decrypt keys stored in its storage backend. It must be unsealed to begin operations. Vault uses a master key to unseal itself and generates this key during initial configuration. But it goes a step ahead and shards that key into N participant keys, any M (<=N) of which are required to unseal it. The idea is that these N keys would be with N different individual admins, M of whom must enter the key at the time of unsealing. Also, the Vault can be sealed back by using just any one of these N keys. The algorithm to shard the master key into M keys is called Shamir's Secret Sharing algorithm.
  4. Authentication backends: Vault integrates with several authentication backends, including a plan user/pass backend, LDAP and ActiveDirectory, and many others. This is used for authenticating clients of Vault that want to access secrets protected by Vault.
  5. Tokens: Tokens are strings that are used to access the actual credentials (such as usernames and passwords). They have limited validity (TTL) and limited renewability. Each token may have any number of policies associated with them which determine what can be accessed using the token. Depending on the secrets engine, the actual credentials are generated only when a user requests them using a token, and are revoked when the token expires.
    1. Root tokens:
    2. Token hierarchies:
    3. Cubbyhole tokens: Cubbyhole tokens are special key-value pairs in which there is a wrapping token and a wrapped token. The wrapping token can only be used twice: first to store the wrapped token, and then to retrieve it. On retrieval, the wrapping token expires and the wrapped token is retrieved. This is useful for generating one time use passwords that need to be securely retrieved.
  6. Policies: A policy consists of a secret path and associated privileges (such as read, write, create, update, get, list, etc.). A token can be used to access secrets from all paths that associated policies grant access to.
This is blog post is a work in progress. Expect more details to be added.


Read more!