Logo

As a fan of nip.io, I wanted to create my own version of it. So I did. This is a simple Rust application that can be deployed to Kubernetes to create a wildcard DNS resolver for your cluster. It’s a fun little project that I hope you’ll enjoy. It uses no external dependencies and is very lightweight, every DNS request and response is handled by the application itself, without any external libraries.

Wildcard DNS for any IP Address. RustyAlias allows you to map any IP Address to a hostname using the following formats (dot, dash or hex):

Without a name:

  • 10.0.0.1.example.com maps to 10.0.0.1
  • 192-168-1-250.example.com maps to 192.168.1.250
  • a000803.example.com maps to 10.0.8.3

With a name:

  • app.10.8.0.1.example.com maps to 10.8.0.1
  • app-116-203-255-68.example.com maps to 116.203.255.68
  • app-c0a801fc.example.com maps to 192.168.1.252
  • customer1.app.10.0.0.1.example.com maps to 10.0.0.1
  • customer2-app-127-0-0-1.example.com maps to 127.0.0.1
  • customer3-app-7f000101.example.com maps to 127.0.1.1

Prerequisites

  • A Kubernetes cluster or a Podman/Docker installation
  • A domain name or subdomain that you control

The domain name or subdomain needs to be specified in the GLUE_NAME environment variable and the RustyAlias public IP in the GLUE_IP. The SOA_NAME and HOSTMASTER environment variables are used to specify the SOA record and the hostmaster email address respectively.

They are needed so that the recursive DNS resolvers on the Internet follow the delegation to your DNS server, when recursively following a dot-notated domain name. For example, 1.ns.example.com -> SOA, 0.1.ns.example.com -> SOA, etc. All the way down to 127.0.0.1.ns.example.com -> A 127.0.0.1.

Installation

Please make sure that you have a domain name or subdomain that you control. You will need to create an NS record (just the one) for the domain or subdomain that points to the public IP address of the RustyAlias server.

Podman (or Docker)

podman run --rm -d \
--name rustyalias \
-p 53:5053/udp \
-e RUST_LOG=info \
-e GLUE_IP=[PUBLIC_IP] \
-e GLUE_NAME=ns.example.com \
-e SOA_NAME=ns.example.com \
-e HOSTMASTER=hostmaster.example.com \
ghcr.io/stenstromen/rustyalias:latest

Kubernetes

The Kubernetes deployment consists of a namespace, a deployment, and a service. The deployment uses the stenstromen/rustyalias image from GitHub Container Registry. The deployment is configured to run a single replica of the RustyAlias server and expose it on port 53. The service is configured to expose the RustyAlias server on port 53.

Namespace

apiVersion: v1
kind: Namespace
metadata:
  name: rustyalias

Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: rustyalias
  namespace: rustyalias
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 1
  selector:
    matchLabels:
      app: rustyalias
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: rustyalias
    spec:
      automountServiceAccountToken: false
      containers:
        - env:
            - name: RUST_LOG
              value: info
            - name: GLUE_NAME
              value: ns.example.com
            - name: SOA_NAME
              value: ns.example.com
            - name: HOSTMASTER
              value: hostmaster.example.com
            - name: GLUE_IP
              value: [PUBLIC_IP]
          image: ghcr.io/stenstromen/rustyalias:v1.2.0
          resources:
            limits:
              cpu: 100m
              memory: 32Mi
            requests:
              cpu: 100m
              memory: 32Mi
          securityContext:
            runAsUser: 65534
            runAsGroup: 65534
            privileged: false
            runAsNonRoot: true
            readOnlyRootFilesystem: true
            allowPrivilegeEscalation: false
            procMount: Default
            capabilities:
              drop: ["ALL"]
            seccompProfile:
              type: RuntimeDefault
          imagePullPolicy: IfNotPresent
          name: rustyalias
          ports:
            - containerPort: 5053
              protocol: UDP
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      terminationGracePeriodSeconds: 30

Service

apiVersion: v1
kind: Service
metadata:
  name: rustyalias-service
  namespace: rustyalias
spec:
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  - IPv6
  ipFamilyPolicy: RequireDualStack
  ports:
  - name: dns
    protocol: UDP
    port: 53
    targetPort: 5053
  selector:
    app: rustyalias
  type: LoadBalancer

Usage

Once the RustyAlias server is running and the NS record is created, you can start using it. You can use the RustyAlias server to resolve any domain name that matches the formats described above. Here are some examples:

dig app.127.0.0.1.ns.example.com -> A 127.0.0.1
dig app-127-0-0-1.ns.example.com -> A 127.0.0.1
dig app-7f000001.ns.example.com  -> A 127.0.0.1

GitHub Repository

The source code for RustyAlias is available on GitHub at Stenstromen/rustyalias.

Leave a Reply

Your email address will not be published. Required fields are marked *