Skip to content

Commit

Permalink
feat(config): log warning if using legacy encryption (#28557)
Browse files Browse the repository at this point in the history
  • Loading branch information
rarkins committed Apr 21, 2024
1 parent b42761d commit ae1d892
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 7 deletions.
12 changes: 8 additions & 4 deletions docs/usage/self-hosted-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,7 @@ This private key is used to decrypt config files.
The corresponding public key can be used to create encrypted values for config files.
If you want a UI to encrypt values you can put the public key in a HTML page similar to <https://app.renovatebot.com/encrypt>.

To create the key pair with GPG use the following commands:
To create the PGP key pair with GPG use the following commands:

- `gpg --full-generate-key` and follow the prompts to generate a key. Name and email are not important to Renovate, and do not configure a passphrase. Use a 4096bit key.

Expand Down Expand Up @@ -926,7 +926,7 @@ sub rsa4096 2021-09-10 [E]
The private key should then be added to your Renovate Bot global config (either using `privateKeyPath` or exporting it to the `RENOVATE_PRIVATE_KEY` environment variable).
The public key can be used to replace the existing key in <https://app.renovatebot.com/encrypt> for your own use.

Any encrypted secrets using GPG must have a mandatory organization/group scope, and optionally can be scoped for a single repository only.
Any PGP-encrypted secrets must have a mandatory organization/group scope, and optionally can be scoped for a single repository only.
The reason for this is to avoid "replay" attacks where someone could learn your encrypted secret and then reuse it in their own Renovate repositories.
Instead, with scoped secrets it means that Renovate ensures that the organization and optionally repository values encrypted with the secret match against the running repository.

Expand All @@ -941,11 +941,15 @@ Instead, with scoped secrets it means that Renovate ensures that the organizatio
Use this field if you need to perform a "key rotation" and support more than one keypair at a time.
Decryption with this key will be tried after `privateKey`.

If you are migrating from the legacy public key encryption approach to use GPG, then move your legacy private key from `privateKey` to `privateKeyOld` and then put your new GPG private key in `privateKey`.
Doing so will mean that Renovate will first try to decrypt using the GPG key but fall back to the legacy key and try that next.
If you are migrating from the legacy public key encryption approach to use a PGP key, then move your legacy private key from `privateKey` to `privateKeyOld` and then put your new PGP private key in `privateKey`.
Doing so will mean that Renovate will first try to decrypt using the PGP key but fall back to the legacy key and try that next.

You can remove the `privateKeyOld` config option once all the old encrypted values have been migrated, or if you no longer want to support the old key and let the processing of repositories fail.

<!-- prettier-ignore -->
!!! note
Renovate now logs a warning whenever repositories use non-PGP encrypted config variables.

## privateKeyPath

Used as an alternative to `privateKey`, if you want the key to be read from disk instead.
Expand Down
29 changes: 26 additions & 3 deletions lib/config/decrypt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export async function tryDecrypt(
privateKey: string,
encryptedStr: string,
repository: string,
keyName: string,
): Promise<string | null> {
let decryptedStr: string | null = null;
if (privateKey?.startsWith('-----BEGIN PGP PRIVATE KEY BLOCK-----')) {
Expand All @@ -97,8 +98,20 @@ export async function tryDecrypt(
}
} else {
decryptedStr = tryDecryptPublicKeyDefault(privateKey, encryptedStr);
if (!is.string(decryptedStr)) {
if (is.string(decryptedStr)) {
logger.warn(
{ keyName },
'Encrypted value is using deprecated default padding, please change to using PGP encryption.',
);
} else {
decryptedStr = tryDecryptPublicKeyPKCS1(privateKey, encryptedStr);
// istanbul ignore if
if (is.string(decryptedStr)) {
logger.warn(
{ keyName },
'Encrypted value is using deprecated PKCS1 padding, please change to using PGP encryption.',
);
}
}
}
return decryptedStr;
Expand Down Expand Up @@ -191,10 +204,20 @@ export async function decryptConfig(
if (privateKey) {
for (const [eKey, eVal] of Object.entries(val)) {
logger.debug('Trying to decrypt ' + eKey);
let decryptedStr = await tryDecrypt(privateKey, eVal, repository);
let decryptedStr = await tryDecrypt(
privateKey,
eVal,
repository,
eKey,
);
if (privateKeyOld && !is.nonEmptyString(decryptedStr)) {
logger.debug(`Trying to decrypt with old private key`);
decryptedStr = await tryDecrypt(privateKeyOld, eVal, repository);
decryptedStr = await tryDecrypt(
privateKeyOld,
eVal,
repository,
eKey,
);
}
if (!is.nonEmptyString(decryptedStr)) {
const error = new Error('config-validation');
Expand Down

0 comments on commit ae1d892

Please sign in to comment.