AI, Machine Learning, DevOps

Using Google Cloud Secret Manager in Alpine Linux Docker containers

Today I will make a quick recap of the recent issue we came across when working with Google Cloud Secret Manager in Alpine Linux.

As mentioned earlier, we’re making our project in GCP and all credentials to our databases and other sensitive data must be well secured.

In Google Cloud, Secret Manager service helps to achieve this by keeping the secrets encrypted and protected by IAM. Briefly, IAM works on the principle of Least Privilege thus giving access levels on each secret. It also has a useful feature IAM Conditions (for example, when the access is decided based on the prefix in Secret Key names)

So, imagine, you need to retrieve some credentials from Google Cloud Secret Manager in your Python Flask app. The app receives a the Secret Key name as environment variable and then fetches the credentials to the database using the value of that Secret Key.

In many cases, if your application isn’t complex, you would want to use Alpine as it reduces the container size significantly. So your base image in your Dockerfile will be like this:

FROM python:3.7-alpine

(Note: as Alpine doesn’t use the standard tooling for building Python extensions, when installing packages, in some cases pip can’t find a precompiled installable package for Alpine. Then you have to install some extra libraries and dependencies. In these situations, sometimes, the Alpine container size might turn up eventually to be even larger. However, it’s worth trying when your project isn’t too complex)

There are multiple ways to access the values from Secret Manager. However, this method of using the client library is considered to the safest, easiest and supported by all GCP services. The secrets are kept only in operative memory and the access is given to a particular container.

It’s just very few lines in your python code:

import requestsfrom import secretmanager  
client = secretmanager.SecretManagerServiceClient()r = requests.get("", headers={'Metadata-Flavor':'Google'})  
project\_id = r.textname = F'projects/{project\_id}/secrets/{secret\_name}/versions/latest'r = client.access\_secret\_version(request={"name": name})

To make import of secretemanager you need to install google-cloud-secret-manager via pip. However it will be causing an error in Alpine. First, you will be seeing Running install for grpcio: still running... for a very long time (be ready for 20–30 mins) followed by the error message indicating that it’s unable to compile.

To be able to install that library, first, you will need install the following libraries

pip install grpcio grpcio-tools

However, these libraries will require some linux dependent libraries. After some time of debugging, the following working set of libraries were concluded:

RUN apk add — no-cache — virtual .build-deps gcc libc-dev \\  
   linux-headers build-base libc6-compat \\  
   && pip install — no-cache-dir -r /tmp/requirements.txt \\  
   && pip install grpcio grpcio-tools google-cloud-secret-manager \\  
   && apk del .build-deps gcc libc-dev build-base linux-headersfrom import secretmanager

Be prepared to wait around 20–30 minutes for the installation of grpcio and grpcio-tools in Alpine.

Though, this is not completely enough. After this installation, you will be able to install google-cloud-secret-manager, however, the import from import secretmanager will cause the following error:

from grpc.\_cython import cygrpc  
ImportError: Error loading shared library

Last missing part in the Dockerfile would be

RUN apk add — no-cache libstdc++

After this, everything should work smoothly and you will be able to access your Secret Key.

Here’s the full version of the Dockerfile

As building such Docker containers with GCP libraries preinstalled takes very long, I’ve found it as a good idea to have them preinstalled in a container that would be used as a base one for our Flask projects I was mentioning in the previous post.

Feel free to use them too.

Here’s the link to the Docker Hub

Docker containers for Flask served through Nginx with GCP libraries preinstalled

I hope, someone will find this useful and this post will help to save some time.

Thanks a lot for reading and feel free to share your thoughts, suggestions or ideas please.