External DNS for ROSA Custom Domain
This content is authored by Red Hat experts, but has not yet been tested on every supported configuration.
Configuring the Custom Domain Operator requires a wildcard CNAME DNS record in your Route53 Hosted Zone. If you do not wish to use a wildcard record, you can use the External DNS Operator to create individual entries for routes.
This document will guide you through deploying and configuring the External DNS Operator with a Custom Domain in ROSA.
Important Note: The ExternalDNS Operator does not support STS yet and uses long lived IAM credentials. This guide will be updated once STS is supported.
Prerequisites
- ROSA Cluster
- AWS CLI
- Route53 Hosted Zone
- A domain
Deploy
Setup Environment
- Set your email and domain
export EMAIL=<YOUR-EMAIL>
export DOMAIN=<YOUR-DOMAIN>
- Set remaining environment variables
export SCRATCH_DIR=/tmp/scratch
export ZONE_ID=$(aws route53 list-hosted-zones-by-name --output json \
--dns-name "$DOMAIN." --query 'HostedZones[0]'.Id --out text | sed 's/\/hostedzone\///')
mkdir -p $SCRATCH_DIR
Custom Domain
Check out the dynamic certificates guide if you do not want to use a wildcard certificate.
Create TLS Key Pair for custom domain using certbot:
Skip this if you already have a key pair.
certbot certonly --manual \ --preferred-challenges=dns \ --email $EMAIL \ --server https://acme-v02.api.letsencrypt.org/directory \ --agree-tos \ --config-dir "$SCRATCH_DIR/config" \ --work-dir "$SCRATCH_DIR/work" \ --logs-dir "$SCRATCH_DIR/logs" \ -d "*.$DOMAIN"
Create TLS secret for custom domain:
Note use your own keypair paths if not using certbot.
CERTS=/tmp/scratch/config/live/$DOMAIN oc new-project my-custom-route oc create secret tls acme-tls --cert=$CERTS/fullchain.pem --key=$CERTS/privkey.pem
Create Custom Domain resource:
cat << EOF | oc apply -f - apiVersion: managed.openshift.io/v1alpha1 kind: CustomDomain metadata: name: acme spec: domain: $DOMAIN certificate: name: acme-tls namespace: my-custom-route EOF
Wait for the domain to be ready:
oc wait --for=condition=Ready customdomains/acme --timeout=300s
External DNS
Deploy the External DNS Operator:
oc new-project external-dns-operator cat << EOF | oc apply -f - apiVersion: operators.coreos.com/v1 kind: OperatorGroup metadata: name: external-dns-group namespace: external-dns-operator spec: targetNamespaces: - external-dns-operator --- apiVersion: operators.coreos.com/v1alpha1 kind: Subscription metadata: name: external-dns-operator namespace: external-dns-operator spec: channel: stable-v1 installPlanApproval: Automatic name: external-dns-operator source: redhat-operators sourceNamespace: openshift-marketplace EOF
Wait until the Operator is running:
oc rollout status deploy external-dns-operator --timeout=300s
Create IAM Policy document that allows ExternalDNS to update Route53 only in your hosted zone:
cat << EOF > $SCRATCH_DIR/externaldns-r53-policy.json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "route53:ChangeResourceRecordSets" ], "Resource": [ "arn:aws:route53:::hostedzone/$ZONE_ID" ] }, { "Effect": "Allow", "Action": [ "route53:ListHostedZones", "route53:ListResourceRecordSets" ], "Resource": [ "*" ] } ] } EOF
Create IAM Policy:
POLICY_ARN=$(aws iam create-policy --policy-name "AllowExternalDNSUpdates" \ --policy-document file://$SCRATCH_DIR/externaldns-r53-policy.json \ --query 'Policy.Arn' --output text)
Create IAM user and attach policy:
Note: This will be changed to STS using IRSA in the future.
aws iam create-user --user-name "externaldns" aws iam attach-user-policy --user-name "externaldns" --policy-arn $POLICY_ARN
Create aws keys for IAM user:
SECRET_ACCESS_KEY=$(aws iam create-access-key --user-name "externaldns")
Create static credentials:
cat << EOF > $SCRATCH_DIR/credentials [default] aws_access_key_id = $(echo $SECRET_ACCESS_KEY | jq -r '.AccessKey.AccessKeyId') aws_secret_access_key = $(echo $SECRET_ACCESS_KEY | jq -r '.AccessKey.SecretAccessKey') EOF
Create secret from credentials:
oc create secret generic external-dns \ --namespace external-dns-operator --from-file $SCRATCH_DIR/credentials
Deploy ExternalDNS controller:
cat << EOF | oc apply -f - apiVersion: externaldns.olm.openshift.io/v1beta1 kind: ExternalDNS metadata: name: $DOMAIN spec: domains: - filterType: Include matchType: Exact name: $DOMAIN provider: aws: credentials: name: external-dns type: AWS source: openshiftRouteOptions: routerName: acme type: OpenShiftRoute zones: - $ZONE_ID EOF
Wait until the controller is running:
oc rollout status deploy external-dns-$DOMAIN --timeout=300s
Test
Create a new route to OpenShift console using your domain:
oc create route reencrypt --service=console console-acme \ --hostname console.$DOMAIN -n openshift-console
Check if DNS record was created automatically by ExternalDNS:
It may take a few minutes for the record to appear in Route53
aws route53 list-resource-record-sets --hosted-zone-id $ZONE_ID \ --query "ResourceRecordSets[?Type == 'CNAME']" | grep console
You can also view the TXT records that indicate they were created by ExternalDNS:
aws route53 list-resource-record-sets --hosted-zone-id $ZONE_ID \ --query "ResourceRecordSets[?Type == 'TXT']" | grep $DOMAIN
Navigate to your custom console domain in the browser and you should see OpenShift login.
echo console.$DOMAIN