dnsmill

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 6, 2024 License: ISC Imports: 12 Imported by: 0

README

dnsmill

Declaratively set your DNS records with dnsmill, powered by libdns.

Use Cases

dnsmill is useful if you already have declarative infrastructure, such as with NixOS. Using this tool, you can ensure that your DNS records match up with your web server of choice without needing to manually update your DNS provider.

Installation

It's recommended that you build this from source using Go 1.21 or later. To do so, simply run:

go install libdb.so/dnsmill/cmd/dnsmill@latest
Nix Flake

The repository contains a Nix flake that you can use to build and run dnsmill. To do so, clone the repository and run the following command:

nix run .#

Usage

First, declare a YAML or JSON file for your DNS profile. Below is a very minimal example for Cloudflare:

config:
  duplicatePolicy: overwrite

providers:
  cloudflare: [libdb.so]

libdb.so:
  dnsmill_test: localhost

This profile sets the dnsmill_test.libdb.so record to 127.0.0.1 and ::1.

Then, you'll need to set your CLOUDFLARE_API_TOKEN environment variable to a scoped API token in your Cloudflare account with the Zone-Zone-Read and Zone-DNS-Edit permissions:

export CLOUDFLARE_API_TOKEN=your_token_here

To apply this profile, put it in a file called profile.yml and run the following command:

dnsmill profile.yml

And that's it! Your DNS should now be set:

Apr  6 03:36:03.701 INF applying fresh libdns record profile=profile.yml domain=libdb.so provider=cloudflare record.type=AAAA record.name=dnsmill_test record.value=::1
Apr  6 03:36:03.702 INF applying fresh libdns record profile=profile.yml domain=libdb.so provider=cloudflare record.type=A record.name=dnsmill_test record.value=127.0.0.1
Apr  6 03:36:05.557 INF applied libdns record profile=profile.yml domain=libdb.so provider=cloudflare record.id=37e833f8a80fabc9747adf6e94aae894 record.type=AAAA record.name=dnsmill_test record.value=::1
Apr  6 03:36:05.557 INF applied libdns record profile=profile.yml domain=libdb.so provider=cloudflare record.id=47c54fd81e07ee8bde61ef0761838f01 record.type=A record.name=dnsmill_test record.value=127.0.0.1

Extending

You can extend dnsmill with more DNS providers that libdns supports. To do so, you must first create a new Go module that contains a new package main that runs dnsmillcmd. For example:

go mod init localhost/dnsmill-custom
cat<<EOF > main.go
package main

import (
    "libdb.so/dnsmill/cmd/dnsmillcmd"
    _ "libdns.so/dnsmill/providers"
    _ "localhost/dnsmill-custom/vercel" # add a custom Vercel provider
)

func main() {
    dnsmillcmd.Main()
}
EOF

Then, you'll need to write a small package that wraps around libdns's provider. To help with that, you can refer to the Vercel provider in this repository. Here, the package is put in the vercel directory:

- dnsmill-custom/ # module localhost/dnsmill-custom
  - main.go
  - go.mod
  - go.sum
  - vercel/
    - vercel.go

Then, you can build and run the package as usual.

Name Origin

The name is a combination of DNS and milling (like mill or milling machine). It's pronounced as "dee-en-es-mill".

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func RegisterProvider

func RegisterProvider(p ProviderFactory)

RegisterProvider registers a DNS provider into the global registry.

Types

type Config

type Config struct {
	DuplicatePolicy DuplicatePolicy `json:"duplicatePolicy,omitempty"`
}

Config configures the behavior of the DNS tool.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns the default configuration for the DNS tool.

type Domain

type Domain string

Domain represents a domain name.

type Domains

type Domains []Domain

Domains represents a list of domain names.

When parsing, it may either parse a single domain name or a list of domain names.

func (*Domains) UnmarshalJSON

func (d *Domains) UnmarshalJSON(data []byte) error

type DuplicatePolicy

type DuplicatePolicy string

DuplicatePolicy is the policy to apply when a duplicate DNS record is found.

const (
	// ErrorOnDuplicate returns an error if a duplicate DNS record is found.
	// It is the safest policy and is the default.
	ErrorOnDuplicate DuplicatePolicy = "error"
	// OverwriteDuplicate overwrites the existing DNS record with the new one.
	OverwriteDuplicate DuplicatePolicy = "overwrite"
)

func (*DuplicatePolicy) UnmarshalJSON

func (d *DuplicatePolicy) UnmarshalJSON(data []byte) error

type HostAddresses

type HostAddresses []string

HostAddresses represents a list of IP addresses and hostnames.

When parsing, it may either parse a single host address or a list of host addresses.

func (*HostAddresses) ResolveIPs

func (a *HostAddresses) ResolveIPs(ctx context.Context) ([]net.IP, error)

ResolveIPs resolves the IP addresses if they are hostnames and returns the IP addresses. This function is not cached. net.DefaultResolver is used to resolve the hostnames.

func (*HostAddresses) UnmarshalJSON

func (a *HostAddresses) UnmarshalJSON(data []byte) error

type Profile

