Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Running "rails credentials:edit" returns "key must be 16 bytes" #33528

Closed
Drillan767 opened this issue Aug 4, 2018 · 15 comments
Closed

Running "rails credentials:edit" returns "key must be 16 bytes" #33528

Drillan767 opened this issue Aug 4, 2018 · 15 comments

Comments

@Drillan767
Copy link

Drillan767 commented Aug 4, 2018

Steps to reproduce

  1. Create (for my case) a Rails API, and set it up normally
  2. Add a RAILS_MASTER_KEY to the figaro-generated application.yml file, with the result of the "rails secret" command
  3. Create a Dockerfile where the context of RAILS_ENV is set to production.
  4. Run bundle exec rails s

Here is the whole Dockerfile

FROM ruby:2.4.3-stretch
RUN apt-get update -qq && apt-get install -y build-essential curl redis-server
RUN curl https://getcaddy.com | bash -s personal
RUN chown root:root /usr/local/bin/caddy && chmod 755 /usr/local/bin/caddy
RUN mkdir /home/some-api
WORKDIR /home/some-api
COPY . ./
RUN bundle install
RUN EDITOR=nano rails credentials:edit

ENV RAILS_ENV=production
ENV RAKE_ENV=production

EXPOSE 3000
CMD ["bundle", "exec", "rails", "s"]

Expected behavior

Everything should work smoothly

Actual behavior

I've seen on some other issues that I somehow needed to delete "master.key" and "credential.yml.enc", and that running rails credentials:edit should create them back. If I keep the original files without changing or deleting them, I get the following error:

/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/message_encryptor.rb:206:in `rescue in _decrypt': ActiveSupport::MessageEncryptor::InvalidMessage (ActiveSupport::MessageEncryptor::InvalidMessage)

If I delete them, I'll get an error saying that the "rails_secret_key" hasn't been defined (I can't retrieve the exact message)

If I run the command rails credentials:edit, I'll get the error

No $EDITOR to open file in. Assign one like this:
EDITOR="mate --wait" bin/rails credentials:edit

(While I've seen a lot of people running this command without trouble)

And, finally, if I run the command EDITOR=nano rails credentials:edit, I get the following error:

/home/jaeger767/.rvm/gems/ruby-2.4.3/gems/activesupport-5.2.0/lib/active_support/message_encryptor.rb:169:in `key=': key must be 16 bytes (ArgumentError)

So I'm stuck, I've tried a lot of solutions, and even running the commands outside the Docker context won't work.

System configuration

Rails version:

Rails 5.2.0

Ruby version:

Ruby 2.4.3 (No problem if I have to update this one)

What should I do? Thank you in advance

P.S. I have absolutely no problem whatsoever when running in development mode

@MiguelSavignano
Copy link

MiguelSavignano commented Aug 5, 2018

@Drillan767
Why you need run RUN EDITOR=nano rails credentials:edit in the Dockerfile?
how are you running the docker image?

@MiguelSavignano
Copy link

MiguelSavignano commented Aug 5, 2018

I can reproduce the error with:

.dockerignore

config/master.key
  1. Delete files config/master.key and config/credentials.yml.enc
  2. run EDITOR=nano rails credentials:edit outside the container. this generate new config/master.key and config/credentials.yml.enc
  3. rebuild container
docker build -t rails-example .

Error:

/usr/local/bundle/gems/activesupport-5.2.0/lib/active_support/message_encryptor.rb:206:in `rescue in _decrypt': ActiveSupport::MessageEncryptor::InvalidMessage (ActiveSupport::MessageEncryptor::InvalidMessage)

In this case when build the container with secretes.yml.enc and without the master.key it's was generate aoutside the container. The new build container have the new secrets.yml.enc and the old master.key, the error ActiveSupport::MessageEncryptor::InvalidMessage it's try to say that.

If your case i'ts the same, you can change the step RUN EDITOR=nano rails credentials:edit
in your dockerfile and replace with ``ARG RAILS_MASTER_KEY```

you need pass rails master key when build the container

docker build -t rails-example --build-arg=$(cat config/master.key) .

@y-yagi
Copy link
Member

y-yagi commented Aug 5, 2018

It is probable that the master key is not set correctly, as MiguelSavignano already explained. Please check the setting.

Also, please use the mailing list or StackOverflow for questions/help, where a wider community will be able to help you. We reserve the issues tracker for issues only. Thanks!

@y-yagi y-yagi closed this as completed Aug 5, 2018
@oskarpearson
Copy link

oskarpearson commented Aug 13, 2018

The Dockerfile containing credentials:edit is very confusing.. but the root cause here is this text from the original problem description:

Add a RAILS_MASTER_KEY to the figaro-generated application.yml file, with the result of the "rails secret" command

