DOH (DNS over HTTPS) or DOT (DNS over TLS) can be used to encrypt DNS requests to avoid privacy leaks over untrusted networks. In the case of Safe Surfer, DOH/DOT can be used to attribute requests to a source device more easily. This is done using the DNS token of the device. For DOH, the DNS token is specified in the path, e.g. https://doh.ss.example.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
. For DOT, the DNS token is specified in the subdomain, e.g. xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.dot.ss.example.com
.
In this guide, we will assume you’ve set up the DNS either in kubernetes or on servers using the ss-config
tool.
All you have to do is set the following keys in your values.yaml
, for either the Helm chart or ss-config
:
dns:
doh:
enabled: true
# Tone down resources for testing
replicas: 1
host: doh.ss.example.com
dot:
enabled: true
# Tone down resources for testing
replicas: 1
host: dot.ss.example.com
Both doh
and dot
require tls
to be configured, but the options here are different for Kubernetes or ss-config
.
To set up a certificate for doh/dot on kubernetes, see the ingress and cert guide. HTTP01 validation is not supported for these services because:
Therefore, a custom certificate or DNS01 hooked up using tls.secretName
are the only options. Just keep in mind that DOT needs a wildcard certificate for its subdomain, e.g. *.dot.ss.example.com
, whereas DOH hosted at doh.ss.example.com
could happily use a certificate generated for *.ss.example.com
like the example shows.
Warning DOH and DOT will automatically re-rollout when the current cert expires according to the time of the cluster. To avoid downtime due to time synchronization issues, re-rollout manually a day or so after the certificate renews. You can do this by e.g.
kubectl rollout restart deployment safesurfer-doh
orkubectl rollout restart deployment safesurfer-dns
if in sidecar mode.
The ss-config
values only support custom
as a cert option, but they also support an additional parameter, certSync
, which periodically retrieves the public key from a host to keep the certificate valid. For example:
dns:
doh:
tls:
custom:
cert:
key:
# Comment out to disable cert sync
certSync:
# Hostname to grab the public SSL cert from
endpoint:
# In systemd calendar timer format
schedule: '*-*-* 4:00:00'
dot:
tls:
custom:
cert:
key:
# Comment out to disable cert sync
certSync:
# Hostname to grab the public SSL cert from
endpoint:
# In systemd calendar timer format
schedule: '*-*-* 4:00:00'
certSync
will check the new certificate matches the private key and isn’t expired before applying it and restarting doh/dot. For convenience, you can use the serveCertOnly
option on doh
or dot
on kubernetes to host the certificate without actually hosting the DNS.
You can get DOH/DOT going on the same IP address, on separate addresses, or even on the same IP address as plain DNS. When using ss-config
, the method is fairly simple. The bindPort
parameter should already start them on the correct addresses to share with each other and plain DNS. On Kubernetes, there are a few different options:
The default kubernetes config will start DOH/DOT as seperate deployments on separate addresses.
To share an address between DOH/DOT, disable the deployment and enable sidecar mode like so:
dns:
dns:
enabled: true
hostNetwork: false
service:
tcp:
# Enabling this will enable DOH/DOT services on the DNS LB
enabled: true
type: LoadBalancer
port: 53
doh:
deployment: false
sidecar: true
host: secure-dns.ss.example.com # Use the same host
dot:
deployment: false
sidecar: true
host: secure-dns.ss.example.com # Use the same host
This may have lower latency than deployment mode, since the DOH/DOT containers are always on the same machine (and within the same local network) as the main DNS container. However, it will be slower to roll out and scale, since the DNS init container must run for each new pod created.
Note In this mode, the the
replicas
,deploymentStrategy
,horizonalPodAutoscaler
,podDisruptionBudget
,service
, andaffinity
fields below have no effect. To make changes to these fields, you’ll have to consider the DNS deployment as a whole using thedns.dns
fields.
After deploying something like the above, remembering to set up certs, you should see a pod like this:
NAME READY STATUS RESTARTS AGE
safesurfer-dns-76fbd7cf8f-8ftqq 5/5 Running 0 13s
And run kubectl get service
to see your new service IP:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
safesurfer-dns-tcp LoadBalancer 10.0.93.39 xx.xx.xxx.xx 53:31978/TCP,443:30879/TCP,853:30384/TCP 24m
The service includes DOH, DOT, and plain DNS, but due to kubernetes limitations the DNS is TCP-only. To truly get plain DNS working alongside DOH and DOT, see the next section.
To get plain DNS going alongside DOH and DOT, we’ll use the host networking mode introduced in the getting started guide. Overwrite the following keys in your values.yaml
:
dns:
dns:
enabled: true
hostNetwork: true
service:
tcp:
enabled: false
sidecarContainers:
healthCheck:
bindPort: 53531
httpSecret:
enabled: true
secret: generate-a-strong-secret
doh:
deployment: false
sidecar: true
host: secure-dns.ss.example.com # Use the same host
dot:
deployment: false
sidecar: true
host: secure-dns.ss.example.com # Use the same host
Then, update the load balancing rules pointing to your node pool as described in the getting started guide. DOH runs on port 8443 and has a HTTP health check on port 8888. Its frontend port should be 443
. DOT runs on port 8358 and has a HTTP health check on port 8889. Its frontend port should be 853
. Both HTTP health checks use the GET method and /
as the path. Remember to allow ports 8443
and 8358
through the firewall.
Once you’ve set up DOH/DOT using any of the above methods, you’re ready to test.
If you’ve set up the API and frontend as part of an earlier guide, you should be able to refresh the frontend to view URLs you can use to test secure DNS. Select Connect
on a device on the Devices page and you should see something like the following:
You can test DOH by putting the URL into your browser settings under Use secure DNS
. This is supported by Firefox, Edge, and Chrome. You can test DOT by using Private DNS on Android or the kdig tool with the +tls
option.
You can test DOH on Apple devices by configuring the .mobileconfig
file download. Add something like the following to your values.yaml
api:
devices:
appleMobileConfig:
dohAddresses: xx.xx.xx.xx
dohHost: secure-dns.ss.example.com
description: Use DNS filtering and logging
name: Secure DNS
extraSettings:
# Make browsers use it by default
braveStable: true
braveBeta: true
braveNightly: true
chrome: true
edge: true
vivaldi: true
chromium: true
firefox: true
yandex: true
identifiers:
payload: com.example.profile
dnsSettings: com.example.profile.dnsSettings
braveStable: com.example.profile.bravestablesettings
braveBeta: com.example.profile.bravebetasettings
braveNightly: com.example.profile.bravenightlysettings
chrome: com.example.profile.chromesettings
edge: com.example.profile.edgesettings
vivaldi: com.example.profile.vivaldisettings
chromium: com.example.profile.chromiumsettings
firefox: com.example.profile.firefoxsettings
yandex: com.example.profile.yandexsettings
Warning Be extremely careful to maintain control of the IP you specify under
dohAddresses
.
After re-deploying, you should now be able to use the Apple Mobileconfig download button on the frontend.