Skip to content

add Hetzner DNS <-> hcloud pairing - #3

Open
aforemny wants to merge 2 commits into
mainfrom
hetzner-dns
Open

add Hetzner DNS <-> hcloud pairing#3
aforemny wants to merge 2 commits into
mainfrom
hetzner-dns

Conversation

@aforemny

@aforemny aforemny commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Declaratively manage Hetzner DNS zones, RRSets, and individual records
via OpenTofu and the official hetznercloud/hcloud provider.

Unlike the local-service pairings this targets a remote cloud API: there
is no upstream service to enable, tokenFile is required, tfstate lives
under a dedicated declarative-hetzner-dns system user, and the
reconciler only waits for the network.

Checks are implemented using a local double of the Hetzner Cloud DNS API
(services/hetzner-dns/emulator.py).

@aforemny
aforemny requested a review from kmein July 17, 2026 14:25
Declaratively manage Hetzner DNS zones, RRSets, and individual records
via OpenTofu and the official hetznercloud/hcloud provider.

Unlike the local-service pairings this targets a remote cloud API: there
is no upstream service to enable, tokenFile is required, tfstate lives
under a dedicated declarative-hetzner-dns system user, and the
reconciler only waits for the network.

Checks are implemented using a local double of the Hetzner Cloud DNS API
(services/hetzner-dns/emulator.py).
@aforemny aforemny self-assigned this Aug 11, 2026
@@ -0,0 +1,299 @@
#!/usr/bin/env python3

@kmein kmein Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to know where the interface implemented here comes from. Is there an OpenAPI spec somewhere? I think a more clean (maybe even automated?) mocking should be possible.

};
serviceConfig = {
ExecStart = "${pkgs.python3}/bin/python3 ${./emulator.py}";
# TODO

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which TODO item is meant here?

environment.systemPackages = [ pkgs.curl ];
environment.etc."hcloud-dns-token".text = apiToken;
environment.etc."hcloud-tsig-key".text = tsigSecret;
systemd.services.hetzner-dns-emulator = {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to have the "Hetzner API" running on another VM?

tf = tflib.hetznerDnsTfConfig cfg;
in
{
options.services.hetzner-dns.runtime = {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a thought: Technically is does not make sense to call this runtime since there is no Hetzner runtime configuration on the server. The design decision is up to you. I have so far enjoyed the uniformity of the module interface here.

nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";

# This repository.
declarative-runtime.url = "github:youruser/declarative-runtime";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
declarative-runtime.url = "github:youruser/declarative-runtime";
declarative-runtime.url = "github:applicative-systems/declarative-runtime";

Create a Hetzner Cloud API token with DNS permissions ("Security > API tokens"
in the Hetzner Cloud console) and place it on the target host — e.g. via
sops-nix or agenix. Point `tokenFile` at that host path. `tokenFile` is
required: a cloud API token cannot be self-bootstrapped.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
required: a cloud API token cannot be self-bootstrapped.
required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants