From b44775ef2a0abf198110b67e5fbb956e0dc135fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Tue, 11 Aug 2026 14:05:37 +0000 Subject: [PATCH] feat(ingress): add public HTTPS ingress configuration with cert-manager support --- modules/amazon-eks-documentdb/README.md | 73 ++++++++++++++++++- .../ingress/cluster-issuer.yaml | 13 ++++ .../ingress/hub-ingresses.yaml | 52 +++++++++++++ .../ingress/hub-public-values.yaml | 7 ++ .../ingress/ingress-nginx-values.yaml | 15 ++++ .../amazon-eks-documentdb/ingress/install.sh | 43 +++++++++++ 6 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 modules/amazon-eks-documentdb/ingress/cluster-issuer.yaml create mode 100644 modules/amazon-eks-documentdb/ingress/hub-ingresses.yaml create mode 100644 modules/amazon-eks-documentdb/ingress/hub-public-values.yaml create mode 100644 modules/amazon-eks-documentdb/ingress/ingress-nginx-values.yaml create mode 100755 modules/amazon-eks-documentdb/ingress/install.sh diff --git a/modules/amazon-eks-documentdb/README.md b/modules/amazon-eks-documentdb/README.md index 24c4faa..4161c64 100644 --- a/modules/amazon-eks-documentdb/README.md +++ b/modules/amazon-eks-documentdb/README.md @@ -213,6 +213,73 @@ rerun after deleting or replacing the DocumentDB cluster. These are public example credentials. Do not use this seed data in a production deployment. +## Public HTTPS ingress + +The [`ingress`](ingress) package installs ingress-nginx behind an +internet-facing AWS Network Load Balancer, installs cert-manager, and creates +Let's Encrypt certificates for exactly these routes: + +| Host | Service | +| ---- | ------- | +| `aws-app.kerberos.lol` | `hub-frontend-svc:80` | +| `aws-api.kerberos.lol` | `hub-api-svc:8081` | + +Keep the Hub chart's global `ingress` value disabled. The module owns these two +Ingress resources so that enabling public access does not also expose the Hub +administration services. + +Install the controllers and resources: + +```bash +./ingress/install.sh +``` + +The script prints the NLB hostname. Create both DNS records as CNAMEs pointing +to that hostname. You can retrieve it again with: + +```bash +kubectl get service ingress-nginx-controller \ + --namespace ingress-nginx \ + --output jsonpath='{.status.loadBalancer.ingress[0].hostname}{"\n"}' +``` + +| DNS name | Type | Target | +| -------- | ---- | ------ | +| `aws-app.kerberos.lol` | CNAME | The ingress-nginx NLB hostname | +| `aws-api.kerberos.lol` | CNAME | The ingress-nginx NLB hostname | + +cert-manager automatically retries its HTTP-01 challenges after DNS resolves; +do not delete pending CertificateRequests. Wait for both certificates: + +```bash +kubectl wait --namespace kerberos-hub \ + --for=condition=Ready certificate/aws-app-kerberos-lol-tls \ + certificate/aws-api-kerberos-lol-tls \ + --timeout=10m +``` + +Set Hub's public URLs with the non-secret values fragment after the certificates +are ready. Include the same private Hub and DocumentDB values used for the +original installation: + +```bash +helm upgrade hub kerberos/hub \ + --version 0.127.0 \ + --namespace kerberos-hub \ + --file your-hub-values.yaml \ + --file hub-documentdb-values.yaml \ + --file ingress/hub-public-values.yaml \ + --atomic \ + --wait +``` + +Verify both public endpoints: + +```bash +curl --fail https://aws-api.kerberos.lol/health +curl --fail --output /dev/null https://aws-app.kerberos.lol/login +``` + ## Persistent volumes The EBS CSI driver is installed, but EKS ships `gp2` as the default storage @@ -238,8 +305,12 @@ EOF ## Tear down ```bash -# Remove the release first so its load balancers and volumes are cleaned up. +# Remove Kubernetes resources first so AWS load balancers and volumes are cleaned up. +kubectl delete -f ingress/hub-ingresses.yaml --ignore-not-found helm uninstall hub -n kerberos-hub +kubectl delete -f ingress/cluster-issuer.yaml --ignore-not-found +helm uninstall cert-manager -n cert-manager +helm uninstall ingress-nginx -n ingress-nginx terraform destroy ``` diff --git a/modules/amazon-eks-documentdb/ingress/cluster-issuer.yaml b/modules/amazon-eks-documentdb/ingress/cluster-issuer.yaml new file mode 100644 index 0000000..d9a7646 --- /dev/null +++ b/modules/amazon-eks-documentdb/ingress/cluster-issuer.yaml @@ -0,0 +1,13 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-prod +spec: + acme: + privateKeySecretRef: + name: letsencrypt-prod-account-key + server: https://acme-v02.api.letsencrypt.org/directory + solvers: + - http01: + ingress: + ingressClassName: nginx diff --git a/modules/amazon-eks-documentdb/ingress/hub-ingresses.yaml b/modules/amazon-eks-documentdb/ingress/hub-ingresses.yaml new file mode 100644 index 0000000..0c77116 --- /dev/null +++ b/modules/amazon-eks-documentdb/ingress/hub-ingresses.yaml @@ -0,0 +1,52 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: hub-frontend-ingress + namespace: kerberos-hub + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + nginx.ingress.kubernetes.io/ssl-redirect: "true" +spec: + ingressClassName: nginx + rules: + - host: aws-app.kerberos.lol + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: hub-frontend-svc + port: + number: 80 + tls: + - hosts: + - aws-app.kerberos.lol + secretName: aws-app-kerberos-lol-tls +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: hub-api-ingress + namespace: kerberos-hub + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + nginx.ingress.kubernetes.io/proxy-body-size: 200m + nginx.ingress.kubernetes.io/ssl-redirect: "true" +spec: + ingressClassName: nginx + rules: + - host: aws-api.kerberos.lol + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: hub-api-svc + port: + number: 8081 + tls: + - hosts: + - aws-api.kerberos.lol + secretName: aws-api-kerberos-lol-tls diff --git a/modules/amazon-eks-documentdb/ingress/hub-public-values.yaml b/modules/amazon-eks-documentdb/ingress/hub-public-values.yaml new file mode 100644 index 0000000..2d86d0d --- /dev/null +++ b/modules/amazon-eks-documentdb/ingress/hub-public-values.yaml @@ -0,0 +1,7 @@ +kerberoshub: + api: + schema: https + url: aws-api.kerberos.lol + frontend: + schema: https + url: aws-app.kerberos.lol diff --git a/modules/amazon-eks-documentdb/ingress/ingress-nginx-values.yaml b/modules/amazon-eks-documentdb/ingress/ingress-nginx-values.yaml new file mode 100644 index 0000000..5902623 --- /dev/null +++ b/modules/amazon-eks-documentdb/ingress/ingress-nginx-values.yaml @@ -0,0 +1,15 @@ +controller: + config: + use-forwarded-headers: "true" + ingressClass: nginx + ingressClassResource: + default: false + enabled: true + name: nginx + service: + annotations: + service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true" + service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing + service.beta.kubernetes.io/aws-load-balancer-type: nlb + externalTrafficPolicy: Local + type: LoadBalancer diff --git a/modules/amazon-eks-documentdb/ingress/install.sh b/modules/amazon-eks-documentdb/ingress/install.sh new file mode 100755 index 0000000..2b0505b --- /dev/null +++ b/modules/amazon-eks-documentdb/ingress/install.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly INGRESS_NGINX_VERSION="4.15.1" +readonly CERT_MANAGER_VERSION="v1.21.1" + +for command in helm kubectl; do + if ! command -v "${command}" >/dev/null 2>&1; then + echo "Missing required command: ${command}" >&2 + exit 1 + fi +done + +helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx --force-update +helm repo add jetstack https://charts.jetstack.io --force-update +helm repo update ingress-nginx jetstack + +helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \ + --version "${INGRESS_NGINX_VERSION}" \ + --namespace ingress-nginx \ + --create-namespace \ + --values "${SCRIPT_DIR}/ingress-nginx-values.yaml" \ + --atomic \ + --wait \ + --timeout 15m + +helm upgrade --install cert-manager jetstack/cert-manager \ + --version "${CERT_MANAGER_VERSION}" \ + --namespace cert-manager \ + --create-namespace \ + --set crds.enabled=true \ + --atomic \ + --wait \ + --timeout 15m + +kubectl apply --filename "${SCRIPT_DIR}/cluster-issuer.yaml" +kubectl wait --for=condition=Ready clusterissuer/letsencrypt-prod --timeout=2m +kubectl apply --filename "${SCRIPT_DIR}/hub-ingresses.yaml" + +kubectl get service ingress-nginx-controller \ + --namespace ingress-nginx \ + --output jsonpath='Load balancer: {.status.loadBalancer.ingress[0].hostname}{"\n"}'