Why we wrote a Kubernetes operator to generate random strings

Leo Sjöberg • October 6, 2022

Earlier this week, I attended KubeHuddle in Edinburgh. Conferences always provide motivation through all the ideas you develop from conversations with people. In talking to various platform engineers at product companies, we realised that we need to simplify the Kubernetes setup for Laravel at Jobilla.

First, some background. At Jobilla, we (kinda sorta) write microservices. We also use Laravel. Laravel’s really built to be used as a full-stack web framework, not for a microservice that might only have two endpoints. Inherent to its design, Laravel requires you to define a few things. Most environment variables are optional, but one that is required is the APP_KEY. This variable is used as the encryption key by Laravel, both for encrypting cookies as well as any use of the encryption module. This key should be unique to the application and environment, meaning that for every new service, a developer needs to do the following:

  1. Generate a new app key: php artisan key:generate
  2. Enter this into a CI variable APP_KEY
  3. Configure a deployment manifest to inject this variable into the application (with APP_KEY: $APP_KEY)
  4. Repeat the whole thing again for the other environment (they need to create a unique key for both production and staging)

While this isn’t terrible, it is annoying. On the platform end, we want to encourage developers to write smaller, more well-contained microservices. Friction like this makes developers less likely to create a new Laravel app if they’re just adding one or two endpoints, contrary to the point of microservices.

So an idea was born: what if we just generate that key for the developer behind the scenes, and don’t make them do anything.

The only requirement for the APP_KEY is that it is 32 bytes long. So all we need to do is generate a 32-byte string! Then, we can abstract out the concept of an “application” so that developers don’t need to care about this part; they just create a LaravelApplication, and automagically have a securely generated APP_KEY injected 🪄.

For our first version, we settled on the following syntax:

1apiVersion: crypto.jobilla.dev/v1alpha1
2kind: RandomString
3metadata:
4 name: your-service-name
5spec:
6 format: base64prefixed
7 writeToSecretRef:
8 name: your-service-name-app-key
9 key: APP_KEY

This will generate a Kubernetes Secret called your-service-name-app-key and store the 32-byte value under the key APP_KEY. Since this is consistent across all Laravel applications, we can automate this part, so that developers only enter an app name (that part is work in progress), and get the deployment and environment configured.

One thing to note is that we support a format. In our implementation, we first generate cryptographically secure random bytes, and convert them to a string. Because we generate bytes rather than text, the string may not be parseable by the system using the data (since it can contain bytes that do not map to a character). Therefore, we support the 3 formats bytes, base64, and base64prefixed. The bytes format takes the 32 bytes and converts them to a string, base64 will base64-encode that string, and finally base64prefixed will take the base64-encoded value and prefix base64: to it. The prefixed option exists because we need to format the variable with that prefix for Laravel to correctly parse it.

With this tiny operator, we’re hoping we can support developers better and make them do less grunt work, and more interesting and creative work!

So how does this benefit us? Recall the list from the beginning of this post: there were 3 steps to be repeated twice every time a new service is created. Once we have this implemented and rolled out, we expect that to be zero steps of manual work for developers. This means less risk for new services being released in a failing state, and lets everyone focus more on solving problems.

You can check out the repository at https://github.com/jobilla/secure-key-operator.

We also have ideas for future features, such as generating a public-private key pair that can be used for JWT signing.