Giter VIP home page Giter VIP logo

Comments (12)

mholt avatar mholt commented on May 18, 2024

I wonder how many DNS providers really require a whole library to be imported in order to set and delete TXT records. For example, when I implemented DigitalOcean's DNS solver I simply used net/http.

If we can strip down the code of each provider to just using standard library functions, then I'm OK with adding more providers as long as they go in their own package.

But if each provider is going to add another tree of dependencies, then... I'd rather avoid that.

from lego.

xi2 avatar xi2 commented on May 18, 2024

I agree with @mholt, that stripping down the code might be the way forward. I started to write a challenge solver for Gandi API before realizing I could make http-01 work with the Stdlib reverse proxy. However, I got far enough to realize that the (huge) Gandi Go package was not necessary and I could just marshall/unmarshall the XML myself quite easily, since as you say it's only a couple of functions needed.

If anyone has a desperate need for a Gandi solver I can finish off what I did. Just leave a comment here. But as I said, I no longer need it just now.

from lego.

willglynn avatar willglynn commented on May 18, 2024

I agree that it's possible to implement many providers in terms of net/http and standard library crypto. On the other hand, take where we are now as a baseline: lego currently uses libraries for AWS Route53, CloudFlare, and DNSimple, so it needs ongoing work to track changes in those libraries. Removing them would mean re-implementing the relevant parts of those libraries, and the ongoing work switches from tracking library changes to tracking protocol changes.

I think it's pragmatic to re-use existing libraries, though admittedly the scale of the AWS client library colors my thinking. (I use both ~/.aws/credentials and credentials from EC2 instance metadata, hence #102.) Obviously using libraries brings undesirable dependency baggage, hence this proposal to externalize DNS challenge providers instead of rewriting minimal versions of them.

from lego.

willglynn avatar willglynn commented on May 18, 2024

Hmm… maybe it makes sense to use both strategies? Keep zero-dependency providers internal, and spin off e.g. lego-dns-route53?

from lego.

xi2 avatar xi2 commented on May 18, 2024

That is a fair point you make @willglynn that tracking libaries is easier than tracking protocols. Especially if the person who writes the solver disappears. Each solver will likely have a different author and they may not stick around to maintain it. But I guess it comes down to balance and a sort of cost/benefit analysis as to whether to use the lib or not.

from lego.

xi2 avatar xi2 commented on May 18, 2024

Thinking about this some more, maybe this would work:

Have each DNS solver in a seperate package, say under:

github.com/xenolf/lego/acme/dns-XXXX

Keep the plain acme package just for the non-dns solvers

An API user would then just import whichever solver they want, and get the bloat they want.

For the CLI app, lego, we could have the default go get action build it with no DNS solver and be nice and light. Then have a build tag, eg go get -tags dnssolvers build it with every dns solver built in, no matter how huge. That would be quite straight forward. On the github download page we could have both precompiled binaries available ("fat" and "thin"), or maybe just "fat" would do.

from lego.

willglynn avatar willglynn commented on May 18, 2024

I've been tinkering with moving DNS providers out of package acme, and I have this in a branch right now. (All the providers are still in a single package at the moment, but it need not stay that way.) There's a registry which lets cli.go ask "which providers do I have?" and to instantiate them as directed. Each provider starts with code like:

func init() {
    Registry.addProvider("digitalocean", "DO_AUTH_TOKEN", func() (acme.ChallengeProvider, error) {
        return NewDNSProviderDigitalOcean(os.Getenv("DO_AUTH_TOKEN"))
    })
}

This model would suit conditional compilation just fine.

I should also mention an additional motivation for my original proposal: I have a use case for an external DNS challenge provider.

One of my clients has a bizarre environment that I expect no one else will ever encounter. I could plop a provider in lego/acme/dns_challenge_bizarre.go, but I wouldn't open a PR because it plainly doesn't belong upstream. Internal-only means I need to maintain a local fork of lego, but supporting external providers means I could use my local --dns=bizarre with a normal, unmodified lego build.

