GithubHelp home page GithubHelp logo

nodecraft / acme-dns-01-cloudflare Goto Github PK

View Code? Open in Web Editor NEW
16.0 5.0 5.0 438 KB

Cloudflare DNS for Let's Encrypt / ACME dns-01 challenges with Greenlock.js and ACME.js

License: MIT License

JavaScript 100.00%
greenlock letsencrypt acme-dns cloudflare lets-encrypt acme-v2 acme hacktoberfest

acme-dns-01-cloudflare's People

Contributors

abskmj avatar ajuanjojjj avatar cherry avatar dependabot[bot] avatar rautherdir avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

acme-dns-01-cloudflare's Issues

Log errors when applying for certificates (Cloudflare)

A colleague has kindly written a node-RED node which uses Acme, and acme-dns-01-cloudflare to auto install certificates for the node-RED community. We are having some problems and your help would be very much appreciated.

When the cert application is made, we are getting error messages despite the cert renewal being successful.

8 Jun 14:09:27 - [info] [acme-client:Certificate Management] Acme certificate_order message =  status =
8 Jun 14:09:29 - [info] [acme-client:Certificate Management] Acme challenge_select message =  status =
8 Jun 14:09:29 - [info] [acme-client:Certificate Management] Acme _challenge_select message =  status =
DNS not propagated yet for _greenlock-dryrun-172cefb6.testsub.digitalnut.co.uk. Checking again in 10000ms. (Attempt 1 / 30)
8 Jun 14:09:55 - [info] [acme-client:Certificate Management] Acme challenge_status message =  status = pending
8 Jun 14:09:57 - [info] [acme-client:Certificate Management] Acme challenge_status message =  status = valid
8 Jun 14:09:58 - [info] [acme-client:Certificate Management] Acme certificate_status message =  status = valid
DNS not propagated yet for _greenlock-dryrun-172cefb6.testsub.digitalnut.co.uk. Checking again in 10000ms. (Attempt 2 / 30)
8 Jun 14:09:58 - [info] [acme-client:Certificate Management] Acme client has stored the new certificate into /home/opc/.node-red/cert.pem
DNS not propagated yet for _greenlock-dryrun-172cefb6.testsub.digitalnut.co.uk. Checking again in 10000ms. (Attempt 3 / 30)
DNS not propagated yet for _acme-challenge.testsub.digitalnut.co.uk. Checking again in 10000ms. (Attempt 1 / 30)
DNS not propagated yet for _greenlock-dryrun-172cefb6.testsub.digitalnut.co.uk. Checking again in 10000ms. (Attempt 4 / 30)
DNS not propagated yet for _acme-challenge.testsub.digitalnut.co.uk. Checking again in 10000ms. (Attempt 2 / 30)
DNS not propagated yet for _greenlock-dryrun-172cefb6.testsub.digitalnut.co.uk. Checking again in 10000ms. (Attempt 5 / 30)
DNS not propagated yet for _acme-challenge.testsub.digitalnut.co.uk. Checking again in 10000ms. (Attempt 3 / 30)

// and continues up to 30/30 before the final line added -

8 Jun 14:15:18 - [error] [acme-client:Certificate Management] Acme error message = Could not verify challenge for '_acme-challenge.testsub.digitalnut.co.uk'. status =

The Cloudflare token has the correct permissions (as per your readme), and your plugin is used with the following settings;

                case "cloudflare": 
                        dns01Challenge = require('acme-dns-01-cloudflare').create({
                        token: node.dnsToken,
                        verifyPropagation: true,
                        verbose: true,
                        retries: 5, // number of propagation retries
                        waitFor: 20000 // delay between retries
                    });

Any ideas why we are getting these errors?

API Token requires access to all zones on account

The readme says to give tokens the permission "Account -> Account Settings: Read" in order to get com.cloudflare.api.account.zone.list to be able to list zones. It turns out that this permission was never meant to be granted this way, and Cloudflare recently "fixed" the "bug" on their end, so this no longer works.

