Skip to content
1 change: 1 addition & 0 deletions docs/flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
| `--[no-]traefik-disable-legacy` | Disable listeners on Resources under the traefik.containo.us API Group |
| `--[no-]traefik-disable-new` | Disable listeners on Resources under the traefik.io API Group |
| `--nat64-networks=NAT64-NETWORKS` | Adding an A record for each AAAA record in NAT64-enabled networks; specify multiple times for multiple possible nets (optional) |
| `--[no-]expose-internal-ipv6` | When using the node source, expose internal IPv6 addresses (optional). Default is true. |
| `--provider=provider` | The DNS provider where the DNS records will be created (required, options: akamai, alibabacloud, aws, aws-sd, azure, azure-dns, azure-private-dns, civo, cloudflare, coredns, digitalocean, dnsimple, exoscale, gandi, godaddy, google, ibmcloud, inmemory, linode, ns1, oci, ovh, pdns, pihole, plural, rfc2136, scaleway, skydns, tencentcloud, transip, ultradns, webhook) |
| `--provider-cache-time=0s` | The time to cache the DNS provider record list requests. |
| `--domain-filter=` | Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional) |
Expand Down
30 changes: 29 additions & 1 deletion docs/sources/nodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,40 @@ This tutorial describes how to configure ExternalDNS to use the cluster nodes as
Using nodes (`--source=node`) as source is possible to synchronize a DNS zone with the nodes of a cluster.

