[Freeipa-users] DNS views: request for comments

Petr Spacek pspacek at redhat.com
Tue Oct 22 16:14:51 UTC 2013


On 22.10.2013 16:44, Martin Kosek wrote:
> On 10/21/2013 10:57 PM, Simo Sorce wrote:
>> Comments inline.
>>
>> On Mon, 2013-10-21 at 18:48 +0200, Petr Spacek wrote:
>>> On 1.10.2013 17:11, Petr Spacek wrote:
>>
>> [trim]

I should make one thing clear:
We already do two-way synchronization between LDAP and DNS server (run-time).

Persistent search (and now syncrepl) dumps content of LDAP database to a 
internal database in DNS server and the bind-dyndb-ldap plugin operates on 
this internal database. I.e. changes done in LDAP are asynchronously applied 
to internal database and vice versa, changes done via DNS protocol are written 
back to LDAP.

This is why we are able to apply any change in LDAP almost immediatelly to DNS 
data. It is true that there are nasty corner cases, but up to now we didn't 
receive many complains about data inconsistency. (This will change after the 
major refactoring in bind-dyndb-ldap 4.0 :-))

>>> Proposal - variant A ("classical" views)
>>> ====================
>>> - keep it simple :-)
>>> - single level inheritance, all views inherit from 'base' (Base is our current
>>> cn=dns subtree, so old and new plugins can co-exist. The base can be empty.)
>>> - the data in views can be modified via DNS updates, a change done to
>>> inherited data creates an override (BIND9 does the same): e.g. name 'r1.z.' is
>>> shared between View1 and View2. Value change in View1 doesn't affect View2.
>>> - particular record from the 'base' can be overriden (deleted/replaced) in any
>>> view
>>> - changes done to the base are propagated to all views
>>>
>>> LDAP schema
>>> -----------
>>> My goal is to maintain 1:1 mapping between "name+view" pair and LDAP DN. This
>>> is crucial for DNS updates. The other option is to maintain some 'record->LDAP
>>> DN database' or do a LDAP search before each DNS update - I would like to
>>> avoid that.
>>>
>>> Each view is stored as separate object under cn=dns.
>>> DN: idnsView=view1, cn=dns
>>> - this object stores settings specific to particular view (allowed clients,
>>> recursion ...)
>>>
>>> Zone in particular view is stored inside view container:
>>> DN: idnsName=zone1, idnsView=view1, dn=dns
>>> - this object can be empty container
>>> - attributes without explicit configuration are inherited from the base
>>> - a zone doesn't appear in the DNS view if the container is not present (i.e.
>>> it is possible to hide the zone from particular view)
>>> 'Override' records for particular name in zone and view are stored as:
>>> DN: idnsName=name1, idnsName=zone1, idnsView=view1, cn=dns
>>
>> Doesn't this scheme means you always have to do 2 searches ? One to find
>> if the object is in the view and one to the base ?
>>
>> We could use multivalued RDNs to achieve something similar but that will
>> require you only one search (assuming it matters).

Reading = 0 searches :-D Psearch/SyncRepl delivers the data from LDAP 
asynchronously to the plugin, almost immediatelly after each change in LDAP.

>>> - values added on top of inherited set are represented as normal DNS
>>> attributes: e.g. aRecord: 192.0.2.1
>>> - values deleted from inherited set - *are open question*: It would be great
>>> if we could store it under the same object as additions, it would make
>>> implementation a bit simpler.
>>> - Would it be acceptable to store override 'delete TXT record "hello"' as
>>> attribute 'tXTRecord;x-deleted: test'?
>>
>> I think this would be acceptable, however what happens if then someone
>> deletes the base object and later on again recreates it ?
>>
>> Will the view still 'mask' it ?
My original idea was: "Yes, it will." The main reason is that user can have 
some tools which do LDAP delete/add instead of replace/modify, so some data 
from the base could be accidentally exposed if we delete 'override' 
automatically with base object.

>> Is this the actual desired outcome maybe ?
This is a good question :-) This is most generic/powerful mechanism but it 
could create some nasty surprises. One drawback is that you have to go and add 
'mask'/'delete' record to affected views (if necessary) when you add a record 
to the base.

Another variants:
aa) Do overrides on name-level instead of record level. I.e. records for 
particular name will not be inherited if the override is present.

Example:
Base definition:
- gateway.example.com. A   203.0.113.66
- gateway.example.com. TXT "this record came from base"
- example.com          MX  10 gateway.example.com.

View definition:
- gateway.example.com. A 10.1.1.1

Result - view:
- gateway.example.com. A  10.1.1.1
- example.com          MX 10 gateway.example.com.

=> A and TXT records from base were not inherited because override for the 
name 'gateway' was present in the view.
=> MX record for name 'example.com' was inherited because there is no override 
with this name in the view.
=> Modification done in 'base' will not affect view in any way if the override 
is present, so there can't be information leak.
=> This approach doesn't require ;x-deleted or cn=deleted trick.

ab) No inheritance at all.
This is what BIND9 does if dynamic updates are enabled. After first update the 
inheritance relationship is broken and views operate independently.

Obviously, this is simplest and clearest solution. Maybe that it is enough for 
most users, look at the support in open source software ...

Maybe that some UI support for copying from one view to the other would be enough?

>> Should we allow Dynamic Updates in Views at all ?
It would be too simple without dynamic updates :-)

I think that we should allow updates, otherwise we can drop all the code for 
DNS updates from SSSD, ipa-client-install etc.

Of course, we can implement first version without support for updates and add 
it later, if there is a demand. We just need to keep it in mind during design.

>>> - The other option is to store deleted attributes in separate object:
>>> DN: cn=deleted, idnsName=record1, idnsName=zone1, idnsView=view1, cn=dns
>>
>> This sound cumbersome and require a 3rd search for every query, nack :)
Again, 0 searches because of syncrepl :-)

>> I like variant A, I think it is the most sensible and the only one
>> really needed. People have an internal view and want to 'filter' it some
>> for the external world or similar.
>>
>>
>>> Proposal - variant B (shared record groups)
>>> ====================
>>> - not so simple to implement, especially update-performance could be an issue
>>> - multiple zones can share the same record group
>>> - each view can contain arbitrary zones anf those zones can inherit arbitrary
>>> record groups - inheritance is fully configurable
>>> - the data in views can be modified via DNS updates, a change done to
>>> inherited data creates an override (BIND9 does the same): e.g. name 'r1.z.' is
>>> shared between View1 and View2. Value change in View1 doesn't affect View2.
>>> - particular record from any shared record group can be overriden
>>> (deleted/replaced) in any zone in any view
>>> - changes done to the shared record group are propagated to all views (this is
>>> the hard part!)
>>
>> Sound very complex not only to build, but to explain to admins as well,
>> is anyone actually going to need this level of complexity, what scenario
>> would really benefit from this that can't be done with A ?
I can see one use case:

Domains 'flower-eshop.com' and 'parfums-eshop.com' are hosted in 'data centre 
1', while domains 'car-eshop.com' and 'software-eshop.com' are hosted in 'data 
centre 2'.

Typically it means that sites in one DC/group share the same set of NS 
records, MX records etc.

So the admin will define record group "DC1":
NS ns1.dc1.examplewebhoster.com.
NS ns2.backup.examplewebhoster.com.
MX 10 mx1.dc1.examplewebhoster.com.
MX 20 mx1.dc2.examplewebhoster.com.

Record group "DC2":
NS ns1.dc2.examplewebhoster.com.
NS ns1.backup.examplewebhoster.com.
MX 20 mx1.dc1.examplewebhoster.com.
MX 10 mx1.dc2.examplewebhoster.com.

Now record group DC1 is assigned to servers hosted at DC1 and so on.
Result = new mail server for DC1 has to be added to single place (the record 
group DC1) and all domains hosted at DC1 will automagically pick up the new 
server.

So you don't need to construct cycles over all servers in DC1, modify each 
record by hand etc.

This sounds nice 'on the paper', but I don't know how big the real demand is ...

>>> LDAP schema
>>> -----------
>>> Group of shared records - container:
>>> DN: idnsRecordGroup=group1, cn=dns
>>>
>>> One shared name:
>>> DN: idnsName=record1, idnsRecordGroup=group1, cn=dns
>>> - contains DNS records for that name as usual
>>>
>>> Each view is stored as separate object under cn=dns.
>>> DN: idnsView=view1, cn=dns
>>>
>>> Zone in particular view is stored inside view container:
>>> DN: idnsName=zone1, idnsView=view1, dn=dns
>>> - zone has a attribute with DNs of inherited record groups
>>>
>>> 'Override' records for particular name in zone and view are stored as:
>>> DN: idnsName=name1, idnsName=zone1, idnsView=view1, cn=dns
>>>
>>>
>>> After each change to any data we have to compute new resulting value. It means
>>> to combine the data for particular name from all record groups and then apply
>>> overrides for particular instance.
>>>
>>> It means a lot of bookkeeping after each change ...
>>>
>>>
>>> Proposal - variant 0
>>> ====================
>>> Do not implement it in bind-dyndb-ldap and wait if Martin Basti succeeds with
>>> his thesis. He is trying to design and implement some generic/pluggable
>>> LDAP<->DNS synchronization mechanism.
>>>
>>> Personally, I think that variant "0" is the best one! :-D One of side effects
>>> is that our depedency on BIND 9 will be lowered and most of the work will be
>>> deferred to the real DNS server.
>>
>>
>> Synchronization is always very, very hard, especially when you throw in
>> the word 'generic'. Especially problematic are races. I would proceed
>> with A unless there is solid evidence this can work with all corner
>> cases and in a short period of time.
>>
>> Simo.
>
>
> I read all the proposals, I would personally stick with variant A as this is
> something that is doable in near future. Variant 0 seems a bit utopic to me,
One year, may be. Views are pretty complex thing - don't forget to integration 
with DNSSEC ...

> especially when speaking about synchronization corner cases. Martin's thesis

Please see the note at the beginning of my e-mail. We already do two-way 
synchronization in bind-dyndb-ldap.

> may prove me wrong, we will see.

Sure. Stand-alone daemon usually has some specific problems which are not so 
problematic for plug-ins, we will see.

-- 
Petr^2 Spacek




More information about the Freeipa-users mailing list