From 6030ce6ab24210ce1fcf08171cab326ea53b0e4c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Vladim=C3=ADr=20=C4=8Cun=C3=A1t?= <vladimir.cunat@nic.cz>
Date: Wed, 22 Jun 2022 16:34:41 +0200
Subject: [PATCH] manager: datamodel: add notes from my brainstorming (WIP)

---
 .../datamodel/design-notes.yml                | 181 ++++++++++++++++++
 1 file changed, 181 insertions(+)
 create mode 100644 manager/knot_resolver_manager/datamodel/design-notes.yml

diff --git a/manager/knot_resolver_manager/datamodel/design-notes.yml b/manager/knot_resolver_manager/datamodel/design-notes.yml
new file mode 100644
index 000000000..916245616
--- /dev/null
+++ b/manager/knot_resolver_manager/datamodel/design-notes.yml
@@ -0,0 +1,181 @@
+###### Working notes about configuration schema
+
+
+## TODO nit: nest one level deeper inside `dnssec`, probably
+dnssec:
+  keep-removed: 0
+  refresh-time: 10s
+  hold-down-time: 30d
+
+## TODO nit: I don't like this name, at least not for the experimental thing we have there
+network:
+  tls:
+    auto_discovery: boolean
+
+#### General questions
+Plurals: do we name attributes in plural if they're a list;
+  some of them even allow a non-list if using a single element.
+
+
+#### New-policy brainstorming
+
+dnssec:
+  # Convert to key: style instead of list?
+  #  - easier to handle in API/CLI (which might be a common action on names with broken DNSSEC)
+  #  - allows to supply a value - stamp for expiration of that NTA
+  #    (absolute time, but I can imagine API/CLI converting from duration when executed)
+  #  - syntax isn't really more difficult, mainly it forces one entry per line (seems OK)
+  negative-trust-anchors:
+    example.org:
+    my.example.net:
+
+
+view:
+  # When a client request arrives, based on the `view` class of rules we may either
+  # decide for a direct answer or for marking the request with a set of tags.
+  # The concepts of matching and actions are a very good fit for this,
+  # and that matches our old policy approach. Matching here should avoid QNAME+QTYPE;
+  # instead it's e.g. suitable for access control.
+  # RPZ files also support rules that fall into this `view` class.
+  #
+  # Selecting a single rule: the most specific client-IP prefix
+  # that also matches additional conditions.
+  - subnet: [ 0.0.0.0/0, ::/0 ]
+    answer: refused
+    # some might prefer `allow: refused` ?
+    # Also, RCODEs are customary in CAPITALS though maybe not in configs.
+
+  - subnet: [ 10.0.0.0/8, 192.168.0.0/16 ]
+    # Adding `tags` implies allowing the query.
+    tags: [ t1, t2, t3 ] # theoretically we could use space-separated string
+    options: # only some of the global options can be overridden in view
+      minimize: true
+      dns64: true
+      rate-limit: # future option, probably (optionally?) structured
+    # LATER: rulesets are a relatively unclear feature for now.
+    #   Their main point is to allow prioritization and avoid
+    #   intermixing rules that come from different sources.
+    #   Also some properties might be specifyable per ruleset.
+    ruleset: tt
+
+  - subnet: [ 10.0.10.0/24 ] # maybe allow a single value instead of a list?
+      # LATER: special addresses?
+      #   - for kresd-internal requests
+      #   - shorthands for all private IPv4 and/or IPv6;
+      #     though yaml's repeated nodes could mostly cover that
+      #     or just copy&paste from docs
+    answer: allow
+
+# Or perhaps a more complex approach?  Probably not.
+# We might have multiple conditions at once and multiple actions at once,
+# but I don't expect these to be common, so the complication is probably not worth it.
+# An advantage would be that the separation of the two parts would be more visible.
+view:
+  - match:
+      subnet: [ 10.0.0.0/8, 192.168.0.0/16 ]
+    do:
+      tags: [ t1, t2, t3 ]
+      options: # ...
+
+
+local-data: # TODO: name
+  #FIXME: tags - allow assigning them to (groups of) addresses/records.
+
+  addresses: # automatically adds PTR records and NODATA (LATER: overridable NODATA?)
+    foo.bar: [ 127.0.0.1, ::1 ]
+    my.pc.corp: 192.168.12.95
+  addresses-files: # files in /etc/hosts format (and semantics like `addresses`)
+    - /etc/hosts
+
+  # Zonefile format seems quite handy here.  Details:
+  #  - probably use `local-data.ttl` from model as the default
+  #  - and . root to avoid confusion if someone misses a final dot.
+  records: |
+    example.net. TXT "foo bar"
+     A 192.168.2.3
+     A 192.168.2.4
+    local.example.org AAAA ::1
+
+  subtrees:
+  nodata: true # impl ATM: defaults to false, set (only) for each rule/name separately
+  # impl: options like `ttl` and `nodata` might make sense to be settable (only?) per ruleset
+
+  subtrees: # TODO: perhaps just allow in the -tagged style, if we can't avoid lists anyway?
+    - type: empty
+      roots: [ sub2.example.org ] # TODO: name it the same as for forwarding
+      tags: [ t2 ]
+    - type: nxdomain
+      # Will we need to support multiple file formats in future and choose here?
+      roots-file: /path/to/file.txt
+    - type: empty
+      roots-url: https://example.org/blocklist.txt
+      refresh: 1d
+      # Is it a separate ruleset?  Optionally?  Persistence?
+      # (probably the same questions for local files as well)
+
+    - type: redirect
+      roots: [ sub4.example.org ]
+      addresses: [ 127.0.0.1, ::1 ]
+
+local-data-tagged: # TODO: name (view?); and even structure seems unclear.
+  # TODO: allow only one "type" per list entry?  (addresses / addresses-files / subtrees / ...)
+  - tags: [ t1, t2 ]
+    addresses: #... otherwise the same as local-data
+  - tags: [ t2 ]
+    records: # ...
+  - tags: [ t3 ]
+    subtrees: empty
+    roots: [ sub2.example.org ]
+
+local-data-tagged: # this avoids lists, so it's relatively easy to amend through API
+  "t1 t2": # perhaps it's not nice that tags don't form a proper list?
+    addresses:
+      foo.bar: [ 127.0.0.1, ::1 ]
+  t4:
+    addresses:
+      foo.bar: [ 127.0.0.1, ::1 ]
+local-data: # avoids lists and merges into the untagged `local-data` config subtree
+  tagged:   # (getting quite deep, though)
+    t1 t2:
+      addresses:
+        foo.bar: [ 127.0.0.1, ::1 ]
+# or even this ugly thing:
+local-data-tagged t1 t2:
+  addresses:
+    foo.bar: [ 127.0.0.1, ::1 ]
+
+forward: # TODO: "name" is from Unbound, but @vcunat would prefer "subtree" or something.
+  - name: '.' # Root is the default so could be omitted?
+    servers: [2001:148f:fffe::1, 2001:148f:ffff::1, 185.43.135.1, 193.14.47.1]
+  # TLS forward, server authenticated using hostname and system-wide CA certificates
+  # https://knot-resolver.readthedocs.io/en/stable/modules-policy.html?highlight=forward#tls-examples
+  - name: '.'
+    servers:
+      - address: [ 192.0.2.1, 192.0.2.2@5353 ]
+        transport: tls
+        pin-sha256: Wg==
+      - address: 2001:DB8::d0c
+        transport: tls
+        hostname: res.example.com
+        ca-file: /etc/knot-resolver/tlsca.crt
+    options:
+      # LATER: allow a subset of options here, per sub-tree?
+      # Though that's not necessarily related to forwarding (e.g. TTL limits),
+      # especially implementation-wise it probably won't matter.
+
+
+# Too confusing approach, I suppose?  Different from usual way of thinking but closer to internal model.
+# Down-sides:
+#   - multiple rules for the same name won't be possible (future, with different tags)
+#   - loading names from a file won't be possible (or URL, etc.)
+rules:
+  example.org: &fwd_odvr
+    type: forward
+    servers: [2001:148f:fffe::1, 2001:148f:ffff::1, 185.43.135.1, 193.14.47.1]
+  sub2.example.org:
+    type: empty
+    tags: [ t3, t5 ]
+  sub3.example.org:
+    type: forward-auth
+    dnssec: no
+
-- 
GitLab