Skip to content

thalassa-cloud/cert-manager-webhook-thalassa

Repository files navigation

cert-manager Webhook for thalassa DNS

A cert-manager DNS01 webhook that solves ACME challenges using Thalassa Cloud DNS. Use it to obtain TLS certificates from Let's Encrypt (or other ACME issuers) for domains whose DNS is hosted on Thalassa Cloud.

Prerequisites

  • cert-manager installed in your cluster (v1.20+)
  • A Thalassa Cloud account with at least one DNS zone
  • Your domain's nameservers delegated to Thalassa Cloud (or the zone created there)
  • Personal access token from the Thalassa Cloud dashboard
  • Your organisation identity (and optionally a project identity if the zone is project-scoped)

How It Works

The webhook implements the cert-manager DNS01 challenge flow:

  1. Present: Creates a TXT record in your Thalassa Cloud DNS zone with the ACME challenge value.
  2. CleanUp: Removes that TXT record after the challenge is validated.

Cert-manager calls this webhook when you request a certificate that uses a DNS01 solver configured with the thalassa provider. DNS changes may take ~25–40s to propagate.

Installation

1. Deploy the webhook

Deploy the webhook into your cluster using your preferred method (Helm chart, raw manifests, etc.). The webhook must run with:

  • GROUP_NAME: Environment variable set to the same group name used in your ClusterIssuer/Issuer (e.g. acme.yourdomain.com).

Ensure the webhook is reachable by cert-manager and that the necessary RBAC and TLS serving configuration are in place (exact steps depend on your deployment method).

2. Create the API credentials Secret

Create a Kubernetes Secret in the same namespace as the Certificate (or the namespace referenced by your Issuer) that holds your Thalassa Cloud personal access token:

apiVersion: v1
kind: Secret
metadata:
  name: thalassa-credentials
type: Opaque
data:
  accessKey: <base64-encoded personal access token>

To base64-encode your token:

echo -n "your-thalassa-personal-access-token" | base64

3. Configure the DNS01 solver

In your ClusterIssuer or Issuer, add a DNS01 solver that uses this webhook and the solver config:

spec:
  acme:
    solvers:
      - dns01:
          webhook:
            groupName: acme.yourdomain.com
            solverName: thalassa
            config:
              apiSecretRef:
                name: thalassa-credentials
                key: accessKey
              organisation: my-org
              # project: my-project   # optional, when the zone is project-scoped
              # baseURL: https://api.thalassa.cloud  # optional, this is the default
  • groupName: Must match the GROUP_NAME env var of the webhook deployment.
  • solverName: Must be thalassa (the name implemented by this webhook).
  • config.apiSecretRef: Reference to the Secret and key that contain the personal access token.
  • config.organisation: Thalassa Cloud organisation identity for API requests.
  • config.project: Optional project identity when DNS zones are project-scoped.
  • config.baseURL: Optional API base URL (defaults to https://api.thalassa.cloud).

OIDC workload identity (recommended for in-cluster installs)

When using the Helm chart, a projected service account token is mounted at /var/run/thalassa-oidc/token with audience https://api.thalassa.cloud/. Before the webhook can call the DNS API, bootstrap workload identity so the webhook Kubernetes service account can authenticate:

# Thalassa-managed cluster (OIDC provider from label kubernetes_cluster_id)
tcloud iam workload-identity-federation bootstrap kubernetes --cluster my-cluster-slug \
  --namespace <cert-manager-namespace> --service-account <cert-manager-webhook-thalassa-sa> \
  --role dns:FullAccess

# Self-managed / custom issuer
tcloud iam workload-identity-federation bootstrap kubernetes --issuer https://k8s.example.com \
  --namespace <cert-manager-namespace> --service-account <cert-manager-webhook-thalassa-sa> \
  --role dns:FullAccess

Set workloadIdentity.cluster or workloadIdentity.issuer in Helm values to print a tailored bootstrap command after helm install. Then configure your Issuer:

config:
  organisation: my-org
  serviceAccountID: sa-xxxxxxxx  # from bootstrap output

No long-lived API token secret is required. Disable the projected volume with projectedToken.enabled: false if you authenticate another way.

Configuration Reference

Field Description
apiSecretRef.name Name of the Secret containing the personal access token.
apiSecretRef.key Key within the Secret (e.g. accessKey).
organisation Thalassa Cloud organisation identity.
project Optional project identity for project-scoped DNS zones.
baseURL Optional API base URL (default: https://api.thalassa.cloud).
serviceAccountID Optional Thalassa service account for OIDC token exchange (uses the pod service account JWT by default).
subjectTokenFile Optional path to a subject JWT file (default with the Helm chart: /var/run/thalassa-oidc/token).
subjectTokenSecretRef Optional secret reference for a custom subject JWT instead of the pod service account token.
clientID Optional OIDC client ID for client credentials flow.
clientSecretRef Secret reference for the OIDC client secret (used with clientID).
oidcTokenURL Optional OIDC token URL override.
insecure Disable TLS certificate verification (development only).

Configure one authentication method: apiSecretRef (personal token), serviceAccountID (OIDC token exchange), or clientID + clientSecretRef (client credentials).

Example config.json (as used in tests or custom deployments):

{
  "apiSecretRef": {
    "Name": "thalassa-credentials",
    "Key": "accessKey"
  },
  "organisation": "my-org"
}

Example: Requesting a Certificate

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-tls
  namespace: default
spec:
  secretName: example-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
    - example.com
    - "*.example.com"

Your ClusterIssuer (or Issuer) must use the thalassa webhook solver as shown in the "Configure the DNS01 solver" section. The domain (e.g. example.com) must be a DNS zone in your Thalassa Cloud organisation (or project, if configured).

Development

Build

make build

Builds a Docker image cert-manager-webhook-thalassa:latest.

Run tests

The project uses the cert-manager DNS01 conformance suite.

  1. Copy and edit the example config and credentials under testdata/thalassa/:
    • config.json.exampleconfig.json
    • thalassa-credentials.yaml.examplethalassa-credentials.yaml
  2. Fill in your personal access token (base64 in the secret), organisation identity, and ensure the secret and config match the solver config (e.g. secret name and key).
  3. Set TEST_ZONE_NAME to a domain that exists as a DNS zone in your Thalassa Cloud account (trailing dot optional).

Then run:

TEST_ZONE_NAME=example.com. make test

Replace example.com. with your actual zone name.

Linting

go vet ./...

If you use golangci-lint (see .golangci.yml):

golangci-lint run