publishlab / node-acme-client

Simple and unopinionated ACME client for Node.js
MIT License
266 stars 52 forks source link

The SSL Certificate And Key Do Not Match When Adding To GCP Load Balancer #87

Closed jalvini closed 3 months ago

jalvini commented 6 months ago

Hello,

So I am trying to add the certificate that I am creating to GCP's load balancer and it is telling me that the The SSL Certificate And Key Do Not Match.

Can someone please let me know why when I create a certificate manually through Lets Encrypt using this line of code

certbot certonly --manual -d test-8.meetubiquity.com --preferred-challenges dns

That returns this certificate it works perfectly:

-----BEGIN CERTIFICATE----- Key Here -----END CERTIFICATE-----

-----BEGIN PRIVATE KEY----- Key Here -----END PRIVATE KEY-----

But when I do the exact same thing using node-acme-client it tells me that the Key does not match?

Here is the code I am using to generate the certificate and private key

initiate-certificate-process.js (First Endpoint Called)

const initiateCertificateProcess = async (domain)=>  {
    let privateKey = await acmeClient.crypto.createPrivateEcdsaKey('P-256');

    const client = new acmeClient.Client({
        directoryUrl: acmeClient.directory.letsencrypt.production,
        accountKey: privateKey,
    });

    await client.createAccount({ termsOfServiceAgreed: true });

    const [key, csr] = await acmeClient.forge.createCsr({
        commonName: domain,
    });

    const order = await client.createOrder({ identifiers: [{ type: 'dns', value: domain }] });

    const authorizations = await client.getAuthorizations(order);
    const challenge = authorizations[0].challenges.find(ch => ch.type === 'dns-01');
    const dnsRecordValue = await client.getChallengeKeyAuthorization(challenge);

    return {
        recordName: `_acme-challenge.${domain}.`,
        recordType: 'TXT',
        recordValue: dnsRecordValue,
        accountKey: privateKey.toString(),
        order: order,
        accountUrl: client.getAccountUrl(),
        csr: csr.toString(),
        authorizations: authorizations,
        challenge: challenge
    };
}

verify-and-complete-ssl-verification.js (Second Endpoint Called)

const verifyAndCompleteSSLVerification = async (domain, accountKeyPem, orderUrl, accountUrl, csr, authorizations, challenge) => {
    const acmeClient = require('acme-client');

    const client = new acmeClient.Client({
        directoryUrl: acmeClient.directory.letsencrypt.production,
        accountKey: accountKeyPem,
        accountUrl: accountUrl
    });

    await client.verifyChallenge(authorizations[0], challenge);
    await client.completeChallenge(challenge);

    await client.waitForValidStatus(challenge);

    const order = await client.getOrder(orderUrl);

    if (order.status === 'pending') {
        await client.finalizeOrder(order, csr);
        await client.waitForValidStatus(order);
    }

   const certificate = await client.getCertificate(order);

    return certificate;
}

I am getting the private key from the first api call

let privateKey = await acmeClient.crypto.createPrivateEcdsaKey('P-256');

which returns:

-----BEGIN PRIVATE KEY----- Key Here -----END PRIVATE KEY-----

And then I am getting the certificate from the second API call

const certificate = await client.getCertificate(order);

which returns:

-----BEGIN CERTIFICATE----- Key Here -----END CERTIFICATE-----

These are the two keys I am adding to my GCP load balancer which gives me back The SSL certificate and key do not match error. If anyone of the project maintainers need the keys that are being created I would be happy to send them to you. They are not being created on a server that will be used for production so they are not super sensitive. I just left them out due to not wanting to add a bunch of cruft if it wasn't needed.

nmorsman commented 6 months ago

The value you've stored in let privateKey = ... is your account key, used to identify you with Let's Encrypt. What you want to use along with the certificate for your load balancer is the key returned from createCsr().