Talisman

Talisman is an open-source tool written in Go by the technology consultancy ThoughtWorks (home of the well-known Martin Fowler).

It's essentially a tool that can hook into the git version control system and attempt to stop you from pushing secrets into your public or private git repositories. As it runs as at the time you do a git push, it's completely agnostic of the repository manager you're using.

For the purposes of this experiment, we're just going to run Talisman on a single project. It can also be run as a git hook that gets run against every git repository on your machine.

Installing Talisman

Talisman is availble on GitHub, so installation is as easy as downloading its installer script and then making it executable:

curl https://thoughtworks.github.io/talisman/install.sh > ~/install-talisman.sh
chmod +x ~/install-talisman.sh

Then, in a directory where git init has already been run:

➜  talisman git:(master) ~/install-talisman.sh
Downloading and verifying binary...

Talisman successfully installed to '.git/hooks/pre-push'.

Testing Talisman

Ok, on to the fun part! Can Talisman really stop you accidently putting secrets into the cloud?

A simple base64-encoded variable

Test 1 was a simple Python file that contained a single, relatively long, base64-encoded variable:

# "I'm a secret, please don't tell anyone about me"
my_secret = 'SSdtIGEgc2VjcmV0LCBwbGVhc2UgZG9uJ3QgdGVsbCBhbnlvbmUgYWJvdXQgbWU='

Upon trying to push, I got the message:

talisman1

So far, so good. On to the next one...

A short base64-encoded variable

Talisman can detect nice, long, base64-encoded strings via its aggressive detector, but how does it do against everyone's favourite password?

# "password1"
my_secret = 'cGFzc3dvcmQx'

Good stuff, it's still working:

talisman2

A hexed SHA256 variable

This time, I've taken "password1", SHA256ed it and expressed it as a hex value:

# "password1" SHA256ed and expressed as a hex value
my_secret = '0b14d501a594442a01c6859541bcb3e8164d183d32937b851835442f69d5c94e'

Again, it spotted it:

talisman3

A private key

For this experiment, I've created an RSA keypair using the command:

ssh-keygen -b 4096 -t rsa -f my_key

This creates two different files: my_key and my_key.pub

my_key:

-----BEGIN RSA PRIVATE KEY-----
MIIJKgIBAAKCAgEA2/jpcmopwncmc/5FVet88RofV6vYyF48zixcUDe3TgmOCuh2
zhUFdQT+fMpfkVdzkGYrdWfdfdasdfafweBcJQCXcneBO/jZM8on/8KfHzNKiqJt
...
-----END RSA PRIVATE KEY-----

my_key.pub:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDb8rFnkz2SvDhD/kVV63zxGh9Xq9jIXjzOLFxQN7dOCY4K6HbOFQV1BP58yl+RV3OQZit1bhZdEqR1q6PB4FwlAJdyd4E7+Nkzyif/wp8fM0qKom0OpzE4fBWg934mD15aGrtdZwnLdKq44snbI3ChSA+aRDBFCXH7ft+oeL8UxiasxNIGHf0NKjYZpuU+eIEgzLGk12P...

As expected, Talisman caught them both:

talisman7

talisman6

No funny business

This time, no base64ing, just a plain-old, hardcoded password:

username = 'stephenfalken'
password = 'joshua'

And again, Talisman caught it:

talisman8

So, it did well! What if I really, really, really want to put a secret in the repository manager?

Sometimes, you really do want to put something that looks like a secret into a git repo:

my_json = 'ew0KICAgJ2hlbGxvJzogJ3dvcmxkJw0KfQ=='

talisman5

Ouch, that really wasn't what I wanted.

In these cases, you can force Talisman to ignore a file by building a .talismanignore file:

echo 'this_is_fine.py' >> .talismanignore

But, the downside of this is where you ignore the file due to a secret-looking value and it ends up containing a secret too. This is pretty bad practice though and possibly breaches separation of concerns.

Conclusion

Talisman is really rather good, providing protection against loading secrets into a git repo. But, there are some potential downsides that need to be understood:

  1. As it acts as a pre-push control, it needs to be installed by the developer on to their own machine. This almost certainly makes governance hard as you may not be able to demand that developers install it on their machines. You probably want to look into gitrob or repo-supervisor as additional controls. The issue with both of these is that they work post-push, meaning that the damage has already been done.
  2. There doesn't seem to be anyway of informing Talisman to ignore a single-line in a file. Instead, you ignore whole files, which could lead to some trouble.
  3. If you were running this against a large project, it could potentially raise quite a few false positives.
  4. There are also potential situations where there could be false negatives and Talisman misses a value. I didn't encounter this in these (admittedly non-complex) scenarios though.

All-in-all a useful tool to add to your armoury...just don't expect it to replace common sense!