It's not really documented anywhere obvious (to me), but the RAILS_MASTER_KEY needs to be exactly 32 characters long. Using rails secret generates a 128 character password, which exceeds the allowable length.

On a newly-generated rails app, the config/master.key is auto-generated, and rails credentials:edit will work as expected.

If, however, you're trying to retroactively add credentials to an existing app, it's tempting to generate a long password and try use that... but if you exceed 32 characters you'll receive the error below:

.../gems/activesupport-5.2.1/lib/active_support/message_encryptor.rb:169:in
 `key=': key must be 16 bytes (ArgumentError)

Full stack trace:

server:testapp oskar$ bundle exec rails credentials:edit
Traceback (most recent call last):
	34: from bin/rails:3:in `<main>'
	33: from bin/rails:3:in `load'
	32: from .../testapp/bin/spring:15:in `<top (required)>'
	31: from .../testapp/bin/spring:15:in `require'
	30: from .../gems/spring-2.0.2/lib/spring/binstub.rb:31:in `<top (required)>'
	29: from .../gems/spring-2.0.2/lib/spring/binstub.rb:31:in `load'
	28: from .../gems/spring-2.0.2/bin/spring:49:in `<top (required)>'
	27: from .../gems/spring-2.0.2/lib/spring/client.rb:30:in `run'
	26: from .../gems/spring-2.0.2/lib/spring/client/command.rb:7:in `call'
	25: from .../gems/spring-2.0.2/lib/spring/client/rails.rb:28:in `call'
	24: from .../gems/spring-2.0.2/lib/spring/client/rails.rb:28:in `load'
	23: from .../testapp/bin/rails:9:in `<top (required)>'
	22: from .../gems/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `require'
	21: from .../gems/activesupport-5.2.1/lib/active_support/dependencies.rb:253:in `load_dependency'
	20: from .../gems/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `block in require'
	19: from .../gems/bootsnap-1.3.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:29:in `require'
	18: from .../gems/bootsnap-1.3.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:20:in `require_with_bootsnap_lfi'
	17: from .../gems/bootsnap-1.3.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:65:in `register'
	16: from .../gems/bootsnap-1.3.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `block in require_with_bootsnap_lfi'
	15: from .../gems/bootsnap-1.3.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require'
	14: from .../gems/railties-5.2.1/lib/rails/commands.rb:18:in `<main>'
	13: from .../gems/railties-5.2.1/lib/rails/command.rb:46:in `invoke'
	12: from .../gems/railties-5.2.1/lib/rails/command/base.rb:65:in `perform'
	11: from .../gems/thor-0.20.0/lib/thor.rb:387:in `dispatch'
	10: from .../gems/thor-0.20.0/lib/thor/invocation.rb:126:in `invoke_command'
	 9: from .../gems/thor-0.20.0/lib/thor/command.rb:27:in `run'
	 8: from .../gems/railties-5.2.1/lib/rails/commands/credentials/credentials_command.rb:24:in `edit'
	 7: from .../gems/railties-5.2.1/lib/rails/commands/credentials/credentials_command.rb:46:in `ensure_credentials_have_been_added'
	 6: from .../gems/railties-5.2.1/lib/rails/generators/rails/credentials/credentials_generator.rb:31:in `add_credentials_file_silently'
	 5: from .../gems/activesupport-5.2.1/lib/active_support/encrypted_configuration.rb:29:in `write'
	 4: from .../gems/activesupport-5.2.1/lib/active_support/encrypted_file.rb:49:in `write'
	 3: from .../gems/activesupport-5.2.1/lib/active_support/encrypted_file.rb:75:in `encrypt'
	 2: from .../gems/activesupport-5.2.1/lib/active_support/message_encryptor.rb:151:in `encrypt_and_sign'
	 1: from .../gems/activesupport-5.2.1/lib/active_support/message_encryptor.rb:169:in `_encrypt'
.../gems/activesupport-5.2.1/lib/active_support/message_encryptor.rb:169:in `key=': key must be 16 bytes (ArgumentError)

Test scenario, on a newly-generated app:

export EDITOR=vim

server:testing-encryption oskar$ rails --version
Rails 5.2.1
server:testing-encryption oskar$ ruby --version
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17]
server:testing-encryption oskar$ rails new testapp
      create
      create  README.md
...

server:testing-encryption oskar$ cd testapp/
server:testapp oskar$ wc -c config/master.key
      32 config/master.key

If I then delete config/credentials.yml.enc and run rails credentials:edit, we'll get a newly-created config/credentials.yml.enc and everything works as-expected.

server:testapp oskar$ rm config/credentials.yml.enc
server:testapp oskar$ bundle exec rails credentials:edit
[All works ok and I go into vim as expected]

If, however I write an additional byte to config/master.key, I get the above error.

server:testapp oskar$ echo -n x >> config/master.key
server:testapp oskar$ wc -c config/master.key
      33 config/master.key
server:testapp oskar$ rm config/credentials.yml.enc
server:testapp oskar$ bundle exec rails credentials:edit
...
/Users/oskar/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.1/lib/active_support/message_encryptor.rb:169:in
`key=': key must be 16 bytes (ArgumentError)

Normally, a https://en.wikipedia.org/wiki/Key_derivation_function takes care of mapping the supplied key in to an encryption key of the appropriate length. Since we're not using one (and I think we should...) we have to keep the key exactly the correct length.

@Drillan767
Copy link
Author

Drillan767 commented Aug 16, 2018

Thank you @oskarpearson for these details! From what you say, I understand way better where my errors come from (i.e, I thought the .../message_encryptor.rb:169:in key=': key must be 16 bytes (ArgumentError)` error message was about the credential Rails was trying to generate). I'll need a few tests to make everything work, I guess, but at least I know where to look!

@benbonnet
Copy link

cat config/master.key | wc -c > 32

echo $(cat config/master.key) | wc -c => 33

What workaround exists to ensure there are no extra chars included which such command ?

@mainangethe
Copy link

mainangethe commented Oct 28, 2019

Guys, you won't believe it. It worked for me when I switched off protection & masking settings in the CI/CD.

When they were masked & protected. it was coping $RAILS_MASTER_KEY as 1 char to congif/master.key which was making Rails complain of 16 bytes need for the key.

But when I relaxed it. It worked. After 16 Good hrs of debugging. -___-

@kayhide
Copy link

kayhide commented May 29, 2020

I got the same issue.

If you are working on a kubernetes cluster and if you are using a secret resource to pass a value, it may adds an extra eol at the end.
It happens on GKE at least.

As a workaround, we can wrap the rails command as:

#!/usr/bin/env bash
RAILS_MASTER_KEY=$(cat <(echo $RAILS_MASTER_KEY))
exec bundle exec rails "$@"

or we can manipulate the env variable at the beginning of the rails boot (maybe config/application.rb?) with:

if (key = ENV["RAILS_MASTER_KEY"])
  ENV["RAILS_MASTER_KEY"] = key.chomp
end

(update)

I was wrong.

My local config/master.key itself has a line feed at the end.
When encoding it into base64, the following command has done well:

$ echo -n $(cat config/master.key) |base64

But it is still confusing because it works as expected on my local environment.

@scratchoo
Copy link

the damage that master.key caused in every deployment is more than the whole prodactivity you gain building apps on Rails :/ :/

@ilvez
Copy link

ilvez commented Aug 10, 2022

If you are working on a kubernetes cluster and if you are using a secret resource to pass a value, it may adds an extra eol at the end.

Thank you for that hint. I was scratching my head like an hour. I edited my K8 secret, but the value had EOL character in it. Then I generated correct base64 encoded secret with cat blah.key | base64 and this worked.

@m-faseeh-qbatch
Copy link

Solved it with the following steps:

  1. Delete both the config/master.key and config/credentials.yml.enc files.
  2. Generate new credentials using EDITOR="nano --wait" bin/rails credentials:edit
  3. The above command generates the new config/master.key and config/credentials.yml.enc files as well as gives a new encryption key that is not saved in any file by default. Copy that key for the next step.
  4. Save the key in your application ENV keys as RAILS_MASTER_KEY.
  5. Reboot your application and it starts working 🎉 .

@johnnyicon
Copy link

johnnyicon commented Aug 30, 2023

I'm getting this error as well with Rails 7.0.7.2, Ruby 2.7.6.

I just tried the solution @m-faseeh-qbatch proposed. It gave me the same error.

To be clear, the error I'm getting is for 32 characters.

/.gem/ruby/2.7.6/gems/activesupport-7.0.7.2/lib/active_support/encrypted_file.rb:125:in `check_key_length': Encryption key must be exactly 32 characters. (ActiveSupport::EncryptedFile::InvalidKeyLengthError)

@abel-tefera
Copy link

Getting the same error as well. Rails 7.0.7 and Ruby 3.2.2

@zzak
Copy link
Member

zzak commented Sep 23, 2023

If someone is able to provide a reproduction script that might identify a bug that would be greatly appreciated, otherwise this ticket just becomes a "me too" thread for anyone who had trouble deploying their application's secrets.

We try to reserve the issue tracker for bugs, please use discuss for support.

@lfalcao
Copy link
Contributor

lfalcao commented Feb 21, 2024

I just set RAILS_MASTER_KEY environment variable (.env) with a 32 char string and it worked. (Ruby 3.2.3 / Rails 6.1.7.7) cc/ @abel-tefera @johnnyicon

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests