external-dns-tencentcloud-webhook

May 12, 2026 · View on GitHub

License Go Report Card

ExternalDNS webhook provider for Tencent Cloud DNS services (DNSPod & PrivateDNS).

Overview

ExternalDNS upstream removed the in-tree tencentcloud provider and recommends the webhook approach. This project implements the webhook protocol as a standalone sidecar.

ServiceZone TypeDescription
DNSPodpublicPublic DNS resolution
PrivateDNSprivateVPC-scoped internal DNS

Architecture

┌──────────────────────────────── Kubernetes Cluster ──────────────────────────────────┐
│                                                                                      │
│  ┌── external-dns-public ──────────┐      ┌── external-dns-private ──────────────┐   │
│  │                                 │      │                                      │   │
│  │  external-dns ──▶ webhook       │      │  external-dns ──▶ webhook            │   │
│  │                   --zone=public │      │                   --zone=private     │   │
│  │                   --domain=     │      │                   --domain=          │   │
│  │                    example.com  │      │                    internal.example  │   │
│  │                                 │      │                   --vpc-id=vpc-xxx   │   │
│  └───────────────┬─────────────────┘      └───────────────┬──────────────────────┘   │
│                  │                                        │                          │
└──────────────────┼────────────────────────────────────────┼──────────────────────────┘
                   ▼                                        ▼
            DNSPod API                               PrivateDNS API
         (public resolution)                      (VPC-scoped resolution)

Each zone type is a separate Helm release with independent RBAC and credentials. This follows the ExternalDNS recommended pattern — separate instances per zone type for security isolation (least-privilege CAM roles) and operational safety (prevent internal services from modifying public DNS).

Only need one zone type? Just deploy one release. The second is optional.

Installation

helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/

No static keys needed. Requires:

  • TKE managed cluster with version >= v1.20.6-tke.27 or >= v1.22.5-tke.1
  • OIDC enabled (TKE Console → Cluster → Basic Info → ServiceAccountIssuerDiscovery)

One-command setup (creates CAM role + generates values):

# Public zone
curl -sSL https://raw.githubusercontent.com/tkestack/external-dns-tencentcloud-webhook/master/scripts/setup.sh \
  | bash -s -- --auth oidc --zone public --domain example.com

# Private zone
curl -sSL https://raw.githubusercontent.com/tkestack/external-dns-tencentcloud-webhook/master/scripts/setup.sh \
  | bash -s -- --auth oidc --zone private --domain internal.example.com

Then install:

helm install external-dns-public external-dns/external-dns \
  -n external-dns --create-namespace \
  -f https://raw.githubusercontent.com/tkestack/external-dns-tencentcloud-webhook/master/deploy/helm/values-base.yaml \
  -f values-public.local.yaml

# China mainland: add values-china.yaml for CCR-hosted images
helm install external-dns-public external-dns/external-dns \
  -n external-dns --create-namespace \
  -f https://raw.githubusercontent.com/tkestack/external-dns-tencentcloud-webhook/master/deploy/helm/values-base.yaml \
  -f https://raw.githubusercontent.com/tkestack/external-dns-tencentcloud-webhook/master/deploy/helm/values-china.yaml \
  -f values-public.local.yaml
Manual values — public zone (without setup script)

Requires CAM role created beforehand. See Prerequisites — OIDC setup for detailed steps.

# values-public.yaml
serviceAccount:
  annotations:
    tke.cloud.tencent.com/role-arn: "qcs::cam::uin/<UIN>:roleName/external-dns-<CLUSTER_ID>-public"
    tke.cloud.tencent.com/audience: "sts.cloud.tencent.com"
    tke.cloud.tencent.com/token-expiration: "86400"

domainFilters:
  - example.com

txtOwnerId: <CLUSTER_ID>-public

provider:
  webhook:
    args:
      - --credential-mode=oidc
      - --zone-type=public
      - --domain-filter=example.com
Manual values — private zone (without setup script)

Requires CAM role with QcloudPrivateDNSFullAccess policy. See Prerequisites — OIDC setup.

# values-private.yaml
serviceAccount:
  annotations:
    tke.cloud.tencent.com/role-arn: "qcs::cam::uin/<UIN>:roleName/external-dns-<CLUSTER_ID>-private"
    tke.cloud.tencent.com/audience: "sts.cloud.tencent.com"
    tke.cloud.tencent.com/token-expiration: "86400"