(Besides being simple, the child process approach also means I could write lego-dns-bizarre in a different language, which would be another win in this particular case.)

If we're leaning towards keeping lego's usual providers self-contained (though possibly not compiled in by default), this particular itch could be scratched separately by adding a --dns=external provider that fork/exec's a child process.

from lego.

xenolf avatar xenolf commented on May 18, 2024

I'm sorry that I'm a bit late to the party but I had to think about this.

As I said in #100 I'm in favor of moving the DNS providers apart from the manual provider out of the ACME package to lessen the dependency burden. The manual provider should remain in the package as I think every challenge should be solvable by just importing the package.

Concerning the other providers, I think it makes sense to put them into their own packages to allow people to only import what they need... Using the DO provider should not mean to import the huge AWS library for example.

I imagine the folder structure as follows:
lego/acme/providers/dns/cloudflare.go

This gives us the freedom to add providers for the other challenges as well. (Some have already been requested like a manual provider for HTTP-01)

For the CLI the best method would probably be to support build tags in order to allow people to customize their build by using go get.

As far as "plugins" to the CLI go I'm torn back and forth. I intended the CLI to be simple and only a thin wrapper around the library and this would kinda break it.

Looking forward to your thoughts.

from lego.

xi2 avatar xi2 commented on May 18, 2024

That is a good point about keeping the manual DNS provider within the core acme package, and within whatever the "basic" build of the CLI is.

from lego.

willglynn avatar willglynn commented on May 18, 2024

I took a stab at some reshuffling in #112.

I put the DNS providers in lego/dns_providers, rather than lego/acme/dns_providers, because there really isn't anything ACME-specific about them. The DNS challenge providers themselves are bits of code that can create and destroy TXT records, but they're totally oblivious to the details.

greping that branch, the only reason providers import the acme package at all is so acme.DNS01Record() can tell them the details of the TXT records they're intended to create. I'd rather create a DNSProvider interface that directly operates on TXT records (and then adapt that interface to conform to acme.ChallengeProvider) instead of having every provider do this independently. Put another way, I think the DNS providers should be described in terms of the records they need to create and destroy, instead of being described in terms of the broader ACME exchange – hence why I made it a sibling instead of a child to acme.

Moving to one package per provider makes total sense to me. Consuming applications can then import lego/acme, which would have direct dependencies on a minimal set of providers, including a manual DNS-01 challenge provider. If the consuming application wants DigitalOcean, they could import …/digitalocean. We could create an additional package like …/all that would pull in all the providers for convenience, so you could depend on that and get everything even as new providers are added.

I think the registry populated on init() solution in #112 is a sound approach. This lets consumers (lego CLI and otherwise) easily get a list of everything that's available, no matter how it got linked into the binary. It's also by no means mandatory; if you know you want the Digital Ocean provider, you could import and call it directly without talking to a registry.

Speaking of available: I think lego should default to including everything. Build tags are a fine thing to offer users that have a reason to want slimmed-down binaries, but convenience is very important for the masses. Features that aren't available out of the box (i.e. things that require recompilation) tend to suffer.

from lego.

xenolf avatar xenolf commented on May 18, 2024

The DNS challenge providers themselves are bits of code that can create and destroy TXT records, but they're totally oblivious to the details.

You are right, I am not objected to making them siblings.

I agree that lego should to import all providers by default. People who are concerned about the size can customize the build by passing in buildflags.

I would also like to think about how providers to other challenges would fit into your approach. I know that at the moment we have more providers for DNS-01 compared to the other two challenges but I expect that to change and I don't want to introduce any barriers for the future.

from lego.

xenolf avatar xenolf commented on May 18, 2024

With the merge of #144, I guess we can close this. Feel free to reopen if there is still something left to discuss.

from lego.

Related Issues (20)

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.