The node source adds an `A` record per each node `externalIP` (if not found, any IPv4 `internalIP` is used instead).
It also adds an `AAAA` record per each node IPv6 `internalIP`.
It also adds an `AAAA` record per each node IPv6 `internalIP`. Refer to the [IPv6 Behavior](#ipv6-behavior) section for more details.
The TTL of the records can be set with the `external-dns.alpha.kubernetes.io/ttl` node annotation.

Nodes marked as **Unschedulable** as per [core/v1/NodeSpec](https://pkg.go.dev/k8s.io/[email protected]/core/v1#NodeSpec) are excluded.
This avoid exposing Unhealthy, NotReady or SchedulingDisabled (cordon) nodes.

## IPv6 Behavior

By default, ExternalDNS exposes the IPv6 `InternalIP` of the nodes. To prevent this, you can use the `--no-expose-internal-ipv6` flag.
**The default behavior will change in the next minor release.** ExternalDNS will no longer expose the IPv6 `InternalIP` addresses by default.
You can still explicitly expose the internal ipv6 addresses by using the `--expose-internal-ipv6` flag, if needed.

### Example spec (without exposing IPv6 `InternalIP` addresses)

```yaml
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: registry.k8s.io/external-dns/external-dns:v0.16.1 # update this to the desired external-dns version
args:
- --source=node # will use nodes as source
- --provider=aws
- --zone-name-filter=external-dns-test.my-org.com # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones
- --domain-filter=external-dns-test.my-org.com
- --aws-zone-type=public
- --registry=txt
- --fqdn-template={{.Name}}.external-dns-test.my-org.com
- --txt-owner-id=my-identifier
- --policy=sync
- --log-level=debug
- --no-expose-internal-ipv6
```

## Manifest (for cluster without RBAC enabled)

```yaml
Expand Down
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ func main() {
ResolveLoadBalancerHostname: cfg.ResolveServiceLoadBalancerHostname,
TraefikDisableLegacy: cfg.TraefikDisableLegacy,
TraefikDisableNew: cfg.TraefikDisableNew,
ExposeInternalIPv6: cfg.ExposeInternalIPV6,
}

// Lookup all the selected sources by names and pass them the desired configuration.
Expand Down
3 changes: 3 additions & 0 deletions pkg/apis/externaldns/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ type Config struct {
IgnoreIngressTLSSpec bool
IgnoreIngressRulesSpec bool
ListenEndpointEvents bool
ExposeInternalIPV6 bool
GatewayName string
GatewayNamespace string
GatewayLabelFilter string
Expand Down Expand Up @@ -240,6 +241,7 @@ var defaultConfig = &Config{
Compatibility: "",
PublishInternal: false,
PublishHostIP: false,
ExposeInternalIPV6: true,
ConnectorSourceServer: "localhost:8080",
Provider: "",
ProviderCacheTime: 0,
Expand Down Expand Up @@ -482,6 +484,7 @@ func App(cfg *Config) *kingpin.Application {
app.Flag("traefik-disable-legacy", "Disable listeners on Resources under the traefik.containo.us API Group").Default(strconv.FormatBool(defaultConfig.TraefikDisableLegacy)).BoolVar(&cfg.TraefikDisableLegacy)
app.Flag("traefik-disable-new", "Disable listeners on Resources under the traefik.io API Group").Default(strconv.FormatBool(defaultConfig.TraefikDisableNew)).BoolVar(&cfg.TraefikDisableNew)
app.Flag("nat64-networks", "Adding an A record for each AAAA record in NAT64-enabled networks; specify multiple times for multiple possible nets (optional)").StringsVar(&cfg.NAT64Networks)
app.Flag("expose-internal-ipv6", "When using the node source, expose internal IPv6 addresses (optional). Default is true.").BoolVar(&cfg.ExposeInternalIPV6)

// Flags related to providers
providers := []string{"akamai", "alibabacloud", "aws", "aws-sd", "azure", "azure-dns", "azure-private-dns", "civo", "cloudflare", "coredns", "digitalocean", "dnsimple", "exoscale", "gandi", "godaddy", "google", "ibmcloud", "inmemory", "linode", "ns1", "oci", "ovh", "pdns", "pihole", "plural", "rfc2136", "scaleway", "skydns", "tencentcloud", "transip", "ultradns", "webhook"}
Expand Down
32 changes: 19 additions & 13 deletions source/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,16 @@ import (
)

type nodeSource struct {
client kubernetes.Interface
annotationFilter string
fqdnTemplate *template.Template
nodeInformer coreinformers.NodeInformer
labelSelector labels.Selector
client kubernetes.Interface
annotationFilter string
fqdnTemplate *template.Template
nodeInformer coreinformers.NodeInformer
labelSelector labels.Selector
exposeInternalIPV6 bool
}

// NewNodeSource creates a new nodeSource with the given config.
func NewNodeSource(ctx context.Context, kubeClient kubernetes.Interface, annotationFilter, fqdnTemplate string, labelSelector labels.Selector) (Source, error) {
func NewNodeSource(ctx context.Context, kubeClient kubernetes.Interface, annotationFilter, fqdnTemplate string, labelSelector labels.Selector, exposeInternalIPv6 bool) (Source, error) {
tmpl, err := parseTemplate(fqdnTemplate)
if err != nil {
return nil, err
Expand Down Expand Up @@ -70,11 +71,12 @@ func NewNodeSource(ctx context.Context, kubeClient kubernetes.Interface, annotat
}

return &nodeSource{
client: kubeClient,
annotationFilter: annotationFilter,
fqdnTemplate: tmpl,
nodeInformer: nodeInformer,
labelSelector: labelSelector,
client: kubeClient,
annotationFilter: annotationFilter,
fqdnTemplate: tmpl,
nodeInformer: nodeInformer,
labelSelector: labelSelector,
exposeInternalIPV6: exposeInternalIPv6,
}, nil
}

Expand Down Expand Up @@ -177,10 +179,14 @@ func (ns *nodeSource) nodeAddresses(node *v1.Node) ([]string, error) {
var ipv6Addresses []string

for _, addr := range node.Status.Addresses {
addresses[addr.Type] = append(addresses[addr.Type], addr.Address)
// IPv6 addresses are labeled as NodeInternalIP despite being usable externally as well.
if addr.Type == v1.NodeInternalIP && suitableType(addr.Address) == endpoint.RecordTypeAAAA {
ipv6Addresses = append(ipv6Addresses, addr.Address)
if ns.exposeInternalIPV6 {
addresses[v1.NodeInternalIP] = append(addresses[v1.NodeInternalIP], addr.Address)
ipv6Addresses = append(ipv6Addresses, addr.Address)
}
} else {
addresses[addr.Type] = append(addresses[addr.Type], addr.Address)
}
}

Expand Down
Loading
Loading