If you have been developing Rails applications for years, there’s a good chance you’ve used:
bin/rails credentials:edit
hundreds of times.
You probably know that Rails stores encrypted credentials in:
config/credentials.yml.enc
and keeps the encryption key separately in:
config/master.key
But did you know that Rails can make:
git diff
show the decrypted, human-readable changes to credentials.yml.enc?
I recently discovered this while working on a Rails 8.1.3.1 application and it was one of those:
“I’ve been using Rails every day for years, and I didn’t know Rails could do this!”
moments.
Let’s see how it works.
First: What is credentials.yml.enc?
Rails encrypted credentials allow us to keep secrets such as:
openai:
api_key: ...
or:
aws:
access_key_id: ...
secret_access_key: ...
inside:
config/credentials.yml.enc
The file is encrypted.
The encryption key is stored separately in:
config/master.key
Rails documentation explicitly states that the encrypted credentials file can be stored in version control as long as the master key remains secure. (Ruby on Rails Guides)
So our repository can contain:
config/โโโ credentials.yml.enc โ encrypted, safe to commitโโโ master.key โ secret, NEVER commit
Editing Rails Credentials
Normally we edit credentials with:
bin/rails credentials:edit
Rails decrypts the credentials, opens them in your configured editor, and encrypts them again when you save.
Conceptually:
credentials.yml.enc
โ
โ decrypt
โผ
Plain YAML
โ
โ edit
โผ
Plain YAML
โ
โ encrypt
โผ
credentials.yml.enc
The plaintext credentials aren’t saved as a normal file.
But What Happens With git diff?
Here’s the interesting part.
If Git simply compared the encrypted files, we’d get something useless:
- 3d9Jx8...random-encrypted-data...+ 7kP2mL...different-encrypted-data...
We wouldn’t know:
- Which credential changed?
- Was a key added?
- Was a key removed?
- Did the API key change?
- Did somebody accidentally modify something?
This is where Rails’ credentials diff integration becomes useful.
Rails + Git textconv
Rails can configure Git to use a special diff driver:
[diff "rails_credentials"] textconv = bin/rails credentials:diff
In my Rails 8.1 application, I found exactly this in:
.git/config
Git therefore doesn’t simply compare the encrypted contents.
Instead:
git diff
โ
โผ
Git sees credentials.yml.enc
โ
โผ
rails_credentials diff driver
โ
โผ
bin/rails credentials:diff
โ
โผ
Rails decrypts the credentials
โ
โผ
Git displays a readable diff
Git itself doesn’t understand Rails encryption.
Rails is providing the text conversion command. Git simply knows how to invoke it.
See It Yourself
Suppose our credentials originally contain:
openai: api_key: OLD_KEY
We change it to:
openai: api_key: NEW_KEY
Now:
git diff
can show a useful diff such as:
+
+openai:
+ api_key: 'sdsdssdsdsdwewewddvcfgfgth'
That’s much more useful than comparing encrypted bytes.
The Experiment That Makes This Obvious
This is what made the behavior click for me.
Run:
git diff -- config/credentials.yml.enc
You get the human-readable credentials diff.
Now bypass Git’s text conversion:
git diff --no-textconv -- config/credentials.yml.enc
Now you see the encrypted content.
Something like:
3d9Jx8...encrypted-data...
That’s the proof.
The file itself is still encrypted.
It’s only the diff representation that’s being transformed.
So What Exactly Does Git Know?
Git doesn’t know anything about:
Railscredentialsmaster.keyAESencryptiondecryption
Git knows:
diff drivertextconv
Rails configures:
rails_credentials
and tells Git:
When displaying a diff for this file,run:bin/rails credentials:diff
That’s a very nice example of two independent tools cooperating:
Rails
โ
โ provides
โผ
credentials:diff
โ
โผ
Git
โ
โ uses
โผ
textconv
How Does Rails Configure It?
Rails provides:
bin/rails credentials:diff --enroll
This enrolls the project in credentials diffing.
The Git attributes include:
config/credentials/*.yml.enc diff=rails_credentials
config/credentials.yml.enc diff=rails_credentials
Rails then ensures the Git diff driver is configured to use:
bin/rails credentials:diff
Rails’ application generator includes this credentials diff enrollment as part of application setup and Rails 7.0 already contained the credentials diffing implementation. (Gem)
So this isn’t actually an 8.1-only feature.
That’s an important distinction.
Is This New in Rails 8.1?
No – and this is an important correction.
The encrypted credentials diff functionality existed before Rails 8.1.
For example, Rails 7.0 already had the credentials:diff implementation, and Rails 7.2’s application generator also enrolled projects in credentials diffing. (Gem)
Rails has supported decrypted Git diffs for encrypted credentials for several versions and Rails 8.x continues to build on the credentials tooling.
Rails 8.1 does introduce other useful credentials functionality. For example, Rails 8.1 added command-line credential fetching, which can be useful for deployment tooling such as Kamal. (Ruby on Rails Guides)
Does This Make My Secrets Unsafe?
No – provided you protect the master key.
The important distinction is:
Git repository
โ
โโโ credentials.yml.enc
โ โ
โ encrypted
โ
โโโ master.key
โ
SECRET
The encrypted file can be committed.
The master key should not be committed. Rails’ security guide explicitly recommends keeping the master key safe and out of version control. (Ruby on Rails Guides)
One Thing to Remember
The decrypted content can appear in your local terminal output.
For example:
git diff
could display:
+
+openai:
+ api_key: 'sdsdssdsdsdwewewddvcfgfgth'
So don’t casually share terminal screenshots containing credential diffs.
Also be careful when copying terminal output into:
- Slack
- GitHub issues
- Pull requests
- screenshots
- blog posts
- AI assistants
NOTE: The encryption protects the file stored in Git, but a decrypted diff is plaintext.
Rails Developer Takeaway
There are three different things here:
1. Encrypted file
config/credentials.yml.enc
This is what is actually stored in Git.
2. Encryption key
config/master.key
This decrypts the credentials and must remain secret.
3. Git diff representation
bin/rails credentials:diff
This is what allows us to see meaningful changes locally.
So:
GitHub
โ
โ encrypted
โผ
credentials.yml.enc
โฒ
โ
master.key
stays secret
Local git diff:
credentials.yml.enc
โ
โผ
credentials:diff
โ
โผ
decrypted representation
โ
โผ
human-readable diff
Try This Yourself
If you’re working on a Rails application, check:
git config --show-origin --get-regexp 'diff|textconv|filter'
You may find:
file:.git/config diff.rails_credentials.textconv bin/rails credentials:diff
Then:
git diff --no-textconv -- config/credentials.yml.enc
Compare that with:
git diff -- config/credentials.yml.enc
The difference is a great way to understand what’s really happening.
Quick Reference
# Edit credentials
bin/rails credentials:edit
# Enroll project in credential diffing
bin/rails credentials:diff --enroll
# Normal readable diff
git diff
# Show the actual encrypted file diff
git diff --no-textconv -- config/credentials.yml.enc
# Inspect Git's configuration
git config --show-origin --get-regexp 'diff|textconv|filter'
# Check Git attributes
git check-attr diff -- config/credentials.yml.enc
Security rule:
Y config/credentials.yml.enc โ commit it
X config/master.key โ NEVER commit it
Rails’ official security guide confirms that encrypted credentials can be stored in version control while the master key must remain protected. (Ruby on Rails Guides)
๐ References
- Rails Security Guide – Encrypted Credentials
- Rails 8.1 Release Notes
- Rails 7.0 credentials diff implementation
- Rails 7.2 Application Generator – Credentials Diff Enrollment
Happy Coding!