Skip to content

Write project overview documentation#368

Open
nrobinaubertin wants to merge 8 commits intomainfrom
overview
Open

Write project overview documentation#368
nrobinaubertin wants to merge 8 commits intomainfrom
overview

Conversation

@nrobinaubertin
Copy link
Collaborator

Overview

Add a project-overview.md documentation file. The goal is to explain the "why" and "how" of the whole DNS suite of this repository.

Checklist

Copy link
Contributor

@erinecon erinecon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much for writing this page! I think it provides a nice overview of the project and how all the charms work together :D

Most of my comments are nits, but my intention was to try to reduce ambiguity and make Vale happy.

@@ -0,0 +1,39 @@
# The DNS charms project

The goal of the suite of DNS charms is to provide an easy-to-use and somewhat opinionated way to deploy DNS for your infrastructure using Juju. Since DNS can be used in many different ways and bind (the DNS server that we use as a workload for these charms) can be configured in many different ways, it is difficult to choose “one true way”. Since we intend to use them for our own infrastructure, we had some constraints that guided our decisions along the way. We still hope that the result is usable by a large majority of people who want a quick, production-ready solution that also scales to quite large deployments.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The goal of the suite of DNS charms is to provide an easy-to-use and somewhat opinionated way to deploy DNS for your infrastructure using Juju. Since DNS can be used in many different ways and bind (the DNS server that we use as a workload for these charms) can be configured in many different ways, it is difficult to choose “one true way”. Since we intend to use them for our own infrastructure, we had some constraints that guided our decisions along the way. We still hope that the result is usable by a large majority of people who want a quick, production-ready solution that also scales to quite large deployments.
The goal of the suite of DNS charms is to provide an easy-to-use and somewhat opinionated way to deploy DNS for your infrastructure using Juju. Since DNS can be used in many different ways and bind (the DNS server that we use as a workload for these charms) can be configured in many different ways, it is difficult to choose “one true way”. Since we intend to use DNS for our own infrastructure, we had some constraints that guided our decisions along the way. We still hope that the result is usable by a large majority of people who want a quick, production-ready solution that also scales to quite large deployments.

"Them" was a bit confusing to me during my read-through, so I added a suggestion to try and clarify it. Feel free to update if I misunderstood


## `dns_record` interface

The first and simplest way to use these charms is by only deploying an authoritative DNS server (here `bind-operator`) and giving it a list of DNS records to be published. We want the operator to be able to give a list of DNS records as they usually would in a zone file. The format should therefore ideally be `host_label`, `TTL`, `record_class`, `record_type` and `record_data`. We can see that in that situation, someone is asking for those records to be published and someone is publishing them. The operator or charm asking for those records will be the requirer and the authoritative nameserver is the provider.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The first and simplest way to use these charms is by only deploying an authoritative DNS server (here `bind-operator`) and giving it a list of DNS records to be published. We want the operator to be able to give a list of DNS records as they usually would in a zone file. The format should therefore ideally be `host_label`, `TTL`, `record_class`, `record_type` and `record_data`. We can see that in that situation, someone is asking for those records to be published and someone is publishing them. The operator or charm asking for those records will be the requirer and the authoritative nameserver is the provider.
The first and simplest way to use these charms is by only deploying an authoritative DNS server (here `bind-operator`) and giving it a list of DNS records to be published. We want the operator to be able to give a list of DNS records as they usually would in a zone file. The format should therefore ideally be `host_label`, `TTL`, `record_class`, `record_type` and `record_data`. We can see that in this situation, someone is asking for those records to be published and someone is publishing them. The operator or charm asking for those records will be the requirer, and the authoritative name server is the provider.

Some nits, and also a change to make Vale happy. But if "nameserver" is the appropriate spelling, then you'll need to add it to the repo's accept.txt file


<img src="./record.png" alt="DNS record" width="480" />

This realization led us to design the `dns_record` interface where the requirer basically sends a list of DNS records with a UUID for each (creating a DNS entry/request that way) and the provider can respond to those requests by stating the status of each request (using the UUID given by the requirer as an identification mechanism).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This realization led us to design the `dns_record` interface where the requirer basically sends a list of DNS records with a UUID for each (creating a DNS entry/request that way) and the provider can respond to those requests by stating the status of each request (using the UUID given by the requirer as an identification mechanism).
This realization led us to design the `dns_record` interface, where the requirer basically sends a list of DNS records with a UUID for each (creating a DNS entry/request that way), and the provider can respond to those requests by stating the status of each request (using the UUID given by the requirer as an identification mechanism).

