# AWS Route53 with same domain for public and private zones This tutorial describes how to setup ExternalDNS using the same domain for public and private Route53 zones and [nginx-ingress-controller](https://github.com/kubernetes/ingress-nginx). It also outlines how to use [cert-manager](https://github.com/jetstack/cert-manager) to automatically issue SSL certificates from [Let's Encrypt](https://letsencrypt.org/) for both public and private records. ## Deploy public nginx-ingress-controller You may be interested with [GKE with nginx ingress](gke-nginx.md) for installation guidelines. Specify `ingress-class` in nginx-ingress-controller container args: ```yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app: external-ingress name: external-ingress-controller spec: replicas: 1 selector: matchLabels: app: external-ingress template: metadata: labels: app: external-ingress spec: containers: - args: - /nginx-ingress-controller - --default-backend-service=$(POD_NAMESPACE)/default-http-backend - --configmap=$(POD_NAMESPACE)/external-ingress-configuration - --tcp-services-configmap=$(POD_NAMESPACE)/external-tcp-services - --udp-services-configmap=$(POD_NAMESPACE)/external-udp-services - --annotations-prefix=nginx.ingress.kubernetes.io - --ingress-class=external-ingress - --publish-service=$(POD_NAMESPACE)/external-ingress env: - name: POD_NAME valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.namespace image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.11.0 livenessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 name: external-ingress-controller ports: - containerPort: 80 name: http protocol: TCP - containerPort: 443 name: https protocol: TCP readinessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 ``` Set `type: LoadBalancer` in your public nginx-ingress-controller Service definition. ```yaml apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "3600" service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: '*' labels: app: external-ingress name: external-ingress spec: externalTrafficPolicy: Cluster ports: - name: http port: 80 protocol: TCP targetPort: http - name: https port: 443 protocol: TCP targetPort: https selector: app: external-ingress sessionAffinity: None type: LoadBalancer ``` ## Deploy private nginx-ingress-controller Make sure to specify `ingress-class` in nginx-ingress-controller container args: ```yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app: internal-ingress name: internal-ingress-controller spec: replicas: 1 selector: matchLabels: app: internal-ingress template: metadata: labels: app: internal-ingress spec: containers: - args: - /nginx-ingress-controller - --default-backend-service=$(POD_NAMESPACE)/default-http-backend - --configmap=$(POD_NAMESPACE)/internal-ingress-configuration - --tcp-services-configmap=$(POD_NAMESPACE)/internal-tcp-services - --udp-services-configmap=$(POD_NAMESPACE)/internal-udp-services - --annotations-prefix=nginx.ingress.kubernetes.io - --ingress-class=internal-ingress - --publish-service=$(POD_NAMESPACE)/internal-ingress env: - name: POD_NAME valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.namespace image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.11.0 livenessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 name: internal-ingress-controller ports: - containerPort: 80 name: http protocol: TCP - containerPort: 443 name: https protocol: TCP readinessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 ``` Set additional annotations in your private nginx-ingress-controller Service definition to create an internal load balancer. ```yaml apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "3600" service.beta.kubernetes.io/aws-load-balancer-internal: 0.0.0.0/0 service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: '*' labels: app: internal-ingress name: internal-ingress spec: externalTrafficPolicy: Cluster ports: - name: http port: 80 protocol: TCP targetPort: http - name: https port: 443 protocol: TCP targetPort: https selector: app: internal-ingress sessionAffinity: None type: LoadBalancer ``` ## Deploy the public zone ExternalDNS Consult [AWS ExternalDNS setup docs](aws.md) for installation guidelines. In ExternalDNS containers args, make sure to specify `aws-zone-type` and `ingress-class`: ```yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app: external-dns-public name: external-dns-public namespace: kube-system spec: replicas: 1 selector: matchLabels: app: external-dns-public strategy: type: Recreate template: metadata: labels: app: external-dns-public spec: containers: - args: - --source=ingress - --provider=aws - --registry=txt - --txt-owner-id=external-dns - --ingress-class=external-ingress - --aws-zone-type=public image: registry.k8s.io/external-dns/external-dns:v0.15.0 name: external-dns-public ``` ## Deploy the private zone ExternalDNS Consult [AWS ExternalDNS setup docs](aws.md) for installation guidelines. In ExternalDNS containers args, make sure to specify `aws-zone-type` and `ingress-class`: ```yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app: external-dns-private name: external-dns-private namespace: kube-system spec: replicas: 1 selector: matchLabels: app: external-dns-private strategy: type: Recreate template: metadata: labels: app: external-dns-private spec: containers: - args: - --source=ingress - --provider=aws - --registry=txt - --txt-owner-id=dev.k8s.nexus - --ingress-class=internal-ingress - --aws-zone-type=private image: registry.k8s.io/external-dns/external-dns:v0.15.0 name: external-dns-private ``` ## Create application Service definitions For this setup to work, you need to create two Ingress definitions for your application. At first, create a public Ingress definition: ```yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: labels: app: app name: app-public spec: ingressClassName: external-ingress rules: - host: app.domain.com http: paths: - backend: service: name: app port: number: 80 pathType: Prefix ``` Then create a private Ingress definition: ```yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: labels: app: app name: app-private spec: ingressClassName: internal-ingress rules: - host: app.domain.com http: paths: - backend: service: name: app port: number: 80 pathType: Prefix ``` Additionally, you may leverage [cert-manager](https://github.com/jetstack/cert-manager) to automatically issue SSL certificates from [Let's Encrypt](https://letsencrypt.org/). To do that, request a certificate in public service definition: ```yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: certmanager.k8s.io/acme-challenge-type: "dns01" certmanager.k8s.io/acme-dns01-provider: "route53" certmanager.k8s.io/cluster-issuer: "letsencrypt-production" kubernetes.io/tls-acme: "true" labels: app: app name: app-public spec: ingressClassName: "external-ingress" rules: - host: app.domain.com http: paths: - backend: service: name: app port: number: 80 pathType: Prefix tls: - hosts: - app.domain.com secretName: app-tls ``` And reuse the requested certificate in private Service definition: ```yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: labels: app: app name: app-private spec: ingressClassName: "internal-ingress" rules: - host: app.domain.com http: paths: - backend: service: name: app port: number: 80 pathType: Prefix tls: - hosts: - app.domain.com secretName: app-tls ```