Super Unicorn Inkmi Logo

Securing Credentials in Golang With Systemd

From a solo entrepreneur

Inkmi is Dream Jobs for CTOs and written as a decoupled monolith in Go, HTMX, Alpinejs, NATS.io and Postgres. I document my adventures and challenges in writing the application here on this blog, tune in again.

When running a Go binary sooner or later, you ask yourself where to get credentials for database access, external services like sending emails and encryption. First, you can’t put them into source control, or they will end up on GitHub. Any supply chain attack that can access your code during a build pipeline can access your secrets.

You can put the secrets in your binary, but anyone with access to the binary can find the secrets. If you use the same binary in testing and development, there is a chance that the binary contains production secrets, if you haven’t properly used build tags.

The Twelve Factor App has secrets stored in ENV variables This is a secure way, but if your environment doesn’t already support this (injecting from a cloud manager), handling those ENV variables can be a pain.

The enterprise way is to use a secret manager like OpenBao. This solution has a lot of appeals, it supports key rotation, more security features and additional niceties. It can rotate the passwords for your database and give your application the new ones. It is a fantastic piece of code. But for a solo entrepreneur, it is another application to run—with failover this might be too much work.

One solution that strikes a good balance between complexity and security is using systemd to manage those credentials. If you already use systemd for deployments then this is the easiest way. Systemd does a lot of things and also can inject credentials into your running applications.

The way systemd does this is by creating a virtual directory with a file for your application to read, that contains those credentials.

It gives your application an environment variable $CREDENTIALS_DIRECTORY that contains a directory to read from. The virtual file can come from different sources. Configuring it to be read from a file:

[Service]
LoadCredential=foobar:/etc/myfoobarcredential.yaml

This injects the file /etc/myfoobarcredential.yaml as a file $CREDENTIALS_DIRECTORY/foobar into your application to read.

db_user: foo
db_password: bar

The file with the credentials needs the correct permissions, so only systemd can read the file, not any user! (systemd can encrypt the file and credentials).

credentialsDir := os.Getenv("CREDENTIALS_DIRECTORY")
if credentialsDir == "" {
  log.Error().Msg("CREDENTIALS_DIRECTORY environment variable is not set")
  return nil
}

With Viper for your configuration manager, the file then can be read with

viper.SetConfigName("foobar")  // name of config file
viper.SetConfigType("yaml")    // specify the config file format
viper.AddConfigPath(credentialsDir) // path to look for the config file

Now the credentials can be accessed in your application just like any other config.

For additional security, consider a library like Memguard to secure credentials in memory (against core dumps, for example).

The benefits of using systemd over reading the file directly:

  • systemd ability to load credentials from somewhere else, not a real file. Credentials can be injected from outside your VM, from the BIOS, or if your environment (e.g., AWS) does support TPM2, from a secured source.
  • You can change the source of the credentials in the future without changes to your code
  • systemd can read an encrypted file and get the key from a secure location - no key management needed in your application
  • systemd can secure your application to disallow reading any other files, so an exploit in your app is unable to access the file system while you can still read the credentials.

About Inkmi

Inkmi is a website with Dream Jobs for CTOs. We're on a mission to transform the industry to create more dream jobs for CTOs. If you're a seasoned CTO looking for a new job, or a senior developer ready for your first CTO calling, head over to https://www.inkmi.com

Other Articles

©️2024 Inkmi - Dream ❤️ Jobs for CTOs | Impressum