Now, in order to list zones, the token must be granted permission to all zones on the account under "zone resources". Unfortunately, there's no way to grant read access to all zones while granting DNS write to only a specific zone, so in order to use acme-dns-01-cloudflare, it is now necessary to grant DNS write access to all zones on my account, even if I only really want to issue certificates under one specific zone.

Perhaps the module could add a config option to specify zone names, so that it doesn't need to try to list them via the API?

(Note: I work for Cloudflare, but I am currently here because I'm trying to add Let's Encrypt support to Sandstorm.io, which is unrelated to my work at Cloudflare.)

Over-eager zone matching

Thanks for the plugin! I've been able to get it up and running with Greenlock with minimal trouble. However, I did hit a roadblock that I would really appreciate some help with.

We own the domains devresults.com and training-devresults.com, but I'm not able to generate certificates for training-devresults.com because of the logic in how the zone is picked from the list of zones thinks that devresults.com is the zone for e.g., *.training-devresults.com:

if(domain.endsWith(zone.name)){

I made the zone check a bit more strict, and the following works for my in my dev environment (check for exact domain or subdomain match):

if(domain === zone.name || domain.endsWith(`.${zone.name}`)){

Can you help me out?

Example / Greenlock broken

Using the Greenlock v4 example, it returns: UnhandledPromiseRejectionWarning: Error: missing 'packageAgent' and also failed to readname and/or 'version' from 'package.json'

There's also no documentation on Greenlock v4 so I'm not entirely sure how to debug this..

Edit: Formatting

Action required: Greenkeeper could not be activated 🚨

🚨 You need to enable Continuous Integration on Greenkeeper branches of this repository. 🚨

To enable Greenkeeper, you need to make sure that a commit status is reported on all branches. This is required by Greenkeeper because it uses your CI build statuses to figure out when to notify you about breaking changes.

Since we didn’t receive a CI status on the greenkeeper/initial branch, it’s possible that you don’t have CI set up yet.
We recommend using:

If you have already set up a CI for this repository, you might need to check how it’s configured. Make sure it is set to run on all new branches. If you don’t want it to run on absolutely every branch, you can whitelist branches starting with greenkeeper/.

Once you have installed and configured CI on this repository correctly, you’ll need to re-trigger Greenkeeper’s initial pull request. To do this, please click the 'fix repo' button on account.greenkeeper.io.

Propagation delay issues

Thanks for writing this plugin! I've used it successfully (along with ACME.js in general) in sandstorm-io/sandstorm#3299.

I had some thoughts on propagation verification.

So, currently, if I pass verifyPropagation: true to the options, the plugin will block until it can actually see the DNS entry show up. That's a nice feature! But it struck me that it's really only telling you if the DNS entry has shown up in the Cloudflare colo closest to you, which is probably not the colo Let's Encrypt itself will be querying. So in practice it's still an estimate, and it's not clear to me if it's all that much better than waiting for a fixed delay period.

A more subtle problem with the current logic is that the plugin makes the first verification query right away after writing the DNS entry to the Cloudflare API. This might paradoxically cause verification to take longer, because this first query will almost always fail, and this negative result will then be cached (perhaps in the local machine's DNS cache, perhaps in caches on Cloudflare's side, etc.). So, the DNS entry will likely arrive at the colo a few seconds later, but the plugin may keep seeing it as missing for a while due to caching, causing verification to take longer than it needs to.

Meanwhile it looks like ACME.js does a verification step of its own. It expects the plugin to have a property called propagationDelay specifying how much time to wait before checking if the DNS entry exists. The Cloudflare plugin doesn't appear to set this property currently, which cases ACME.js to print a warning and then use 5 seconds as a default. After the delay, ACME.js does its own DNS lookup and bails out immediately if it can't find the DNS entry. In my experimentation, it seems that 5 seconds is not often long enough for Cloudflare, so when verifyPropagation is disabled, the plugin commonly fails.

With all that in mind, some specific ideas for improvements:

  • Perhaps acme-dns-01-cloudflare should set propagationDelay to something like 15 seconds when verifyPropagation is off, and zero when it is on. That'll silence the warning and should provide reasonable behavior either way. I am currently doing exactly this as a hack in Sandstorm: sandstorm-io/sandstorm@a931920

  • When verifyPropagation is on, wait 5-10 seconds before the first verification attempt. This should make verification take less time overall since it won't pollute caches in the common case that propagation happens quickly.

  • When verifyPropagation is on, the stderr output is pretty verbose and makes it look like things are going horribly wrong when in fact it's working as intended. Specifically right now it repeatedly prints things like:

      Error: Could not verify DNS for _acme-challenge.zero.kentonshouse.com
          at Function.verifyPropagation (node_modules/acme-dns-01-cloudflare/index.js:146:12)
          at Challenge.set (node_modules/acme-dns-01-cloudflare/index.js:46:5)
      Waiting for 10000 ms before attempting propagation verification retry 1 / 30.
    

    This could maybe be reduced to a single line like: "DNS not propagated yet. Will check again in 10 seconds. (attempt 1/30)"

  • I noticed that even when verifyPropagation is off, the plugin seems to verify deletions. But deletions only happen as the very last step of the ACME.js process and there's really no need to verify them, so this just adds a lot of stderr spam for no reason. Maybe verification of deletions should be skipped?

Using with Greenlock-Express

Does anyone have any idea where the greenlock-express config this needs to be inserted? I cannot get this to work at all.

[Bug ?] doesn't seem to ever be able to perform domain validation

Hi, I've been trying to generate let's encrypt certs using Greenlock v4 with cloudflare DNS challenge but it doesn't seem to ever be able to perform any form of verification.

I'm using node v12.14.1

I'm using a very basic setup for testing purposes :

'use strict';

var pkg = require('./package.json');
var Greenlock = require('greenlock');
var greenlock = Greenlock.create({
    packageRoot: __dirname,
    configDir: __dirname,
    packageAgent: pkg.name + '/' + pkg.version,
    maintainerEmail: "<my email address>",
    staging: true,
    notify: function(event, details) {
        if ('error' === event) {
            // `details` is an error object in this case
            console.error(details);
        }
    }
});

greenlock.manager.defaults({
    // The "Let's Encrypt Subscriber" (often the same as the maintainer)
    // NOT the end customer (except where that is also the maintainer)
    subscriberEmail: '<my email address>',
    agreeToTerms: true,
    store: {
        module: "greenlock-store-fs",
        basePath: "./store/certs"
    },
    challenges: {
        "dns-01": {
            module: "acme-dns-01-cloudflare",
            email: "<my cloudflare email address>",
            key: "<my global api key>"
        }
    }
});

greenlock.add({
    subject: "<my domain>",
    altnames: ["<my domain>"]
});

I'm getting the following output:

Error: DNS record deletion not yet propagated for _greenlock-dryrun-16ba4f41.<my domain>
    at Function.verifyPropagation (/c/Users/coren/PhpstormProjects/greenlocktest/node_modules/acme-dns-01-cloudflare/index.js:173:13)
    at async /c/Users/coren/PhpstormProjects/greenlocktest/node_modules/acme-dns-01-cloudflare/index.js:103:5
Waiting for 10000 ms before attempting propagation verification retry 1 / 30.
Error: queryTxt ENOTFOUND _acme-challenge.<my domain>
    at QueryReqWrap.onresolve [as oncomplete] (dns.js:202:19) {
  errno: 'ENOTFOUND',
  code: 'ENOTFOUND',
  syscall: 'queryTxt',
  hostname: '_acme-challenge.<my domain>',
  context: 'cert_issue',
  subject: '<my domain>',
  altnames: [ '<my domain>' ]
}
Error: queryTxt ENOTFOUND _acme-challenge.<my domain>
    at QueryReqWrap.onresolve [as oncomplete] (dns.js:202:19) {
  errno: 'ENOTFOUND',
  code: 'ENOTFOUND',
  syscall: 'queryTxt',
  hostname: '_acme-challenge.<my domain>',
  context: 'cert_issue',
  subject: '<my domain>',
  altnames: [ '<my domain>' ],
  toJSON: [Function: errorToJSON],
  _site: {
    subject: '<my domain>',
    altnames: [ '<my domain>' ],
    renewAt: 1
  }
}
Error: queryTxt ENOTFOUND _acme-challenge.<my domain>
    at QueryReqWrap.onresolve [as oncomplete] (dns.js:202:19) {
  errno: 'ENOTFOUND',
  code: 'ENOTFOUND',
  syscall: 'queryTxt',
  hostname: '_acme-challenge.<my domain>'
}
Waiting for 10000 ms before attempting propagation verification retry 1 / 30.
Error: queryTxt ENOTFOUND _greenlock-dryrun-16ba4f41.<my domain>
    at QueryReqWrap.onresolve [as oncomplete] (dns.js:202:19) {
  errno: 'ENOTFOUND',
  code: 'ENOTFOUND',
  syscall: 'queryTxt',
  hostname: '_greenlock-dryrun-16ba4f41.<my domain>'
}
Waiting for 10000 ms before attempting propagation verification retry 2 / 30.

and this continues like this until it eventually stops by itself, but without any certificate generated for my domain.

I'm not sure wether I'm doing something wrong or not, I'm posting the issue here since I don't have any greenlock log after your module's one, feel free to correct me if I'm wrong!

Thanks in advance for the help :)

Add CI pipeline for testing (GitHub Actions)

This includes linting, and then testing on supported Node versions. https://travis-ci.org/ is probably the best idea.

For running the test.js, we need to think about how to do that in a way that won't expose any credentials. Perhaps we need to stub Cloudflare's API as well as http/dns to faux-verify? I'm not sure about the best way to implement this yet.

Error the "id" argument must be of a type String

I had this code running before. Or I made a small change. I'm getting a strange error, I cant figure out what I'm doing wrong

index.js

const Greenlock = require('greenlock');
const acmeDnsCloudflare = require('acme-dns-01-cloudflare');
const pkg = require('./package.json');

const TOKEN = "xxxx";
const EMAIL = "xxx@xxx"

const cloudflareDns01 = new acmeDnsCloudflare({
    token: TOKEN,
    verifyPropagation: true,
    verbose: true
});

console.log('dirname', __dirname);
const greenlock = Greenlock.create({
    staging: true,
    debug: true,
    maintainerEmail: EMAIL,
    packageRoot: "/home/xxx/cert_test",
    packageAgent: pkg.name + '/' + pkg.version,
    configDir: "/home/xxx/store",
    notify: function(event, details) {
        if ('error' === event) {
            // `details` is an error object in this case
            console.error(details);
        }
    }
});

greenlock.manager.defaults({
    agreeToTerms: true,
    subscriberEmail: EMAIL,
    packageRoot: __dirname,
    store: {
        module: "greenlock-store-fs",
        basePath: `/home/popcorn/WebstormProjects/webserver/cert_test/store/certs`
    },
    challenges: {
        "dns-01": cloudflareDns01
    }
});

greenlock.add({
    subject: "localh.app",
    altnames: ["localh.app", "*.localh.app"]
}).then(function(){
    console.log("SUCCESS");
}).catch(console.error);

Having an error:

Could not load 'undefined'
Did you install it?
        npm install --save undefined
TypeError [ERR_INVALID_ARG_TYPE]: The "id" argument must be of type string. Received undefined
    at new NodeError (node:internal/errors:259:15)
    at validateString (node:internal/validators:123:11)
    at Module.require (node:internal/modules/cjs/loader:965:3)
    at require (node:internal/modules/cjs/helpers:88:18)
    at Object.P._loadHelper (/home/xxx/cert_test/node_modules/@root/greenlock/plugins.js:29:32)
    at Object.P._loadChallenge (/home/popcorn/xxx/cert_test/node_modules/@root/greenlock/plugins.js:18:14)
    at /home/popcorn/xxx/cert_test/node_modules/@root/greenlock/greenlock.js:456:26
    at Array.map (<anonymous>)
    at Object.greenlock._order (/home/popcorn/xxx/cert_test/node_modules/@root/greenlock/greenlock.js:455:41)
    at async Object.greenlock._renew (/home/popcorn/xxx/cert_test/node_modules/@root/greenlock/greenlock.js:335:9) {

HTTPError: Response code 400 (Bad Request)

Hi there,

Thanks for this amazing project!

I'm running into this issue where I get Response code 400 (Bad Request) from Cloudflare. It does seem to work once in a while but I don't know why.

(node:15786) [DEP0066] DeprecationWarning: OutgoingMessage.prototype._headers is deprecated
HTTPError: Response code 400 (Bad Request) ErrorClass [HTTPError]: Response code 400 (Bad Request)
    at /node_modules/got/index.js:123:13
    at processTicksAndRejections (internal/process/task_queues.js:97:5) {
  message: 'Response code 400 (Bad Request)',
  host: 'api.cloudflare.com',
  hostname: 'api.cloudflare.com',
  method: 'POST',
  path: '/client/v4/zones/***********************/dns_records',
  statusCode: 400,
  statusMessage: 'Bad Request',
  context: 'cert_issue',
  subject: 'test.example.com',
  altnames: [ 'test.example.com' ]
}

I'm also experiencing #7.

Any ideas?

Fails to resolve challenge when requesting wildcard of subdomain

Hi guys! When requesting the format *.sub.example.com the challenge appears to fail with the following exception:

{ Error: queryTxt ENOTFOUND _acme-challenge.dev.mydomain.io
    at QueryReqWrap.onresolve [as oncomplete] (dns.js:196:19)
  errno: 'ENOTFOUND',
  code: 'ENOTFOUND',
  syscall: 'queryTxt',
  hostname: '_acme-challenge.dev.mydomain.io' }
Waiting for 10000 ms before attempting propagation verification retry 1 / 30.

Error: Could not verify DNS for _acme-challenge.dev.mydomain.io
    at Function.verifyPropagation (C:\DStack\apps\mydomain\ssl\development\node_modules\acme-dns-01-cloudflare\index.js:121:12)
Waiting for 10000 ms before attempting propagation verification retry 2 / 30.

[acme-v2] handled(?) rejection as errback:
Error: [acme-v2] (E_STATE_INVALID) challenge state for '*.dev.mydomain.io': 'invalid'
    at C:\DStack\apps\mydomain\ssl\development\node_modules\acme-v2\node.js:518:29
    at process._tickCallback (internal/process/next_tick.js:68:7)

Reporting here due to errback stating an issue with the 'challenge state'

Edit:
Only appears to fail when requesting; dev.mydomain.io,*.dev.mydomain.io

Appears to get stuck adding acme-challenge.dev.mydomain.io

Promise.reject() should take Error instead of string

Hey, noticed another minor issue with ACME.js. I saw this in my log:

Unhandled exception in Promise:  TypeError: Cannot create property 'action' on string 'No TXT records found for _acme-challenge.zero.kentonshouse.com'
    at /programs/server/npm/node_modules/@root/acme/acme.js:781:17
    at /programs/server/npm/node_modules/meteor/promise/node_modules/meteor-promise/fiber_pool.js:43:40

It looks like the string comes from here:

return Promise.reject(`No TXT records found for ${fullRecordName}`);

The trouble is that this is throwing a bare string, but ACME.js expects errors to be of type Error. In particular it does this:

https://git.rootprojects.org/root/acme.js/src/branch/master/acme.js#L492-L497

.catch(function(err) {
	err.action = 'challenge_remove';
	err.altname = ch.altname;
	err.type = ch.type;
	ACME._notify(me, noopts, 'error', err);
});

So err at least has to be an object. I think it's normal convention to pass Error objects to Promise.reject().

(You could also replace return Promise.reject(...) with throw ... which is equivalent in async functions and is a little bit less verbose.)

On another note, I am not sure why an error was being thrown in my case. The certificate was successfully issued and all DNS entries were successfully cleaned up so it seems like everything worked... so not sure what the error was about. :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.