domainFilters:
  - internal.example.com

txtOwnerId: <CLUSTER_ID>-private

extraArgs:
  - --publish-internal-services

provider:
  webhook:
    args:
      - --credential-mode=oidc
      - --zone-type=private
      - --domain-filter=internal.example.com
      - --vpc-id=vpc-xxxxxxxx

Uses QcloudPrivateDNSFullAccess policy. --publish-internal-services enables ClusterIP Services to create DNS records.

Details: OIDC guide | Prerequisites

Credential mode B: Static credentials

Works on any Kubernetes cluster (TKE, self-managed, EKS, etc). No cluster type or version restriction.

Using the setup script (creates Secret + generates values):

curl -sSL https://raw.githubusercontent.com/tkestack/external-dns-tencentcloud-webhook/master/scripts/setup.sh \
  | bash -s -- --auth static --zone public --domain example.com

Or manually:

# 1. Create Secret
kubectl create namespace external-dns
kubectl -n external-dns create secret generic tencentcloud-credentials \
  --from-literal=TENCENTCLOUD_SECRET_ID=<ID> \
  --from-literal=TENCENTCLOUD_SECRET_KEY=<KEY>

# 2. Install
helm install external-dns-public external-dns/external-dns \
  -n external-dns \
  -f https://raw.githubusercontent.com/tkestack/external-dns-tencentcloud-webhook/master/deploy/helm/values-base.yaml \
  -f values-static.yaml
values-static.yaml — public zone
domainFilters:
  - example.com

txtOwnerId: <CLUSTER_ID>-public

provider:
  webhook:
    args:
      - --zone-type=public
      - --domain-filter=example.com
    env:
      - name: TENCENTCLOUD_SECRET_ID
        valueFrom:
          secretKeyRef:
            name: tencentcloud-credentials
            key: TENCENTCLOUD_SECRET_ID
      - name: TENCENTCLOUD_SECRET_KEY
        valueFrom:
          secretKeyRef:
            name: tencentcloud-credentials
            key: TENCENTCLOUD_SECRET_KEY
      - name: TENCENTCLOUD_REGION
        value: "ap-guangzhou"
values-static.yaml — private zone
domainFilters:
  - internal.example.com

txtOwnerId: <CLUSTER_ID>-private

extraArgs:
  - --publish-internal-services

provider:
  webhook:
    args:
      - --zone-type=private
      - --domain-filter=internal.example.com
      - --vpc-id=vpc-xxxxxxxx
    env:
      - name: TENCENTCLOUD_SECRET_ID
        valueFrom:
          secretKeyRef:
            name: tencentcloud-credentials
            key: TENCENTCLOUD_SECRET_ID
      - name: TENCENTCLOUD_SECRET_KEY
        valueFrom:
          secretKeyRef:
            name: tencentcloud-credentials
            key: TENCENTCLOUD_SECRET_KEY
      - name: TENCENTCLOUD_REGION
        value: "ap-guangzhou"

Details: Static credentials guide

Managing both public and private zones

Deploy two separate Helm releases (external-dns-public + external-dns-private), each with its own permissions and values. See public-private-zones guide.

Verify

kubectl -n external-dns get pods
# external-dns-public-xxx   2/2   Running

kubectl -n external-dns logs -l app.kubernetes.io/instance=external-dns-public -c webhook
# "Starting webhook provider server on localhost:8888"

Uninstall

helm uninstall external-dns-public -n external-dns

Configuration

Webhook argDefaultDescription
--credential-modestaticstatic or oidc (TKE RRSA)
--zone-typepublicpublic (DNSPod) or private (PrivateDNS)
--domain-filterLimit to specific domain (repeatable)
--vpc-idVPC ID (required for private zone)
--dry-runfalseLog changes without applying

Full reference: docs/reference/configuration.md

Guides

TopicLink
Prerequisites (OIDC vs Static)docs/getting-started/prerequisites.md
OIDC mode: how it works + troubleshootingdocs/guides/credential-oidc.md
Static mode: config file migrationdocs/guides/credential-static.md
Managing public + private zonesdocs/guides/public-private-zones.md
Migrating from in-tree providerdocs/guides/migration.md
Provider-specific annotationsdocs/reference/annotations.md
FAQexternal-dns official FAQ

Development

See docs/development/ for building, releasing, and Taskfile reference.

License

Apache License 2.0 — see LICENSE.