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.
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