external-dns
Synchronizes Kubernetes Services, Ingresses and related sources with DNS providers. Apache-2.0. linux/amd64.
Pin this image by digest.
published Latest tag v0.23.0-tpio.1. Pin by digest. Usage is on this page.
Pin by digest
oci.thepeoples.io/hardened/external-dns@sha256:de0e5484b88efce284532ee015e03bfcc79952d687fbac7199d50b14738d6a1aPull:
podman pull oci.thepeoples.io/hardened/external-dns@sha256:de0e5484b88efce284532ee015e03bfcc79952d687fbac7199d50b14738d6a1aVerify:
cosign verify --key https://thepeoples.io/keys/oci.thepeoples.io.pub --insecure-ignore-tlog oci.thepeoples.io/hardened/external-dns@sha256:de0e5484b88efce284532ee015e03bfcc79952d687fbac7199d50b14738d6a1aPublished 2026-10-20T13:33:54Z154.9 MiB compressed
Usage
Validated against this published digest: official-chart install, runtime digest, actual nonroot UID 65532, /healthz, Prometheus metrics, discovered source endpoints, CREATE of an annotated hostname, and registry/source gauge sync. Functional evidence.
external-dns runs as UID/GID 65532:65532 (the chart already uses those ids). The official chart constructs the image as {{ repository }}:{{ tag }} with no registry split; production values set repository: oci.thepeoples.io/hardened/external-dns. Chart policy is required (create-only, sync, or upsert-only); production sets upsert-only so records are never deleted. Keep replicaCount: 1 because the controller has no leader election. Chart default provider.name is aws. Production values set linode for this platform's clusters. Set LINODE_TOKEN (or the credentials for a different provider) and a unique txtOwnerId before install. Do not commit the token. Restrict domainFilters to the zones you manage.
The Service stays private (ClusterIP) on port 7979. external-dns needs Kubernetes API access to watch sources, so the values create RBAC and keep the service-account token mounted. Grant only the source permissions you enable. Annotate Services or Ingresses with external-dns.kubernetes.io/hostname (and target when the record should not follow the Service IP). The v0.22.0+ default prefix is external-dns.kubernetes.io/; the legacy external-dns.alpha.kubernetes.io/ prefix is ignored unless --enable-legacy-annotation-prefix is set.
Production Helm values (metrics enabled, image pinned by digest):
# Official external-dns chart 1.23.0. Replace both image placeholders
# with the tag/digest from the published catalog; a pending recipe is not a release.
# The chart image helper concatenates repository:tag with no registry split.
# Chart container UID/GID is already 65532. Chart policy is required.
fullnameOverride: external-dns
replicaCount: 1 # No leader election; more than one replica would double-write records.
nodeSelector: {kubernetes.io/arch: amd64, kubernetes.io/os: linux}
serviceAccount: {create: true, automountServiceAccountToken: true}
rbac: {create: true}
image:
repository: oci.thepeoples.io/hardened/external-dns
tag: "v0.23.0-tpio.1@sha256:de0e5484b88efce284532ee015e03bfcc79952d687fbac7199d50b14738d6a1a"
pullPolicy: IfNotPresent
sources:
- service
- ingress
# Chart default provider is aws. Override to your DNS host and set credentials
# before install. This platform's clusters use Linode (LINODE_TOKEN).
provider:
name: linode
# Required: create-only, sync, or upsert-only. upsert-only never deletes records.
policy: upsert-only
registry: txt
# Set txtOwnerId to a unique id for this cluster before install.
txtOwnerId: cluster-1
interval: 1m
triggerLoopOnEvent: true
logLevel: info
logFormat: json
# Restrict managed zones. An empty filter considers every zone the provider returns.
domainFilters: []
securityContext:
privileged: false
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 65532
runAsGroup: 65532
capabilities: {drop: [ALL]}
podSecurityContext:
runAsNonRoot: true
fsGroup: 65534
seccompProfile: {type: RuntimeDefault}
resources:
requests: {cpu: 50m, memory: 64Mi}
limits: {cpu: "1", memory: 256Mi}
service: {enabled: true, port: 7979}
serviceMonitor: {enabled: false}
namespaced: falsehelm repo add external-dns https://kubernetes-sigs.github.io/external-dns
helm repo update external-dns
helm upgrade --install external-dns external-dns/external-dns --version 1.23.0 \
--namespace dns --create-namespace -f values-hardened.yamlThe example Service is external-dns.dns.svc:7979. Metrics are on the same port. Forward the Service in a separate terminal:
kubectl -n dns port-forward service/external-dns 7979:7979Then check liveness and Prometheus metrics:
curl -fsS http://127.0.0.1:7979/healthz
curl -fsS http://127.0.0.1:7979/metrics/healthz or pod Ready alone is not a functional pass. A working controller creates or updates records for annotated sources and exposes source/registry gauges.
For existing Kustomize manifests that use the upstream image, pin this replacement in images:
images:
- name: registry.k8s.io/external-dns/external-dns
newName: oci.thepeoples.io/hardened/external-dns
digest: sha256:de0e5484b88efce284532ee015e03bfcc79952d687fbac7199d50b14738d6a1a # v0.23.0-tpio.1Verify the latest published digest
cosign verify --key https://thepeoples.io/keys/oci.thepeoples.io.pub --insecure-ignore-tlog oci.thepeoples.io/hardened/external-dns@sha256:de0e5484b88efce284532ee015e03bfcc79952d687fbac7199d50b14738d6a1a
cosign verify-attestation --key https://thepeoples.io/keys/oci.thepeoples.io.pub --insecure-ignore-tlog --type https://thepeoples.io/attestations/hardened-gate/v1 oci.thepeoples.io/hardened/external-dns@sha256:de0e5484b88efce284532ee015e03bfcc79952d687fbac7199d50b14738d6a1aThe report views show the predicate types and commands for SPDX, scanner and optional OpenVEX attestations. Inspect the verified predicates as well as the signature. Publish and rescan reports for each tag. Gate is 0 CRITICAL / 0 HIGH from Trivy and Grype. MEDIUM/LOW are listed; they do not block publish. Remaining-CVE tables live here. 154.9 MiB · Publication scan reports: Trivy · Grype · gate · Scan index Corresponding source for MEDIUM/LOW are best-effort and non-blocking. Remaining counts: Fixed-version availability does not guarantee a compatible fix. Counts retain scanner gate semantics; the list deduplicates identical package/version records. Different scanner IDs can describe the same advisory.Evidence
v0.23.0-tpio.1 · worst-of Trivy and Grype at publish.v0.23.0-tpio.1 is at /oci/hardened/external-dns/v0.23.0-tpio.1/source/.Scanner CVE / ID Package Installed Severity Fixed version available
This image is here as the DNS record synchronizer.
Status: published. Platform: linux/amd64.
Available tags and scan history
v0.23.0-tpio.1
Digest:
oci.thepeoples.io/hardened/external-dns@sha256:de0e5484b88efce284532ee015e03bfcc79952d687fbac7199d50b14738d6a1aPublished 2026-10-20T13:33:54Z UTC.
This tag used the first-publish cooldown break-glass (first publish; PhreeStyle GO 2026-10-19 12:26 PM CT).
Publication scan reports: Trivy / Grype / gate / OpenVEX
SPDX SBOM · OpenVEX: not present
Corresponding source available at /oci/hardened/external-dns/v0.23.0-tpio.1/source/, including exact upstream archives, SHA-256 sums, packaging, rebuild recipe and recorded changes.
| Scanned (UTC) | Kind / gate | Trivy | Grype | Scanner DB versions/dates |
|---|---|---|---|---|
| 2026-10-20T13:24:18Z | publish / pass | CRITICAL 0HIGH 0MEDIUM 0LOW 0 | CRITICAL 0HIGH 0MEDIUM 0LOW 0 | Trivy 0.75.0 / DB {"DownloadedAt": "2026-10-20T13:22:20.798411005Z", "NextUpdate": "2026-10-21T07:17:35.36859973Z", "UpdatedAt": "2026-10-20T07:17:35.368599961Z", "Version": 2} / 2026-10-20T07:17:35.368599961Z; Grype 0.120.1 / schema v6.1.10 / 2026-10-20T06:29:49Z |
MEDIUM/LOW are best-effort and non-blocking. Remaining counts:
MEDIUM 0LOW 0Fixed-version availability does not guarantee a compatible fix.Remaining MEDIUM/LOW findings (0 distinct scanner/package/version records; 0 with fixed versions available)
Scanner CVE / ID Package Installed Severity Fixed version available
Counts retain scanner gate semantics; the list deduplicates identical package/version records. Different scanner IDs can describe the same advisory.
Rebuild and licence
The recipe rebuilds the binary from the pinned release with a digest-pinned Go toolchain, the standard golang.org/x/net@v0.60.0 bump, and a scratch runtime under UID 65532. Publication requires fresh unsuppressed 0 CRITICAL / 0 HIGH scans and functional validation for the exact digest.
Licence: Apache-2.0.
external-dns is Apache-2.0. Corresponding source is the official v0.23.0 tag tarball plus the Containerfile and recorded module changes. The archive license file is LICENSE.md.