Nits, trying to add some pauses to the sentence since it's long. Maybe this is just a native English reader thing, but I find that the commas help me digest the sentence better.


This realization led us to design the `dns_record` interface where the requirer basically sends a list of DNS records with a UUID for each (creating a DNS entry/request that way) and the provider can respond to those requests by stating the status of each request (using the UUID given by the requirer as an identification mechanism).

And this is exactly what we do when relating `bind-operator` to dns-integrator and configuring the latter with a list of DNS record requests: we are abstracting away the zone file to just a list of DNS records and `bind-operator` is doing the hard work of stitching together all the requests from all the requirers into a cohesive set of DNS zone files that can be consumed and published by bind.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
And this is exactly what we do when relating `bind-operator` to dns-integrator and configuring the latter with a list of DNS record requests: we are abstracting away the zone file to just a list of DNS records and `bind-operator` is doing the hard work of stitching together all the requests from all the requirers into a cohesive set of DNS zone files that can be consumed and published by bind.
And this is exactly what we do when integrating `bind-operator` to `dns-integrator` and configuring the latter with a list of DNS record requests: we are abstracting away the zone file to just a list of DNS records, and `bind-operator` is doing the hard work of stitching together all the requests from all the requirers into a cohesive set of DNS zone files that can be consumed and published by bind.


## Handling DNS record request merges

We just explained that all DNS record requests received by `bind-operator` through its `dns_record` relations are merged into one cohesive set of zone files for it to publish. This is very different from what traditional DNS servers do, and it is also opinionated in the way those files are created.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
We just explained that all DNS record requests received by `bind-operator` through its `dns_record` relations are merged into one cohesive set of zone files for it to publish. This is very different from what traditional DNS servers do, and it is also opinionated in the way those files are created.
We just explained that all DNS record requests received by `bind-operator` through its `dns_record` relation are merged into one cohesive set of zone files for it to publish. This is very different from what traditional DNS servers do, and it is also opinionated in the way those files are created.

Unless there are multiple dns_record relations that are set up?


<img src="./merge.png" alt="Requests merging" width="680" />

This conflict handling mechanism is one expression of our opinionated way to handle this DNS deployment since it doesn't really exist in the DNS world. We wanted to make sure that operators of different teams would not step on each other's shoes while deploying applications and relating them to `bind-operator`. If you want the usual round-robin response that a DNS server like bind should give when multiple records with different data are published, we are working on allowing conflicts on a per-record basis in the `dns_record` interface.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This conflict handling mechanism is one expression of our opinionated way to handle this DNS deployment since it doesn't really exist in the DNS world. We wanted to make sure that operators of different teams would not step on each other's shoes while deploying applications and relating them to `bind-operator`. If you want the usual round-robin response that a DNS server like bind should give when multiple records with different data are published, we are working on allowing conflicts on a per-record basis in the `dns_record` interface.
This conflict handling mechanism is one expression of our opinionated way to handle this DNS deployment since it doesn't really exist in the DNS world. We wanted to make sure that operators of different teams would not step on each other's shoes while deploying applications and integrating them to `bind-operator`. If you want the usual round-robin response that a DNS server like bind should give when multiple records with different data are published, we are working to allow conflicts on a record-by-record basis in the `dns_record` interface.

Trying to make Vale happier, but if you prefer the "per-record" syntax, then I recommend wrapping the paragraph with ignore flags like

<!-- vale Canonical.025a-latinisms-with-english-equivalents = NO -->
Paragraph goes here
<!-- vale Canonical.025a-latinisms-with-english-equivalents = YES -->


## Adding a policy layer

