In deel 1, hebben we een snelle rondleiding gehad door S/MIME, waarbij we keken naar het ondertekenen en versleutelen van onze berichtstromen over verschillende mailclients. Deel 2 leidde ons door een eenvoudig opdrachtregelprogramma om e-mails te ondertekenen en te versleutelen en ze vervolgens via SparkPost te verzenden. Deel 3 toonde hoe je veilige mailstromen kunt injecteren in on-premises platforms zoals Port25 PowerMTA en Momentum.
In deze serie hebben we gezien hoe het opnemen van een S/MIME-handtekening vrij eenvoudig is. S/MIME versleutelde mail verzenden is complexer omdat je openbare sleutels van ontvangers moet verkrijgen. Het is één ding wanneer je een mailclient voor mensen gebruikt zoals Thunderbird – maar hoe kan dat werken met app-gegeneerde e-mailstromen?
Maar wacht – er is een andere manier om in Mordor die sleutels te krijgen. Je service kan je klanten uitnodigen (via e-mail, natuurlijk) om je een ondertekende mail terug te sturen naar een bekend klantenserviceadres. Met de magische krachten van SparkPost Inbound Relay webhooks, zullen we die publieke sleutel extraheren en opslaan voor jou om te gebruiken.
We kunnen dit samenvatten in een eenvoudig toepassingsgeval:
Als ontvanger van berichten geef ik je service mijn persoonlijke e-mailhandtekening via e-mail, zodat in de toekomst e-mails versleuteld in S/MIME-vorm naar mij kunnen worden verzonden.
Vanuit dit laten we enkele meer gedetailleerde vereisten afleiden:
We hebben een altijd-actieve, betrouwbare inkomende e-mailservice nodig om die ondertekende e-mails te ontvangen.
Er mogen geen speciale eisen aan het mailformaat zijn, anders dan dat het een S/MIME-handtekening moet bevatten.
Omdat iedereen een mail naar deze service kan proberen te sturen, moet deze defensief worden ontworpen, bijvoorbeeld om “spoof” berichten van kwaadwillenden te weigeren. Er moeten meerdere controlelagen zijn.
Als alles in orde is, slaat de service het certificaat op in een bestand, met behulp van het bekende platte tekst Privacy-Enhanced Mail (PEM) formaat.
Er zijn enkele niet-functionele vereisten:
Machine-to-machine webhook services kunnen moeilijk te zien zijn alleen vanuit responsies op wat erbinnen gebeurt. De service moet uitgebreide mensleesbare applicatieniveau-logs bieden. Met name moet het parsen en controleren van het certificaat worden gelogd.
We voegen testcases toe voor de interne app, met behulp van het mooie Pytest framework, en draaien die tests automatisch bij inchecken via Travis CI integratie met GitHub.
OK – laten we beginnen!
1. Overzicht van de oplossing
Hier is hoe de algehele oplossing eruit zal zien.
2. Installeren, configureren en starten van de webapp
We beginnen met dit gedeelte, zodat we het volledig getest hebben voordat we de inkomende relay webhooks aansluiten.
De webapp is opgenomen in hetzelfde GitHub project als delen 1 – 3, dus als je die delen hebt gevolgd, heb je het al. Hier zijn de nieuwe onderdelen:
Programma readSMIMEsig.py – lees een e-mail en parseer tussenliggende en gebruikerscertificaten.
Programma webapp.py – eenvoudige Flask-compatibele webapplicatie voor gebruik met SparkPost Inbound Relay Webhooks.
webapp.ini – configuratiebestand voor het bovenstaande. Een configbestand maakt het mogelijk dezelfde waarden eenvoudig door te geven aan zowel opdrachtlijn-als webapplicaties.
Je moet ervoor zorgen dat je host het juiste TCP-poortnummer open heeft voor inkomende verzoeken van buitenaf zodat SparkPost berichten naar je app kan POSTen. Als je bijvoorbeeld gehost wordt op AWS EC2, moet je de Security Group van je instantie configureren.
Instructies voor het configureren en starten van de webapp worden hier gegeven – het is vrij eenvoudig. Om te controleren of je app draait en toegankelijk is van buitenaf, kun je (lege) verzoeken verzenden vanaf een andere host met behulp van curl, bijvoorbeeld:
curl -X POST https://app.trymsys.net:8855/
Je zou een reactie moeten zien zoals:
{"message":"Onbekende Content-Type in verzoekheaders"}
Dit is goed – je app draait!
In webapp.log op je host, zie je uitvoer die hierop lijkt:
2019-01-15 00:11:07,575,root,INFO,Verzoek van 38.96.5.10,scheme=https,path=/ 2019-01-15 00:11:07,575,root,INFO,| len(headers)=3,len(body)=None 2019-01-15 00:11:07,575,root,INFO,| Onbekende Content-Type: None
Om je te helpen direct met echte data in je app te spelen, kun je dit specifieke Postman verzoek uit de projectrepox importeren. Dit simuleert wat je SparkPost account zal doen, d.w.z. het stuurt een https POST die een e-mail met een specifiek, geldig certificaat (van een testaccount van mij) naar je app bevat.
Je hoeft alleen het doeladres in het verzoek (in het grijze vak hierboven) te wijzigen om overeen te komen met je installatie. Als je de tokenwaarde in webapp.ini hebt gewijzigd, pas dan de headerwaarde in Postman aan om overeen te komen.
Als je app werkt, krijg je een “200 OK” reactie terug in Postman. Je host webapp.log-bestand bevat uitvoer zoals dit:
2019-01-15 00:11:48,554,root,INFO,Verzoek van 38.96.5.10,scheme=https,path=/ 2019-01-15 00:11:48,554,root,INFO,| len(headers)=10,len(body)=14778 2019-01-15 00:11:48,555,root,INFO,| msg_from=bob.lumreeker@gmail.com,rcpt_to=secureme@inbound.thetucks.com,len(email_rfc822)=9223 2019-01-15 00:11:48,599,root,INFO,| from=bob.lumreeker@gmail.com,DKIM geslaagd 2019-01-15 00:11:48,600,root,INFO,| content-type=multipart/signed; protocol="application/pkcs7-signature"; micalg=sha-256; boundary="------------ms010908020707040304020406",content-description=None 2019-01-15 00:11:48,600,root,INFO,| content-type=text/plain; charset=utf-8; format=flowed,content-description=None 2019-01-15 00:11:48,600,root,INFO,| content-type=application/pkcs7-signature; name="smime.p7s",content-description=S/MIME Cryptographic Signature 2019-01-15 00:11:48,600,root,INFO,| filename=smime.p7s,bytes=3998 2019-01-15 00:11:48,601,root,INFO,| Certificaat: subject email_address=['bob.lumreeker@gmail.com'],not_valid_before=2018-10-03 00:00:00,not_valid_after=2019-10-03 23:59:59,hash_algorithm=sha256,key_size=2048 bytes, issuer={'countryName': 'GB', 'stateOrProvinceName': 'Greater Manchester', 'localityName': 'Salford', 'organizationName': 'COMODO CA Limited', 'commonName': 'COMODO RSA Client Authentication and Secure Email CA'} 2019-01-15 00:11:48,602,root,INFO,| Certificaat: subject email_address=[],not_valid_before=2013-01-10 00:00:00,not_valid_after=2028-01-09 23:59:59,hash_algorithm=sha384,key_size=2048 bytes, issuer={'countryName': 'GB', 'stateOrProvinceName': 'Greater Manchester', 'localityName': 'Salford', 'organizationName': 'COMODO CA Limited', 'commonName': 'COMODO RSA Certification Authority'} 2019-01-15 00:11:48,616,root,INFO,| geschreven bestand ./bob.lumreeker@gmail.com.crt,bytes=1870,ok=True
Voor een snelle gezond verstand controle, kijk naar de laatste regel – als er staat "geschreven bestand", dan ben je goed. De rest van dit toont het DKIM controle- en certificaatvalidatieproces.
3. Inkomend relay webhooks instellen met SparkPost
Ten eerste selecteren we een domein om te gebruiken als ons inkomend berichtadres – hier zal het inbound.thetucks.com zijn. Richt je domein in volgens deze gids. Hier zijn de stappen die ik in detail heb gebruikt:
3.1 Voeg MX Records toe
Je hebt toegang nodig tot het account van je specifieke internetprovider. Als je klaar bent, kun je ze controleren met dig – hier is het commando voor mijn domein.
dig +short MX inbound.thetucks.com
Je zou moeten zien:
10 rx3.sparkpostmail.com. 10 rx1.sparkpostmail.com. 10 rx2.sparkpostmail.com.
3.2 Maak een inkomend domein aan
Gebruik de SparkPost Postman API collectie, waarbij je de Inbound Domains / Create .. oproep selecteert. De body van de POST-aanvraag bevat je domein, bijvoorbeeld:
{ "domain": "inbound.thetucks.com" }
3.3 Maak een Relay Webhook aan
Maak een inbound relay webhook aan met behulp van de relevante Postman-oproep. De berichtbody in mijn geval bevat:
{ "name": "Certificate Collection Webhook", "target": "https://app.trymsys.net:8855/", "auth_token": "t0p s3cr3t t0k3n", "match": { "protocol": "SMTP", "domain": "inbound.thetucks.com" } }
Zoals eerder vermeld, raad ik aan om een auth_token te zetten naar je eigen geheime waarde, zoals ingesteld in het webapp.ini-bestand op je host.
Je “target” waarde moet overeenkomen met je hostadres en TCP-poort waar je de webapp host.
Je “domain” waarde moet overeenkomen met je MX records die zijn ingesteld in stap 1.
Dat is het! De leidingen zijn aangelegd. Je zou nu certificaten naar je inkomende adres moeten kunnen sturen, ze worden verwerkt en verschijnen op je webapplicatiehost – in dit geval een bestand genaamd bob.lumreeker@gmail.com.crt.
Nu kun je versleutelde e-mails naar Bob sturen, met behulp van de tools beschreven in delen 2 & 3 van deze serie.
Je kunt de inhoud van een certificaat bekijken met:
openssl x509 -inform PEM -in bob.lumreeker\@gmail.com.crt -text -noout
4. Internals: DKIM-controle, certificaatvalidatie
De app controleert of ontvangen e-mails geldige DKIM hebben en controleert dat de certificaten zelf geldig zijn, zoals hier beschreven. Er zijn ook implementatieopmerkingen en ideeën voor verder werk.
Samenvattend…
We hebben gezien hoe openbare sleutels van ontvangers gemakkelijk kunnen worden verzameld door een e-mail te sturen naar een adres voor inkomende relay webhooks. Eenmaal gedaan, kunnen die ontvangers hun berichten in S/MIME-versleutelde vorm ontvangen.
Dat was het voor nu! Veel succes met verzenden.