Blog / Defense-In-Depth / Email Strict Transport Security with MTA-STS

Email Strict Transport Security with MTA-STS

Email. Insecure by design. SMTP was designed in an era of high trust and low understanding of the shenanigans that would later arise on the Internet. In particular, encryption, let alone email strict transport security, was not something baked in from the start. Let’s fix that!

After waves of spam and snooping and phishing and ransomware etc., many band-aids were added over the years. DNS-based realtime blackhole lists (DNSRBL), STARTTLS, authentication, DANE, … so many. Did you know some email providers don’t even allow encrypting your mail in transit?

After spending yesterday double and triple checking our DMARC, DKIM, SPF (due to some suspected delivery problems), I decided to enable MTA-STS. Why not, one more standard can’t hurt right? If you want to understand some of the issues this is addressing, this article from The Register is a good spot to start.

In a nutshell, in MTA-STS, you add 2 more DNS records (because its a general purpose database of key/value pairs, right?), and then add a new web site (which must be proper TLS), with a single file (/.well-known/mta-sts.txt). And boom. You now have Strict Transport Security (STS) on your Mail Transfer Agent (MTA). As you know we are all-in on the TLS, placing our domain(s) on the HSTS preload list. Encryption or GTFO.

email strict transport security
MTA-STS checker

Now, it might seem like a pain to bring up a new web site just for this. But, hold my beer, we got this. Cuz cloud native and Kubernetes. Engage your peril-sensitive sunglasses, here come some YAML. You can skip to the GitHub if you want to use it and start enjoying email strict transport security today.

---
apiVersion: apps/v1
kind: Deployment
metadata:
name: server
namespace: mta-sts
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.17.5
ports:
- containerPort: 80
name: http
protocol: TCP
volumeMounts:
- name: config
mountPath: /usr/share/nginx/html/.well-known
volumes:
- name: config
configMap:
name: config
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
certmanager.k8s.io/cluster-issuer: letsencrypt-prod
kubernetes.io/ingress.class: nginx-transparent
ingress.kubernetes.io/ssl-redirect: "true"
name: ingress
namespace: mta-sts
spec:
rules:
host: mta-sts.agilicus.com http:   paths: backend:
serviceName: service
servicePort: http
path: /
host: mta-sts.agilicus.ca http:   paths: backend:
serviceName: service
servicePort: http
path: /
tls:
hosts: mta-sts.agilicus.com
mta-sts.agilicus.ca
secretName: mta-sts-tls 
---
apiVersion: v1
kind: ConfigMap
metadata:
name: config
namespace: mta-sts
data:
mta-sts.txt: |
version: STSv1
mode: testing
mx: aspmx.l.google.com
mx: alt1.aspmx.l.google.com
mx: alt2.aspmx.l.google.com
mx: alt3.aspmx.l.google.com
mx: alt4.aspmx.l.google.com
max_age: 604800
---
apiVersion: v1
kind: Service
metadata:
name: service
namespace: mta-sts
spec:
ports:
name: http
port: 80
protocol: TCP
targetPort: http
selector:
app: nginx
type: ClusterIP 

Leave a Reply

Your email address will not be published.