Muchos proyectos de software usan secretos, por lo general, claves para API externas o credenciales para acceder a un recurso externo, como una base de datos. Su aplicación necesita estas claves en tiempo de ejecución, por lo que debe poder proporcionarlas cuando implemente su aplicación o como un paso en la preparación de su entorno de implementación.
En este artículo, le mostraré cómo usar git-crypt para que pueda mantener de manera segura los secretos de su aplicación en sus repositorios de código fuente, incluso si son públicos.
La mayoría de los proyectos tienen algún tipo de claves o credenciales secretas. Por ejemplo, si su aplicación está alojada en Heroku , puede proporcionar una clave API para su aplicación Heroku mediante un comando como este:
$ heroku config: set API_KEY =my-sooper-sekrit-api-key
Al ejecutar este comando antes de (re)implementar su aplicación, le asigna una variable de entorno en tiempo de ejecución llamada API_KEY con el valor my-sooper-sekrit-api-key. Sin embargo, hacer un seguimiento de estos valores secretos fuera de Heroku (o donde sea que implemente su aplicación) sigue siendo un desafío.
Siempre trato de configurar mis proyectos para que pueda ejecutar un solo comando para implementarlos desde cero sin ningún paso manual separado. Para nuestro ejemplo, esto significa que necesito almacenar el valor my-sooper-sekrit-api-key en algún lugar para que mi código de implementación pueda usarlo (en este caso, para ejecutar heroku config:set... el comando anterior).
El código fuente de mi proyecto siempre se almacena en git y, por lo general, se aloja en github.com o bitbucket.com o en algún otro servicio de alojamiento de código fuente. Podría almacenar mi valor API_KEY en mi repositorio de código fuente, sin embargo, esto tiene algunas desventajas:
Podría almacenar mis secretos en algún lugar separado del código fuente de mi aplicación, pero esto tiene sus propios problemas:
Git-crypt tiene como objetivo resolver este problema cifrando sus secretos cada vez que los envía a su repositorio de git y descifrándolos cada vez que los extrae. Esto sucede de manera transparente, desde su punto de vista. Por lo tanto, los secretos están en texto sin cifrar en lo que respecta a usted y su código de implementación, pero nadie más puede leerlos, incluso si su código fuente está en un repositorio público de Github.
Veamos un ejemplo.
1. Instale git-crypt.
Hay instrucciones para Linux, Mac y Windows en la página de instalación de git-crypt
Si, como yo, está usando una Mac con Homebrew instalado, puede ejecutar:
$ brew install git-crypt
2. Cree un nuevo repositorio de git.
$ mkdir myproject $ cd myproject $ git init $ echo "This is some text" > file.txt $ git add file.txt $ git commit -m "Initial commit"
Ahora tenemos un repositorio git que contiene un solo archivo de texto.
$ git-crypt init
Deberías ver la salida:
Generating key...
Antes de hacer cualquier otra cosa, ejecute el siguiente comando:
$ git-crypt export -key ../git-crypt-key
Este comando crea una copia de la clave simétrica de git-crypt que se generó para este repositorio. Lo estamos colocando en el directorio sobre este repositorio para que podamos reutilizar la misma clave en varios repositorios de git.
De forma predeterminada, git-crypt almacena la clave generada en el archivo .git/git-crypt/keys/default para que pueda lograr el mismo resultado ejecutando cp .git/git-crypt/keys/default ../git-crypt- llave
Este archivo git-crypt-key es importante. Es la clave que puede desbloquear todos los archivos cifrados en nuestro repositorio. Más adelante veremos cómo utilizar esta clave.
Imagine que nuestra aplicación necesita una clave API y queremos almacenarla en un archivo llamado api.key.
Antes de agregar ese archivo a nuestro repositorio, le diremos a git-crypt que queremos que el archivo api.key se cifre cada vez que lo confirmemos.
Hacemos eso usando el archivo .gitattributes. Este es un archivo que podemos usar para agregar metadatos adicionales a nuestro repositorio de git. No es específico de git-crypt, por lo que es posible que ya tenga un archivo .gitattributes en su repositorio. Si es así, solo agregue las líneas relevantes, no reemplace todo el archivo.
En nuestro caso, no tenemos un archivo .gitattributes, por lo que debemos crear uno. El archivo .gitattributes contiene líneas de la forma:
[file pattern] attr1 =value1 attr2 =value2
Para git-crypt, el patrón de archivo debe coincidir con todos los archivos que queremos que git-crypt cifre, y los atributos son siempre los mismos: filter y diff, los cuales establecemos en git-crypt.
Entonces, nuestro archivo .gitattributes debería contener esto:
api.key filter =git-crypt diff =git-crypt
Cree ese archivo, agréguelo y confírmelo a su repositorio de git:
$ echo "api.key filter=git-crypt diff=git-crypt" > .gitattributes $ git add .gitattributes $ git commit -m "Tell git-crypt to encrypt api.key"
Usé el nombre de archivo literal api.key en mi archivo .gitattributes, pero puede ser cualquier patrón de archivo que incluya los archivos que desea cifrar, por lo que podría haber usado *.key, por ejemplo. Alternativamente, puede simplemente agregar una línea para cada archivo que desee cifrar.
Puede ser fácil cometer un error en su archivo .gitattributes si está tratando de proteger varios archivos con una sola entrada de patrón. Por lo tanto, recomiendo encarecidamente leer esta sección del archivo README de git-crypt , que destaca algunos de los problemas comunes.
Ahora que le hemos dicho a git-crypt que queremos cifrar el archivo api.key, agreguemos eso a nuestro repositorio.
Siempre es una buena idea probar su configuración agregando primero un valor ficticio y confirmando que está encriptado con éxito, antes de confirmar su secreto real.
$ echo "dummy value" > api.key
Todavía no hemos agregado api.key a git, pero podemos verificar qué hará git-crypt ejecutando:
$ git-crypt status
Debería ver el siguiente resultado:
encrypted : api.key not encrypted : .gitattributes not encrypted : file.txt
Entonces, aunque el archivo api.key aún no se ha enviado a nuestro repositorio de git, esto le indica que git-crypt lo cifrará por usted.
Agreguemos y confirmemos el archivo:
$ git add api.key $ git commit -m "Added the API key file"
Le hemos dicho a git-crypt que encripte y hemos agregado api.key a nuestro repositorio. Sin embargo, si nos fijamos, nada parece diferente:
$ cat api. key dummy value
La razón de esto es que git-crypt cifra y descifra de forma transparente los archivos a medida que los empuja y extrae a su repositorio. Por lo tanto, el archivo api.key parece un archivo normal de texto claro.
$ file api .key api .key : ASCII text
Una forma de confirmar que sus archivos realmente se están cifrando es enviar su repositorio a GitHub. Cuando vea el archivo api.key mediante la interfaz web de GitHub, verá que es un archivo binario encriptado en lugar de texto.
Una forma más fácil de ver cómo se vería el repositorio para alguien sin la clave de descifrado es ejecutar:
$ git-crypt lock
Ahora, si miramos nuestro archivo api.key, las cosas son diferentes:
$ file api .key api .key : data $ cat api .key GITCRYPTROܮ 7 y\R*^
Verá una salida de basura diferente a la que obtengo, pero está claro que el archivo está encriptado. Esto es lo que se almacenaría en GitHub.
Para volver a tener un archivo api.key de texto claro, ejecute:
$ git- crypt unlock ../git- crypt -key
El archivo ../git-crypt-key es el que guardamos anteriormente usando git-crypt export-key...
Hagamos un repaso rápido de dónde estamos ahora.
El archivo git-crypt-key es muy importante. Sin él, no podrá descifrar ninguno de los archivos cifrados en su repositorio. Cualquiera que tenga una copia de ese archivo tiene acceso a todos los secretos encriptados en su repositorio. Por lo tanto, debe mantener ese archivo seguro y protegido.
Usamos git-crypt init y git-crypt export-key para crear nuestro archivo git-crypt-key. Pero, si tenemos que tener un archivo de claves separado para cada uno de nuestros repositorios, entonces no hemos mejorado mucho nuestra gestión de secretos.
Afortunadamente, es muy fácil usar el mismo archivo de claves de git-crypt para varios repositorios de git.
Para usar un archivo de clave existente, simplemente use git-crypt unlock en lugar de git-crypt init cuando configure su repositorio git para usar git-crypt, así:
$ mkdir my-other-project # At the same directory level as `myproject` $ cd my-other-project $ git init $ echo "Something" > file.txt $ git add file.txt $ git commit -m "initial commit" $ git-crypt unlock ../git-crypt-key
Si ejecuta el comando de desbloqueo de git-crypt antes de agregar cualquier archivo a su repositorio de git, verá un mensaje como este:
fatal: You are on a branch yet to be born Error: 'git checkout' failed git-crypt has been set up but existing encrypted files have not been decrypted
Esto todavía funciona bien, pero es un poco confuso, así que me aseguré de agregar y confirmar al menos un archivo antes de ejecutar git-crypt unlock...
Reutilizar su archivo de clave de git-crypt es conveniente, pero significa que si alguien más obtiene una copia de su archivo de clave, todos sus secretos cifrados quedan expuestos.
Este es el mismo tipo de compensación de seguridad que usar un administrador de contraseñas como LastPass o 1password . En lugar de administrar varios secretos (contraseñas), cada uno con su propio riesgo de exposición, los guarda todos en un almacén seguro y usa una única contraseña maestra para desbloquearlos.
La idea aquí es que es más fácil manejar un secreto importante que muchos secretos menores.
Git-crypt es una excelente manera de mantener los secretos que sus aplicaciones necesitan en el repositorio de git, junto con el código fuente de la aplicación. Sin embargo, como cualquier otra medida de seguridad, no siempre va a ser adecuada o aconsejable.
Aquí hay algunas cosas a considerar para decidir si es la solución adecuada para su proyecto en particular:
Hay más información en esta sección del README de git-crypt .
En lugar de administrar su archivo de clave git-crypt directamente, hay una mejor manera de administrar repositorios encriptados al integrar git-crypt con gpg , de modo que pueda usar su clave privada gpg para descifrar el repositorio git. Esto también le permite agregar múltiples colaboradores a un repositorio de git sin transmitir ningún secreto entre las partes. Sin embargo, esto requiere una configuración más complicada, así que lo dejaremos para otro artículo.