type Profile struct {
	// Config configures the behavior of the DNS tool.
	Config Config `json:"config,omitempty"`
	// Providers lists the DNS providers that are used in the profile.
	// Note that each provider will require its own secret environment variables
	// to be set.
	Providers map[string]ProviderConfig `json:"providers,omitempty"`
	// Domains maps domain names to their subdomains and DNS records.
	Domains map[Domain]SubdomainRecords `json:"domains,omitempty"`
}

Profile represents a DNS profile. It contains the configuration and DNS records for multiple domains.

When parsing the JSON, if no "domains" field is present, then every field that is not "config" is considered a domain name and is filled into the "domains" field.

func NewProfile

func NewProfile() *Profile

NewProfile creates a new empty profile with a default config.

func ParseProfileAsJSON

func ParseProfileAsJSON(r io.Reader) (*Profile, error)

ParseProfileAsJSON parses the profile from the JSON data.

func ParseProfileAsYAML

func ParseProfileAsYAML(r io.Reader) (*Profile, error)

ParseProfileAsYAML parses the profile from the YAML data.

func (*Profile) Apply

func (p *Profile) Apply(ctx context.Context, logger *slog.Logger, dryRun bool) error

Apply applies the profile to the DNS providers.

If dryRun is true, it will convert the profile to libdns records and log them without applying them to the providers. This is useful for debugging and testing the profile without affecting the DNS records.

If an error occurs, it will finish applying the profile to other zones before returning the error. This way, the profile is applied as much as possible before failing. Multiple errors will be joined using errors.Join.

func (*Profile) UnmarshalJSON

func (p *Profile) UnmarshalJSON(data []byte) error

UnmarshalJSON unmarshals the JSON data into the profile.

func (*Profile) Validate

func (p *Profile) Validate() error

Validate validates the profile.

type Provider

type Provider interface {
	libdns.RecordAppender // policy = error
	libdns.RecordSetter   // policy = overwrite
}

Provider describes a DNS provider. It must be safe for concurrent use.

type ProviderConfig

type ProviderConfig struct {
	// Domains lists the domains that are managed by the provider.
	Domains Domains `json:"domains"`
}

ProviderConfig describes the configuration for a DNS provider.

When parsing as JSON, it can be parsed as a list of domains or the actual ProviderConfig instance itself.

func (*ProviderConfig) UnmarshalJSON

func (c *ProviderConfig) UnmarshalJSON(data []byte) error

type ProviderFactory

type ProviderFactory struct {
	// New creates a new DNS provider.
	New func(ctx context.Context) (Provider, error)
	// Name is the name of the DNS provider.
	Name string
	// DocURL is the URL to the documentation of the DNS provider.
	DocURL string
}

ProviderFactory allows a DNS provider to be created. The factory has metadata associated with it.

func ListProviders

func ListProviders() []ProviderFactory

ListProviders returns the list of registered DNS providers.

type Records

type Records struct {
	// Hosts indirectly represents A and AAAA records. The host addresses are
	// resolved into a list of IP addresses, with IPv4 addresses being handled
	// as A records and IPv6 addresses being handled as AAAA records.
	Hosts *HostAddresses `json:"hosts,omitempty"`

	// CNAME represents a single CNAME record.
	CNAME string `json:"cname,omitempty"`
}

Records represents a list of DNS records.

When parsing, it may either parse:

  • A single IPv4 or IPv6 address, which is parsed as a single host address.
  • A list of IPv4 or IPv6 addresses and hostnames, which is parsed as a list of host addresses.
  • A struct with exactly a single field representing the type of record corresponding to its value.

func (*Records) Convert

func (r *Records) Convert(ctx context.Context, subdomain Subdomain) ([]libdns.Record, error)

Convert converts the records assigned to the given subdomain into a list of [libdns.Record]s.

func (*Records) UnmarshalJSON

func (r *Records) UnmarshalJSON(data []byte) error

type Subdomain

type Subdomain string

Subdomain represents a subdomain of a root domain. It does not include the root domain itself. If "@", it represents the root domain.

const RootDomain Subdomain = "@"

RootDomain represents the root domain as a special subdomain.

type SubdomainRecords

type SubdomainRecords map[Subdomain]Records

SubdomainRecords maps subdomains to their DNS records.

func (SubdomainRecords) Convert

func (r SubdomainRecords) Convert(ctx context.Context) ([]libdns.Record, error)

Convert converts the subdomain records into a list of [libdns.Record]s.

Directories

Path Synopsis
cmd
dnsmill
Package main is the main dnsmill command.
Package main is the main dnsmill command.
internal
Package providers imports all the providers within this folder.
Package providers imports all the providers within this folder.
cloudflare
Package cloudflare provides the Cloudflare DNS provider for dnsmill.
Package cloudflare provides the Cloudflare DNS provider for dnsmill.
namecheap
Package namecheap provides the Namecheap DNS provider for dnsmill.
Package namecheap provides the Namecheap DNS provider for dnsmill.
netlify
Package netlify provides the Netlify DNS provider for dnsmill.
Package netlify provides the Netlify DNS provider for dnsmill.
porkbun
Package porkbun provides the Porkbun DNS provider for dnsmill.
Package porkbun provides the Porkbun DNS provider for dnsmill.
vercel
Package vercel provides the Vercel DNS provider for dnsmill.
Package vercel provides the Vercel DNS provider for dnsmill.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL