Managed DNS
By default, the Route53 hosted zones that an AWS HostedCluster uses must exist
before the cluster is created. hypershift create infra aws (or the platform
consuming HyperShift) creates them:
- the public and private ingress zones, which hold the guest cluster's
*.appsrecords; - the
{cluster-name}.hypershift.localprivate zone, which PrivateLink clusters use for the records that let workers reach the control plane through the PrivateLink endpoint.
With managed DNS, the Control Plane Operator (CPO) creates and reconciles these zones itself, in the AWS account the cluster runs in. It can also delegate the public ingress zone from its parent zone, and create the ACME DNS-01 challenge record that certificate tooling needs.
Tech Preview
Managed DNS is gated by the AWSManagedDNS feature gate, which is
part of the TechPreviewNoUpgrade feature set. The HyperShift Operator (HO)
must be installed with --tech-preview-no-upgrade for the
spec.platform.aws.managedDNS field to be available. See
Feature Gates.
Managed DNS is opt-in per HostedCluster and can only be enabled at creation time, so installing an HO with this feature does not change existing clusters.
Zones and domains
Which zones the CPO manages depends on the VPC setup:
| Zone | Standard VPC | Shared VPC |
|---|---|---|
Public ingress zone ({ingressDomainPrefix}.{clusterBaseDomain}) |
Created and owned by the CPO | Created and owned by the CPO |
| Private ingress zone (same name, associated with the cluster VPC) | Created and owned by the CPO | Not managed. The VPC owner's private zone is used. |
{cluster-name}.hypershift.local private zone (PrivateLink clusters only, i.e. endpointAccess is PublicAndPrivate or Private) |
Created and owned by the CPO | Not managed. The VPC owner's local zone is used. |
Managed zones are tagged with spec.platform.aws.resourceTags.
The ingress zones are named {ingressDomainPrefix}.{clusterBaseDomain}, where
{clusterBaseDomain} is {baseDomainPrefix}.{baseDomain} from spec.dns. When
baseDomainPrefix is not set, the HostedCluster name is used as the prefix; when
it is set to an empty string, {clusterBaseDomain} is just {baseDomain}.
The guest cluster's apps domain moves under the ingress zones, to
apps.{ingressDomainPrefix}.{clusterBaseDomain}. Guest cluster routes, such as
the console, use this domain. Control plane endpoints such as the API server and
OAuth server are published separately through their service publishing
strategies, and managed DNS does not change where they resolve.
For example, a HostedCluster named example with baseDomain: example.com and
ingressDomainPrefix: in gets:
- ingress zones
in.example.example.com - apps domain
apps.in.example.example.com - local zone
example.hypershift.local, if it uses PrivateLink
How it works
Two CPO controllers share the work: the HostedControlPlane (HCP) controller
manages the ingress zones, and the AWS PrivateLink controller manages the
.hypershift.local zone. Errors in either are retried, and do not block the
rest of the HCP reconcile.
Ingress zones
The CPO checks the ingress zones periodically during HCP reconciliation, and
less often once AWSManagedDNSAvailable is True. On each check, it:
- Verifies the public ingress zone recorded in status still exists, and creates it if not.
- For standard VPC clusters, does the same for the private ingress zone, associating it with the cluster VPC in the cluster region.
- Records the zones it manages in
status.platform.aws.dnsZoneson the HCP: both ingress zones for standard VPC clusters, and only the public ingress zone for shared VPC clusters. The HO copies this to the HostedCluster status. - If
delegationis set, creates the ACME DNS-01 challenge CNAME and, inExternalDNSmode, theDNSEndpointfor NS delegation. See Delegation. - Sets the
AWSManagedDNSAvailablecondition. See Checking status.
Local zone
For PrivateLink clusters on a standard VPC, each time the PrivateLink controller
reconciles an AWSEndpointService, it verifies the
{cluster-name}.hypershift.local zone exists, and creates it associated with the
cluster VPC if not. It records the zone ID in the AWSEndpointService
status.dnsZoneID, then writes the PrivateLink endpoint records into the zone.
Errors are reported in the AWSEndpointAvailable condition, which the HO
copies to the HostedCluster.
Guest cluster DNS configuration
The Hosted Cluster Config Operator (HCCO) sets the guest cluster's
dns.config to the managed zones, so the ingress operator creates the *.apps
wildcard records in them:
apiVersion: config.openshift.io/v1
kind: DNS
metadata:
name: cluster
spec:
baseDomain: example.example.com
publicZone:
id: Z0123456789ABCDEFGHIJ # PublicIngress zone ID
privateZone:
id: Z9876543210JIHGFEDCBA # PrivateIngress zone ID; for shared VPC, spec.dns.privateZoneID
Existing zones
When creating a zone, the CPO first looks for an existing zone with the same name:
- Private zones (ingress and
.hypershift.local): an existing zone is adopted only if it is associated with the cluster VPC in the cluster region. A same-name private zone on another VPC is never adopted. - Public ingress zone: any existing public zone with the same name in the account is adopted.
Warning
An adopted public zone is treated as owned by the cluster, and is deleted along with its records when the cluster is deleted. Make sure the ingress zone name is not already in use in the account.
Out-of-band changes and deletion
If a managed zone is deleted outside of HyperShift, the CPO creates a new one on
its next check, records the new zone ID in status, and the HCCO points
dns.config at the new zone.
When the HostedCluster is deleted, the CPO deletes the DNSEndpoint and each
managed zone, clearing the records in it first. Cleanup skips NS and SOA records,
so a zone that holds NS records for child delegations retains them; AWS then
refuses to delete the zone until those records are removed by hand. If the CPO's
AWS credentials are no longer valid at that point, it logs the error and leaves
the zones in place.
Prerequisites
- The HO is installed with
--tech-preview-no-upgrade. -
The IAM roles for the cluster grant the Route53 permissions that managed DNS needs. Because the managed zone IDs are not known when the roles are created, these permissions apply to all hosted zones in the account. Pass
--managed-dnstohypershift create cluster aws, or tohypershift create iam awsif you create IAM separately, to add them:CPO role, in addition to its EC2 permissions. Attach this as an additional policy, or add its statements to the role's existing policy:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "route53:ListHostedZones", "route53:GetHostedZone", "route53:CreateHostedZone", "route53:DeleteHostedZone", "route53:ChangeTagsForResource" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "route53:ChangeResourceRecordSets", "route53:ListResourceRecordSets" ], "Resource": "arn:aws:route53:::hostedzone/*" } ] }Ingress operator role:
route53:ChangeResourceRecordSetsonarn:aws:route53:::hostedzone/*, instead of only the public and private zones that exist at infrastructure creation time.If you manage IAM roles outside the HyperShift CLI, add these permissions yourself. Without them, zone creation fails with
AccessDenied. -
For
ExternalDNSdelegation, external-dns is deployed with the AWS provider and can write to the parent zone. See ExternalDNS mode.
Enabling managed DNS
managedDNS can only be set when the HostedCluster is created. It cannot be
added or removed later, and ingressDomainPrefix cannot be changed.
delegation can be changed after creation.
Note
If the HO was installed without --tech-preview-no-upgrade, the HostedCluster
CRD does not include managedDNS. kubectl rejects the field, but clients
that do not request strict field validation, including the HyperShift CLI,
have it pruned, and the cluster is created without managed DNS. Check that
spec.platform.aws.managedDNS is set after creating the cluster.
Using the CLI
Pass --managed-dns to hypershift create cluster aws. The CLI sets
ingressDomainPrefix to in and creates the IAM roles with the permissions
listed above:
hypershift create cluster aws \
--name example \
--namespace clusters \
--base-domain example.com \
--region us-east-1 \
--aws-creds ${AWS_CREDS} \
--pull-secret ${PULL_SECRET} \
--release-image ${RELEASE_IMAGE} \
--node-pool-replicas 2 \
--managed-dns
The CLI does not configure delegation. To enable it or use a different prefix,
add --render --render-sensitive, edit spec.platform.aws.managedDNS in the
output, and apply it. --render-sensitive keeps the generated Secrets, including
the pull secret the HostedCluster references, in the output; without it the
applied cluster references a Secret that was never created. The rendered
manifests contain sensitive material, so handle them accordingly.
Using the API
apiVersion: hypershift.openshift.io/v1beta1
kind: HostedCluster
metadata:
name: example
namespace: clusters
spec:
dns:
baseDomain: example.com
platform:
type: AWS
aws:
region: us-east-1
managedDNS:
# Required. 1-63 lowercase alphanumeric characters or '-', starting and
# ending with an alphanumeric character. Immutable.
ingressDomainPrefix: in
# Optional. Omit to only create zones; the consuming platform then
# handles NS delegation and certificates.
delegation:
nsDelegationMode: ExternalDNS # or Manual
# ...
Delegation
The public ingress zone only resolves publicly once the enclosing authoritative
public zone holds NS records pointing to it. This is whichever zone is
authoritative for the parent domain; it need not be a dedicated zone for
{clusterBaseDomain}. The CLI, for example, looks up the public zone for
baseDomain.
When delegation is omitted, the CPO only creates the zones. NS delegation and
certificate management are left to the consuming platform, and
AWSManagedDNSAvailable becomes True as soon as the zones exist.
When delegation is set, the CPO also creates an ACME DNS-01 challenge CNAME in
the public ingress zone. This lets certificate tooling answer challenges for the
apps domain from the parent zone:
_acme-challenge.apps.in.example.example.com. CNAME _acme-challenge.example.example.com.
How the NS records get into the parent zone depends on nsDelegationMode.
In both modes, the CPO then waits until the ingress zone's NS records resolve
before reporting success.
ExternalDNS mode
The CPO creates a DNSEndpoint in the HCP namespace ({namespace}-{name} of
the HostedCluster, for example clusters-example), owned by the
HostedControlPlane:
apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
name: example-ingress-delegation
namespace: clusters-example
spec:
endpoints:
- dnsName: in.example.example.com
recordType: NS
recordTTL: 300
targets: # name servers of the public ingress zone
- ns-1.awsdns-01.org
- ns-2.awsdns-02.co.uk
- ns-3.awsdns-03.com
- ns-4.awsdns-04.net
external-dns writes this record to the parent zone. This requires external-dns
deployed by hypershift install with --external-dns-provider=aws, with
credentials and a --external-dns-domain-filter that cover the parent zone. With
the AWS provider, hypershift install also installs the DNSEndpoint CRD and
starts external-dns with --source=crd and NS added to its managed record types.
See External DNS for setting up external-dns.
Manual mode
The CPO publishes the public zone's name servers in
status.platform.aws.dnsZones[].nameServers, and the consuming platform creates
the NS records in the parent zone:
kubectl get hostedcluster example -n clusters \
-o jsonpath='{.status.platform.aws.dnsZones[?(@.zoneType=="PublicIngress")].nameServers}'
Checking status
The CPO reports progress through the AWSManagedDNSAvailable condition, which
is set on the HCP and mirrored to the HostedCluster:
kubectl get hostedcluster example -n clusters \
-o jsonpath='{.status.conditions[?(@.type=="AWSManagedDNSAvailable")]}'
| Status | Reason | Meaning |
|---|---|---|
True |
ManagedDNSSuccess |
The zones exist. When delegation is set, the ingress zone's NS records also resolve. |
False |
NSDelegationPending |
The zones exist but the ingress zone's NS records do not resolve yet. If delegation stays unresolved, the message changes to ask you to check the NS records in the parent zone. In ExternalDNS mode, the message includes any error from reconciling the DNSEndpoint. |
False |
ManagedDNSError |
Creating or verifying a zone, or creating the ACME CNAME, failed. The message contains the AWS error. |
The CPO checks NS resolution with a lookup from its own pod, so it uses the management cluster's DNS resolvers.
The managed ingress zones are listed in the HostedCluster status:
kubectl get hostedcluster example -n clusters -o jsonpath='{.status.platform.aws.dnsZones}'
[
{
"zoneType": "PublicIngress",
"zoneID": "Z0123456789ABCDEFGHIJ",
"name": "in.example.example.com",
"nameServers": ["ns-1.awsdns-01.org", "ns-2.awsdns-02.co.uk", "ns-3.awsdns-03.com", "ns-4.awsdns-04.net"]
},
{
"zoneType": "PrivateIngress",
"zoneID": "Z9876543210JIHGFEDCBA",
"name": "in.example.example.com"
}
]
Shared VPC clusters only list the PublicIngress zone. The .hypershift.local
zone is recorded in the AWSEndpointService status (status.dnsZoneID), not in
dnsZones.
Troubleshooting
ManagedDNSError, orAWSEndpointAvailableisFalse, with anAccessDeniedmessage: the CPO role lacks the managed DNS permissions. Recreate the IAM roles with--managed-dns, or add the permissions listed in Prerequisites.- Workers cannot reach the control plane on a PrivateLink cluster: check the
AWSEndpointAvailablecondition for errors creating the{cluster-name}.hypershift.localzone, and check that the zone in theAWSEndpointServicestatus.dnsZoneIDexists and is associated with the cluster VPC. - Stuck in
NSDelegationPending:- Check that the parent zone has NS records for the ingress zone, for example
with
dig NS in.example.example.com. - In
ExternalDNSmode, check that the{name}-ingress-delegationDNSEndpointexists in the HCP namespace, and look for errors in the external-dns logs in thehypershiftnamespace. - If the records resolve from your workstation, check that they also resolve from the management cluster, which is where the CPO looks them up.
- Check that the parent zone has NS records for the ingress zone, for example
with
*.appsrecords missing: check that the guestdns.configpublic and private zone IDs matchstatus.platform.aws.dnsZones, and look at the ingress operator'sDNSRecordstatus in the guest cluster:kubectl get dnsrecords -n openshift-ingress-operator -o yaml.- Zones left behind after deletion: if the CPO's AWS credentials were no longer valid when the cluster was deleted, the zones are left in place. Delete them in Route53.