diff --git a/hieradata/roles/infra/dns/externaldns.eyaml b/hieradata/roles/infra/dns/externaldns.eyaml new file mode 100644 index 0000000..4181982 --- /dev/null +++ b/hieradata/roles/infra/dns/externaldns.eyaml @@ -0,0 +1,2 @@ +--- +externaldns::externaldns_key_secret: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEABqbZiK1NDTU+w2k7orz2HrB0EXwun7hn4pR6TeCHMp2IfrkPxlQT+f1J9c0PqJaAKvnyz+Cx0xNCrlnONqk+J57f48kYKYV+Vw+L0AYHYFj8/TizY5CwLpJS2XKyfRd4iEsWMonvfIYn71t3+YuXm4dkoEqGekW93qCr/KFtjAu0K3e+ypyl4EJqWokiUs7IbcSBNvrjUkP4yR8F/wHVKM1E5yfr+D1+nmMmt7Ob/J+am14492TppE2C7Xadg4us+kdYtuBsv9kTSi1GwwqUDjbeJVmfK3pKHjXdF+PI07AFLzo5bBZTJOzQfQ4SywpH8R5BDQoUCyHiaskB5wrmSDBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBB2LU9ZhefSg9PqqkwnfV65gDBvXuXco0moKCGjHqm5KcojWCK1BoS/+mltlr8kw9grZjN9jxHRLn1FjgBlq418c8w=] diff --git a/hieradata/roles/infra/dns/externaldns.yaml b/hieradata/roles/infra/dns/externaldns.yaml new file mode 100644 index 0000000..33e2652 --- /dev/null +++ b/hieradata/roles/infra/dns/externaldns.yaml @@ -0,0 +1,12 @@ +--- +hiera_include: + - externaldns + +externaldns::bind_master_hostname: 'ausyd1nxvm2127.main.unkin.net' +externaldns::k8s_zones: + - 'k8s.syd1.au.unkin.net' + - '200.18.198.in-addr.arpa' +externaldns::slave_servers: + - 'ausyd1nxvm2128.main.unkin.net' + - 'ausyd1nxvm2129.main.unkin.net' +externaldns::externaldns_key_algorithm: 'hmac-sha256' diff --git a/modules/externaldns/manifests/init.pp b/modules/externaldns/manifests/init.pp new file mode 100644 index 0000000..2a08fc7 --- /dev/null +++ b/modules/externaldns/manifests/init.pp @@ -0,0 +1,15 @@ +# ExternalDNS BIND module - automatically configures master or slave +class externaldns ( + Stdlib::Fqdn $bind_master_hostname, + Array[Stdlib::Fqdn] $k8s_zones = [], + Array[Stdlib::Fqdn] $slave_servers = [], + String $externaldns_key_secret = '', + String $externaldns_key_algorithm = 'hmac-sha256', +) { + + if $trusted['certname'] == $bind_master_hostname { + include externaldns::master + } else { + include externaldns::slave + } +} \ No newline at end of file diff --git a/modules/externaldns/manifests/master.pp b/modules/externaldns/manifests/master.pp new file mode 100644 index 0000000..538119c --- /dev/null +++ b/modules/externaldns/manifests/master.pp @@ -0,0 +1,45 @@ +# ExternalDNS BIND master server class +class externaldns::master inherits externaldns { + + include bind + + # Query PuppetDB for slave server IP addresses + $slave_ips = $externaldns::slave_servers.map |$fqdn| { + puppetdb_query("inventory[facts.networking.ip] { certname = '${fqdn}' }")[0]['facts.networking.ip'] + }.filter |$ip| { $ip != undef } + + # Create TSIG key for ExternalDNS authentication + bind::key { 'externaldns-key': + algorithm => $externaldns::externaldns_key_algorithm, + secret => $externaldns::externaldns_key_secret, + } + + # Create ACL for slave servers + if !empty($slave_ips) { + bind::acl { 'dns-slaves': + addresses => $slave_ips, + } + } + + # Create master zones for each Kubernetes domain + $externaldns::k8s_zones.each |$zone| { + bind::zone { $zone: + zone_type => 'master', + dynamic => true, + allow_updates => ['key externaldns-key'], + allow_transfers => empty($slave_ips) ? { + true => [], + false => ['dns-slaves'], + }, + ns_notify => !empty($slave_ips), + also_notify => $slave_ips, + dnssec => false, + } + } + + # Create default view to include the zones + bind::view { 'externaldns': + recursion => false, + zones => $externaldns::k8s_zones, + } +} \ No newline at end of file diff --git a/modules/externaldns/manifests/slave.pp b/modules/externaldns/manifests/slave.pp new file mode 100644 index 0000000..0af7f80 --- /dev/null +++ b/modules/externaldns/manifests/slave.pp @@ -0,0 +1,36 @@ +# ExternalDNS BIND slave server class +class externaldns::slave inherits externaldns { + + include bind + + # Query PuppetDB for master server IP address + $query = "inventory[facts.networking.ip] { certname = '${externaldns::bind_master_hostname}' }" + $master_ip = puppetdb_query($query)[0]['facts.networking.ip'] + + # Create TSIG key for zone transfers (same as master) + bind::key { 'externaldns-key': + algorithm => $externaldns::externaldns_key_algorithm, + secret => $externaldns::externaldns_key_secret, + } + + # Create ACL for master server + bind::acl { 'dns-master': + addresses => [$master_ip], + } + + # Create slave zones for each Kubernetes domain + $externaldns::k8s_zones.each |$zone| { + bind::zone { $zone: + zone_type => 'slave', + masters => [$master_ip], + allow_notify => ['dns-master'], + ns_notify => false, + } + } + + # Create default view to include the zones + bind::view { 'externaldns': + recursion => false, + zones => $externaldns::k8s_zones, + } +} \ No newline at end of file diff --git a/modules/externaldns/metadata.json b/modules/externaldns/metadata.json new file mode 100644 index 0000000..7066707 --- /dev/null +++ b/modules/externaldns/metadata.json @@ -0,0 +1,38 @@ +{ + "name": "externaldns", + "version": "1.0.0", + "author": "puppet-prod", + "summary": "BIND configuration for Kubernetes ExternalDNS integration", + "license": "Apache-2.0", + "source": "", + "dependencies": [ + { + "name": "puppetlabs/stdlib", + "version_requirement": ">= 4.0.0" + }, + { + "name": "puppetlabs/concat", + "version_requirement": ">= 1.0.0" + } + ], + "operatingsystem_support": [ + { + "operatingsystem": "CentOS" + }, + { + "operatingsystem": "RedHat" + }, + { + "operatingsystem": "Ubuntu" + }, + { + "operatingsystem": "Debian" + } + ], + "requirements": [ + { + "name": "puppet", + "version_requirement": ">= 4.0.0" + } + ] +} \ No newline at end of file diff --git a/site/roles/manifests/infra/dns/externaldns.pp b/site/roles/manifests/infra/dns/externaldns.pp new file mode 100644 index 0000000..d3b630c --- /dev/null +++ b/site/roles/manifests/infra/dns/externaldns.pp @@ -0,0 +1,11 @@ +# BIND server role for ExternalDNS integration +class roles::infra::dns::externaldns { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + } else { + include profiles::defaults + include profiles::base + include externaldns + } +} \ No newline at end of file