[Configuratie] Omgaan met wachtwoorden en secrets

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • Lethalis
  • Registratie: April 2002
  • Niet online
Ik plaats dit in programming, omdat het echt zo'n dingetje is waar programmeurs veel mee bezig (zouden moeten) zijn.

Stel een applicatie moet inloggen bij een database, hoe gaat deze applicatie zich authenticeren?

Dan heb ik grofweg de volgende manieren gevonden:

Plaintext wachtwoorden in environment variabelen
Dit zie ik vaak terug op internet, ook in combinatie met Docker containers. Een container moet natuurlijk zo "ephemeral" mogelijk zijn, dus geef je configuratie aan hem mee (in plaats van dat de configuratie in de container staat).

Er bestaat echter het gevaar dat het wachtwoord dan lekt, getuige het volgende topic (wat ook deels inspiratie is voor dit topic, maar vooral een discussie over Laravel is / wordt):

[Laravel] Security

Gebruik je een Docker management tool als Portainer, dan staan je wachtwoorden ook plaintext in beeld en dat vind ik niet zo tof.

Plaintext wachtwoorden in configuratiebestanden
Dit zie ik ook vaak, zowel meegeleverd met de applicatie, als ook los van de applicatie.

Het eerste is natuurlijk niet aan te raden, want het zal er ook vaak toe leiden dat programmeurs deze configuratiewaarden ook committen naar een hun source control en het daarmee (onbedoeld) overal en nergens naartoe verspreiden. Getuige de verhalen over mensen die hun AWS keys op github plaatsen:

https://medium.com/@naggu...l-experience-960be7aad039

:F

Een (iets betere) oplossing is dan om de configuratiebestanden buiten de application root te plaatsen. Ze komen niet meer onbedoeld in source control terecht en de kans dat je ze per ongeluk exposed is daarmee een stuk kleiner. Ook kun je de rechten vergaand instellen. Op Linux kun je bijvoorbeeld Mandatory Access Control (selinux) gebruiken en configureren dat alleen bepaalde processen bepaalde bestanden kunnen lezen.

Dit is een oplossing die ik nog wel aardig vind.

White box cryptography
Dit kom ik ook nog weleens tegen. Credentials worden dan symmetrisch versleuteld met een key die embedded is in de applicatie en weer ontsleuteld op het moment dat het nodig is. Eigenlijk schiet je hier niet zoveel mee op, want als iemand de embedded key weet, kan hij de rest ook ontsleutelen. Bovendien loert het gevaar dat je die key weer commit naar source control.

Wat mij betreft geeft dit vooral schijnveiligheid.

Integrated Windows security (op Windows)
Vanuit mijn werk als .NET ontwikkelaar ben ik bekend met Integrated Security (SSPI). Kortom, ik stel in dat SQL Server in mixed mode draait en configureer voor bepaalde Windows accounts dat ze bepaalde rechten hebben op SQL Server.

Vervolgens draai ik mijn applicaties met die accounts en stel de connection string zo in dat hij Integrated Security moet gebruiken.

Windows regelt dan de authenticatie voor mij en ik hoef helemaal geen wachtwoorden in mijn configuratie te plaatsen. Zolang ik er maar voor zorg dat de Windows authenticatie werkt (dus zowel app server als db server moeten dezelfde account + wachtwoord hebben, of je gebruikt Active Directory).

Kerberos
Dit is de achterliggende techniek die Integrated Security op Windows gebruikt. Kerberos kun je natuurlijk ook op Linux gebruiken:

https://help.ubuntu.com/lts/serverguide/kerberos.html.en

Zelf heb ik hier nog geen ervaring mee, maar het lijkt me een aardige oplossing. Al moet ik nog wat verder er induiken hoe het nou precies zit met die tickets en hoe je nou elke keer een nieuwe krijgt (dat zal de PAM module waarschijnlijk doen?).

HashiCorp Vault
Na een tijdje Google-fu kwam ik op spring.io de volgende blog entry tegen:

https://spring.io/blog/20...naging-secrets-with-vault

Dit klinkt op zich ook wel goed. De grap is dat de vault zelf onvoldoende gegevens bevat om de informatie te ontsleutelen. Na een reboot moet er altijd iemand handmatig de vault "unsealen" door een passphrase in te voeren.

Ik ben nog niet in de implementatiedetails gedoken, maar ik vermoed dat het met een random gekozen master key werkt + meerdere sub key slots voor elke operator (zoals het bij LUKS werkt). Omdat je de passphrase nodig hebt om de master key te ontsleutelen, kun je er helemaal niks mee zolang de vault niet "unsealed" is.

Alsnog moeten de clients wel tickets hebben en kun je hiermee wel bij de configuratiewaarden...

Een service van het besturingssysteem (Data Protection API / Keychains)
Als ik bijvoorbeeld voor een Windows client applicatie een wachtwoord moet opslaan, kan ik daarvoor de Data Protection API gebruiken:

https://docs.microsoft.co...a?view=netframework-4.7.2

Op de Mac heb je Keychain Access. Is er ook zoiets voor Linux? Mijn eerste zoekopdrachten leveren weinig positiefs op:

https://github.com/dotnet/corefx/issues/22510

Conclusie / vraag
Hoe gaan jullie om met wachtwoorden en overige secrets bij het ontwikkelen en deployen van applicaties?

Vinden jullie het zinvol om zoiets als HashiCorp Vault te gebruiken? Of gebruiken jullie losse configuratiebestanden met vergaande access control? Of leef je in een corporate environment met een Kerberos server? (op Linux of Active Directory op Windows)

Of doe je iets wat ik hier nog niet noem?

Wat vinden jullie het beste, maar ook meest praktische?

[ Voor 6% gewijzigd door Lethalis op 10-12-2018 11:21 ]

Ask yourself if you are happy and then you cease to be.

Alle reacties


Acties:
  • 0 Henk 'm!

  • ThomasG
  • Registratie: Juni 2006
  • Laatst online: 23-09 14:00
Je bent nu vooral bezig met het opslaan en uitlezen van de wachtwoorden, maar het grootste veiligheidsprobleem zit hem in dat de wachtwoorden in het geheugen van de applicatie blijven staan. Zodra het wachtwoord niet meer nodig is, dient dit explicit uit het geheugen verwijderd te worden; dus niet wachten op de garbage collector, e.d.

Het liefste sla je de wachtwoorden helemaal niet op, maar dat levert weer een onwerkbare situatie op. Je wilt niet iedere keer de wachtwoorden opnieuw invoeren.

Een manier zou zijn om het configuratiebestand te versleutelen, bij het opstarten eenmalig de sleutel opgeven, zorgen dat de applicatie met alle services (database, e.d.) verbind, en daarna de wachtwoorden den configuratiebestand uit het geheugen verwijderen. Het probleem hiervan is dat mocht het een time-out krijgen, dan het er vervolgens ook niet meer bij kan.

Wat bij ons de voorkeur heeft is om de verantwoordelijkheden en beveiliging zoveel mogelijk te spreiden. Wij hebben niet een grote applicatie die vervolgend verbind met de database. Onze front/backend applicatie draait een losse servers, maar heeft geen directe toegang tot de database. En weet dus ook de wachtwoorden daarvan niet. Dit draait op een losse servers (microservices met een verantwoordelijkheid) die niet direct via het internet toegankelijk zijn, en via een bus/api verbinding heeft met de applicatie (waarbij voor veel zaken de access token van de gebruiker wordt gebruikt om te kijken of acties wel/niet mogen).

Mocht er een lek zitten in onze applicatie en/of publiek toegankelijke server, dan heeft dat natuurlijk wel een aantal consequenties. Maar de schade valt relatief mee, een database dump maken is bijvoorbeeld met enkel die server niet mogelijk. Vooral omdat je vanaf de publieke server enkel een aantal specifieke porten kunt bereiken op de servers met de microservices, en verder niets (dus ook geen SSH). De configuratiebestanden voor deze services zijn alleen leesbaar door de user waar de microservice op draait, e.d.

Natuurlijk is er een kans dat die servers gehacked worden, maar dan hebben we een groter probleem dan dat het database wachtwoord e.d. lekt. Wel is het zo dat iedere microservice een eigen database account heeft, en alleen mag schrijven naar tabellen van zijn verantwoordelijkheid, en alleen mag lezen uit tabellen die het daadwerkelijk nodig heeft voor zijn taken; meestal loopt dat via een andere microservice.

Zo kun je ook microservices hebben voor AWS onderdelen e.d. hebben, zodat die sleutels niet zonder meer kunnen lekken.

Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 06-10 13:59
Het is nogal afhankelijk van hoe je die containers deployed. Als je op Kubernetes deployed gebruik je over 't algemeen Kubernetes secrets (die worden als env vars meegegeven). Op Productie zullen alleen bepaalde mensen daarbij kunnen. In m'n vorige project konden developers alleen bij de K8s secrets op Dev en Test. Onder water zijn er verschillende adapters voor die secrets, o.a. uit Vault.

In m'n huidige project deployen we op AWS ECS. Ook daar is een mechanisme via AWS SSM waarbij secrets geinjecteerd worden als env vars vanuit een store. En wederom is dat op Prod gescheiden van Dev.

Oftewel; het is vooral afhankelijk van waar je deployed. Om je docker-containers relatief onafhankelijk te houden is het het makkelijkst om uit te gaan van env vars. Het deployment platform heeft dan de taak deze vars beschikbaar te maken.

Een andere optie is een config server die dat serveert; nadeel is dat dit meer tijd kost kwa implementatie en lastiger platform/stack onafhankelijk te maken en te houden.

En tenslotte; het is onmogelijk technisch te voorkomen dat mensen deze env vars misbruiken door ze bijvoorbeeld in de logs af te drukken. Een goed peer-review proces hiervoor inrichten is belangrijker dan denken dat het technisch te doen is. En natuurlijk gebruik je per service least-privilege credentials
ThomasG schreef op maandag 10 december 2018 @ 10:03:
Je bent nu vooral bezig met het opslaan en uitlezen van de wachtwoorden, maar het grootste veiligheidsprobleem zit hem in dat de wachtwoorden in het geheugen van de applicatie blijven staan.
Het is in de meeste gevallen gewoon nodig. API secrets bijvoorbeeld heb je elk request nodig. AWS credentials ook. Daar ga je niet voorkomen dat deze paraat blijven (en dus stiekem in de logs gedumpt worden).

En als een kwaadwillende dergelijke toegang heeft, heeft het had nullen van passwords geen zin, dat kan 'ie dan ongedaan maken.

[ Voor 21% gewijzigd door Hydra op 10-12-2018 10:16 ]

https://niels.nu


Acties:
  • 0 Henk 'm!

  • Harrie_
  • Registratie: Juli 2003
  • Niet online

Harrie_

⠀                  🔴 🔴 🔴 🔴 🔴

Ik plaat altijd een config-bestand buiten de webroot waar plaintext de SQL-user en wachtwoord instaan. De SQL-user in kwestie ken ik dan alleen benodigde rechten toe (select, insert, update).

Hoeder van het Noord-Meierijse dialect


Acties:
  • 0 Henk 'm!

  • Lethalis
  • Registratie: April 2002
  • Niet online
Hydra schreef op maandag 10 december 2018 @ 10:14:
Oftewel; het is vooral afhankelijk van waar je deployed. Om je docker-containers relatief onafhankelijk te houden is het het makkelijkst om uit te gaan van env vars. Het deployment platform heeft dan de taak deze vars beschikbaar te maken.

Een andere optie is een config server die dat serveert; nadeel is dat dit meer tijd kost kwa implementatie en lastiger platform/stack onafhankelijk te maken en te houden.
Dit heeft me nog tot de volgende optie gebracht: dat het operating system het voor jou regelt.

Als ik bijvoorbeeld voor een Windows client applicatie een wachtwoord moet opslaan, kan ik daarvoor de Data Protection API gebruiken:

https://docs.microsoft.co...a?view=netframework-4.7.2

