Gem Credentials Management with Gemstash
ruby, gems, gemstash
13 Nov 2023 ・ Featured at Ruby Weekly #678
How can we efficiently manage gem credentials across the team?
When your project grows, you may reach out to commercial gems (like Sidekiq Pro) for help or want to extract some business logic into private gems.
Bundler has a way to set the credentials for commercial/private gems, but everyone has to set it. Each developer in the team, your build/deploy processes, and some of your jobs in the CI. It will get even worse when you have gems from multiple private sources.
That may be fine until you are forced to change (rotate) the credentials for one of the used commercial gems (e.g., when they are leaked). Or, the worst-case, when your current credentials stop working (e.g., you forget to renew the license and end up with new credentials 😅).
How to solve it?
So, as the title states, we can solve it with a private instance of the Gemstash server.
What is Gemstash?
Gemstash is both a cache for remote servers such as https://rubygems.org, and a private gem source.
That will solve two problems:
- We will have only one place to set the credentials for all the gems from private sources.
- We will have all the gems cached, so we won’t need to fetch them from the remote source every time. That can be handy when the remote source is slow, unavailable, or the credentials stop working.
To set the credentials, we have to set an ENV variable. The naming is the same as for Bundler but with the
GEMSTASH_ prefix (example below for Sidekiq gems):
For testing, we can run the Gemstash server like this:
GEMSTASH_GEMS__CONTRIBSYS__COM=user:pass gemstash start --no-daemonize --config-file config.yml.erb
That will allow us to use it in our
http://localhost:9292 is the URL to our local Gemstash server:
source "http://localhost:9292/" ruby "3.2.2" source "http://localhost:9292/upstream/gems.contribsys.com" do gem "sidekiq-pro", "~> 5.5.7" end
Notice the changes:
- On line 1, we replaced the
rubygems.orgsource with our local Gemstash server. All gems will be served (and cached) by our Gemstash, which will use
rubygems.orgto fetch them by default.
- On line 5, we prefixed the
http://localhost:9292/upstream/, which will use our stored credentials and fetch the gems from this source. See docs.
It won’t require credentials when running
➜ bundle install Fetching gem metadata from http://localhost:9292/upstream/gems.contribsys.com.. Fetching gem metadata from http://localhost:9292/............ Using bundler 2.4.10 Using connection_pool 2.4.1 Using rack 2.2.7 Using redis 4.8.1 Using sidekiq 6.5.9 Fetching sidekiq-pro 5.5.8 Installing sidekiq-pro 5.5.8 Bundle complete! 1 Gemfile dependency, 6 gems now installed. Use `bundle info [gemname]` to see where a bundled gem is installed.
Securing the Gemstash server
By default, access to the Gemstash server is not protected, even for the private gems.
You (or your DevOps team) are responsible for doing it!
Or anyone with your Gemstash server URL can fetch the private or commercial gems you are paying for.
The easiest way is to set the Basic Auth for the server with one or many users. If you can automate it, you can create credentials for each developer and remove them when they leave the project.
The main benefit is that the credentials for commercial gems won’t be shared anymore, so they can not leaked that easily. If you need to rotate the credentials, you will update them in only one place: on the Gemstash server.
Are you using Dokku?
Do you like it? You can subscribe to RSS (you know how), or follow me on Mastodon.