Mounting secrets as files

Docker, Kubernetes and OpenShift allow mounting secrets as files i.e. instead of having a secret as an environment variable you can specify it as a file in a volume somewhere.

Very useful for setting things like certificates needed for signing things where you may have a bunch of certificates that are supplied by clients.

Is there some way to do this in Aptible or a best practice on how to do something that has the same effect? I was hoping for something like aptible config:set --something <path-to-file> <local file name>

Oh!
We’re very interested in something like this, as well.

We use Hashicorp Vault to store most of our secrets. But the initial login to Vault requires some sort of secret, and there isn’t an ideal way to deliver that secret securely, that I can see. Environment variables are not private enough.

I like @michaelpc 's suggestion of providing a file to mount in the container. I can imagine wanting to mount a small tree of files, perhaps we’d provide a .zip archive. Maybe those files would end up in an /.aptible directory at the root of the container, or something.

Secrets can currently only be exposed to containers as environment variables. It is possible to write the contents of an environment variable to a file, we do this in a number of images used on the platform including the PostgreSQL Database Image, which is the primary way to work around this. An ENTRYPOINT for an application like this would look something like:

#!/bin/sh

# if/else optional depending on your needs
if [ -n "${FILE_VAR_1}" ]; then
  echo "${FILE_VAR_1}" > some_file_1.txt
else
  echo "FILE_VAR_1 not defined"
  exit 1
fi

...

if [ -n "${FILE_VAR_N}" ]; then
  echo "${FILE_VAR_N}" > some_file_n.txt
else
  echo "FILE_VAR_N not defined"
  exit 1
fi

exec "$@"

The content of a local file can be loaded into a variable like so:

aptible config:set --app my-app FILE_VAR_1="$(cat file_1.txt)"

The other common way to work around this is to use a service, like @Damon mentioned, such as Hashicorp Vault, AWS Secrets Manager, etc. Then, in the image ENTRYPOINT or as needed, use credentials passed in via the environment to pull secrets.

In situations where you have many secrets, e.g. a certificate per client, storing the data in a service like those mentioned above or integrating management of the secrets into the App and storing them in a Database would probably be more convenient than managing them through the App’s configuration.

For those interested in managing secret files through environment variables, here’s an ENTRYPOINT for that:

#!/bin/sh

set -e

FILE_CONTENT_PREFIX='__FILE__'
FILE_PATH_PREFIX='__FILE_PATH__'

files="$(env | grep -E "^${FILE_PATH_PREFIX}" | sed -E "s/${FILE_PATH_PREFIX}([^=]+)=.*\$/\1/")"

for file in $files; do
  content_var="${FILE_CONTENT_PREFIX}${file}"
  path_var="${FILE_PATH_PREFIX}${file}"
  file_content="$(eval echo "\"\$${content_var}\"")"
  file_path="$(eval echo "\"\$${path_var}\"")"

  # if/else optional depeding on your needs
  if [ -n "$file_content" ]; then
    if [ -n "$file_path" ]; then
      echo "$file_content" > "$file_path"
    else
      echo "$path_var is empty"
      exit 1
    fi
  else
    echo "$content_var is empty"
    exit 1
  fi
done

exec "$@"

The content of the file goes in a variable prefixed with __FILE__ and the path of the file to write the content to is prefixed with __FILE_PATH__. For example:

Environment:

__FILE_PATH__FOO=foo.txt
__FILE__FOO="foo bar baz"
__FILE_PATH__BAR=/bar.txt
__FILE__BAR="1\n2\n3"

In the container:

> cat foo.txt
foo bar baz
> cat /bar.txt
1
2
3

So to create a new file all you have to do is:

aptible config:set --app my-app __FILE_PATH__BAZ=baz.txt __FILE__BAZ='some content'

Thanks all - yes, turning env vars into files is what we’ve gone with for now. Maybe not as elegant as an inbuilt solution but it works.