reverseproxy: check renewal against cert instead of the files

This commit is contained in:
Girish Ramakrishnan
2022-11-17 16:34:36 +01:00
parent 00771d8197
commit 5d0309f1ca

View File

@@ -61,19 +61,17 @@ function nginxLocation(s) {
return `~ ^(?!(${re.slice(1)}))`; // negative regex assertion - https://stackoverflow.com/questions/16302897/nginx-location-not-equal-to-regex
}
function getExpiryDate(certFilePath) {
assert.strictEqual(typeof certFilePath, 'string');
function getExpiryDate(cert) {
assert(Buffer.isBuffer(cert));
if (!fs.existsSync(certFilePath)) return null; // not found
const result = safe.child_process.spawnSync('/usr/bin/openssl', [ 'x509', '-enddate', '-noout', '-in', certFilePath ]);
const result = safe.child_process.spawnSync('/usr/bin/openssl', [ 'x509', '-enddate', '-noout' ], { input: cert });
if (!result) return null; // some error
const notAfter = result.stdout.toString('utf8').trim().split('=')[1];
const notAfterDate = new Date(notAfter);
const daysLeft = (notAfterDate - new Date())/(24 * 60 * 60 * 1000);
debug(`expiryDate: ${certFilePath} notAfter=${notAfter} daysLeft=${daysLeft}`);
debug(`expiryDate: notAfter=${notAfter} daysLeft=${daysLeft}`);
return notAfterDate;
}
@@ -90,13 +88,11 @@ async function isOcspEnabled(certFilePath) {
}
// checks if the certificate matches the options provided by user (like wildcard, le-staging etc)
function providerMatchesSync(domainObject, certFilePath) {
function providerMatchesSync(domainObject, cert) {
assert.strictEqual(typeof domainObject, 'object');
assert.strictEqual(typeof certFilePath, 'string');
assert(Buffer.isBuffer(cert));
if (!fs.existsSync(certFilePath)) return false; // not found
const subjectAndIssuer = safe.child_process.execSync(`/usr/bin/openssl x509 -noout -subject -issuer -in "${certFilePath}"`, { encoding: 'utf8' });
const subjectAndIssuer = safe.child_process.execSync('/usr/bin/openssl x509 -noout -subject -issuer', { encoding: 'utf8', input: cert });
if (!subjectAndIssuer) return false; // something bad happenned
const subject = subjectAndIssuer.match(/^subject=(.*)$/m)[1];
@@ -114,7 +110,7 @@ function providerMatchesSync(domainObject, certFilePath) {
const mismatch = issuerMismatch || wildcardMismatch;
debug(`providerMatchesSync: ${certFilePath} subject=${subject} domain=${domain} issuer=${issuer} `
debug(`providerMatchesSync: subject=${subject} domain=${domain} issuer=${issuer} `
+ `wildcard=${isWildcardCert}/${wildcard} prod=${isLetsEncryptProd}/${prod} `
+ `issuerMismatch=${issuerMismatch} wildcardMismatch=${wildcardMismatch} match=${!mismatch}`);
@@ -301,12 +297,12 @@ async function getAcmeCertificate(fqdn, domainObject) {
const certName = getAcmeCertificateNameSync(fqdn, domainObject);
const privateKey = await blobs.get(`${blobs.CERT_PREFIX}-${certName}.key`);
const key = await blobs.get(`${blobs.CERT_PREFIX}-${certName}.key`);
const cert = await blobs.get(`${blobs.CERT_PREFIX}-${certName}.cert`);
if (!privateKey || !cert) return null;
if (!key || !cert) return null;
return { privateKey, cert };
return { key, cert };
}
async function writeAcmeCertificate(fqdn, domainObject) {
@@ -332,12 +328,13 @@ async function needsRenewal(fqdn, domainObject) {
assert.strictEqual(typeof fqdn, 'string');
assert.strictEqual(typeof domainObject, 'object');
const { certFilePath } = getAcmeCertificatePathSync(fqdn, domainObject);
const certificate = await getAcmeCertificate(fqdn, domainObject);
if (!certificate) return true;
const notAfter = getExpiryDate(certFilePath);
const notAfter = getExpiryDate(certificate.cert);
const isExpiring = (notAfter - new Date()) <= (30 * 24 * 60 * 60 * 1000); // expiring in a month
if (!isExpiring && providerMatchesSync(domainObject, certFilePath)) return false;
debug(`needsRenewal: ${certFilePath} cert requires renewal`);
if (!isExpiring && providerMatchesSync(domainObject, certificate.cert)) return false;
debug(`needsRenewal: ${fqdn} cert requires renewal`);
return true;
}