In reverse chronological order Thoughts and Writings

About me About me

Hello!

Thanks for visiting my website. I run a technology-focused consultancy that helps companies use open-source software to solve problems and participate in the ecosystem (see my profile on LinkedIn for more information).

I have been a core developer of the Zope/Plone project, contributed to numerous open-source projects over the years including Apache Airflow and Apache NiFi and PostgreSQL. I wrote a popular HTML/XML template engine for Python and a PostgreSQL driver written in TypeScript, among other projects.

Airplane
Photo by Jeremy Bishop on Unsplash

Tue, 12 September 202314:49:00 GMT

Switching to managed encryption keys

In most systems I come across, private keys are all over the place, made available as secrets to the workloads that need them. The trouble is not just that sometimes, secrets are not really secret, but more fundamentally, that private keys are something that we don't need to handle directly at all, they're basically too hot to handle 🔥.

Instead, we can use a remote service to manage our private keys such as Azure Key Vault, obviating the need to handle them ourselves. In this way, private keys become infrastruture.

Ideally, the keys managed by the service are in fact generated there, too, such that at no point in time is the key ever available to you. We can ask the service to sign or decrypt some data, but the actual key is never revealed.

But before we talk about how we can switch to such managed keys, let's look at a few example use-cases:

  • Authentication

    Lots of systems are integrated using public/private key pairs. For example, when we commit to GitHub, many developers use SSH to connect, using key pair-based authentication; or when we connect to a database, the authentication protocol might use key pair-based authentication instead of a password, for an extra layer of transport security.

  • Session signing

    Most web applications require the signing of session cookies, a token that proves to the web application that you're logged in, or simply that you have an "open session". Typically, this is configured using a locally available signing key, but again, we can improve security by using a managed key (and it's possible to be clever here and amortize the cost of using the managed key over a period of time or number of sessions created).

The operation we need in both of these cases is the ability to sign a payload. Managed keys are perfect for this!

Case Study: Using managed keys to authenticate to Snowflake

The Snowflake client library for Python has an authentication system that supports multiple methods. Working on a data platform solution for Grundfos, a Danish company and also the world's largest pump manufacturer, I contributed a change to extend this authentication system to accomodate managed keys (the existing system supported only concrete private keys such as a file on disk).

For Python, the cryptography package has become the defacto standard for encryption. The RSAPrivateKey interface represents an abstract private key that uses traditional RSA asymmetric encryption.

With the change linked above, it's now possible to implement a custom private key object which defers operations to a managed key service since the Snowflake library now takes bytes | RSAPrivateKey as input.

I'm collaborating with Microsoft to provide this functionality out of the box with the azure-keyvault-keys package, a feature that's likely to go into the next release. In code, this would look like the following:

from azure.keyvault.keys import KeyClient
from azure.keyvault.keys.crypto import ManagedRsaKey
from snowflake.connector import connect

key_client = KeyClient(
    "https://<keyvault-name>.vault.azure.net/",
    credential=AZURE_CREDENTIAL
)

ctx = connect(
    # Here goes the usual connection parameters
    ...
    private_key=ManagedRsaKey(KEY_NAME, key_client)
)

The prerequisite to have this work is to use ALTER USER ... SET RSA_PUBLIC_KEY = '<key-data>'. You can download the public key in PEM-format (suitable as key data here) using the portal or Azure CLI:

$ az keyvault key download     \
    --vault-name <keyvault-name> \
    -n <key-name>                \
    --encoding PEM               \
    -f /dev/stdout

Private keys disguised as secrets

In many systems, private keys are often being referred to as secrets. For example, in Airflow, there's a secret_key which "cryptographic components can use this to sign cookies and other things".

In order to switch to managed encryption keys, we must recognize these situations and create the necessary interfaces.

Reducing cost

Using managed keys is not free. There is a cost for each operation, but for Azure Key Vault for example, using standard RSA 2048-bit keys, these operations are as cheap as reading a secret. As mentioned previously, in some cases, we can be clever and use a surrogate signing key for a period of time. This also reduces the operational dependence on the remote service.

These costs (and infrastructure complexity) should be easily offset by the much lessened burden of compliance with security protocol. If you never saw a private key, there is no risk having compromised it. Access to using a managed key can be granted on a higher level and revoked just as easily.

Archive: