@@ -90,6 +90,19 @@ Secretul nu se comite în repo. Dacă avem nevoie de integrare cu un manager de |
||
| 90 | 90 |
./scripts/sync_local_hosts.sh --apply --verify |
| 91 | 91 |
``` |
| 92 | 92 |
|
| 93 |
+## Convenții de nume |
|
| 94 |
+ |
|
| 95 |
+`madagascar.xdev.ro` este domeniul implicit al rețelei interne. În `config/hosts.yaml` se declară doar numele canonice/FQDN-urile necesare. |
|
| 96 |
+ |
|
| 97 |
+Pentru orice nume `*.madagascar.xdev.ro`, aplicația derivă automat aliasul scurt prin eliminarea sufixului `.madagascar.xdev.ro`. |
|
| 98 |
+ |
|
| 99 |
+Exemple: |
|
| 100 |
+ |
|
| 101 |
+- `autonas01.madagascar.xdev.ro` produce automat aliasul `autonas01` |
|
| 102 |
+- `pmx.baobab.madagascar.xdev.ro` produce automat aliasul `pmx.baobab` |
|
| 103 |
+ |
|
| 104 |
+Aliasurile derivate nu se declară separat în `hosts.yaml`. Ele apar în API, monitoring export și `local-hosts.tsv` ca nume efective. |
|
| 105 |
+ |
|
| 93 | 106 |
## Git și managementul cheilor |
| 94 | 107 |
|
| 95 | 108 |
Varianta obligatorie pentru servicii automate este să citească `config/hosts.yaml` din git, nu să depindă de HTTP neautentificat. Serviciile care sincronizează DNS, monitorizare sau inventare primesc chei dedicate, cu acces minim. |
@@ -24,9 +24,12 @@ Implementarea versionată este: |
||
| 24 | 24 |
|
| 25 | 25 |
| Fișier | Rol | |
| 26 | 26 |
|--------|-----| |
| 27 |
-| `config/local-hosts.tsv` | sursa unică pentru IP-uri, hostname-uri și aliasuri locale | |
|
| 27 |
+| `config/hosts.yaml` | registrul versionat pentru hosturi și FQDN-uri canonice | |
|
| 28 |
+| `config/local-hosts.tsv` | manifest DNS generat, cu aliasuri scurte derivate | |
|
| 28 | 29 |
| `scripts/sync_local_hosts.sh` | generează și sincronizează `/etc/hosts`, `cloaking-rules.txt` și `/ip dns static` | |
| 29 | 30 |
|
| 31 |
+`madagascar.xdev.ro` este domeniul implicit. Pentru orice nume `*.madagascar.xdev.ro`, aliasul scurt este derivat automat. De exemplu, `autonas01.madagascar.xdev.ro` publică și `autonas01`, iar `pmx.baobab.madagascar.xdev.ro` publică și `pmx.baobab`. Aliasurile derivate nu se declară separat în `config/hosts.yaml`. |
|
| 32 |
+ |
|
| 30 | 33 |
## Ierarhia surselor |
| 31 | 34 |
|
| 32 | 35 |
Când inventarele se contrazic, ordinea de încredere este: |
@@ -22,6 +22,8 @@ Secrets live outside git in `/etc/xdev/host-manager.env`. |
||
| 22 | 22 |
|
| 23 | 23 |
The web UI is OTP-protected for all registry data, downloads, exports, and writes. Automation should consume this repository through git with dedicated read-only keys, not through unauthenticated HTTP. |
| 24 | 24 |
|
| 25 |
+The default internal domain is `madagascar.xdev.ro`. Short aliases are derived automatically from FQDNs, so `autonas01.madagascar.xdev.ro` also publishes `autonas01` without declaring it separately. |
|
| 26 |
+ |
|
| 25 | 27 |
The local host CA stores private material outside git under `var/ca`. Initialize it on jumper with: |
| 26 | 28 |
|
| 27 | 29 |
```bash |
@@ -14,8 +14,6 @@ hosts: |
||
| 14 | 14 |
names: |
| 15 | 15 |
- "baobab.madagascar.xdev.ro" |
| 16 | 16 |
- "pmx.baobab.madagascar.xdev.ro" |
| 17 |
- - "baobab" |
|
| 18 |
- - "pmx.baobab" |
|
| 19 | 17 |
roles: |
| 20 | 18 |
- "proxmox" |
| 21 | 19 |
- "pmx" |
@@ -31,8 +29,6 @@ hosts: |
||
| 31 | 29 |
names: |
| 32 | 30 |
- "ebony.madagascar.xdev.ro" |
| 33 | 31 |
- "pmx.ebony.madagascar.xdev.ro" |
| 34 |
- - "ebony" |
|
| 35 |
- - "pmx.ebony" |
|
| 36 | 32 |
roles: |
| 37 | 33 |
- "proxmox" |
| 38 | 34 |
- "pmx" |
@@ -48,8 +44,6 @@ hosts: |
||
| 48 | 44 |
names: |
| 49 | 45 |
- "tapia.madagascar.xdev.ro" |
| 50 | 46 |
- "pmx.tapia.madagascar.xdev.ro" |
| 51 |
- - "tapia" |
|
| 52 |
- - "pmx.tapia" |
|
| 53 | 47 |
roles: |
| 54 | 48 |
- "proxmox" |
| 55 | 49 |
- "pmx" |
@@ -64,7 +58,6 @@ hosts: |
||
| 64 | 58 |
dns_ip: "192.168.10.21" |
| 65 | 59 |
names: |
| 66 | 60 |
- "autonas01.madagascar.xdev.ro" |
| 67 |
- - "autonas01" |
|
| 68 | 61 |
roles: |
| 69 | 62 |
- "storage" |
| 70 | 63 |
sources: |
@@ -77,7 +70,6 @@ hosts: |
||
| 77 | 70 |
dns_ip: "192.168.10.22" |
| 78 | 71 |
names: |
| 79 | 72 |
- "autonas02.madagascar.xdev.ro" |
| 80 |
- - "autonas02" |
|
| 81 | 73 |
roles: |
| 82 | 74 |
- "storage" |
| 83 | 75 |
sources: |
@@ -91,8 +83,6 @@ hosts: |
||
| 91 | 83 |
names: |
| 92 | 84 |
- "anjothibe.madagascar.xdev.ro" |
| 93 | 85 |
- "pbs.anjothibe.madagascar.xdev.ro" |
| 94 |
- - "anjothibe" |
|
| 95 |
- - "pbs.anjothibe" |
|
| 96 | 86 |
roles: |
| 97 | 87 |
- "pbs" |
| 98 | 88 |
- "backup" |
@@ -108,8 +98,6 @@ hosts: |
||
| 108 | 98 |
names: |
| 109 | 99 |
- "andrafiabe.madagascar.xdev.ro" |
| 110 | 100 |
- "pbs.andrafiabe.madagascar.xdev.ro" |
| 111 |
- - "andrafiabe" |
|
| 112 |
- - "pbs.andrafiabe" |
|
| 113 | 101 |
roles: |
| 114 | 102 |
- "pbs" |
| 115 | 103 |
- "backup" |
@@ -124,7 +112,6 @@ hosts: |
||
| 124 | 112 |
dns_ip: "192.168.2.102" |
| 125 | 113 |
names: |
| 126 | 114 |
- "mazeri.madagascar.xdev.ro" |
| 127 |
- - "mazeri" |
|
| 128 | 115 |
roles: |
| 129 | 116 |
- "service" |
| 130 | 117 |
sources: |
@@ -138,7 +125,6 @@ hosts: |
||
| 138 | 125 |
dns_ip: "192.168.2.103" |
| 139 | 126 |
names: |
| 140 | 127 |
- "toltec.madagascar.xdev.ro" |
| 141 |
- - "toltec" |
|
| 142 | 128 |
roles: |
| 143 | 129 |
- "service" |
| 144 | 130 |
sources: |
@@ -152,7 +138,6 @@ hosts: |
||
| 152 | 138 |
dns_ip: "192.168.2.107" |
| 153 | 139 |
names: |
| 154 | 140 |
- "zabbix.madagascar.xdev.ro" |
| 155 |
- - "zabbix" |
|
| 156 | 141 |
roles: |
| 157 | 142 |
- "monitoring" |
| 158 | 143 |
sources: |
@@ -167,7 +152,6 @@ hosts: |
||
| 167 | 152 |
names: |
| 168 | 153 |
- "jumper.madagascar.xdev.ro" |
| 169 | 154 |
- "hosts.madagascar.xdev.ro" |
| 170 |
- - "jumper" |
|
| 171 | 155 |
roles: |
| 172 | 156 |
- "entrypoint" |
| 173 | 157 |
- "dns" |
@@ -1,24 +1,21 @@ |
||
| 1 | 1 |
# Local DNS manifest for the madagascar network. |
| 2 |
+# Generated by scripts/host_manager.pl from config/hosts.yaml. |
|
| 2 | 3 |
# |
| 3 | 4 |
# Format: |
| 4 | 5 |
# hosts_ip<TAB>dns_ip<TAB>name [aliases...] |
| 5 | 6 |
# |
| 6 |
-# hosts_ip is written to /etc/hosts on is-vpn-gw. |
|
| 7 |
-# dns_ip is written to dnscrypt-proxy cloaking rules and MikroTik static DNS. |
|
| 8 |
-# Use different values only for host-local exceptions such as jumper. |
|
| 9 |
-# |
|
| 10 | 7 |
# Priority rule: |
| 11 | 8 |
# - DHCP lease/reservation on 192.168.2.1 is canonical for LAN IP allocation. |
| 12 | 9 |
# - madagascar.json is canonical for cluster roles and service interfaces. |
| 13 | 10 |
# - This file publishes approved local DNS records derived from those sources. |
| 14 |
-192.168.10.91 192.168.10.91 baobab.madagascar.xdev.ro pmx.baobab.madagascar.xdev.ro baobab pmx.baobab |
|
| 15 |
-192.168.10.92 192.168.10.92 ebony.madagascar.xdev.ro pmx.ebony.madagascar.xdev.ro ebony pmx.ebony |
|
| 16 |
-192.168.10.93 192.168.10.93 tapia.madagascar.xdev.ro pmx.tapia.madagascar.xdev.ro tapia pmx.tapia |
|
| 11 |
+192.168.2.96 192.168.2.96 andrafiabe.madagascar.xdev.ro pbs.andrafiabe.madagascar.xdev.ro andrafiabe pbs.andrafiabe |
|
| 12 |
+192.168.2.95 192.168.2.95 anjothibe.madagascar.xdev.ro pbs.anjothibe.madagascar.xdev.ro anjothibe pbs.anjothibe |
|
| 17 | 13 |
192.168.10.21 192.168.10.21 autonas01.madagascar.xdev.ro autonas01 |
| 18 | 14 |
192.168.10.22 192.168.10.22 autonas02.madagascar.xdev.ro autonas02 |
| 19 |
-192.168.2.95 192.168.2.95 anjothibe.madagascar.xdev.ro pbs.anjothibe.madagascar.xdev.ro anjothibe pbs.anjothibe |
|
| 20 |
-192.168.2.96 192.168.2.96 andrafiabe.madagascar.xdev.ro pbs.andrafiabe.madagascar.xdev.ro andrafiabe pbs.andrafiabe |
|
| 15 |
+192.168.10.91 192.168.10.91 baobab.madagascar.xdev.ro pmx.baobab.madagascar.xdev.ro baobab pmx.baobab |
|
| 16 |
+192.168.10.92 192.168.10.92 ebony.madagascar.xdev.ro pmx.ebony.madagascar.xdev.ro ebony pmx.ebony |
|
| 17 |
+127.0.0.1 192.168.2.100 jumper.madagascar.xdev.ro hosts.madagascar.xdev.ro jumper hosts |
|
| 21 | 18 |
192.168.2.102 192.168.2.102 mazeri.madagascar.xdev.ro mazeri |
| 19 |
+192.168.10.93 192.168.10.93 tapia.madagascar.xdev.ro pmx.tapia.madagascar.xdev.ro tapia pmx.tapia |
|
| 22 | 20 |
192.168.2.103 192.168.2.103 toltec.madagascar.xdev.ro toltec |
| 23 | 21 |
192.168.2.107 192.168.2.107 zabbix.madagascar.xdev.ro zabbix |
| 24 |
-127.0.0.1 192.168.2.100 jumper.madagascar.xdev.ro hosts.madagascar.xdev.ro jumper |
|
@@ -192,11 +192,12 @@ sub save_registry {
|
||
| 192 | 192 |
sub registry_payload {
|
| 193 | 193 |
my ($registry) = @_; |
| 194 | 194 |
my $problems = analyze_hosts($registry->{hosts});
|
| 195 |
+ my @hosts = map { host_payload($_) } @{ $registry->{hosts} };
|
|
| 195 | 196 |
return {
|
| 196 | 197 |
version => $registry->{version},
|
| 197 | 198 |
updated_at => $registry->{updated_at},
|
| 198 | 199 |
policy => $registry->{policy},
|
| 199 |
- hosts => $registry->{hosts},
|
|
| 200 |
+ hosts => \@hosts, |
|
| 200 | 201 |
problems => $problems, |
| 201 | 202 |
counts => {
|
| 202 | 203 |
hosts => scalar @{ $registry->{hosts} },
|
@@ -214,7 +215,7 @@ sub upsert_host {
|
||
| 214 | 215 |
my $dns_ip = clean_scalar($payload->{dns_ip} || '');
|
| 215 | 216 |
return send_json($client, 400, { error => 'missing_ip' }) unless $hosts_ip && $dns_ip;
|
| 216 | 217 |
|
| 217 |
- my @names = clean_list($payload->{names});
|
|
| 218 |
+ my @names = remove_derived_names(clean_list($payload->{names}));
|
|
| 218 | 219 |
return send_json($client, 400, { error => 'missing_names' }) unless @names;
|
| 219 | 220 |
|
| 220 | 221 |
my $registry = load_registry(); |
@@ -271,6 +272,11 @@ sub analyze_hosts {
|
||
| 271 | 272 |
for my $name (@{ $host->{names} || [] }) {
|
| 272 | 273 |
push @problems, problem($host, 'duplicate-name', "Duplicate name $name") if $names{$name}++;
|
| 273 | 274 |
} |
| 275 |
+ my %declared = map { $_ => 1 } @{ $host->{names} || [] };
|
|
| 276 |
+ for my $derived (derived_names($host)) {
|
|
| 277 |
+ push @problems, problem($host, 'redundant-derived-name', "Name $derived is derived from madagascar.xdev.ro") |
|
| 278 |
+ if $declared{$derived};
|
|
| 279 |
+ } |
|
| 274 | 280 |
if (($host->{hosts_ip} || '') ne ($host->{dns_ip} || '') && ($host->{hosts_ip} || '') ne '127.0.0.1') {
|
| 275 | 281 |
push @problems, problem($host, 'split-ip', 'hosts_ip differs from dns_ip; check that this is intentional'); |
| 276 | 282 |
} |
@@ -278,6 +284,48 @@ sub analyze_hosts {
|
||
| 278 | 284 |
return \@problems; |
| 279 | 285 |
} |
| 280 | 286 |
|
| 287 |
+sub host_payload {
|
|
| 288 |
+ my ($host) = @_; |
|
| 289 |
+ my %copy = %$host; |
|
| 290 |
+ $copy{names} = [ effective_names($host) ];
|
|
| 291 |
+ $copy{declared_names} = [ @{ $host->{names} || [] } ];
|
|
| 292 |
+ $copy{derived_names} = [ derived_names($host) ];
|
|
| 293 |
+ return \%copy; |
|
| 294 |
+} |
|
| 295 |
+ |
|
| 296 |
+sub effective_names {
|
|
| 297 |
+ my ($host) = @_; |
|
| 298 |
+ my @names = @{ $host->{names} || [] };
|
|
| 299 |
+ push @names, derived_names($host); |
|
| 300 |
+ return unique_preserve(@names); |
|
| 301 |
+} |
|
| 302 |
+ |
|
| 303 |
+sub derived_names {
|
|
| 304 |
+ my ($host) = @_; |
|
| 305 |
+ my @derived; |
|
| 306 |
+ for my $name (@{ $host->{names} || [] }) {
|
|
| 307 |
+ next unless $name =~ /^(.+)\.madagascar\.xdev\.ro$/; |
|
| 308 |
+ push @derived, $1 if length $1; |
|
| 309 |
+ } |
|
| 310 |
+ return unique_preserve(@derived); |
|
| 311 |
+} |
|
| 312 |
+ |
|
| 313 |
+sub remove_derived_names {
|
|
| 314 |
+ my @names = @_; |
|
| 315 |
+ my %derived; |
|
| 316 |
+ for my $name (@names) {
|
|
| 317 |
+ next unless $name =~ /^(.+)\.madagascar\.xdev\.ro$/; |
|
| 318 |
+ $derived{$1} = 1;
|
|
| 319 |
+ } |
|
| 320 |
+ return grep { !$derived{$_} } @names;
|
|
| 321 |
+} |
|
| 322 |
+ |
|
| 323 |
+sub unique_preserve {
|
|
| 324 |
+ my @values = @_; |
|
| 325 |
+ my %seen; |
|
| 326 |
+ return grep { !$seen{$_}++ } @values;
|
|
| 327 |
+} |
|
| 328 |
+ |
|
| 281 | 329 |
sub problem {
|
| 282 | 330 |
my ($host, $code, $message) = @_; |
| 283 | 331 |
return { host_id => $host->{id}, code => $code, message => $message };
|
@@ -297,8 +345,9 @@ sub render_local_hosts_tsv {
|
||
| 297 | 345 |
$out .= "# - This file publishes approved local DNS records derived from those sources.\n"; |
| 298 | 346 |
for my $host (sort { $a->{id} cmp $b->{id} } @{ $registry->{hosts} }) {
|
| 299 | 347 |
next unless ($host->{status} || 'active') eq 'active';
|
| 300 |
- next unless @{ $host->{names} || [] };
|
|
| 301 |
- $out .= join("\t", $host->{hosts_ip}, $host->{dns_ip}, join(' ', @{ $host->{names} })) . "\n";
|
|
| 348 |
+ my @names = effective_names($host); |
|
| 349 |
+ next unless @names; |
|
| 350 |
+ $out .= join("\t", $host->{hosts_ip}, $host->{dns_ip}, join(' ', @names)) . "\n";
|
|
| 302 | 351 |
} |
| 303 | 352 |
return $out; |
| 304 | 353 |
} |
@@ -309,11 +358,14 @@ sub render_monitoring {
|
||
| 309 | 358 |
for my $host (sort { $a->{id} cmp $b->{id} } @{ $registry->{hosts} }) {
|
| 310 | 359 |
next unless ($host->{status} || 'active') eq 'active';
|
| 311 | 360 |
next if ($host->{monitoring} || 'pending') eq 'disabled';
|
| 361 |
+ my @names = effective_names($host); |
|
| 312 | 362 |
push @hosts, {
|
| 313 | 363 |
id => $host->{id},
|
| 314 |
- primary_name => $host->{names}[0],
|
|
| 364 |
+ primary_name => $names[0], |
|
| 315 | 365 |
address => $host->{dns_ip},
|
| 316 |
- aliases => [ @{ $host->{names} || [] } ],
|
|
| 366 |
+ aliases => \@names, |
|
| 367 |
+ declared_names => [ @{ $host->{names} || [] } ],
|
|
| 368 |
+ derived_names => [ derived_names($host) ], |
|
| 317 | 369 |
roles => [ @{ $host->{roles} || [] } ],
|
| 318 | 370 |
monitoring => $host->{monitoring} || 'pending',
|
| 319 | 371 |
notes => $host->{notes} || '',
|