NPM should support registry-scoped config options for specifying the paths to the client certificate and key used in registry fetches.
These options should also be acceptable as authentication credentials by npm publish
and friends.
Currently you can set a cert
and key
config options at the top level, which means they can be used in connections against any registry. Ideally a client certificate would only be presented to the registry that actually needs it, and you should be able to use different ones depending on the registry.
Additionally, the cert
and key
options are the actual contents of the cert/key, rather than paths to them. This means you either need to put them in .npmrc
— possibly keeping it in sync with the actual keys/certs — or you have to specify them as env vars. Both options potentially weaken security (e.g. .npmrc
could be accidentally checked in or read by other users, npm_config_key
could be extracted from /proc/<pid>/environ
, etc.).
Lastly, custom registries may wish to authenticate solely via mutual TLS (i.e. no username/pass/token, just a client cert+key). This check currently prevents that, so additional credentials are always needed to avoid ENEEDAUTH
.
- [FEATURE] registry-scoped certfile and keyfile options
- [BUG] ENEEDAUTH when authenticating against a registry via mTLS
- [BUG] npm_config_... variables don't work for specifying a scoped registry password/auth/authToken
NPM should support two new registry-scoped config options: certfile
and keyfile
, e.g.
//my.registry.example/npm/:certfile=~/.secret/stuff.crt
//my.registry.example/npm/:keyfile=~/.secret/stuff.key
These options should also be acceptable as authentication credentials from the standpoint of npm publish
so that you don't get ENEEDAUTH
if other credentials are not set.
The contents of these files should then be used as the key
and cert
options in any fetches against that registry.
There are some workarounds, but they all have pain points and security concerns:
- Specify
npm_config_cert
andnpm_config_key
env vars- 👎 key may be read by other local users (from
/proc/<pid>/environ
) - 👎 values may need to be kept in sync with source of truth for key/cert
- 👎 need to set these dynamically if you need to push to multiple registries
- 👎 key may be read by other local users (from
- Specify
key
andcert
in project.npmrc
- 👎 credentials may be inadvertently checked in
- 👎 file may be read by other local users (depending on permissions)
- 👎 file may need to be kept in sync with source of truth for key/cert
- 👎 need to change this file if you need to push to multiple registries
- Specify
key
andcert
in$HOME/.npmrc
- 👎 file may be read by other local users (depending on permissions)
- 👎 file may need to be kept in sync with source of truth for key/cert
- 👎 need to change this file if you need to push to multiple registries
- Specify
key
andcert
in a custom.npmrc
specified vianpm_config_userconfig
/--userconfig
- 👎 file may be read by other users (depending on permissions)
- 👎 file may need to be kept in sync with source of truth for key/cert
- 👎 need to set
userconfig
dynamically if you need to push to multiple registries
If your registry authenticates solely via mTLS
, you may be able to work around it, but it gets complicated:
- You can use something besides
npm publish
or invokelibnpmpublish
yourself to get around theENEEDAUTH
check. - You can set some explicit/bogus credentials, but you might need to do some custom work to make your registry accept/ignore them.
- If you are doing dual publishing, there are some gotchas:
- You can put scoped credentials in an
.npmrc
file, but that has similar issues ascert
/key
workarounds above. - You can set top-level env vars like
npm_config_username
/npm_config__password
, but that has similar issues asnpm_config_cert
/npm_config_key
above. - You can't set a scoped registry password/auth/authToken via env vars due to this bug.
- You can put scoped credentials in an
- Resolve scoped
certfile
/keyfile
options and use them, i.e.npm-registry-fetch
: UpdategetAuth
+Auth
to resolve any scopedcertfile
andkeyfile
options into correspondingcert
andkey
properties, and updateregFetch
to use them in thefetch
call.
- Accept
certfile
/keyfile
as valid creds, i.e.@npmcli/config
: UpdategetCredentialsByURI
to process scopedcertfile
/keyfile
options and then set them in the returned credentials.npm
: Update thisnoCreds
check to acceptcertfile
/keyfile
as creds.npm-registry-fetch
: Future work to implement theENEEDAUTH
check here should also take this into account.
- Should the scoped
keyfile
config option instead be named_keyfile
? Technically it's not sensitive, though it points at something sensitive. If we prefix it with an underscore it would be affected by this bug. - Should registry-scoped
certfile
/keyfile
options override more generalcert
/key
options innpm-registry-fetch
? I think the answer should be yes, but perhaps there are scenarios where you wouldn't want that? - Should we go ahead and implement the npm-registry-fetch
ENEEDAUTH
check as part of this change? That should let us skip steps 2.1. and 2.2 altogether, and we could drop the currentnoCreds
check fromnpm
.