init
This commit is contained in:
38
ansible/roles/dns/push_powerdns_configs_to_node/readme.md
Normal file
38
ansible/roles/dns/push_powerdns_configs_to_node/readme.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# example dns path in Debian13
|
||||
App → glibc resolver → /etc/resolv.conf (127.0.0.53) → systemd-resolved → 192.168.0.1 (Proxmox)
|
||||
|
||||
# before role running
|
||||
```bash
|
||||
sudo systemctl disable --now systemd-resolved
|
||||
|
||||
sudo rm -f /etc/resolv.conf
|
||||
echo -e "nameserver 1.1.1.1\nnameserver 8.8.8.8" | sudo tee /etc/resolv.conf
|
||||
|
||||
docker compose down
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
```bash
|
||||
# pdns-auth web/api через nginx
|
||||
curl -i -H 'Host: auth.infra.hran' http://127.0.0.1/
|
||||
|
||||
# recursor web/api через nginx
|
||||
curl -i -H 'Host: recursor.infra.hran' http://127.0.0.1/
|
||||
|
||||
# dnsdist web через nginx
|
||||
curl -i -H 'Host: dnsdist.infra.hran' http://127.0.0.1/
|
||||
curl -i -u 'admin:CHANGE_ME_DNSDIST_WEB_PASSWORD' -H 'Host: dnsdist.infra.hran' http://127.0.0.1/
|
||||
|
||||
# windows
|
||||
C:\Windows\System32\drivers\etc\hosts
|
||||
|
||||
127.0.0.1 auth.infra.hran
|
||||
127.0.0.1 recursor.infra.hran
|
||||
127.0.0.1 dnsdist.infra.hran:8084
|
||||
|
||||
# check from browser
|
||||
http://dnsdist.infra.hran:8080/
|
||||
http://auth.infra.hran:8080/
|
||||
http://recursor.infra.hran:8080/
|
||||
```
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
- name: ensure directory structure exists
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0755"
|
||||
loop:
|
||||
- "{{ dns_stack_root }}"
|
||||
- "{{ dns_stack_root }}/postgres/initdb"
|
||||
- "{{ dns_stack_root }}/pdns-auth"
|
||||
- "{{ dns_stack_root }}/pdns-recursor"
|
||||
- "{{ dns_stack_root }}/dnsdist"
|
||||
- "{{ dns_stack_root }}/nginx"
|
||||
|
||||
- name: render stack files
|
||||
ansible.builtin.template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ dns_stack_root }}/{{ item.dest }}"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0644"
|
||||
loop:
|
||||
- { src: "docker-compose.yml.j2", dest: "docker-compose.yml" }
|
||||
- { src: ".env.j2", dest: ".env", mode: "0600" }
|
||||
- {
|
||||
src: "postgres/initdb/01-pdns-schema.sql.j2",
|
||||
dest: "postgres/initdb/01-pdns-schema.sql",
|
||||
}
|
||||
- { src: "pdns-auth/pdns.conf.j2", dest: "pdns-auth/pdns.conf" }
|
||||
- {
|
||||
src: "pdns-recursor/recursor.conf.j2",
|
||||
dest: "pdns-recursor/recursor.conf",
|
||||
}
|
||||
- { src: "dnsdist/dnsdist.conf.j2", dest: "dnsdist/dnsdist.conf" }
|
||||
- { src: "nginx/nginx.conf.j2", dest: "nginx/nginx.conf" }
|
||||
register: rendered
|
||||
@@ -0,0 +1,41 @@
|
||||
addLocal("0.0.0.0:53")
|
||||
addLocal("[::]:53")
|
||||
|
||||
-- ACL для клиентов, которым вообще можно отвечать
|
||||
addACL("127.0.0.0/8") -- localhost на IPv4 (машина сама себе).
|
||||
addACL("10.0.0.0/8") -- приватные сети RFC1918 (часто VPN/корп сеть).
|
||||
addACL("172.16.0.0/12") -- приватные 172.16–172.31 (сюда попадает и 172.30.x, docker-сеть).
|
||||
addACL("192.168.0.0/16") -- типичная домашняя LAN.
|
||||
addACL("::1/128") -- localhost на IPv6.
|
||||
addACL("fc00::/7") -- IPv6 ULA (аналог приватных)
|
||||
addACL("fe80::/10") --IPv6 link-local (адреса “на линке”, часто у интерфейса).
|
||||
|
||||
newServer({
|
||||
address="172.30.0.11:5300",
|
||||
pool="auth",
|
||||
name="pdns-auth"
|
||||
})
|
||||
|
||||
newServer({
|
||||
address="172.30.0.12:5301",
|
||||
pool="recursor",
|
||||
name="pdns-recursor"
|
||||
})
|
||||
|
||||
-- Авторитативные зоны -> в pool auth, остальное -> recursor
|
||||
local authZones = newSuffixMatchNode()
|
||||
authZones:add("infra.hran.")
|
||||
|
||||
pc = newPacketCache(100000, {maxTTL=86400, minTTL=0, temporaryFailureTTL=60})
|
||||
getPool("recursor"):setCache(pc)
|
||||
getPool("auth"):setCache(pc)
|
||||
|
||||
addAction(SuffixMatchNodeRule(authZones), PoolAction("auth"))
|
||||
addAction(AllRule(), PoolAction("recursor"))
|
||||
|
||||
webserver("0.0.0.0:8084")
|
||||
setWebserverConfig({
|
||||
password="CHANGE_ME_DNSDIST_WEB_PASSWORD",
|
||||
apiKey="CHANGE_ME_DNSDIST_KEY",
|
||||
acl="127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, ::1/128, fc00::/7, fe80::/10"
|
||||
})
|
||||
@@ -0,0 +1,142 @@
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16
|
||||
container_name: dnsstack-postgres
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Kyiv
|
||||
POSTGRES_DB: pdns
|
||||
POSTGRES_USER: pdns
|
||||
POSTGRES_PASSWORD: CHANGE_ME_POSTGRES_PASSWORD
|
||||
volumes:
|
||||
- /opt/dns-stack/postgres/data:/var/lib/postgresql/data
|
||||
- ./postgres/initdb:/docker-entrypoint-initdb.d:ro
|
||||
networks:
|
||||
dnsnet:
|
||||
ipv4_address: "172.30.0.10"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB} -h 127.0.0.1 -p 5432"]
|
||||
interval: 2s
|
||||
timeout: 3s
|
||||
retries: 30
|
||||
start_period: 10s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
tag: "dnsstack.postgres"
|
||||
max-size: "20m"
|
||||
max-file: "10"
|
||||
|
||||
pdns-auth:
|
||||
image: powerdns/pdns-auth-50:latest
|
||||
container_name: dnsstack-pdns-auth
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
TZ: Europe/Kyiv
|
||||
volumes:
|
||||
- ./pdns-auth/pdns.conf:/etc/powerdns/pdns.conf:ro
|
||||
networks:
|
||||
dnsnet:
|
||||
ipv4_address: "172.30.0.11"
|
||||
expose:
|
||||
- "5300"
|
||||
- "8083"
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 10064
|
||||
hard: 10064
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
tag: "dnsstack.pdns-auth"
|
||||
max-size: "20m"
|
||||
max-file: "10"
|
||||
|
||||
pdns-recursor:
|
||||
image: powerdns/pdns-recursor-53:latest
|
||||
container_name: dnsstack-pdns-recursor
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Kyiv
|
||||
volumes:
|
||||
- ./pdns-recursor/recursor.conf:/etc/powerdns/recursor.conf:ro
|
||||
networks:
|
||||
dnsnet:
|
||||
ipv4_address: "172.30.0.12"
|
||||
expose:
|
||||
- "5301"
|
||||
- "8082"
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 10064
|
||||
hard: 10064
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
tag: "dnsstack.pdns-recursor"
|
||||
max-size: "20m"
|
||||
max-file: "10"
|
||||
|
||||
dnsdist:
|
||||
image: powerdns/dnsdist-20:latest
|
||||
container_name: dnsstack-dnsdist
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- pdns-auth
|
||||
- pdns-recursor
|
||||
environment:
|
||||
TZ: Europe/Kyiv
|
||||
volumes:
|
||||
- ./dnsdist/dnsdist.conf:/etc/dnsdist/dnsdist.conf:ro
|
||||
networks:
|
||||
dnsnet:
|
||||
ipv4_address: "172.30.0.2"
|
||||
ports:
|
||||
- "53:53/udp"
|
||||
- "53:53/tcp"
|
||||
expose:
|
||||
- "8084"
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 65535
|
||||
hard: 65535
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
tag: "dnsstack.dnsdist"
|
||||
max-size: "50m"
|
||||
max-file: "10"
|
||||
|
||||
nginx:
|
||||
image: nginx:1.27-alpine
|
||||
container_name: dnsstack-nginx
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- pdns-auth
|
||||
- pdns-recursor
|
||||
- dnsdist
|
||||
environment:
|
||||
TZ: Europe/Kyiv
|
||||
volumes:
|
||||
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
networks:
|
||||
dnsnet:
|
||||
ipv4_address: "172.30.0.3"
|
||||
ports:
|
||||
- "80:80/tcp"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
tag: "dnsstack.nginx"
|
||||
max-size: "20m"
|
||||
max-file: "10"
|
||||
|
||||
networks:
|
||||
dnsnet:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: "172.30.0.0/24"
|
||||
@@ -0,0 +1,53 @@
|
||||
worker_processes auto;
|
||||
|
||||
events { worker_connections 1024; }
|
||||
|
||||
http {
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
|
||||
# auth.infra.hran -> pdns-auth:8083
|
||||
server {
|
||||
listen 80;
|
||||
server_name auth.infra.hran;
|
||||
|
||||
location / {
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_pass http://pdns-auth:8083;
|
||||
}
|
||||
}
|
||||
|
||||
# recursor.infra.hran -> pdns-recursor:8082
|
||||
server {
|
||||
listen 80;
|
||||
server_name recursor.infra.hran;
|
||||
|
||||
location / {
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_pass http://pdns-recursor:8082;
|
||||
}
|
||||
}
|
||||
|
||||
# dnsdist.infra.hran -> dnsdist:8084
|
||||
server {
|
||||
listen 80;
|
||||
server_name dnsdist.infra.hran;
|
||||
|
||||
location / {
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_pass http://dnsdist:8084;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
local-address=0.0.0.0,::
|
||||
local-port=5300
|
||||
|
||||
launch=gpgsql
|
||||
gpgsql-host=postgres
|
||||
gpgsql-port=5432
|
||||
gpgsql-dbname=pdns
|
||||
gpgsql-user=pdns
|
||||
gpgsql-password=CHANGE_ME_POSTGRES_PASSWORD
|
||||
|
||||
api=yes
|
||||
api-key=CHANGE_ME_PDNS_API_KEY
|
||||
|
||||
webserver=yes
|
||||
webserver-address=0.0.0.0
|
||||
webserver-port=8083
|
||||
webserver-allow-from=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
|
||||
|
||||
disable-axfr=yes
|
||||
version-string=anonymous
|
||||
loglevel=4
|
||||
@@ -0,0 +1,46 @@
|
||||
# PowerDNS Recursor 5.1+ YAML config
|
||||
|
||||
incoming:
|
||||
listen:
|
||||
- "0.0.0.0:5301"
|
||||
- "[::]:5301"
|
||||
allow_from:
|
||||
- "127.0.0.0/8"
|
||||
- "10.0.0.0/8"
|
||||
- "172.16.0.0/12"
|
||||
- "192.168.0.0/16"
|
||||
- "::1/128"
|
||||
- "fc00::/7"
|
||||
- "fe80::/10"
|
||||
|
||||
outgoing:
|
||||
source_address:
|
||||
- "0.0.0.0"
|
||||
- "::"
|
||||
|
||||
webservice:
|
||||
webserver: true
|
||||
address: "0.0.0.0"
|
||||
port: 8082
|
||||
api_key: "CHANGE_ME_RECURSOR_API_KEY"
|
||||
allow_from:
|
||||
- "127.0.0.0/8"
|
||||
- "10.0.0.0/8"
|
||||
- "172.16.0.0/12"
|
||||
- "192.168.0.0/16"
|
||||
- "::1/128"
|
||||
- "fc00::/7"
|
||||
- "fe80::/10"
|
||||
|
||||
logging:
|
||||
loglevel: 6
|
||||
quiet: false
|
||||
|
||||
recursor:
|
||||
version_string: "anonymous"
|
||||
|
||||
forward_zones_recurse:
|
||||
- zone: "."
|
||||
forwarders:
|
||||
- "1.1.1.1"
|
||||
- "8.8.8.8"
|
||||
@@ -0,0 +1,103 @@
|
||||
-- PowerDNS Generic PostgreSQL schema (gpgsql)
|
||||
-- Source: PowerDNS pdns/modules/gpgsqlbackend/schema.pgsql.sql
|
||||
|
||||
CREATE TABLE domains (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
master VARCHAR(128) DEFAULT NULL,
|
||||
last_check INT DEFAULT NULL,
|
||||
type TEXT NOT NULL,
|
||||
notified_serial INT DEFAULT NULL,
|
||||
account VARCHAR(40) DEFAULT NULL,
|
||||
options TEXT DEFAULT NULL,
|
||||
catalog VARCHAR(255) DEFAULT NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX name_index ON domains(name);
|
||||
CREATE INDEX catalog_idx ON domains(catalog);
|
||||
|
||||
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,
|
||||
disabled BOOL DEFAULT 'f',
|
||||
ordername VARCHAR(255),
|
||||
auth BOOL DEFAULT 't'
|
||||
);
|
||||
|
||||
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 ordername ON records(ordername);
|
||||
|
||||
CREATE TABLE supermasters (
|
||||
ip INET NOT NULL,
|
||||
nameserver VARCHAR(255) NOT NULL,
|
||||
account VARCHAR(40) NOT NULL,
|
||||
PRIMARY KEY (ip, nameserver)
|
||||
);
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
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);
|
||||
|
||||
CREATE TABLE domainmetadata (
|
||||
id SERIAL PRIMARY KEY,
|
||||
domain_id INT NOT NULL,
|
||||
kind VARCHAR(32),
|
||||
content TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX domainmetadata_idx ON domainmetadata(domain_id, kind);
|
||||
|
||||
CREATE TABLE cryptokeys (
|
||||
id SERIAL PRIMARY KEY,
|
||||
domain_id INT NOT NULL,
|
||||
flags INT NOT NULL,
|
||||
active BOOL,
|
||||
published BOOL DEFAULT TRUE,
|
||||
content TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX domainidindex ON cryptokeys(domain_id);
|
||||
|
||||
CREATE TABLE tsigkeys (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(255),
|
||||
algorithm VARCHAR(50),
|
||||
secret VARCHAR(255)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
|
||||
|
||||
CREATE TABLE luarecords (
|
||||
id SERIAL PRIMARY KEY,
|
||||
domain_id INT NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
type VARCHAR(10) NOT NULL,
|
||||
content VARCHAR(65535) NOT NULL,
|
||||
ttl INT NOT NULL,
|
||||
prio INT DEFAULT NULL,
|
||||
disabled BOOL DEFAULT 'f',
|
||||
ordername VARCHAR(255),
|
||||
auth BOOL DEFAULT 't'
|
||||
);
|
||||
|
||||
CREATE INDEX luarecord_name_index ON luarecords(name);
|
||||
CREATE INDEX luarecord_nametype_index ON luarecords(name, type);
|
||||
CREATE INDEX luarecord_domain_id ON luarecords(domain_id);
|
||||
CREATE INDEX luarecord_ordername ON luarecords(ordername);
|
||||
Reference in New Issue
Block a user