nodecraft / acme-dns-01-cloudflare Goto Github PK
View Code? Open in Web Editor NEWCloudflare DNS for Let's Encrypt / ACME dns-01 challenges with Greenlock.js and ACME.js
License: MIT License
Cloudflare DNS for Let's Encrypt / ACME dns-01 challenges with Greenlock.js and ACME.js
License: MIT License
🚨 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.
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
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?
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:
acme-dns-01-cloudflare/index.js
Line 104 in a8e4d40
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. :)
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
:
acme-dns-01-cloudflare/index.js
Line 228 in 450850f
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?
As title. The README needs to be updated to include ACME.js example usage, and maybe other use-cases?
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) {
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 :)
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?
Does anyone have any idea where the greenlock-express config this needs to be inserted? I cannot get this to work at all.
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.
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.)
Using the Greenlock v4 example, it returns: UnhandledPromiseRejectionWarning: Error: missing 'packageAgent' and also failed to read
name 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
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?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.