Op de Mac heb je Keychain Access. Is er ook zoiets voor Linux? Mijn eerste zoekopdrachten leveren weinig positiefs op:

https://github.com/dotnet/corefx/issues/22510
ThomasG schreef op maandag 10 december 2018 @ 10:03:
Wat bij ons de voorkeur heeft is om de verantwoordelijkheden en beveiliging zoveel mogelijk te spreiden. Wij hebben niet een grote applicatie die vervolgend verbind met de database. Onze front/backend applicatie draait een losse servers, maar heeft geen directe toegang tot de database. En weet dus ook de wachtwoorden daarvan niet. Dit draait op een losse servers (microservices met een verantwoordelijkheid) die niet direct via het internet toegankelijk zijn, en via een bus/api verbinding heeft met de applicatie (waarbij voor veel zaken de access token van de gebruiker wordt gebruikt om te kijken of acties wel/niet mogen).
Dit is inderdaad een manier om de attack surface te verkleinen. Zodra je de verantwoordelijkheid beperkt tot een bepaalde service / systeem, wordt het overzichtelijker om deze te beveiligen.

[ Voor 29% gewijzigd door Lethalis op 10-12-2018 11:14 ]

Ask yourself if you are happy and then you cease to be.


Acties:
  • +1 Henk 'm!

  • Kettrick
  • Registratie: Augustus 2000
  • Laatst online: 00:14

Kettrick

Rantmeister!

Hydra schreef op maandag 10 december 2018 @ 10:14:
In m'n huidige project deployen we op AWS ECS. Ook daar is een mechanisme via AWS SSM waarbij secrets geinjecteerd worden als env vars vanuit een store. En wederom is dat op Prod gescheiden van Dev.
ECS ondersteund sinds een paar weken de parameter store als secret store, dit maakt het een en ander een stuk makkelijker. Voorheen gebruikte we een van de vele ssm-wrappers, maar dat is niet meer nodig. Hierdoor staan al onze secrets centraal in de parameter strore end kunnen we onze task via terraform makkelijk beheren,

Wij hebben een aparte terraform module in git welke exclusief gebruikt wordt voor SSM secrets en deze word opgeslagen in keybase en is dus volledig encrypted.

Hoe je het ook doet, op een goed moment heeft je applicatie de secrets nodig om zijn werk te doen en heb je de secrets plaintext nodig, en zolang dat het geval is kan een hacker er ook bij. Zelfs tools als ansible vault en aws secrets manager lossen dat niet op, als een hacker eenmaal binnen is kan hij dezelfde requests doen en met de tijdelijke credentials aan de slag.

Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 06-10 13:59
Kettrick schreef op maandag 10 december 2018 @ 11:21:
ECS ondersteund sinds een paar weken de parameter store als secret store
Yup! Staat toevallig voor deze week op de lijst om mee aan de slag te gaan voor een nieuwe service.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • Lethalis
  • Registratie: April 2002
  • Niet online
Kettrick schreef op maandag 10 december 2018 @ 11:21:
[...]
Hoe je het ook doet, op een goed moment heeft je applicatie de secrets nodig om zijn werk te doen en heb je de secrets plaintext nodig, en zolang dat het geval is kan een hacker er ook bij. Zelfs tools als ansible vault en aws secrets manager lossen dat niet op, als een hacker eenmaal binnen is kan hij dezelfde requests doen en met de tijdelijke credentials aan de slag.
Maar heb je altijd die plain text secrets nodig? Op het moment dat je een andere vorm van authenticatie gebruikt, zoals Kerberos, dan heb je in feite alleen een tijdelijk geldende ticket die applicatie X toegang verleent tot service Y.

Ik vraag mij dus af of mensen niet te snel voor de makkelijke weg kiezen. Natuurlijk is het lastiger om te configureren dan gewoon wat wachtwoorden te gebruiken.

[ Voor 4% gewijzigd door Lethalis op 11-12-2018 08:33 ]

Ask yourself if you are happy and then you cease to be.


Acties:
  • 0 Henk 'm!

  • Kettrick
  • Registratie: Augustus 2000
  • Laatst online: 00:14

Kettrick

Rantmeister!

Lethalis schreef op dinsdag 11 december 2018 @ 08:28:
[...]

Maar heb je altijd die plain text secrets nodig? Op het moment dat je een andere vorm van authenticatie gebruikt, zoals Kerberos, dan heb je in feite alleen een tijdelijk geldende ticket die applicatie X toegang verleent tot service Y.
Kerberos is praktisch alleen bruikbaar binnen je eigen omgeving, en zelfs daar geldt dat je iets nodig hebt om je token op te vragen, en dat moet je uiteindeijk ook weer opslaan, het probleem blijft zich verplaatsen maar veranderd niet :).
Ik vraag mij dus af of mensen niet te snel voor de makkelijke weg kiezen. Natuurlijk is het lastiger om te configureren dan gewoon wat wachtwoorden te gebruiken.
Uiteraard hangt het erg af van je applicatie, maar de meeste secrets waar ik mee te maken heb zijn externe API keys, in deze gevallen is heb je geen keuze maar gebruik je de authenticatie die je verplicht wordt te gebruiken.

Daarbij vind ik persoonklijk kerberos een ontzettend overcomplex systeem dat meer problemen veroorzaakt dan het oplost :X

In de praktijk ontkom je vrijwel niet aan dit probleem, ik zou me dan ook vooral richten op het centraal opslaan van secrets en het toepassen van een strak toegangbeleid tot deze secrets. In het geval van AWS kan je dat doen door per instance/applicatie een IAM rol toe te kennen die alleen toegang heeft tot de relevante secrets.

Een eerdere comment over het opsplitsen van appliacties is ook een goede oplossing hiervoor, onze publieke apps hebben geen toegang tot databases en secrets maar alleen via API's.

Acties:
  • 0 Henk 'm!

  • Lethalis
  • Registratie: April 2002
  • Niet online
Kettrick schreef op dinsdag 11 december 2018 @ 23:15:
[...]
In de praktijk ontkom je vrijwel niet aan dit probleem, ik zou me dan ook vooral richten op het centraal opslaan van secrets en het toepassen van een strak toegangbeleid tot deze secrets. In het geval van AWS kan je dat doen door per instance/applicatie een IAM rol toe te kennen die alleen toegang heeft tot de relevante secrets.

Een eerdere comment over het opsplitsen van applicaties is ook een goede oplossing hiervoor, onze publieke apps hebben geen toegang tot databases en secrets maar alleen via API's.
Je hebt op zich een punt. Wel moet ik dan mijn vraag misschien herformuleren qua scope: wat is de beste manier om met secrets om te gaan in een eigen omgeving?

Onze applicaties draaien namelijk niet in de cloud, maar on premises. Zoals @Hydra al schreef, is het de wijze waarop je hiermee omgaat afhankelijk van waar de applicaties gedeployed worden.

Tsja, dan ben ik wel benieuwd - bij gebrek aan een cloudoplossing die dit deels uit handen neemt - hoe je dit het beste on premises aanpakt.

Een extra barrière opwerpen door een scheiding te maken in publieke en niet publieke API's is natuurlijk wel een idee, maar geeft ook een hoop overhead (als je dit voor alles moet gaan doen).

PS
Omdat ik benieuwd was hoe Mono zijn "managed implementatie" doet van de Data Protection API, heb ik de code doorgespit en ben ik terecht gekomen bij de KeyPairPersistence class:

https://github.com/mono/m...phy/KeyPairPersistence.cs

Hoop scary shit die daar in staat.

code:
1
2
3
4
5
6
7
8
9
10
11
unsafe private static bool ProtectMachine (string path)
        {
            // we cannot protect on some filsystem (like FAT)
            if (CanSecure (path)) {
                fixed (char* fpath = path) {
                    return _ProtectMachine (fpath);
                }
            }
            // but Mono still needs to run on them :(
            return true;
}

Nou jongens, het lukt niet... laten we maar gewoon doen alsof alles koek en ei is 8)7

[ Voor 22% gewijzigd door Lethalis op 12-12-2018 09:24 ]

Ask yourself if you are happy and then you cease to be.

Pagina: 1