Merge pull request 'PowerDNS instead of bind9' (#2) from kunsi-feature-powerdns-instead-of-bind into main
All checks were successful
bundlewrap/pipeline/head This commit looks good
All checks were successful
bundlewrap/pipeline/head This commit looks good
Reviewed-on: https://git.kunsmann.eu/kunsi/bundlewrap/pulls/2
This commit is contained in:
commit
5635571f97
35 changed files with 739 additions and 330 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
.secrets.cfg
|
.secrets.cfg
|
||||||
|
__pycache__
|
||||||
|
|
|
@ -67,10 +67,12 @@ pkg_apt = {
|
||||||
|
|
||||||
'arping': {},
|
'arping': {},
|
||||||
'at': {},
|
'at': {},
|
||||||
|
'build-essential': {},
|
||||||
'bzip2': {},
|
'bzip2': {},
|
||||||
'curl': {},
|
'curl': {},
|
||||||
'diffutils': {},
|
'diffutils': {},
|
||||||
'dnsutils': {},
|
'dnsutils': {},
|
||||||
|
'git': {},
|
||||||
'grep': {},
|
'grep': {},
|
||||||
'gzip': {},
|
'gzip': {},
|
||||||
'htop': {},
|
'htop': {},
|
||||||
|
@ -88,6 +90,7 @@ pkg_apt = {
|
||||||
'netcat': {},
|
'netcat': {},
|
||||||
'nmap': {},
|
'nmap': {},
|
||||||
'python3': {},
|
'python3': {},
|
||||||
|
'python3-dev': {},
|
||||||
'python3-pip': {},
|
'python3-pip': {},
|
||||||
'python3-virtualenv': {},
|
'python3-virtualenv': {},
|
||||||
'tar': {},
|
'tar': {},
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
% for key in keys:
|
|
||||||
key ${key['name']} {
|
|
||||||
algorithm ${key['algorithm']};
|
|
||||||
secret "${key['secret']}";
|
|
||||||
};
|
|
||||||
% endfor
|
|
|
@ -1,30 +0,0 @@
|
||||||
include "/etc/bind/keys.conf";
|
|
||||||
|
|
||||||
% for zone in sorted(primary_zones):
|
|
||||||
zone "${zone}" IN {
|
|
||||||
type master;
|
|
||||||
file "/var/lib/bind/primary/${zone}";
|
|
||||||
};
|
|
||||||
% endfor
|
|
||||||
|
|
||||||
|
|
||||||
zone "10.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
|
|
||||||
|
|
||||||
zone "16.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
|
|
||||||
zone "17.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
|
|
||||||
zone "18.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
|
|
||||||
zone "19.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
|
|
||||||
zone "20.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
|
|
||||||
zone "21.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
|
|
||||||
zone "22.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
|
|
||||||
zone "23.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
|
|
||||||
zone "24.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
|
|
||||||
zone "25.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
|
|
||||||
zone "26.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
|
|
||||||
zone "27.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
|
|
||||||
zone "28.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
|
|
||||||
zone "29.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
|
|
||||||
zone "30.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
|
|
||||||
zone "31.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
|
|
||||||
|
|
||||||
zone "168.192.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
|
|
|
@ -1,3 +0,0 @@
|
||||||
% for o in node.metadata.get('bind', {}).get('options', []):
|
|
||||||
<%include file="options/${o}"/>
|
|
||||||
% endfor
|
|
|
@ -1,146 +0,0 @@
|
||||||
from os import listdir
|
|
||||||
from os.path import isfile, join
|
|
||||||
from datetime import datetime
|
|
||||||
from subprocess import check_output
|
|
||||||
|
|
||||||
ZONE_HEADER = """
|
|
||||||
; _ ____ _ _ _____ _ _ _ _ ____
|
|
||||||
; / \\ / ___| | | |_ _| | | | \\ | |/ ___|
|
|
||||||
; / _ \\| | | |_| | | | | | | | \\| | | _
|
|
||||||
; / ___ \\ |___| _ | | | | |_| | |\\ | |_| |
|
|
||||||
; /_/ \\_\\____|_| |_| |_| \\___/|_| \\_|\\____|
|
|
||||||
;
|
|
||||||
; --> Diese Datei wird von BundleWrap verwaltet! <--
|
|
||||||
|
|
||||||
$TTL 60
|
|
||||||
@ IN SOA ns-1.kunbox.net. hostmaster.kunbox.net. (
|
|
||||||
{serial}
|
|
||||||
3600
|
|
||||||
3600
|
|
||||||
86400
|
|
||||||
300
|
|
||||||
)
|
|
||||||
@ IN NS bind01.gce.kunbox.net.
|
|
||||||
IN NS b.ns14.net.
|
|
||||||
IN NS c.ns14.net.
|
|
||||||
IN NS d.ns14.net.
|
|
||||||
"""
|
|
||||||
|
|
||||||
svc_systemd = {
|
|
||||||
'bind9': {
|
|
||||||
'needs': {
|
|
||||||
'pkg_apt:bind9',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
pkg_apt = {
|
|
||||||
'bind9': {},
|
|
||||||
}
|
|
||||||
|
|
||||||
directories = {
|
|
||||||
"/var/lib/bind/primary": {
|
|
||||||
'group': 'bind',
|
|
||||||
'needs': {
|
|
||||||
'pkg_apt:bind9',
|
|
||||||
},
|
|
||||||
'owner': 'bind',
|
|
||||||
'purge': True,
|
|
||||||
},
|
|
||||||
"/var/log/named": {
|
|
||||||
'group': 'bind',
|
|
||||||
'needs': {
|
|
||||||
'pkg_apt:bind9',
|
|
||||||
},
|
|
||||||
'owner': 'bind',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
files = {
|
|
||||||
"/etc/bind/keys.conf": {
|
|
||||||
'content_type': 'mako',
|
|
||||||
'group': 'bind',
|
|
||||||
'mode': '0440',
|
|
||||||
'context': {
|
|
||||||
'keys': node.metadata.get('bind', {}).get('keys', []),
|
|
||||||
},
|
|
||||||
'triggers': {
|
|
||||||
'svc_systemd:bind9:reload',
|
|
||||||
},
|
|
||||||
'needs': {
|
|
||||||
'pkg_apt:bind9',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"/etc/bind/named.conf.options": {
|
|
||||||
'content_type': 'mako',
|
|
||||||
'group': 'bind',
|
|
||||||
'mode': '0440',
|
|
||||||
'triggers': {
|
|
||||||
'svc_systemd:bind9:reload',
|
|
||||||
},
|
|
||||||
'needs': {
|
|
||||||
'pkg_apt:bind9',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if node.metadata.get('bind', {}).get('rndc', ''):
|
|
||||||
files['/etc/bind/rndc.conf'] = {
|
|
||||||
'mode': '0440',
|
|
||||||
'source': 'rndc/{}'.format(node.metadata['bind']['rndc']),
|
|
||||||
'content_type': 'mako',
|
|
||||||
'triggers': {
|
|
||||||
'svc_systemd:bind9:reload',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
# this looks for zones either directly at data/bind/zones/ or in a subdirectory if so configured
|
|
||||||
zone_path = join(
|
|
||||||
repo.path,
|
|
||||||
'data', 'bind', 'files', 'zones',
|
|
||||||
node.metadata.get('bind', {}).get('zone_path', ""),
|
|
||||||
)
|
|
||||||
|
|
||||||
primary_zones = set()
|
|
||||||
|
|
||||||
for zone in listdir(zone_path):
|
|
||||||
if not isfile(join(zone_path, zone)) or zone.startswith(".") or zone.startswith("_"):
|
|
||||||
continue
|
|
||||||
|
|
||||||
output = check_output(['git', 'log', '-1', '--pretty=%ci', join(zone_path, zone)]).decode('utf-8').strip()
|
|
||||||
serial = datetime.strptime(output, '%Y-%m-%d %H:%M:%S %z').strftime('%y%m%d%H%M')
|
|
||||||
|
|
||||||
primary_zones.add(zone)
|
|
||||||
|
|
||||||
files["/var/lib/bind/primary/{}".format(zone)] = {
|
|
||||||
'content_type': 'mako',
|
|
||||||
'context': {
|
|
||||||
'header': ZONE_HEADER.format(serial=serial),
|
|
||||||
'metadata_records': node.metadata.get('bind', {}).get('zones_primary', {}).get(zone, {}).get('records', []),
|
|
||||||
},
|
|
||||||
'mode': '0444',
|
|
||||||
'owner': 'bind',
|
|
||||||
'source': 'zones/{}'.format(join(node.metadata.get('bind', {}).get('zone_path', ""), zone)),
|
|
||||||
'triggers': {
|
|
||||||
'svc_systemd:bind9:reload',
|
|
||||||
},
|
|
||||||
'needs': {
|
|
||||||
'pkg_apt:bind9'
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
primary_zones.union(set(node.metadata.get('bind', {}).get('zones_primary', {}).keys()))
|
|
||||||
|
|
||||||
files['/etc/bind/named.conf.local'] = {
|
|
||||||
'content_type': 'mako',
|
|
||||||
'context': {
|
|
||||||
'primary_zones': list(primary_zones),
|
|
||||||
},
|
|
||||||
'group': 'bind',
|
|
||||||
'triggers': {
|
|
||||||
'svc_systemd:bind9:reload',
|
|
||||||
},
|
|
||||||
'needs': {
|
|
||||||
'pkg_apt:bind9',
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
from bundlewrap.metadata import atomic
|
|
||||||
|
|
||||||
|
|
||||||
defaults = {
|
|
||||||
'icinga2_api': {
|
|
||||||
'bind': {
|
|
||||||
'services': {
|
|
||||||
'BIND PROCESS': {
|
|
||||||
'command_on_monitored_host': '/usr/lib/nagios/plugins/check_procs -C named -c 1:1',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
@metadata_reactor
|
|
||||||
def port_checks(metadata):
|
|
||||||
services = {}
|
|
||||||
|
|
||||||
for interface in metadata.get('bind/listen', set()):
|
|
||||||
services[f'BIND PORT {interface}'] = {
|
|
||||||
'check_command': 'tcp',
|
|
||||||
'vars.tcp_address': metadata.get(f'interfaces/{interface}/ip_addresses')[0],
|
|
||||||
'vars.tcp_port': 53,
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
'icinga2_api': {
|
|
||||||
'bind': {
|
|
||||||
'services': services,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
@metadata_reactor
|
|
||||||
def generate_dns_entries_for_nodes(metadata):
|
|
||||||
results = set()
|
|
||||||
|
|
||||||
for rnode in repo.nodes:
|
|
||||||
node_name_split = rnode.name.split('.')
|
|
||||||
node_name_split.reverse()
|
|
||||||
dns_name = '.'.join(node_name_split)
|
|
||||||
ip4 = None
|
|
||||||
ip6 = None
|
|
||||||
|
|
||||||
# We only need this for GCE, because machines over there don't
|
|
||||||
# have a public ipv4 address.
|
|
||||||
if rnode.metadata.get('external_ipv4', None):
|
|
||||||
ip4 = rnode.metadata.get('external_ipv4')
|
|
||||||
|
|
||||||
for iface, config in sorted(rnode.metadata.get('interfaces', {}).items()):
|
|
||||||
if not ip4 and 'ipv4' in config:
|
|
||||||
ip4 = sorted(config['ipv4'])[0]
|
|
||||||
|
|
||||||
if not ip6 and 'ipv6' in config:
|
|
||||||
ip6 = sorted(config['ipv6'])[0]
|
|
||||||
|
|
||||||
if ip4:
|
|
||||||
results.add('{} IN A {}'.format(dns_name, ip4))
|
|
||||||
|
|
||||||
if ip6:
|
|
||||||
results.add('{} IN AAAA {}'.format(dns_name, ip6))
|
|
||||||
|
|
||||||
return {
|
|
||||||
'bind': {
|
|
||||||
'zones_primary': {
|
|
||||||
'kunbox.net': {
|
|
||||||
'records': results,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,6 +1,7 @@
|
||||||
pkg_apt = {
|
pkg_apt = {
|
||||||
'postgresql-11': {},
|
'postgresql-11': {},
|
||||||
'postgresql-client-11': {},
|
'postgresql-client-11': {},
|
||||||
|
'postgresql-server-dev-11': {},
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.has_bundle('zfs'):
|
if node.has_bundle('zfs'):
|
||||||
|
|
2
bundles/powerdns/files/bind.conf
Normal file
2
bundles/powerdns/files/bind.conf
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
launch+=bind
|
||||||
|
bind-config=/etc/powerdns/named.conf
|
6
bundles/powerdns/files/named.conf
Normal file
6
bundles/powerdns/files/named.conf
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
% for zone in sorted(zones):
|
||||||
|
zone "${zone}" {
|
||||||
|
file "/var/lib/powerdns/zones/${zone}";
|
||||||
|
type native;
|
||||||
|
};
|
||||||
|
% endfor
|
28
bundles/powerdns/files/pdns.conf
Normal file
28
bundles/powerdns/files/pdns.conf
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
launch=
|
||||||
|
include-dir=/etc/powerdns/pdns.d
|
||||||
|
|
||||||
|
api=yes
|
||||||
|
api-key=${api_key}
|
||||||
|
webserver=yes
|
||||||
|
|
||||||
|
disable-syslog=yes
|
||||||
|
log-timestamp=no
|
||||||
|
|
||||||
|
max-tcp-connections=500
|
||||||
|
max-tcp-connections-per-client=10
|
||||||
|
|
||||||
|
security-poll-suffix=
|
||||||
|
|
||||||
|
server-id=${my_hostname}
|
||||||
|
|
||||||
|
default-ttl=60
|
||||||
|
|
||||||
|
% if is_secondary:
|
||||||
|
# Primary servers: ${', '.join(sorted(my_primary_servers['nodes']))}
|
||||||
|
slave=yes
|
||||||
|
superslave=yes
|
||||||
|
allow-notify-from=${','.join(sorted(my_primary_servers['ips']))}
|
||||||
|
% else:
|
||||||
|
allow-notify-from=
|
||||||
|
master=yes
|
||||||
|
% endif
|
6
bundles/powerdns/files/pgsql.conf
Normal file
6
bundles/powerdns/files/pgsql.conf
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
launch+=gpgsql
|
||||||
|
gpgsql-host=localhost
|
||||||
|
gpgsql-port=5432
|
||||||
|
gpgsql-dbname=powerdns
|
||||||
|
gpgsql-user=powerdns
|
||||||
|
gpgsql-password=${password}
|
105
bundles/powerdns/files/schema.pgsql.sql
Normal file
105
bundles/powerdns/files/schema.pgsql.sql
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
-- 4.3 schema, https://doc.powerdns.com/authoritative/backends/generic-postgresql.html
|
||||||
|
|
||||||
|
CREATE TABLE domains (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
master VARCHAR(128) DEFAULT NULL,
|
||||||
|
last_check INT DEFAULT NULL,
|
||||||
|
type VARCHAR(6) NOT NULL,
|
||||||
|
notified_serial BIGINT DEFAULT NULL,
|
||||||
|
account VARCHAR(40) DEFAULT NULL,
|
||||||
|
CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX name_index ON domains(name);
|
||||||
|
|
||||||
|
ALTER TABLE domains OWNER TO ${user};
|
||||||
|
|
||||||
|
CREATE TABLE records (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
domain_id INT DEFAULT NULL,
|
||||||
|
name VARCHAR(255) DEFAULT NULL,
|
||||||
|
type VARCHAR(10) DEFAULT NULL,
|
||||||
|
content VARCHAR(65535) DEFAULT NULL,
|
||||||
|
ttl INT DEFAULT NULL,
|
||||||
|
prio INT DEFAULT NULL,
|
||||||
|
change_date INT DEFAULT NULL,
|
||||||
|
disabled BOOL DEFAULT 'f',
|
||||||
|
ordername VARCHAR(255),
|
||||||
|
auth BOOL DEFAULT 't',
|
||||||
|
CONSTRAINT domain_exists
|
||||||
|
FOREIGN KEY(domain_id) REFERENCES domains(id)
|
||||||
|
ON DELETE CASCADE,
|
||||||
|
CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX rec_name_index ON records(name);
|
||||||
|
CREATE INDEX nametype_index ON records(name,type);
|
||||||
|
CREATE INDEX domain_id ON records(domain_id);
|
||||||
|
CREATE INDEX recordorder ON records (domain_id, ordername text_pattern_ops);
|
||||||
|
|
||||||
|
ALTER TABLE records OWNER TO ${user};
|
||||||
|
|
||||||
|
CREATE TABLE supermasters (
|
||||||
|
ip INET NOT NULL,
|
||||||
|
nameserver VARCHAR(255) NOT NULL,
|
||||||
|
account VARCHAR(40) NOT NULL,
|
||||||
|
PRIMARY KEY(ip, nameserver)
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE supermasters OWNER TO ${user};
|
||||||
|
|
||||||
|
CREATE TABLE comments (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
domain_id INT NOT NULL,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
type VARCHAR(10) NOT NULL,
|
||||||
|
modified_at INT NOT NULL,
|
||||||
|
account VARCHAR(40) DEFAULT NULL,
|
||||||
|
comment VARCHAR(65535) NOT NULL,
|
||||||
|
CONSTRAINT domain_exists
|
||||||
|
FOREIGN KEY(domain_id) REFERENCES domains(id)
|
||||||
|
ON DELETE CASCADE,
|
||||||
|
CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX comments_domain_id_idx ON comments (domain_id);
|
||||||
|
CREATE INDEX comments_name_type_idx ON comments (name, type);
|
||||||
|
CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
|
||||||
|
|
||||||
|
ALTER TABLE comments OWNER TO ${user};
|
||||||
|
|
||||||
|
CREATE TABLE domainmetadata (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
domain_id INT REFERENCES domains(id) ON DELETE CASCADE,
|
||||||
|
kind VARCHAR(32),
|
||||||
|
content TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX domainidmetaindex ON domainmetadata(domain_id);
|
||||||
|
|
||||||
|
ALTER TABLE domainmetadata OWNER TO ${user};
|
||||||
|
|
||||||
|
CREATE TABLE cryptokeys (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
domain_id INT REFERENCES domains(id) ON DELETE CASCADE,
|
||||||
|
flags INT NOT NULL,
|
||||||
|
active BOOL,
|
||||||
|
content TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX domainidindex ON cryptokeys(domain_id);
|
||||||
|
ALTER TABLE cryptokeys OWNER TO ${user};
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE tsigkeys (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name VARCHAR(255),
|
||||||
|
algorithm VARCHAR(50),
|
||||||
|
secret VARCHAR(255),
|
||||||
|
CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
|
||||||
|
|
||||||
|
ALTER TABLE tsigkeys OWNER TO ${user};
|
163
bundles/powerdns/items.py
Normal file
163
bundles/powerdns/items.py
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
from datetime import datetime
|
||||||
|
from os import listdir
|
||||||
|
from os.path import isfile, join
|
||||||
|
from subprocess import check_output
|
||||||
|
|
||||||
|
zone_path = join(repo.path, 'data', 'powerdns', 'files', 'bind-zones')
|
||||||
|
|
||||||
|
ZONE_HEADER = """
|
||||||
|
; _ ____ _ _ _____ _ _ _ _ ____
|
||||||
|
; / \\ / ___| | | |_ _| | | | \\ | |/ ___|
|
||||||
|
; / _ \\| | | |_| | | | | | | | \\| | | _
|
||||||
|
; / ___ \\ |___| _ | | | | |_| | |\\ | |_| |
|
||||||
|
; /_/ \\_\\____|_| |_| |_| \\___/|_| \\_|\\____|
|
||||||
|
;
|
||||||
|
; --> Diese Datei wird von BundleWrap verwaltet! <--
|
||||||
|
|
||||||
|
$TTL 60
|
||||||
|
@ IN SOA ns-1.kunbox.net. hostmaster.kunbox.net. (
|
||||||
|
{serial}
|
||||||
|
3600
|
||||||
|
3600
|
||||||
|
86400
|
||||||
|
300
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
for rnode in sorted(repo.nodes_in_group('dns')):
|
||||||
|
ZONE_HEADER += '@ IN NS {}.\n'.format(rnode.metadata.get('powerdns', {}).get('my_hostname', rnode.hostname))
|
||||||
|
|
||||||
|
directories = {
|
||||||
|
'/etc/powerdns/pdns.d': {
|
||||||
|
'purge': True,
|
||||||
|
'needs': {
|
||||||
|
'pkg_apt:pdns-server',
|
||||||
|
'pkg_apt:pdns-backend-bind',
|
||||||
|
'pkg_apt:pdns-backend-pgsql',
|
||||||
|
},
|
||||||
|
'triggers': {
|
||||||
|
'svc_systemd:pdns:restart',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'/var/lib/powerdns/zones': {
|
||||||
|
'purge': True,
|
||||||
|
'needs': {
|
||||||
|
'pkg_apt:pdns-backend-bind',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
files = {
|
||||||
|
'/etc/powerdns/pdns.conf': {
|
||||||
|
'content_type': 'mako',
|
||||||
|
'context': {
|
||||||
|
'api_key': node.metadata['powerdns']['api_key'],
|
||||||
|
'my_hostname': node.metadata['powerdns'].get('my_hostname', node.name),
|
||||||
|
'is_secondary': node.metadata['powerdns'].get('is_secondary', False),
|
||||||
|
'my_primary_servers': node.metadata['powerdns'].get('my_primary_servers', {}),
|
||||||
|
},
|
||||||
|
'needs': {
|
||||||
|
'pkg_apt:pdns-server',
|
||||||
|
},
|
||||||
|
'triggers': {
|
||||||
|
'svc_systemd:pdns:restart',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
svc_systemd = {
|
||||||
|
'pdns': {
|
||||||
|
'needs': {
|
||||||
|
'directory:',
|
||||||
|
'file:',
|
||||||
|
'pkg_apt:pdns-server',
|
||||||
|
'pkg_apt:pdns-backend-bind',
|
||||||
|
'pkg_apt:pdns-backend-pgsql',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
actions = {
|
||||||
|
'powerdns_reload_zones': {
|
||||||
|
'triggered': True,
|
||||||
|
'command': 'pdns_control rediscover; pdns_control reload',
|
||||||
|
'needs': {
|
||||||
|
'svc_systemd:pdns',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.metadata['powerdns'].get('features', {}).get('bind', False):
|
||||||
|
primary_zones = set()
|
||||||
|
for zone in listdir(zone_path):
|
||||||
|
if not isfile(join(zone_path, zone)) or zone.startswith(".") or zone.startswith("_"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
output = check_output(['git', 'log', '-1', '--pretty=%ci', join(zone_path, zone)]).decode('utf-8').strip()
|
||||||
|
serial = datetime.strptime(output, '%Y-%m-%d %H:%M:%S %z').strftime('%y%m%d%H%M')
|
||||||
|
except:
|
||||||
|
serial = datetime.now().strftime('%y%m%d0000')
|
||||||
|
|
||||||
|
primary_zones.add(zone)
|
||||||
|
|
||||||
|
files["/var/lib/powerdns/zones/{}".format(zone)] = {
|
||||||
|
'content_type': 'mako',
|
||||||
|
'context': {
|
||||||
|
'header': ZONE_HEADER.format(serial=serial),
|
||||||
|
'metadata_records': node.metadata.get('powerdns', {}).get('bind-zones', {}).get(zone, {}).get('records', []),
|
||||||
|
},
|
||||||
|
'source': 'bind-zones/{}'.format(zone),
|
||||||
|
'triggers': {
|
||||||
|
'action:powerdns_reload_zones',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
files['/etc/powerdns/pdns.d/bind.conf'] = {
|
||||||
|
'needs': {
|
||||||
|
'pkg_apt:pdns-backend-bind',
|
||||||
|
},
|
||||||
|
'triggers': {
|
||||||
|
'action:powerdns_reload_zones',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
files['/etc/powerdns/named.conf'] = {
|
||||||
|
'content_type': 'mako',
|
||||||
|
'context': {
|
||||||
|
'zones': primary_zones,
|
||||||
|
},
|
||||||
|
'needs': {
|
||||||
|
'pkg_apt:pdns-backend-bind',
|
||||||
|
},
|
||||||
|
'triggers': {
|
||||||
|
'action:powerdns_reload_zones',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.metadata['powerdns'].get('features', {}).get('pgsql', False):
|
||||||
|
files['/etc/powerdns/pdns.d/pgsql.conf'] = {
|
||||||
|
'content_type': 'mako',
|
||||||
|
'context': {
|
||||||
|
'password': node.metadata['postgresql']['users']['powerdns']['password'],
|
||||||
|
},
|
||||||
|
'needs': {
|
||||||
|
'pkg_apt:pdns-backend-pgsql',
|
||||||
|
},
|
||||||
|
'triggers': {
|
||||||
|
'action:powerdns_reload_zones',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
files['/etc/powerdns/schema.pgsql.sql'] = {}
|
||||||
|
|
||||||
|
actions['powerdns_load_pgsql_schema'] = {
|
||||||
|
'command': node.metadata['postgresql']['users']['powerdns']['password'].format_into('PGPASSWORD={} psql -h 127.0.0.1 -d powerdns -U powerdns -w < /etc/powerdns/schema.pgsql.sql'),
|
||||||
|
'unless': 'sudo -u postgres psql -d powerdns -c "\dt" | grep domains 2>&1 >/dev/null',
|
||||||
|
'needs': {
|
||||||
|
'bundle:postgresql',
|
||||||
|
'file:/etc/powerdns/schema.pgsql.sql',
|
||||||
|
},
|
||||||
|
'needed_by': {
|
||||||
|
'svc_systemd:pdns',
|
||||||
|
},
|
||||||
|
}
|
91
bundles/powerdns/metadata.py
Normal file
91
bundles/powerdns/metadata.py
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
from bundlewrap.exceptions import NoSuchGroup
|
||||||
|
|
||||||
|
defaults = {
|
||||||
|
'apt': {
|
||||||
|
'packages': {
|
||||||
|
'pdns-server': {},
|
||||||
|
'pdns-tools': {},
|
||||||
|
'pdns-backend-bind': {},
|
||||||
|
'pdns-backend-pgsql': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'powerdns': {
|
||||||
|
'api_key': repo.vault.password_for('{} powerdns api'.format(node.name)),
|
||||||
|
},
|
||||||
|
'postgresql': {
|
||||||
|
'users': {
|
||||||
|
'powerdns': {
|
||||||
|
'password': repo.vault.password_for('{} postgresql powerdns'.format(node.name)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'databases': {
|
||||||
|
'powerdns': {
|
||||||
|
'owner': 'powerdns',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor
|
||||||
|
def get_ips_of_primary_nameservers(metadata):
|
||||||
|
if not metadata.get('powerdns/is_secondary', False):
|
||||||
|
return {}
|
||||||
|
|
||||||
|
ips = set()
|
||||||
|
nodes = set()
|
||||||
|
for rnode in repo.nodes_in_group('dns'):
|
||||||
|
if not rnode.metadata.get('powerdns/is_secondary', False):
|
||||||
|
ips.update({
|
||||||
|
str(ip) for ip in repo.libs.tools.resolve_identifier(repo, rnode.name)
|
||||||
|
})
|
||||||
|
nodes.add(rnode.name)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'powerdns': {
|
||||||
|
'my_primary_servers': {
|
||||||
|
'ips': ips,
|
||||||
|
'nodes': nodes,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor
|
||||||
|
def generate_dns_entries_for_nodes(metadata):
|
||||||
|
results = set()
|
||||||
|
|
||||||
|
for rnode in repo.nodes:
|
||||||
|
node_name_split = rnode.name.split('.')
|
||||||
|
node_name_split.reverse()
|
||||||
|
dns_name = '.'.join(node_name_split)
|
||||||
|
ip4 = None
|
||||||
|
ip6 = None
|
||||||
|
|
||||||
|
# We only need this for GCE, because machines over there don't
|
||||||
|
# have a public ipv4 address.
|
||||||
|
if rnode.metadata.get('external_ipv4', None):
|
||||||
|
ip4 = rnode.metadata.get('external_ipv4')
|
||||||
|
|
||||||
|
for iface, config in sorted(rnode.metadata.get('interfaces', {}).items()):
|
||||||
|
if not ip4 and 'ipv4' in config:
|
||||||
|
ip4 = sorted(config['ipv4'])[0]
|
||||||
|
|
||||||
|
if not ip6 and 'ipv6' in config:
|
||||||
|
ip6 = sorted(config['ipv6'])[0]
|
||||||
|
|
||||||
|
if ip4:
|
||||||
|
results.add('{} IN A {}'.format(dns_name, ip4))
|
||||||
|
|
||||||
|
if ip6:
|
||||||
|
results.add('{} IN AAAA {}'.format(dns_name, ip6))
|
||||||
|
|
||||||
|
return {
|
||||||
|
'powerdns': {
|
||||||
|
'bind-zones': {
|
||||||
|
'kunbox.net': {
|
||||||
|
'records': results,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
14
bundles/powerdnsadmin/files/config.py
Normal file
14
bundles/powerdnsadmin/files/config.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
SALT = '${repo.vault.decrypt('encrypt$gAAAAABfidFVqVEgWvlXgP-GSQUgVtcTxzoZx2G8VYWHaGKRpgaLDchlTRcKwqgvfG5orNpXt7aDd5i2aehi6cvIlxYNdL87twfVhDLBDho8j-Uz5Vga8-9cEzEZULl5pFCIcRlYUCKyEIOcdXSaLCM3p8pGjrh-O8_g49rbADKmLFoJx2vVTVs=')}'
|
||||||
|
SECRET_KEY = '${repo.vault.password_for('{} powerdnsadmin secret_key'.format(node.name))}'
|
||||||
|
BIND_ADDRESS = '127.0.0.1'
|
||||||
|
PORT = 9191
|
||||||
|
OFFLINE_MODE = True
|
||||||
|
|
||||||
|
SQLA_DB_USER = 'powerdnsadmin'
|
||||||
|
SQLA_DB_PASSWORD = '${node.metadata['postgresql']['users']['powerdnsadmin']['password']}'
|
||||||
|
SQLA_DB_HOST = '127.0.0.1'
|
||||||
|
SQLA_DB_NAME = 'powerdnsadmin'
|
||||||
|
SQLALCHEMY_TRACK_MODIFICATIONS = True
|
||||||
|
SQLALCHEMY_DATABASE_URI = 'postgresql://' + SQLA_DB_USER + ':' + SQLA_DB_PASSWORD + '@' + SQLA_DB_HOST + '/' + SQLA_DB_NAME
|
||||||
|
|
||||||
|
SAML_ENABLED = False
|
14
bundles/powerdnsadmin/files/powerdnsadmin.service
Normal file
14
bundles/powerdnsadmin/files/powerdnsadmin.service
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
[Unit]
|
||||||
|
Description=PowerDNS-Admin
|
||||||
|
After=network.target postgresql.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=powerdnsadmin
|
||||||
|
Group=powerdnsadmin
|
||||||
|
Environment=FLASK_CONF=/opt/powerdnsadmin/config.py
|
||||||
|
WorkingDirectory=/opt/powerdnsadmin/src
|
||||||
|
ExecStartPre=-/bin/chown powerdnsadmin:powerdnsadmin /opt/powerdnsadmin/src/powerdnsadmin/static
|
||||||
|
ExecStart=/opt/powerdnsadmin/venv/bin/gunicorn 'powerdnsadmin:create_app()'
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
87
bundles/powerdnsadmin/items.py
Normal file
87
bundles/powerdnsadmin/items.py
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
assert node.has_bundle('nodejs')
|
||||||
|
assert node.has_bundle('postgresql')
|
||||||
|
|
||||||
|
directories = {
|
||||||
|
'/opt/powerdnsadmin/src': {},
|
||||||
|
}
|
||||||
|
|
||||||
|
git_deploy = {
|
||||||
|
'/opt/powerdnsadmin/src': {
|
||||||
|
'repo': 'https://github.com/ngoduykhanh/PowerDNS-Admin.git',
|
||||||
|
'rev': 'master',
|
||||||
|
'triggers': {
|
||||||
|
'action:powerdnsadmin_install_deps',
|
||||||
|
'action:powerdnsadmin_upgrade_database',
|
||||||
|
'action:powerdnsadmin_compile_assets',
|
||||||
|
'svc_systemd:powerdnsadmin:restart',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
files = {
|
||||||
|
'/opt/powerdnsadmin/config.py': {
|
||||||
|
'content_type': 'mako',
|
||||||
|
},
|
||||||
|
'/etc/systemd/system/powerdnsadmin.service': {
|
||||||
|
'triggers': {
|
||||||
|
'action:systemd-reload',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
actions = {
|
||||||
|
'powerdnsadmin_create_virtualenv': {
|
||||||
|
'command': '/usr/bin/python3 -m virtualenv -p python3 /opt/powerdnsadmin/venv/',
|
||||||
|
'unless': 'test -d /opt/powerdnsadmin/venv/',
|
||||||
|
'needs': {
|
||||||
|
'directory:/opt/powerdnsadmin', # provided by bundle:users
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'powerdnsadmin_install_deps': {
|
||||||
|
'triggered': True,
|
||||||
|
'command': '/opt/powerdnsadmin/venv/bin/pip install -r /opt/powerdnsadmin/src/requirements.txt',
|
||||||
|
'needs': {
|
||||||
|
'action:powerdnsadmin_create_virtualenv',
|
||||||
|
'pkg_apt:',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'powerdnsadmin_install_deps': {
|
||||||
|
'triggered': True,
|
||||||
|
'command': '/opt/powerdnsadmin/venv/bin/pip install -r /opt/powerdnsadmin/src/requirements.txt',
|
||||||
|
'needs': {
|
||||||
|
'action:powerdnsadmin_create_virtualenv',
|
||||||
|
'pkg_apt:',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'powerdnsadmin_upgrade_database': {
|
||||||
|
'triggered': True,
|
||||||
|
'command': 'FLASK_CONF=/opt/powerdnsadmin/config.py FLASK_APP=/opt/powerdnsadmin/src/powerdnsadmin/__init__.py /opt/powerdnsadmin/venv/bin/flask db upgrade',
|
||||||
|
# TODO unless
|
||||||
|
'needs': {
|
||||||
|
'action:powerdnsadmin_install_deps',
|
||||||
|
'bundle:postgresql',
|
||||||
|
'pkg_apt:',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'powerdnsadmin_compile_assets': {
|
||||||
|
'triggered': True,
|
||||||
|
'command': 'cd /opt/powerdnsadmin/src && yarn install --pure-lockfile && FLASK_APP=/opt/powerdnsadmin/src/powerdnsadmin/__init__.py /opt/powerdnsadmin/venv/bin/flask assets build',
|
||||||
|
'needs': {
|
||||||
|
'action:powerdnsadmin_install_deps',
|
||||||
|
'pkg_apt:',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
svc_systemd = {
|
||||||
|
'powerdnsadmin': {
|
||||||
|
'needs': {
|
||||||
|
'file:/opt/powerdnsadmin/config.py',
|
||||||
|
'file:/etc/systemd/system/powerdnsadmin.service',
|
||||||
|
'git_deploy:/opt/powerdnsadmin/src',
|
||||||
|
'action:powerdnsadmin_install_deps',
|
||||||
|
'action:powerdnsadmin_upgrade_database',
|
||||||
|
'action:powerdnsadmin_compile_assets',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
35
bundles/powerdnsadmin/metadata.py
Normal file
35
bundles/powerdnsadmin/metadata.py
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
defaults = {
|
||||||
|
'apt': {
|
||||||
|
'packages': {
|
||||||
|
'default-libmysqlclient-dev': {},
|
||||||
|
'libffi-dev': {},
|
||||||
|
'libldap2-dev': {},
|
||||||
|
'libsasl2-dev': {},
|
||||||
|
'libssl-dev': {},
|
||||||
|
'libxml2-dev': {},
|
||||||
|
'libxmlsec1-dev': {},
|
||||||
|
'libxslt1-dev': {},
|
||||||
|
'pkg-config': {},
|
||||||
|
'python3-psycopg2': {},
|
||||||
|
'python3-wheel': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'users': {
|
||||||
|
'powerdnsadmin': {
|
||||||
|
'home': '/opt/powerdnsadmin',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'postgresql': {
|
||||||
|
'users': {
|
||||||
|
'powerdnsadmin': {
|
||||||
|
'password': repo.vault.password_for('{} postgresql powerdnsadmin'.format(node.name)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'databases': {
|
||||||
|
'powerdnsadmin': {
|
||||||
|
'owner': 'powerdnsadmin',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
|
@ -1,28 +0,0 @@
|
||||||
${header}
|
|
||||||
|
|
||||||
$ORIGIN franzi.business.
|
|
||||||
|
|
||||||
@ IN A 94.130.52.224
|
|
||||||
IN AAAA 2a01:4f8:10b:2a5f::2
|
|
||||||
IN MX 10 mx0.kunbox.net.
|
|
||||||
IN TXT v=spf1 mx ~all
|
|
||||||
|
|
||||||
* IN A 94.130.52.224
|
|
||||||
IN AAAA 2a01:4f8:10b:2a5f::2
|
|
||||||
|
|
||||||
grafana IN A 165.232.105.69
|
|
||||||
IN AAAA 2a03:b0c0:1:e0::627:8001
|
|
||||||
|
|
||||||
icinga IN A 165.232.42.173
|
|
||||||
IN AAAA 2a03:b0c0:1:e0::665:8001
|
|
||||||
|
|
||||||
sewfile IN A 116.203.205.248
|
|
||||||
IN AAAA 2a01:4f8:c0c:c71b::1
|
|
||||||
IN TXT v=spf1 a mx ~all
|
|
||||||
|
|
||||||
|
|
||||||
_matrix._tcp IN SRV 10 10 8448 matrix
|
|
||||||
|
|
||||||
2019._domainkey IN TXT v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwkg6UAcu3V98hal1UVf6yB0WT1CKDS0AK83CUlSP8bUwraPxkxK1nkQOUsmjbQs6a3FhdsKprMi32GeUaTVvZg81JIybPk3jNugfNWfSjs2TXPomYu+XD2pmmbR3cZlzC5NGR2nmBFt/P/S2ihPHj35KziiBIwK1TdvOi1M2+upCjK33Icco0ByCm0gJpD2O0cbqcBcUKqd6X440vYhNXH1ygp0e91P0iRnvS9sg6yD0xjD8kD6j/8GfxBY+9bpU3EvDoBgyJSbjw5b6PUVJbKMXzw1NIRNj0SXKs5BakjS8+7u62vR11IPCYRwy+yr0rDT0tNegM7gStIIgoTpOoQIDAQAB
|
|
||||||
_dmarc IN TXT v=DMARC1; p=none; rua=mailto:postmaster@kunsmann.eu; ruf=mailto:postmaster@kunsmann.eu; fo=0:d:s; adkim=r; aspf=r
|
|
||||||
_token._dnswl IN TXT gg3mbwjx9bbuo5osvhq7oz6bc881wcmc
|
|
|
@ -1,27 +0,0 @@
|
||||||
${header}
|
|
||||||
|
|
||||||
$ORIGIN kunbox.net.
|
|
||||||
|
|
||||||
@ IN A 94.130.52.224
|
|
||||||
IN AAAA 2a01:4f8:10b:2a5f::2
|
|
||||||
|
|
||||||
; Needs to have a working Mail address, otherwise Telekom goes mimimi
|
|
||||||
IN MX 10 mx0
|
|
||||||
IN TXT v=spf1 mx ~all
|
|
||||||
|
|
||||||
; Mail servers
|
|
||||||
mx0 IN A 94.130.52.224
|
|
||||||
IN AAAA 2a01:4f8:10b:2a5f::2
|
|
||||||
*.mx0 IN CNAME mx0
|
|
||||||
|
|
||||||
% for record in sorted(metadata_records):
|
|
||||||
${record}
|
|
||||||
% endfor
|
|
||||||
|
|
||||||
2019._domainkey IN TXT v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwkg6UAcu3V98hal1UVf6yB0WT1CKDS0AK83CUlSP8bUwraPxkxK1nkQOUsmjbQs6a3FhdsKprMi32GeUaTVvZg81JIybPk3jNugfNWfSjs2TXPomYu+XD2pmmbR3cZlzC5NGR2nmBFt/P/S2ihPHj35KziiBIwK1TdvOi1M2+upCjK33Icco0ByCm0gJpD2O0cbqcBcUKqd6X440vYhNXH1ygp0e91P0iRnvS9sg6yD0xjD8kD6j/8GfxBY+9bpU3EvDoBgyJSbjw5b6PUVJbKMXzw1NIRNj0SXKs5BakjS8+7u62vR11IPCYRwy+yr0rDT0tNegM7gStIIgoTpOoQIDAQAB
|
|
||||||
_dmarc IN TXT v=DMARC1; p=none; rua=mailto:postmaster@kunsmann.eu; ruf=mailto:postmaster@kunsmann.eu; fo=0:d:s; adkim=r; aspf=r
|
|
||||||
_token._dnswl IN TXT 6akc10htbgmg56e072w0w2n0wql4oezu
|
|
||||||
|
|
||||||
f2k1.de._report._dmarc IN TXT v=DMARC1
|
|
||||||
franzi.business._report._dmarc IN TXT v=DMARC1
|
|
||||||
kunsmann.eu._report._dmarc IN TXT v=DMARC1
|
|
|
@ -1,15 +0,0 @@
|
||||||
${header}
|
|
||||||
|
|
||||||
$ORIGIN kunsmann.eu.
|
|
||||||
|
|
||||||
@ IN A 94.130.52.224
|
|
||||||
IN AAAA 2a01:4f8:10b:2a5f::2
|
|
||||||
IN MX 10 mx0.kunbox.net.
|
|
||||||
IN TXT v=spf1 a mx ~all
|
|
||||||
|
|
||||||
* IN A 94.130.52.224
|
|
||||||
IN AAAA 2a01:4f8:10b:2a5f::2
|
|
||||||
|
|
||||||
2019._domainkey IN TXT v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwkg6UAcu3V98hal1UVf6yB0WT1CKDS0AK83CUlSP8bUwraPxkxK1nkQOUsmjbQs6a3FhdsKprMi32GeUaTVvZg81JIybPk3jNugfNWfSjs2TXPomYu+XD2pmmbR3cZlzC5NGR2nmBFt/P/S2ihPHj35KziiBIwK1TdvOi1M2+upCjK33Icco0ByCm0gJpD2O0cbqcBcUKqd6X440vYhNXH1ygp0e91P0iRnvS9sg6yD0xjD8kD6j/8GfxBY+9bpU3EvDoBgyJSbjw5b6PUVJbKMXzw1NIRNj0SXKs5BakjS8+7u62vR11IPCYRwy+yr0rDT0tNegM7gStIIgoTpOoQIDAQAB
|
|
||||||
_dmarc IN TXT v=DMARC1; p=none; rua=mailto:postmaster@kunsmann.eu; ruf=mailto:postmaster@kunsmann.eu; fo=0:d:s; adkim=r; aspf=r
|
|
||||||
_token._dnswl IN TXT 5mx0rv9ru8s1zz4tf4xlt48osh09czmg
|
|
28
data/powerdns/files/bind-zones/franzi.business
Normal file
28
data/powerdns/files/bind-zones/franzi.business
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
${header}
|
||||||
|
|
||||||
|
$ORIGIN franzi.business.
|
||||||
|
|
||||||
|
@ IN A 94.130.52.224
|
||||||
|
IN AAAA 2a01:4f8:10b:2a5f::2
|
||||||
|
IN MX 10 mx0.kunbox.net.
|
||||||
|
IN TXT "v=spf1 mx ~all"
|
||||||
|
|
||||||
|
* IN A 94.130.52.224
|
||||||
|
IN AAAA 2a01:4f8:10b:2a5f::2
|
||||||
|
|
||||||
|
grafana IN A 165.232.105.69
|
||||||
|
IN AAAA 2a03:b0c0:1:e0::627:8001
|
||||||
|
|
||||||
|
icinga IN A 165.232.42.173
|
||||||
|
IN AAAA 2a03:b0c0:1:e0::665:8001
|
||||||
|
|
||||||
|
sewfile IN A 116.203.205.248
|
||||||
|
IN AAAA 2a01:4f8:c0c:c71b::1
|
||||||
|
IN TXT "v=spf1 a mx ~all"
|
||||||
|
|
||||||
|
|
||||||
|
_matrix._tcp IN SRV 10 10 8448 matrix
|
||||||
|
|
||||||
|
2019._domainkey IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwkg6UAcu3V98hal1UVf6yB0WT1CKDS0AK83CUlSP8bUwraPxkxK1nkQOUsmjbQs6a3FhdsKprMi32GeUaTVvZg81JIybPk3jNugfNWfSjs2TXPomYu+XD2pmmbR3cZlzC5NGR2nmBFt/P/S2ihPHj35KziiBIwK1TdvOi1M2+upCjK33Icco0ByCm0gJpD2O0cbqcBcUKqd6X440vYhNXH1ygp0e91P0iRnvS9sg6yD0xjD8kD6j/8GfxBY+9bpU3EvDoBgyJSbjw5b6PUVJbKMXzw1NIRNj0SXKs5BakjS8+7u62vR11IPCYRwy+yr0rDT0tNegM7gStIIgoTpOoQIDAQAB"
|
||||||
|
_dmarc IN TXT "v=DMARC1; p=none; rua=mailto:postmaster@kunsmann.eu; ruf=mailto:postmaster@kunsmann.eu; fo=0:d:s; adkim=r; aspf=r"
|
||||||
|
_token._dnswl IN TXT "gg3mbwjx9bbuo5osvhq7oz6bc881wcmc"
|
30
data/powerdns/files/bind-zones/kunbox.net
Normal file
30
data/powerdns/files/bind-zones/kunbox.net
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
${header}
|
||||||
|
|
||||||
|
$ORIGIN kunbox.net.
|
||||||
|
|
||||||
|
@ IN A 94.130.52.224
|
||||||
|
IN AAAA 2a01:4f8:10b:2a5f::2
|
||||||
|
|
||||||
|
; Needs to have a working Mail address, otherwise Telekom goes mimimi
|
||||||
|
IN MX 10 mx0
|
||||||
|
IN TXT "v=spf1 mx ~all"
|
||||||
|
|
||||||
|
; Mail servers
|
||||||
|
mx0 IN A 94.130.52.224
|
||||||
|
IN AAAA 2a01:4f8:10b:2a5f::2
|
||||||
|
*.mx0 IN CNAME mx0
|
||||||
|
|
||||||
|
; Nameservers
|
||||||
|
ns-1 IN A 34.89.208.78
|
||||||
|
|
||||||
|
% for record in sorted(metadata_records):
|
||||||
|
${record}
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
2019._domainkey IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwkg6UAcu3V98hal1UVf6yB0WT1CKDS0AK83CUlSP8bUwraPxkxK1nkQOUsmjbQs6a3FhdsKprMi32GeUaTVvZg81JIybPk3jNugfNWfSjs2TXPomYu+XD2pmmbR3cZlzC5NGR2nmBFt/P/S2ihPHj35KziiBIwK1TdvOi1M2+upCjK33Icco0ByCm0gJpD2O0cbqcBcUKqd6X440vYhNXH1ygp0e91P0iRnvS9sg6yD0xjD8kD6j/8GfxBY+9bpU3EvDoBgyJSbjw5b6PUVJbKMXzw1NIRNj0SXKs5BakjS8+7u62vR11IPCYRwy+yr0rDT0tNegM7gStIIgoTpOoQIDAQAB"
|
||||||
|
_dmarc IN TXT "v=DMARC1; p=none; rua=mailto:postmaster@kunsmann.eu; ruf=mailto:postmaster@kunsmann.eu; fo=0:d:s; adkim=r; aspf=r"
|
||||||
|
_token._dnswl IN TXT "6akc10htbgmg56e072w0w2n0wql4oezu"
|
||||||
|
|
||||||
|
f2k1.de._report._dmarc IN TXT "v=DMARC1"
|
||||||
|
franzi.business._report._dmarc IN TXT "v=DMARC1"
|
||||||
|
kunsmann.eu._report._dmarc IN TXT "v=DMARC1"
|
15
data/powerdns/files/bind-zones/kunsmann.eu
Normal file
15
data/powerdns/files/bind-zones/kunsmann.eu
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
${header}
|
||||||
|
|
||||||
|
$ORIGIN kunsmann.eu.
|
||||||
|
|
||||||
|
@ IN A 94.130.52.224
|
||||||
|
IN AAAA 2a01:4f8:10b:2a5f::2
|
||||||
|
IN MX 10 mx0.kunbox.net.
|
||||||
|
IN TXT "v=spf1 a mx ~all"
|
||||||
|
|
||||||
|
* IN A 94.130.52.224
|
||||||
|
IN AAAA 2a01:4f8:10b:2a5f::2
|
||||||
|
|
||||||
|
2019._domainkey IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwkg6UAcu3V98hal1UVf6yB0WT1CKDS0AK83CUlSP8bUwraPxkxK1nkQOUsmjbQs6a3FhdsKprMi32GeUaTVvZg81JIybPk3jNugfNWfSjs2TXPomYu+XD2pmmbR3cZlzC5NGR2nmBFt/P/S2ihPHj35KziiBIwK1TdvOi1M2+upCjK33Icco0ByCm0gJpD2O0cbqcBcUKqd6X440vYhNXH1ygp0e91P0iRnvS9sg6yD0xjD8kD6j/8GfxBY+9bpU3EvDoBgyJSbjw5b6PUVJbKMXzw1NIRNj0SXKs5BakjS8+7u62vR11IPCYRwy+yr0rDT0tNegM7gStIIgoTpOoQIDAQAB"
|
||||||
|
_dmarc IN TXT "v=DMARC1; p=none; rua=mailto:postmaster@kunsmann.eu; ruf=mailto:postmaster@kunsmann.eu; fo=0:d:s; adkim=r; aspf=r"
|
||||||
|
_token._dnswl IN TXT "5mx0rv9ru8s1zz4tf4xlt48osh09czmg"
|
|
@ -3,7 +3,7 @@ ${header}
|
||||||
$ORIGIN trans-agenda.eu.
|
$ORIGIN trans-agenda.eu.
|
||||||
|
|
||||||
@ IN MX 10 mx0.kunbox.net.
|
@ IN MX 10 mx0.kunbox.net.
|
||||||
IN TXT v=spf1 a mx ~all
|
IN TXT "v=spf1 a mx ~all"
|
||||||
|
|
||||||
part.of.the IN A 94.130.52.224
|
part.of.the IN A 94.130.52.224
|
||||||
part.of.the IN AAAA 2a01:4f8:10b:2a5f::2
|
part.of.the IN AAAA 2a01:4f8:10b:2a5f::2
|
|
@ -7,6 +7,17 @@ groups['webserver'] = {
|
||||||
|
|
||||||
groups['dns'] = {
|
groups['dns'] = {
|
||||||
'bundles': {
|
'bundles': {
|
||||||
'bind',
|
'postgresql',
|
||||||
|
'powerdns',
|
||||||
|
},
|
||||||
|
'metadata': {
|
||||||
|
'powerdns': {
|
||||||
|
'features': {
|
||||||
|
'bind': True,
|
||||||
|
'pgsql': True,
|
||||||
|
},
|
||||||
|
# Overridden in node metadata for primary server
|
||||||
|
'is_secondary': True,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
31
libs/tools.py
Normal file
31
libs/tools.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
from bundlewrap.exceptions import NoSuchGroup, NoSuchNode
|
||||||
|
from ipaddress import ip_address
|
||||||
|
|
||||||
|
def resolve_identifier(repo, identifier):
|
||||||
|
"""
|
||||||
|
Try to resolve an identifier (group or node). Return a set of ip
|
||||||
|
addresses valid for this identifier.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
nodes = {repo.get_node(identifier)}
|
||||||
|
except NoSuchNode:
|
||||||
|
try:
|
||||||
|
nodes = repo.nodes_in_group(identifier)
|
||||||
|
except NoSuchGroup:
|
||||||
|
try:
|
||||||
|
return {ip_address(identifier)}
|
||||||
|
except:
|
||||||
|
return set()
|
||||||
|
|
||||||
|
found_ips = set()
|
||||||
|
for node in nodes:
|
||||||
|
for interface, config in node.metadata.get('interfaces', {}).items():
|
||||||
|
for ip in config.get('ipv4', set()):
|
||||||
|
found_ips.add(ip_address(ip))
|
||||||
|
for ip in config.get('ipv4', set()):
|
||||||
|
found_ips.add(ip_address(ip))
|
||||||
|
|
||||||
|
if node.metadata.get('external_ipv4'):
|
||||||
|
found_ips.add(ip_address(node.metadata.get('external_ipv4')))
|
||||||
|
|
||||||
|
return found_ips
|
11
nodes/a.ns14.net.py
Normal file
11
nodes/a.ns14.net.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# This node is not actually part of this repository, it's a DNS server
|
||||||
|
# managed by AutoDNS. It needs a node file, because we're using that to
|
||||||
|
# auto-generate DNS configs.
|
||||||
|
|
||||||
|
nodes['a.ns14.net'] = {
|
||||||
|
'hostname': 'a.ns14.net',
|
||||||
|
'dummy': True,
|
||||||
|
'groups': {
|
||||||
|
'dns',
|
||||||
|
},
|
||||||
|
}
|
11
nodes/b.ns14.net.py
Normal file
11
nodes/b.ns14.net.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# This node is not actually part of this repository, it's a DNS server
|
||||||
|
# managed by AutoDNS. It needs a node file, because we're using that to
|
||||||
|
# auto-generate DNS configs.
|
||||||
|
|
||||||
|
nodes['b.ns14.net'] = {
|
||||||
|
'hostname': 'b.ns14.net',
|
||||||
|
'dummy': True,
|
||||||
|
'groups': {
|
||||||
|
'dns',
|
||||||
|
},
|
||||||
|
}
|
11
nodes/c.ns14.net.py
Normal file
11
nodes/c.ns14.net.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# This node is not actually part of this repository, it's a DNS server
|
||||||
|
# managed by AutoDNS. It needs a node file, because we're using that to
|
||||||
|
# auto-generate DNS configs.
|
||||||
|
|
||||||
|
nodes['c.ns14.net'] = {
|
||||||
|
'hostname': 'c.ns14.net',
|
||||||
|
'dummy': True,
|
||||||
|
'groups': {
|
||||||
|
'dns',
|
||||||
|
},
|
||||||
|
}
|
11
nodes/d.ns14.net.py
Normal file
11
nodes/d.ns14.net.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# This node is not actually part of this repository, it's a DNS server
|
||||||
|
# managed by AutoDNS. It needs a node file, because we're using that to
|
||||||
|
# auto-generate DNS configs.
|
||||||
|
|
||||||
|
nodes['d.ns14.net'] = {
|
||||||
|
'hostname': 'd.ns14.net',
|
||||||
|
'dummy': True,
|
||||||
|
'groups': {
|
||||||
|
'dns',
|
||||||
|
},
|
||||||
|
}
|
|
@ -1,9 +1,14 @@
|
||||||
# ns-3.kunbox.net
|
# ns-1.kunbox.net
|
||||||
# Frankfurt, Germany
|
# Frankfurt, Germany
|
||||||
|
|
||||||
nodes['gce.bind01'] = {
|
nodes['gce.bind01'] = {
|
||||||
|
'bundles': {
|
||||||
|
'nodejs',
|
||||||
|
'powerdnsadmin',
|
||||||
|
},
|
||||||
'groups': {
|
'groups': {
|
||||||
'dns',
|
'dns',
|
||||||
|
'webserver',
|
||||||
},
|
},
|
||||||
'metadata': {
|
'metadata': {
|
||||||
'interfaces': {
|
'interfaces': {
|
||||||
|
@ -15,6 +20,22 @@ nodes['gce.bind01'] = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'external_ipv4': '34.89.208.78',
|
'external_ipv4': '34.89.208.78',
|
||||||
|
'nginx': {
|
||||||
|
'vhosts': {
|
||||||
|
'ns-1.kunbox.net': {
|
||||||
|
'proxy': {
|
||||||
|
'/': {
|
||||||
|
'target': 'http://127.0.0.1:8000/',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'powerdns': {
|
||||||
|
'is_secondary': False,
|
||||||
|
'secondary_nameservers': 'dns',
|
||||||
|
'my_hostname': 'ns-1.kunbox.net',
|
||||||
|
},
|
||||||
'vm': {
|
'vm': {
|
||||||
'cpu': 1,
|
'cpu': 1,
|
||||||
'ram': 1,
|
'ram': 1,
|
||||||
|
|
Loading…
Reference in a new issue