New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: 'backend' plugin over gRPC/HTTPS #1842

Closed
ahmetb opened this Issue May 31, 2018 · 12 comments

Comments

Projects
None yet
3 participants
@ahmetb
Contributor

ahmetb commented May 31, 2018

Currently through plugins like file or hosts, CoreDNS is dynamically programmable to serve RRSets through various files that are being watched or polled (every few seconds).

However if you want to run CoreDNS in highly available (multi-replica) mode, you need to figure out how to update these files read by the plugins in a coordinated/atomic fashion. Also, parsing files every time when they're modified has:

  • atomicity considerations (coredns must not read half-written file)
  • cost of parsing the file again.

I think CoreOS should provide a way to specify a backend address as the destination for querying. This would be a new plugin named backend:

example.com.:1053 {
    backend 10.11.12.13:8053[, ...]
    cache
}

The backends might be implemented in gRPC or HTTP(S) JSON API (perhaps named backend_grpc, ...). I think CloudFlare’s DNS-over-HTTPS API already provides a good interface for creating Question/Reply protos.

The plugin would be responsible for:

  • serializing the Question from dns.Msg into proto
  • making the request to specified backend(s) (client side round-robin?)
  • deserializing Answers from proto back into dns.Msg

I think this would allow:

  • implementation of backends that can serve RRSets:
  • implementation of backends that don't need to know about DNS (that only know about the protos)
  • implementation of without contributing an in-tree plugin to CoreDNS and recompiling
  • implementation of backends that are highly available (or backed by highly available storage systems like MySQL, Redis, Cloud Spanner etc). If anyone wants to store their RR data in redis, they can just write a gRPC service that can query redis.

Thoughts?
cc: @miekg

@miekg

This comment has been minimized.

Member

miekg commented Jun 1, 2018

See #1663 and #1226 that have context on how can do this; although no code has emerged yet.

I welcome such a plugin, and we should probably just make when (with warts and all) and see where it goes.

@johnbelamaric

This comment has been minimized.

Member

johnbelamaric commented Jun 1, 2018

I don't see how this is different than the proxy or forward plugins? Proxy does exactly these when used with gRPC:

  • serializing the Question from dns.Msg into proto
  • making the request to specified backend(s) (client side round-robin?)
  • deserializing Answers from proto back into dns.Msg
@ahmetb

This comment has been minimized.

Contributor

ahmetb commented Jun 1, 2018

@johnbelamaric Looks like proxy's protocol grpc [insecure|CACERT|KEY CERT|KEY CERT CACERT] setting is indeed what I'm looking for.

However the proto doesn't look that great since it relies on byte serialization of dns.Msg. I would've preferred more descriptive proto message fields, such as: https://developers.cloudflare.com/1.1.1.1/dns-over-https/json-format/ that reduces dependency on miekg/dns package and/or binary/wire format of a DNS message, in general.

This might be sufficient for what I'm looking for, so I'll go try that. In the meanwhile, feel free to close this, as it looks like the functionality is already there.

@ahmetb

This comment has been minimized.

Contributor

ahmetb commented Jun 1, 2018

[elaborating the problem with bytes msg in my previous comment]

As an implementer of this gRPC service, I now have to figure out how to deserialize bytes msg into a struct properly. If I'm using Go, this might be easier, but if my backend is Python or Java, I need to actually look for a library that can do that.

Whereas if we actually constructed this DnsPacket with fields like these, the implementer now does not need to know about DNS wire format much. Maybe I'm looking at implementing an "easier" protocol in addition to existing grpc?

@johnbelamaric

This comment has been minimized.

Member

johnbelamaric commented Jun 1, 2018

PR welcome to make a Protobuf message that mirrors DoH format for gRPC. You may even be able to do it without breaking the current API, by making the current message a "oneof" with either a byte-format message or a fully-defined message. You'll need to pack the fully-defined message into a regular Msg before pushing it into the plugin chain.

@ahmetb

This comment has been minimized.

Contributor

ahmetb commented Jun 1, 2018

I may take a stab at it.

@miekg

This comment has been minimized.

Member

miekg commented Jun 1, 2018

The DoH format is DNS wireformat (base64 encoded for GET, raw bytes for POST). And don't think there is much benefit in redefining this in protobuf format. As the DNS is so old, most clients should be able to parse the raw bytes anyway.

@ahmetb

This comment has been minimized.

Contributor

ahmetb commented Jun 2, 2018

I was referring to JSON format for CloudFlare's DoH implementation.
Regardless, I guess most languages that one would choose to implement a DNS serving backend would have 3rd party libraries/modules to process raw messages. So this may not be a real problem.

@miekg

This comment has been minimized.

Member

miekg commented Jun 2, 2018

@ahmetb

This comment has been minimized.

Contributor

ahmetb commented Jun 2, 2018

That's fascinating. There's so many details to DNS that a beginner shall nt try to invent something new like a new transport format. I will close this and probably look at implementing a boilerplate grpc server for CoreDNS proxy backend.

@ahmetb ahmetb closed this Jun 2, 2018

@ahmetb

This comment has been minimized.

Contributor

ahmetb commented Jun 6, 2018

So I have implemented a backend that talks over gRPC, here are the challenges I observed.

  • The main theme is that you still need to know a lot about how a DNS package is crafted.
  • The developer needs to learn how to respond to a DNS query (i.e. get the first question, set the RD bit, set the AA bit (if applicable),...)
  • It wasn't clear if I don't set SERVFAIL that coredns would set it

Since this is a niche area, most people probably aren't building grpc backends to serve DNS, so I think we don't need to do anything here.

@miekg

This comment has been minimized.

Member

miekg commented Jun 6, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment