leanmind logo leanmind text logo

Blog

Refactorización Avanzada

Dominar el refactoring productivo para maximizar el retorno de la inversión.

Trabajar con ficheros de credenciales en Docker

Por Cristian Suárez Vera

¿Has trabajado alguna vez con Google Cloud? ¿Has intentado desplegar tu aplicación desde una pipeline mediante una imagen de Docker? Esta es la situación a la que nos hemos enfrentado mi compañero Mario Pinto y un servidor, Cristian Suárez. Digo enfrentado porque hemos llegado a un punto de conflicto en el que no teníamos claro cómo hacer para inyectar el fichero de configuración de Google Cloud. Un fichero firestore.json el cual no está subido en el repositorio por motivos de seguridad.

Con esto nos vimos ante dos posibles soluciones:

  1. Subirlo a algún servicio dentro de la propia nube de Google y descargarlo en el momento de la construcción de la imagen de docker.
  2. Ponerlo como texto en una variable de entorno en la pipeline y crear el fichero en ejecución cuando creamos la imagen.

Hemos optado por la segunda. Esta opción era más rápida, sencilla y no dependía de un servicio de terceros. Todo apuntaba a que era la opción correcta en este momento. Para poder implementar esto hemos tenido que modificar un poco la imagen de Docker y la pipeline. Te contamos a continuación cómo lo hemos hecho.

Fichero a copiar

El siguiente fichero firestore.json es el que queríamos copiar, te lo dejamos como ejemplo sin los valores reales:

    {
      "type": "service_account",
      "project_id": <project_id>,
      "private_key_id": <private_key_id>,
      "private_key": "-----BEGIN PRIVATE KEY-----<secret>\\n-----END PRIVATE KEY-----\\n",
      "client_email": "email@<project-id>.iam.gserviceaccount.com",
      "client_id": <client_id>,
      "auth_uri": "<https://accounts.google.com/o/oauth2/auth>",
      "token_uri": "<https://oauth2.googleapis.com/token>",
      "auth_provider_x509_cert_url": "<https://www.googleapis.com/oauth2/v1/certs>",
      "client_x509_cert_url": "<https://www.googleapis.com/robot/v1/metadata/x509/><client_email>",
      "universe_domain": "googleapis.com"
    }

Como puedes ver este fichero, es lo suficientemente complejo como para que al añadirlo en una variable de entorno genere más de un problema. Para solucionar esto lo que hacemos es guardar en base64 en la variable de entorno. Para generar este contenido ejecutamos el siguiente comando:

    cat credentials.json | base64

El resultado de este comando lo usaremos como valor de nuestra variable de entorno. En este caso en Github como un secret.

⚠️

OJO, este resultado lo debemos guardar como una única línea de texto. Debemos eliminar todos los saltos de línea que nos haya generado el comando.

Dockerfile

El siguiente paso es poder leer esta variable en el propio fichero de Dockerfile. Hemos optado por hacerlo en el entrypoint de la aplicación, de esta forma el contenido del fichero no está en la imagen creada, se crea en el mismo momento que arrancamos el contenedor.

Para hacer esta lectura y transformación desde el base64 añadimos esta línea echo $CREDENTIALS_JSON| base64 -d > credendials.json . Lo que deja el fichero de la siguiente forma:

    # INSTRUCTIONS
    
    ENV FIRESTORE_CREDENTIALS=""
    
    ## MORE INSTRUCTIONS
    
    ENTRYPOINT ["/bin/sh", "-c", "echo $CREDENTIALS_JSON| base64 -d > credentials.json && <another instruction>"]

Pipeline

Esto no es todo, nos queda el último paso: leer la variable desde la pipeline. Para ello basta con añadir un parámetro en el comando de run de docker para inyectar esta variable mediante la opción --set-env-vars, dejando la pipeline similar a lo siguiente:

    name: Deploy to Google Cloud Run
    
    on:
      push:
        branches: [ "main" ]
    
    jobs:
      build-test-deploy:
        runs-on: ubuntu-latest
        steps:
          - name: Checkout code
            uses: actions/checkout@v4
            
          ## other irrelevant steps
            
          - name: Deploy to Google Cloud Run
            run: |
              gcloud run deploy ${{ secrets.GCP_SERVICE_NAME }} \
                #Another credentials \
                --set-env-vars FIRESTORE_CREDENTIALS=${{ secrets.FIRESTORE_CREDENTIALS }}              

Conclusiones

Con esta solución podemos evitar la necesidad de dependencias externas como pueden ser algún tipo de almacenamiento como S3 o algún vault. Una solución segura y relativamente sencilla para implementar.

Tener un fichero incluido en el proyecto con todas las credenciales, tal como sugiere Google, no es solo una mala práctica, es que encima requiere de un nuevo desarrollo cuando un cambio de configuración es requerido (un nuevo commit y despliegue), esto rompe con muchas de las reglas de 12factor app.

¿Lo habías hecho así antes? ¿Crees que sería mejor hacerlo de otra forma?

Publicado el 25/06/2025 por
Cristian image

Cristian Suárez Vera

https://criskrus.com

¿Quieres más? te invitamos a suscribirte a nuestro boletín para avisarte cada vez que recopilemos contenido de calidad que compartir.

Si disfrutas leyendo nuestro blog, ¿imaginas lo divertido que sería trabajar con nosotros? ¿te gustaría?

Impulsamos el crecimiento profesional de tu equipo de developers