- 1199 words -
This blog is a platform for me to experiment with front end technologies and to write about random stuff I do on my free time. I keep everything versioned on Github in a public repository because it's easy and because so far I didn't have anything to keep secret in this repo. This changed recently so I decided to use EncFS
to keep secret files encrypted in my Github repo and have them easily accessible on my local copy of the repo. Here is how I did it.
Recently I started to collect pieces of wisdom I hear at my workplace. I intend to share this knowledge in some form because I believe it could be useful to a lot of my peers, but so far I'm not sure how I will do that so I want to keep track of them somewhere and this blog's repo is an easy place. So I started writing a couple of them in a draft and I also wrote the name of the coworkers who gave me these pieces of advice. Before I committed the document I realized that I was about to publish some personal thoughts of people I really appreciate and respect without asking for their consent, not cool.
So here is what I wanted to have:
To do that I opted for the following solution:
src/.secrets
directory in my repo. This directory will hold my secret files encrypted.src/secrets/
in which the secrets will be decrypted when I build the site locally, eleventy will have to build this directory too.An important warning
The solution I'm presenting here is dealing with very low importance documents. I don't plan to store any applications secrets like an API key or any sensitive document. So while I'm confident this solution fits my threat model I am in no way encouraging you to use it in production without a proper review of your risks.
I'll be using EncFS
a tool providing an encrypted file system in the user space: It translates the file system operations one would be doing into the equivalent encrypted operations on the file system.
The usage is quite simple:
encfs /path/to/secrets/ /path/to/cleartext
This command will take the /path/to/secrets/
directory and mount it in /path/to/cleartext/
one can then add any file or directory to the second directory and they will be stored encrypted in the first one.
The first step is to create my two directories in my repo:
mkdir -p src/.secrets src/secrets
Then setting up the encrypted file system, one important detail: encfs
only takes absolute paths. One can use ${PWD}
to avoid having to write the whole path:
encfs ${PWD}/.secret ${PWD}/secret
On the first invocation encfs
will show a prompt with several options to configure the encrypted volume, I didn't input anything as the standard mode seemed enough to me.
Then it asks for a password which will be used to encrypt/decrypt the volume. I used a strong password as my encrypted files will be available to anyone on Github I don't want the password to be easily brute forced. (If you do the same thing, please go with 50+ characters and use a password manager instead of your brain or a post-it note)
Once this is done a new file is created in the secret repository holding the configuration for next encfs
invocations. From now on and until I unmount the clear directory every new file I create in it will be stored encrypted in the secret directory.
Now I want this encrypted directory to be as seamless as possible in my local workflow, so I created the two following bash scripts:
# decrypt_secrets.sh
#!/usr/bin/env bash
CLEAR_DIR='src/secrets'
SECRET_DIR='src/.secrets'
# Check if there are some files in the clear directory
if [ -n "$(ls -A $CLEAR_DIR 2>/dev/null)" ]
then
echo "Secrets repository seems already decrypted."
exit 0
fi
mkdir -p "$CLEAR_DIR"
encfs "${PWD}/$SECRET_DIR" "${PWD}/$CLEAR_DIR"
This script will run when I build my site locally so it does the following:
encfs
to mount the decrypted directory.# unmount_secrets.sh
#!/usr/bin/env bash
CLEAR_DIR='src/secrets'
fusermount -u "${PWD}/$CLEAR_DIR"
This one is not in my local CI. I use it when I'm done working to unmount the clear directory.
With the decrypt_secrets.sh
wrapper created I can update my package.json
:
"scripts": {
"dev": "npm run build:clean && npm run secrets:decrypt && ELEVENTY_ENV=dev npx @11ty/eleventy --input=src --output=docs --serve",
"build": "ELEVENTY_ENV=prod npx @11ty/eleventy --input=src --output=docs",
"build:clean": "rm -rf docs",
"secrets:decrypt": "./tools/secrets/decrypt_secrets",
"secrets:unmount": "./tools/secrets/unmount_secrets"
},
So now when I use npm run dev
in my local environment my decryption script is run. However when my CI on Github runs npm run build
my secrets are not touched.
There is one last piece of configuration to add: the ignored files. Until now I only had a .gitignore
file in my repo with two purposes:
node_modules/
and docs/
(my local build file)Now I have a new directory src/secrets
which I want eleventy to build (locally) but I don't want to track on git (since that would completely defeat the purpose of all this encryption thing I've been doing).
So I had to do the following:
First tell eleventy to not use the .gitignore
file. This is done by adding this to my .eleventy.js
config file. Now git will still respect .gitignore
but eleventy will use the .eleventyignore
file to exclude files from the build.
eleventyConfig.setUseGitIgnore(false);
Then my .gitignore
remains untouched
And finally I added .eleventyignore
with the following content:
node_modules/
docs/
src/secrets/
With this setup I am able to add my secret list of pieces of wisdom to my src/secrets/
directory, see it built when I run npm run dev
, commit the content of src/.secrets/
once I am done and push the encrypted version of my file on Github 🎉
I hope that reading this article gave you an idea to experiment on your own project. Remember a side project doesn't have to be perfect it only have to be fun 😃
Posts in the same category: [eleventy]