8 Commits

Author SHA1 Message Date
135
55b45642e4 WIP. создание реверсных зон по умолчанию для списка префиксов. 2024-02-20 23:46:10 +03:00
Alexey Kovrizhkin
e3ded07a44 add: more comments 2024-02-20 11:29:30 +03:00
Alexey Kovrizhkin
1983467640 add: comments 2024-02-20 10:10:35 +03:00
Alexey Kovrizhkin
5ce2895ddf fix: include 2023-12-19 02:49:27 +03:00
Alexey Kovrizhkin
5665d001d4 woodpecker updates 2023-12-19 02:30:52 +03:00
Alexey Kovrizhkin
3c61753bd3 dcape v3 2023-12-19 02:20:04 +03:00
Aleksei Kovrizhkin
8862bb2bc8 Merge pull request #2 from anp135/master
v3 support
2023-09-02 18:58:19 +03:00
135
2794a48901 v3 support 2023-08-28 17:43:14 +03:00
6 changed files with 172 additions and 98 deletions

View File

@@ -1,23 +0,0 @@
---
kind: pipeline
type: docker
name: powerdns
steps:
- name: deploy_local
pull: never
image: ${DCAPE_COMPOSE}
commands:
- . setup config
- make update
volumes:
- name: dockersock
path: /var/run/docker.sock
volumes:
- name: dockersock
host:
path: /var/run/docker.sock
# docker run powerdns pdnsutil check-zone

23
.woodpecker.yml Normal file
View File

@@ -0,0 +1,23 @@
# lint this file
# go install github.com/woodpecker-ci/woodpecker/cmd/cli@latest
# cli lint .woodpecker.yml
variables:
- &dcape_img 'dcape-compose'
clone:
git:
image: woodpeckerci/plugin-git
settings:
lfs: false
tags: false
steps:
deploy:
image: *dcape_img
commands:
- make .config-link
- make update
volumes:
- /var/run/docker.sock:/var/run/docker.sock

114
Makefile
View File

