Prudent publishing to npm
Rowan Merewood
Posted on August 21, 2019
This post shares a few practices I find helpful for keeping my publishing of packages to npm a bit more isolated from my personal environment. I think there are good principles here, but they may be a bit specific to my project and platform. Please do comment with variants or tips for your own environment. Hey - maybe even do a whole post of your own!
π Sign up to npm with a separate email
This is good practice for most developer channels - whether it's publishing an Android app in the Play Store, your account for a particular API you rely on, or your npm account. There are a number of reasons for doing this:
- β Accounts get banned by mistake! You as a person on npm is different to the account that owns your packages. If one gets banned, it doesn't affect the other.
- π€ Other people may need access. While an organization is the right solution long-term, sometimes there are emergencies or one-offs and sharing access to the one specific account is definitely better than your personal one!
- π This email may need to be public. You may want to provide support or perhaps you just get random enquiries. Using a separate address lets you manage that as it's own thing.
No real instructions on this one... source that email address wherever you want!
π Publish using a separate local user
This has more explicit security benefits than using a separate email (which frankly is more about your personal happiness).
Most of the issues here come from other packages getting compromised and injecting malicious code. Two specific incidents here were with some of the ESLint packages including code that stole npm tokens and the event-stream
package getting compromised to steal cryptocurrency. Creating an isolated user helps mitigate this by reducing the exposure. So, for example if there is an exploited package that's able to kick in during the deployment process - it won't have access to your personal user. Likewise, an exploited package in your development environment won't have access to your deployment process.
If you're being really conscientious, then you should really ensure all your npm operations run as a separate user but that does start to turn into a lot of overhead.
I'm a Linux user, so these instructions are all based on my Bash shell environment. Please do share if there are tweaks for your own platform!
π£ Right, let's get our user created:
$ sudo adduser deploy-npm
You'll be prompted to create a password. Obviously use something solid, but we don't need to care what it is. We're going to use sudo
when we access it.
π΅οΈ Now we need to configure the environment for the new deploy-npm
user. We'll use sudo
to log in to that account:
$ sudo -i -u deploy-npm
The user will need to have access to a version of Node and npm
. I use nvm
to manage this, so the first thing I'm doing is following their install instructions and getting the LTS version of Node. You can go about this however you want. For example, maybe you already have Node installed system-wide and it's therefore immediately available for the new user.
βοΈ Verify your set-up just by checking the npm
version:
$ npm -v
π Now it's time to log in to the account! Unsurprisingly, that done with:
$ npm login
π If you haven't already enabled two-factor authentication on your account this is an ideal time to do it! This means even if your account is compromised or the tokens stolen the attacker still can't do anything without that second authentication mechanism.
$ npm profile enable-2fa auth-and-writes
πΎ We also need a local copy of the repo. Our deploy user isn't going to commit anything and doesn't have SSH credentials set up anyway, so we're just going to use the HTTP version. This assumes your code is on GitHub, but any read-only checkout is what you're aiming for here.
$ git clone https://github.com/someUser/my-package.git
π The assumption here is that you've already appropriately tagged the repo ready for a release. So, let's change into the directory and checkout the tag.
$ cd my-package
$ git checkout tags/0.0.1
π That's all the set-up done, so now we publish! Assuming you did enable 2FA, you're going to get asked for your confirmation code here.
$ npm-publish
For my use, I've wrapped that up in a script that I can use to publish a given tag. This first one is running as the deploy-npm
user and is effectively just the commands we used above. I've saved it as deploy-npm.sh
in the user's home directory.
#! /bin/bash
cd &&
source .nvm/nvm.sh &&
cd my-package &&
git fetch &&
git checkout tags/$1 &&
npm publish
Finally, I have a script in my own account that does the appropriate sudo
call to run as the deploy-npm
user.
#! /bin/bash
sudo -H -s -u deploy-npm /home/deploy-npm/deploy-npm.sh $1
π€ Now, after I've tagged up a release I just run:
$ deploy-npm.sh 0.0.2
If you're still looking to tighten things up, try this post from Liran with a selection of other useful tips.
Posted on August 21, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.