249 lines
6.0 KiB
Nix
249 lines
6.0 KiB
Nix
{
|
|
pkgs,
|
|
pkgs-unstable,
|
|
lib,
|
|
config,
|
|
...
|
|
}:
|
|
let
|
|
cfg = config.services.octodns;
|
|
secrets = config.age.secrets;
|
|
|
|
types = {
|
|
ttlOptions = default: {
|
|
ttl = lib.mkOption {
|
|
type = lib.types.int;
|
|
default = default;
|
|
};
|
|
};
|
|
defaults = lib.types.submodule {
|
|
options = {
|
|
A = lib.mkOption {
|
|
type = lib.types.submodule {
|
|
options = types.ttlOptions cfg.defaults.ttl;
|
|
};
|
|
default = { };
|
|
};
|
|
AAAA = lib.mkOption {
|
|
type = lib.types.submodule {
|
|
options = types.ttlOptions cfg.defaults.ttl;
|
|
};
|
|
default = { };
|
|
};
|
|
CNAME = lib.mkOption {
|
|
type = lib.types.submodule {
|
|
options = types.ttlOptions cfg.defaults.ttl;
|
|
};
|
|
default = { };
|
|
};
|
|
MX = lib.mkOption {
|
|
type = lib.types.submodule {
|
|
options = types.ttlOptions cfg.defaults.ttl;
|
|
};
|
|
default = { };
|
|
};
|
|
TXT = lib.mkOption {
|
|
type = lib.types.submodule {
|
|
options = types.ttlOptions cfg.defaults.ttl;
|
|
};
|
|
default = { };
|
|
};
|
|
}
|
|
// (types.ttlOptions 3600);
|
|
};
|
|
aRecord = lib.types.submodule {
|
|
options = {
|
|
values = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
default = [ ];
|
|
};
|
|
ttl = lib.mkOption {
|
|
type = lib.types.int;
|
|
default = cfg.defaults.A.ttl;
|
|
};
|
|
};
|
|
};
|
|
aaaaRecord = lib.types.submodule {
|
|
options = {
|
|
values = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
default = [ ];
|
|
};
|
|
ttl = lib.mkOption {
|
|
type = lib.types.int;
|
|
default = cfg.defaults.AAAA.ttl;
|
|
};
|
|
};
|
|
};
|
|
cnameRecord = lib.types.submodule {
|
|
options = {
|
|
target = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = null;
|
|
};
|
|
toRoot = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = false;
|
|
};
|
|
ttl = lib.mkOption {
|
|
type = lib.types.int;
|
|
default = cfg.defaults.CNAME.ttl;
|
|
};
|
|
};
|
|
};
|
|
mxValue = lib.types.submodule {
|
|
options = {
|
|
exchange = lib.mkOption {
|
|
type = lib.types.str;
|
|
};
|
|
preference = lib.mkOption {
|
|
type = lib.types.int;
|
|
default = 10;
|
|
};
|
|
};
|
|
};
|
|
mxRecord = lib.types.submodule {
|
|
options = {
|
|
values = lib.mkOption {
|
|
type = lib.types.listOf types.mxValue;
|
|
default = [ ];
|
|
};
|
|
ttl = lib.mkOption {
|
|
type = lib.types.int;
|
|
default = cfg.defaults.MX.ttl;
|
|
};
|
|
};
|
|
};
|
|
txtRecord = lib.types.submodule {
|
|
options = {
|
|
values = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
default = [ ];
|
|
};
|
|
ttl = lib.mkOption {
|
|
type = lib.types.int;
|
|
default = cfg.defaults.AAAA.ttl;
|
|
};
|
|
};
|
|
};
|
|
records = lib.types.submodule {
|
|
options = {
|
|
A = lib.mkOption {
|
|
type = types.aRecord;
|
|
default = { };
|
|
};
|
|
AAAA = lib.mkOption {
|
|
type = types.aaaaRecord;
|
|
default = { };
|
|
};
|
|
CNAME = lib.mkOption {
|
|
type = types.cnameRecord;
|
|
default = { };
|
|
};
|
|
MX = lib.mkOption {
|
|
type = types.mxRecord;
|
|
default = { };
|
|
};
|
|
TXT = lib.mkOption {
|
|
type = types.txtRecord;
|
|
default = { };
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
yamlFormat = pkgs.formats.yaml { };
|
|
|
|
zoneFile = yamlFormat.generate "octodns-zone" (
|
|
lib.filterAttrs (_: records: (lib.length records) > 0) (
|
|
lib.mapAttrs (
|
|
_: types:
|
|
lib.filter
|
|
(
|
|
{
|
|
values ? [ ],
|
|
value ? null,
|
|
...
|
|
}:
|
|
(lib.length values) > 0 || !(builtins.isNull value)
|
|
)
|
|
(
|
|
lib.mapAttrsToList (
|
|
type:
|
|
{ ttl, ... }@options:
|
|
if (type == "CNAME") then
|
|
let
|
|
inherit (options) target toRoot;
|
|
value = if toRoot then "${config.networking.domain}." else target;
|
|
in
|
|
{
|
|
inherit type ttl value;
|
|
}
|
|
else
|
|
{
|
|
inherit type ttl;
|
|
inherit (options) values;
|
|
}
|
|
) types
|
|
)
|
|
) cfg.records
|
|
)
|
|
);
|
|
|
|
zonesDir = pkgs.linkFarm "octodns-zones" {
|
|
"${config.networking.domain}.yaml" = zoneFile;
|
|
};
|
|
|
|
configFile = yamlFormat.generate "octodns-config.yaml" {
|
|
providers = {
|
|
config = {
|
|
class = "octodns.provider.yaml.YamlProvider";
|
|
directory = zonesDir;
|
|
default_ttl = cfg.defaults.ttl;
|
|
};
|
|
hetzner = {
|
|
class = "octodns_hetzner.HetznerProvider";
|
|
token = "env/HETZNER_API_TOKEN";
|
|
};
|
|
};
|
|
|
|
zones."*" = {
|
|
sources = [ "config" ];
|
|
targets = [ "hetzner" ];
|
|
};
|
|
};
|
|
|
|
octodns = pkgs-unstable.octodns.withProviders (_: [
|
|
pkgs-unstable.octodns-providers.hetzner
|
|
]);
|
|
in
|
|
{
|
|
options.services.octodns = {
|
|
enable = lib.mkEnableOption "Enable octodns";
|
|
records = lib.mkOption {
|
|
type = lib.types.attrsOf types.records;
|
|
default = { };
|
|
};
|
|
defaults = lib.mkOption {
|
|
type = types.defaults;
|
|
default = { };
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
systemd.services.octodns = {
|
|
enable = true;
|
|
description = "OctoDNS";
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
ExecStart = "${octodns}/bin/octodns-sync --config-file ${configFile} --doit";
|
|
DynamicUser = true;
|
|
EnvironmentFile = secrets.hetzner.path;
|
|
RemainAfterExit = true;
|
|
};
|
|
wantedBy = lib.optionals config.services.nginx.enable [ "nginx.service" ];
|
|
before = lib.optionals config.services.nginx.enable [ "nginx.service" ];
|
|
};
|
|
};
|
|
}
|