@@ -1,9 +1,10 @@
# app custom Makefile # app dcape v3 dns-config Makefile.
SHELL = /bin/sh SHELL = /bin/sh
CFG = .env CFG = .env
CFG_BAK ?= $(CFG).bak
SOURCES ?= $(wildcard *.sql) SOURCES ?= _lib.sql $(wildcard *.sql)
OBJECTS = $(SOURCES:.sql=.done) OBJECTS = $(SOURCES:.sql=.done)
OBJECTSDIRECT = $(SOURCES:.sql=.direct) OBJECTSDIRECT = $(SOURCES:.sql=.direct)
@@ -11,99 +12,76 @@ OBJECTSDIRECT = $(SOURCES:.sql=.direct)
# app custom config # app custom config
# comments prefixed with '#- ' will be copied to $(CFG).sample # comments prefixed with '#- ' will be copied to $(CFG).sample
#- Postgresql container name (access via docker)
PG_CONTAINER ?= dcape_db_1
#- PowerDNS DB user name
PGUSER ?= pdns
#- PowerDNS DB name
PGDATABASE ?= pdns
#- Used ONLY for direct DB access without docker (update-direct)
PGPASSWORD ?=
#- ACME zone suffix #- ACME zone suffix
ACME_DOMAIN ?= ACME_DOMAIN ?=
#- This NS hostname for use in all SOA #- This NS hostname for use in all SOA
NSERVER ?= NSERVER ?=
#- db container
DB_CONTAINER ?= #
#- PowerDNS DB user name
PGUSER ?= pdns
#- PowerDNS DB name
PGDATABASE ?= pdns
#- Used ONLY for direct DB access without docker (update-direct)
PGPASSWORD ?=
#- Used ONLY for direct DB access without docker (update-direct)
DB_PORT_LOCAL ?=
USE_DCAPE_DC := no
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
all: help
-include $(CFG) -include $(CFG)
export export
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# dcape v1 comparibility
start-hook: update ifneq ($(findstring $(MAKECMDGOALS),psql),)
USE_DB := yes
stop: else ifneq ($(findstring $(MAKECMDGOALS),psql-local),)
USE_DB := yes
ifndef DB_PORT_LOCAL
$(error "DB_PORT_LOCAL must be set - $(MAKECMDGOALS)")
endif
endif
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
## Usage # Find and include DCAPE_ROOT/Makefile
#: #- dcape compose docker image
DCAPE_COMPOSE ?= dcape-compose
DCAPE_ROOT ?= $(shell docker inspect -f "{{.Config.Labels.dcape_root}}" $(DCAPE_COMPOSE))
ifeq ($(shell test -e $(DCAPE_ROOT)/Makefile.app && echo -n yes),yes)
include $(DCAPE_ROOT)/Makefile.app
else
include /opt/dcape/Makefile.app
endif
# ------------------------------------------------------------------------------
## DB operations
#:
.PHONY: update
## Load updated zone files via running PG container
update: $(OBJECTS) update: $(OBJECTS)
%.done: %.sql %.done: %.sql
@echo "*** $< ***" @echo "*** $< ***"
@csum=$$(md5sum $< | sed 's/ .*//') ; \ @csum=$$(md5sum $< | sed 's/ .*//') ; \
cat $< | docker exec -i $$PG_CONTAINER psql -U $$PGUSER -d $$PGDATABASE -vcsum=$$csum -vACME_DOMAIN=$(ACME_DOMAIN) -vNSERVER=$(NSERVER) > $@ cat $< | docker exec -i $$DB_CONTAINER psql -U $$PGUSER -d $$PGDATABASE -vcsum=$$csum -vACME_DOMAIN=$(ACME_DOMAIN) -vNSERVER=$(NSERVER) > $@
## Load updated zone files via psql connection ## Load updated zone files via psql connection
update-direct: $(CFG) $(OBJECTSDIRECT) update-direct: $(CFG) $(OBJECTSDIRECT)
%.direct: %.sql %.direct: %.sql
@echo "*** $< ***" @echo "*** $< ***"
@source $(CFG) && cat $< | PGPASSWORD=$$PGPASSWORD psql -h localhost -U $$PGUSER > $@ @source $(CFG) && cat $< | PGPASSWORD=$${PGPASSWORD:?Must be set} psql -h localhost -U $$PGUSER -p $${DB_PORT_LOCAL:?Must be set} > $@
## Run psql via running PG container
psql:
@docker exec -it $$PG_CONTAINER psql -U $$PGUSER $$PGDATABASE
# ------------------------------------------------------------------------------
## Other
#:
# This code generates $(CFG).sample from Makefile vars with previous comment line(s)
# See https://gist.github.com/LeKovr/2697fe02504d7c081b0bf79427c93db6
# Internal: generate config sample data
.env.temp.mk:
@echo "define CFVAR" > $@
@grep -A 1 -h "^#- " $(MAKEFILE_LIST) | grep -vE "^--" \
| sed -E 's/^([^\n ]+)\ *\??=([^\n]*)$$/\1=$$(\1)\n/ ; s/^(#)-/\1/' >> $@
@echo "endef" >> $@
ifneq ($(findstring $(MAKECMDGOALS),config $(CFG).sample),)
include .env.temp.mk
endif
# Internal: generate config sample
$(CFG).sample: .env.temp.mk
@echo "# dcape-dns config file, generated by 'make config'\n" > $@
@echo "$$CFVAR" >> $@
@rm -f $<
## generate sample config
config: $(CFG).sample
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
## Remove .done files ## Remove .done files
clean: clean:
rm -rf $(OBJECTS) rm -rf $(OBJECTS)
# This code handles group header and target comment with one or two lines only
## list Makefile targets
## (this is default target)
help:
@grep -A 1 -h "^## " $(MAKEFILE_LIST) \
| sed -E 's/^--$$// ; /./{H;$$!d} ; x ; s/^\n## ([^\n]+)\n(## (.+)\n)*(.+):(.*)$$/" " "\4" "\1" "\3"/' \
| sed -E 's/^" " "#" "(.+)" "(.*)"$$/"" "" "" ""\n"\1 \2" "" "" ""/' \
| xargs printf "%s\033[36m%-15s\033[0m %s %s\n"

View File

@@ -5,7 +5,10 @@ This project contains Makefile and sample sql zone definition for loading zones
## Requirements ## Requirements
* [dcape](https://github.com/TenderPro/dcape) installed on remote host with pdns and gitea running * linux 64bit (git, make, wget, gawk, openssl)
* [docker](http://docker.io)
* [dcape](https://github.com/dopos/dcape)
* Git service ([github](https://github.com), [gitea](https://gitea.io) or [gogs](https://gogs.io))
## Usage ## Usage

View File

@@ -41,7 +41,7 @@ SELECT x, soa_upd(x) FROM unnest(ARRAY[
*/ */
-- result was changed to bigint -- result was changed to bigint
DROP FUNCTION IF EXISTS domain_id(text,text); -- DROP FUNCTION IF EXISTS domain_id(text,text);
CREATE OR REPLACE FUNCTION domain_id(a_name TEXT, a_type TEXT DEFAULT 'NATIVE') RETURNS BIGINT AS $_$ CREATE OR REPLACE FUNCTION domain_id(a_name TEXT, a_type TEXT DEFAULT 'NATIVE') RETURNS BIGINT AS $_$
/* /*
@@ -64,14 +64,17 @@ $_$ LANGUAGE plpgsql;
CREATE OR REPLACE PROCEDURE acme_insert(a_domain_id BIGINT, a_name TEXT, a_ip TEXT, a_ttl INT) AS $_$ CREATE OR REPLACE PROCEDURE acme_insert(a_domain_id BIGINT, a_name TEXT, a_ip TEXT, a_ttl INT) AS $_$
/* /*
Добавление в зону для заданного a_ip записей для передачи ему контроля над зоной a_name. Добавление в зону для заданного a_ip записей для передачи ему контроля над зоной a_name.
Это используется в DNS-01 challenge ACME Это используется в DNS-01 ACME challenge в конфигурации, когда на отдельный a_ip выносятся
* все сервисы домена (их имена - a_name и *.a_name)
* DNS сервис для обновления сертификатов (ns.a_name)
В этом случае traefik при обновлении сертификатов будет прописывать в спец. зоне ключи через API (power)dns сервера.
*/ */
BEGIN BEGIN
WITH acme(name, type, content) AS (VALUES WITH acme(name, type, content) AS (VALUES
( a_name, 'A', a_ip) ( a_name, 'A', a_ip) -- зону резолвим в a_ip
, ('*.' || a_name, 'A', a_ip) , ('*.' || a_name, 'A', a_ip) -- wildcard зоны резолвим в a_ip
, ('acme-' || a_name, 'NS', 'ns.' || a_name) , ('acme-' || a_name, 'NS', 'ns.' || a_name) -- создаем специальную зону для DNS-01, её резолвит NS сервер, доступный по a_ip
, ('_acme-challenge.' || a_name, 'CNAME', 'acme-' || a_name) , ('_acme-challenge.' || a_name, 'CNAME', 'acme-' || a_name) -- делегируем DNS-01 зоны a_name в специальную зону
) )
INSERT INTO records (domain_id, name, ttl, type, prio, content) INSERT INTO records (domain_id, name, ttl, type, prio, content)
SELECT a_domain_id, name, a_ttl, type, 0, content SELECT a_domain_id, name, a_ttl, type, 0, content

90
arpa.sql Normal file
View File

@@ -0,0 +1,90 @@
-- This file control sum
SET vars.csum TO :'csum';
-- This zone copy hostname
SET vars.ns TO :'NSERVER';
DO $$
-- Наполнение
DECLARE
v_domain text; -- domain name
v_domain_id integer; -- internal domain id
v_ns_admin text := 'hostmaster.example.ru'; -- master DNS admin email
v_soa text; -- zone SOA
v_prefixes cidr[] := ARRAY[
'10.0.0.0/8', -- Private-Use Networks
'100.64.0.0/10', -- CG-NAT
'127.0.0.0/8', -- Loopback
'172.16.0.0/12', -- LLA
'169.254.0.0/16', -- Private-Use Networks
'192.0.0.0/24', -- IETF Protocol Assignments
'192.0.2.0/24', -- TEST-NET-1
'192.88.99.0/24', -- 6to4 Relay Anycast
'192.168.0.0/16', -- Private-Use Networks
'198.18.0.0/15', -- Network Interconnect Device Benchmark Testing
'198.51.100.0/24', -- TEST-NET-2
'203.0.113.0/24' -- TEST-NET-3
];
v_prefixes24 cidr[];
v_prefix cidr;
v_arr text[];
BEGIN
-- пересобираем список префиксов по /24
-- ToDo: префиксы выходящие за границы /8 =< prefix < /24 пропускать
FOREACH v_prefix IN ARRAY v_prefixes LOOP
-- получили размерность
FOR i IN 0 .. 2^(24 - masklen(v_prefix))-1 LOOP
-- добавили каждую /24
v_prefixes24 := ARRAY_APPEND(v_prefixes24, set_masklen(v_prefix + 256 * i, 24));
-- RAISE NOTICE '% %: %', v_prefix, i, set_masklen(v_prefix + 256 * i, 24);
END LOOP;
END LOOP;
FOREACH v_prefix IN ARRAY v_prefixes24 LOOP
-- собираем имя зоны
v_domain := concat_ws('.', -- собираем полностью итоговый v_domain в формате $oct3.$oct2.$oct1.in-addr.arpa
array_to_string( -- результат превращаем в текст
array_reverse( -- разворачиваем массив в обратном направлении для in-addr.arpa
trim_array( -- отрезаем от массива последний октет с маской, так как для /24 в in-addr.arpa надо 3 октета
string_to_array(v_prefix::text, '.'), -- v_prefix переводим в text и разбираем в массив через '.'
1
)
),'.'
),
'in-addr.arpa'
);
SELECT INTO v_domain_id id FROM domains WHERE name = v_domain;
IF NOT FOUND THEN
-- зона отсутствует, будем генерить зону по умолчанию
RAISE NOTICE 'Stub generator for prefix:% zone:%', v_prefix, v_domain;
ELSE
-- зона уже создана, пропустить stub-функционал
RAISE NOTICE 'zone:% already exists, skip stub generation', v_domain;
CONTINUE;
END IF;
/*
чексуммы у зоны нет, поэтому достаточно будет первого запуска по
файлу со спецификой зоны, чтобы затереть зону-заглушку
получаем/создаём домен ID
*/
v_domain_id := domain_id(v_domain);
-- собираем SOA
v_soa := soa_mk(v_domain_id, v_ns_admin);
-- в принципе если мы здесь, то предполагается, что зоны такой не существовало
-- и записей, соответственно, нет. но тем не менее
DELETE FROM records WHERE domain_id = v_domain_id;
-- генерим зону по умолчанию
INSERT INTO records (domain_id, name, ttl, type, prio, content) VALUES
(v_domain_id, v_domain, 10800, 'SOA', 0, v_soa)
, (v_domain_id, v_domain, 10800, 'NS', 0, 'ns1.example.ru')
, (v_domain_id, v_domain, 10800, 'NS', 0, 'ns2.example.ru')
;
END LOOP;
END;
$$;