Skip to content

Dynamic, whitelabel-style Ingress to your application

If your application allows for end-customers to use their custom domain, we've offered Caddy to provide on-demand SSL certificates for a while.

However with our Kubernetes reference solution there is a more native and scalable solution through the Nginx Ingress Controller and Cert-manager.

Our recommended way is that your application interacts directly with the Kubernetes API to register (and de-register) Ingress objects on-demand. You can find a list of official and community-supported K8s client libraries in the documentation.

Via the API you can submit an Ingress for the end-customer's domain, for example:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/tls-acme: "true"
  labels:
    use-http-solver: "true"
  name: www-example-com
  namespace: my-namespace
spec:
  ingressClassName: nginx
  rules:
    - host: www.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-service
                port:
                  name: http
  tls:
    - secretName: www-example-com-tls
      hosts:
        - www.example.com

Here's an example of how to create such Ingress via the Node.js K8s library: https://github.com/kubernetes-client/javascript/blob/master/examples/ingress.js.

Of course your application will also need credentials and the correct permissions to allow interaction with the K8s API. This can be controlled through Service Accounts and RBAC.

Create a ServiceAccount:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-app
  namespace: my-namespace

Create a Role with the proper permissions:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: my-app
  namespace: my-namespace
rules:
- apiGroups: ["networking.k8s.io"]
  resources: ["ingresses"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

Create a RoleBinding to attach the Role to the ServiceAccount:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: my-app
  namespace: my-namespace
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: my-app
subjects:
- kind: ServiceAccount
  name: my-app
  namespace: my-namespace

Set the ServiceAccount for your Pod:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: my-namespace
spec:
  template:
    metadata:
    # ...
    spec:
      serviceAccountName: my-app
      containers:
      # ...

This will automount the service account's Secret in your Pod and you can extract the required credentials from the following location:

  • Token: /var/run/secrets/kubernetes.io/serviceaccount/token
  • CA cert: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt

As endpoint of the API server it is recommended to use kubernetes.default.svc.

Note

Most client libraries will automatically pick up these credentials.

For more information on accessing the API from a Pod, and an example using the Go client library, check out the official documentation: https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a-pod.