![]()
This is a simple implementation of a DNS over HTTPS (DoH) server using Kubernetes. The server is implemented using the dns-over-https protocol. The server is hosted on Kubernetes and uses the cert-manager to automatically provision TLS certificates for the server.
The container image for the Kubernetes deployment is maintained by GitHub.com/m13253, which is a DoH server implementation in Go.
Kubernetes Deployment
Below is a highly secure Deployment and ConfigMap of the DoH server on Kubernetes. It does not run as root and uses a non-root user. The deployment also uses a read-only file system, with a temporary -scratch- /server and /tmp directory (notice the initContainers).
ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: doh-config
namespace: default
data:
UPSTREAM_DNS_SERVER: 'udp:1.1.1.1:53' # Cloudflare DNS
DOH_HTTP_PREFIX: '/query'
DOH_SERVER_LISTEN: ':8080'
DOH_SERVER_TIMEOUT: '10'
DOH_SERVER_TRIES: '3'
DOH_SERVER_VERBOSE: 'false'
Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: doh
namespace: default
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 1
selector:
matchLabels:
app: doh
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
app: doh
spec:
automountServiceAccountToken: false
initContainers:
- name: init-copy-server
image: satishweb/doh-server:v2.3.6-alpine
command: ['sh', '-c', 'cp -r /server/* /init-server/']
volumeMounts:
- mountPath: /init-server
name: server
containers:
- name: doh
image: satishweb/doh-server:v2.3.6-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
protocol: TCP
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /tmp
name: tmp
- mountPath: /server
name: server
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 64Mi
securityContext:
runAsUser: 65534
runAsGroup: 65534
privileged: false
runAsNonRoot: true
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
procMount: Default
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
livenessProbe:
httpGet:
path: /q?name=en.wikipedia.org
port: 8080
readinessProbe:
httpGet:
path: /q?name=en.wikipedia.org
port: 8080
envFrom:
- configMapRef:
name: doh-config
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
terminationGracePeriodSeconds: 30
volumes:
- name: tmp
emptyDir: {}
- name: server
emptyDir: {}
securityContext:
fsGroup: 65534
Kubernetes Service and Ingress
The service and ingress for the DoH server are as follows, I use the nginx-ingress controller for the ingress and a cert-manager cluster issuer named letsencrypt-prod.
Service
apiVersion: v1
kind: Service
metadata:
name: doh-service
namespace: default
spec:
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- port: 8080
protocol: TCP
targetPort: 8080
selector:
app: doh
Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/rewrite-target: /
name: doh-ingress
namespace: default
spec:
ingressClassName: nginx
rules:
- host: doh.example.com
http:
paths:
- backend:
service:
name: doh-service
port:
number: 8080
path: /
pathType: Prefix
tls:
- hosts:
- doh.example.com
secretName: doh-tls
Testing and Implementing the DoH Server
To test the DoH server, you can use the curl command to query the server. Below is an example of a query to the DoH server.
curl -s -H 'accept: application/dns-json' 'https://doh.example.com/query?name=example.com&type=A'
The above command will return a JSON response with the DNS query for the domain example.com.
Firefox Configuration
You can also configure Firefox to use the DoH server. To do this, open Firefox and go to about:config. Search for network.trr.mode and set the value to 3. Then search for network.trr.uri and set the value to https://doh.example.com/query.