Now that we understand that `bind-operator` is made to publish record requests from applications deployed by various teams, it raises the question of security: which application, or more specifically which records, will we allow to go through the publishing process? We wanted this approval operation to be doable by humans and software alike. We therefore designed the `dns-policy` charm. This operator is meant to sit between bind and the requirer application, working as a provider for the requirer and a requirer for bind. All the record requests are accumulated in a database on the workload, and an overlay Django application exposes a GUI and an API to approve and/or deny those requests. All requests are uniquely identified by their UUID (generated by the requirer) so that if a record was previously approved, its data may change without having to approve it again. We made that decision because we wanted to reduce toil when an application needs to regularly change its data. The idea is that if an application has the right to publish some data on a host label in a domain, then it will retain that right until it is revoked.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Now that we understand that `bind-operator` is made to publish record requests from applications deployed by various teams, it raises the question of security: which application, or more specifically which records, will we allow to go through the publishing process? We wanted this approval operation to be doable by humans and software alike. We therefore designed the `dns-policy` charm. This operator is meant to sit between bind and the requirer application, working as a provider for the requirer and a requirer for bind. All the record requests are accumulated in a database on the workload, and an overlay Django application exposes a GUI and an API to approve and/or deny those requests. All requests are uniquely identified by their UUID (generated by the requirer) so that if a record was previously approved, its data may change without having to approve it again. We made that decision because we wanted to reduce toil when an application needs to regularly change its data. The idea is that if an application has the right to publish some data on a host label in a domain, then it will retain that right until it is revoked.
Now that we understand that `bind-operator` is made to publish record requests from applications deployed by various teams, it raises the question of security: which application, or more specifically which records, will we allow to go through the publishing process? We wanted this approval operation to be doable by humans and software alike. We therefore designed the `dns-policy` charm. This operator is meant to sit between bind and the requirer application, working as both a provider for the requirer application and as a requirer for bind. All the record requests are accumulated in a database on the workload, and an overlay Django application exposes a GUI and an API to approve and/or deny those requests. All requests are uniquely identified by their UUID (generated by the requirer application) so that if a record was previously approved, its data may change without having to approve it again. We made that decision because we wanted to reduce toil when an application needs to regularly change its data. The idea is that if an application has the right to publish some data on a host label in a domain, then it will retain that right until it is revoked.

Nits, the two usages of "requirer" were a bit difficult for me to disentangle. Please correct my suggestion if I misunderstood!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was a bit confused about how this diagram related to the text. What do the colors represent?


## A charm for each DNS server

With `bind-operator` and dns-integrator, we have the core functionality necessary for our DNS setup. But we still want to be able to mimic the classic “hidden primary” setup where the primary DNS server is not visible in the zones and these are served by a set of secondaries instead. This is where the `dns-secondary` charm comes into play. When `bind-operator` gets related to `dns-secondary`, it rewrites the configuration for the zone, removing references to its own units in favor of those of `dns-secondary` and then transfers its zones to `dns-secondary`. Now `dns-secondary` can serve them without leaking any IP address of the primary deployment.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
With `bind-operator` and dns-integrator, we have the core functionality necessary for our DNS setup. But we still want to be able to mimic the classic “hidden primary” setup where the primary DNS server is not visible in the zones and these are served by a set of secondaries instead. This is where the `dns-secondary` charm comes into play. When `bind-operator` gets related to `dns-secondary`, it rewrites the configuration for the zone, removing references to its own units in favor of those of `dns-secondary` and then transfers its zones to `dns-secondary`. Now `dns-secondary` can serve them without leaking any IP address of the primary deployment.
With `bind-operator` and `dns-integrator`, we have the core functionality necessary for our DNS setup. But we still want to be able to mimic the classic “hidden primary” setup where the primary DNS server is not visible in the zones and these are served by a set of secondaries instead. This is where the `dns-secondary` charm comes into play. When `bind-operator` gets integrated to `dns-secondary`, it rewrites the configuration for the zone, removing references to its own units in favor of those of `dns-secondary` and then transfers its zones to `dns-secondary`. Now `dns-secondary` can serve the zones without leaking the IP address of the primary deployment.

Nits, and trying to clarify what dns-secondary is serving


With `bind-operator` and dns-integrator, we have the core functionality necessary for our DNS setup. But we still want to be able to mimic the classic “hidden primary” setup where the primary DNS server is not visible in the zones and these are served by a set of secondaries instead. This is where the `dns-secondary` charm comes into play. When `bind-operator` gets related to `dns-secondary`, it rewrites the configuration for the zone, removing references to its own units in favor of those of `dns-secondary` and then transfers its zones to `dns-secondary`. Now `dns-secondary` can serve them without leaking any IP address of the primary deployment.

We also want to be able to deploy DNS resolvers, and that's the role of the `dns-resolver` charm. Once related to `bind-operator` or `dns-secondary`, it will serve their zones without being involved in their definition.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
We also want to be able to deploy DNS resolvers, and that's the role of the `dns-resolver` charm. Once related to `bind-operator` or `dns-secondary`, it will serve their zones without being involved in their definition.
We also want to be able to deploy DNS resolvers, and that's the role of the `dns-resolver` charm. Once integrated to `bind-operator` or `dns-secondary`, it will serve their zones without being involved in their definition.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants