Eerste les: lek uw geheimen niet in een medium post-illustratie

De beste manier om geheimen in uw app op te slaan, is niet om geheimen in uw app op te slaan

Disclaimer: de methode die in dit artikel wordt beschreven, is sterk afhankelijk van AWS. Dat gezegd hebbende, kan het concept nog steeds van toepassing zijn op andere providers ...

Als u ooit een app op internet hebt gebouwd, stuitte u op het geheim houden (databasegegevens, API-sleutels, enz.) Op uw server.

Historisch gezien hebben ontwikkelaars verschillende manieren gevonden om dit te bereiken. Elk van hen draagt ​​een bepaald niveau van veiligheid en gemak. Ik zal je er doorheen leiden, zodat je een idee kunt krijgen van waar we vandaan komen.

Geheimen opslaan in uw code

# settings / instance_settings.py
STRIPE_API_KEY = '3ef8-843a-49dc-a34d' # Vertel het aan niemand! plz?

Dit is duidelijk de meest handige methode. Je schrijft je API-sleutel als een constante in je code, vervolgens duw je deze naar je bronbeheer en voilà!

Maar het is ook de minst veilige methode. U heeft gewoon toegestaan ​​dat een belangrijk geheim wordt verspreid op de computer van elke ontwikkelaar (of externe schijven), op de opslag van uw broncontroleprovider, op de server van uw CI-provider, enz. Dit verhoogt het risico dat dit geheim zou kunnen lekken aanzienlijk.

Geheimen bewaren in de omgeving

stripe_api_key = os.environ ["STRIPE_API_KEY"]

Dit is er een die ik vrij vaak heb gebruikt. U moet deze omgevingsvariabelen op elke server handmatig instellen of een soort orchestrator gebruiken om dat voor u af te handelen, wat iets minder handig is dan de vorige methode. Desondanks heeft het het voordeel dat slechts enkele vertrouwde personen er toegang toe hebben.

Er zijn nog steeds enkele problemen: een eenvoudige verkeerde configuratie (zoals het uitvoeren van een productieserver in de foutopsporingsmodus) of een beveiligingsfout kunnen leiden tot het lekken van alle omgevingsvariabelen.

Geheimen opslaan in de database

Ik zal hier kort op ingaan: u moet uw database-inloggegevens nog steeds ergens buiten hebben en daarmee het doel verslaan om uw geheimen daar te onthullen. Bovendien verhoogt het hebben van dagelijkse back-ups van de API-sleutels van al uw services op een bepaald moment ook het risico op een lek.

Een geheimensynchronisatieservice gebruiken

Er zijn SaaS die aanbieden om voor je API-sleutels en andere geheimen te zorgen. Ze houden ze veilig en laten u ze indien nodig bij hun service opvragen. We hebben nog steeds hetzelfde probleem als de vorige methode: u hebt een zeer geheime API-sleutel nodig om al uw API-sleutels te krijgen.

Geheimen opslaan in uw code ... maar gecodeerd

Een moderne versie van de eerste methode is om de geheimen in uw code te coderen, waardoor hun waarden niet worden blootgesteld aan uw bronbeheer, andere ontwikkelaars, enzovoort. Om deze geheimen te ontcijferen, moet de server echter nog steeds een sleutel beheren. Dit komt terug op de kwestie van het verspreiden en onderhouden van één groot geheim dat alle andere geheimen ontsluit.

Waarom is het onveilig?

Deze methoden hebben allemaal hetzelfde kenmerk; ze houden nog steeds geheimen in op uw server en die kunnen lekken of worden gestolen

In het slechtste geval

Stel je het volgende scenario voor. Een aanvaller heeft op uw server ingebroken met behulp van een beveiligingslek in Apache. Hij / zij begint vervolgens te zoeken naar databasegegevens en API-sleutels in uw configuratiebestand, uw code, de omgeving. Als je geheimen op de een of andere manier verborgen / gecodeerd genoeg zijn, zal de aanvaller niets vinden. Maar dat betekent niet dat hij / zij daar zal stoppen. Met behulp van zoiets als LiME kon de hacker nog steeds in de geheugendump van de server bladeren om die geheimen te achterhalen.

We kunnen het beter doen

Even voorstellen:

Servicetoegang zonder referenties met een IAM-geverifieerde API-gateway als proxy ™

(Ik ben verschrikkelijk in het vinden van pakkende namen en dit is niet echt een handelsmerk)

Overzicht

Kortom, we gebruiken de instantierol van onze EC2-instance om een ​​veilige aanroep naar een API-gateway te maken, die deze vervolgens naar de gewenste service stuurt, nadat we de aanvraag hebben gewijzigd door de vereiste referenties toe te voegen. Ew! Dat is veel informatie voor een enkele zin.

Ze zeggen dat een foto meer dan 1000 woorden waard is. UITDAGING AANVAARD

Nog steeds verloren? Laten we dit ontleden

Om dit te laten werken, moeten we eerst de native manier voor EC2-instanties (of ECS Containers en Lambdas) gebruiken om andere AWS-bronnen aan te roepen, namelijk door IAM-rollen te gebruiken.

Ten tweede moeten we een Rest API-bron maken in API Gateway. Er zijn enkele specifieke configuraties die moeten worden toegepast zodat de hoofdtekst, headers en query-parameters kunnen worden doorgegeven. Bovendien moeten we het verzoek wijzigen zodat we de beoogde servicegegevens kunnen invoeren. Ten slotte moeten we het geheime wapen activeren: op IAM gebaseerde autorisatie.

De derde en laatste stap bestaat uit het ondertekenen van de URL voordat de gewenste proxy-services worden gebeld.

¿Que?

Voor degenen onder u die niet al te vertrouwd zijn met de technologieën die ik zojuist heb genoemd en nog steeds niet zeker zijn waar dit allemaal over gaat, hier is een vergelijking van voor en na het gebruik van Credentials-less servicetoegang met behulp van een IAM geverifieerde API Gateway als een proxy ™:

Ik gebruik de bekende GitHub API en Postman voor deze demonstratie:

Voordien (Direct bellen naar GitHub):

Na (Bel proxy via API Gateway):

Ik kan je al horen zeggen:

U vertelde ons dat dit geen referenties was en ik zie een toegangssleutel, een geheime sleutel en een token !!!

Dit komt omdat mijn laptop niet het geheime wapen heeft. Zodra u dit op een EC2-exemplaar in gebruik neemt, worden deze tijdelijke beveiligingsreferenties automatisch opgehaald uit de metagegevens van het exemplaar. Als het concept van tijdelijke inloggegevens nieuw voor u is, volgt hier een fragment uit de documentatie (nadruk van mij):

Een toepassing op het exemplaar [...] krijgt de machtigingen voor de acties en bronnen die u voor de rol hebt gedefinieerd via de beveiligingsreferenties die aan de rol zijn gekoppeld. Deze beveiligingsgegevens zijn tijdelijk en we roteren ze automatisch. We stellen nieuwe gegevens ten minste vijf minuten vóór het verlopen van de oude gegevens beschikbaar.

Dus, om eerlijk te zijn, zou een meer nauwkeurige beschrijving voor deze methode Servicetoegang zijn met een door IAM geverifieerde API Gateway als proxy zonder het gebruik van langetermijnreferenties. We kunnen het er echter over eens zijn dat "tijdelijke inloggegevens die worden gebruikt voor het ondertekenen van oproepen naar proxy-services beperkt via IAM" veel minder aantrekkelijk zijn voor aanvallers dan gewone API-sleutels en andere langetermijngeheimen.

Dit is een enorme upgrade vanuit een beveiligingsperspectief

Opmerkelijke beveiligingsverbeteringen:

  • Tijdelijke inloggegevens hoeven nooit door ontwikkelaars te worden verwerkt
  • Ze worden programmatisch opgevraagd, dus het is niet nodig om ze in een configuratiebestand te schrijven
  • Als ze worden gelekt of gestolen, werken deze tijdelijke inloggegevens maximaal een uur
  • Alle aanvragen kunnen worden geregistreerd in CloudWatch voor controle
  • U kunt de gerichte API beperken met behulp van een IAM-beleid

Het laatste punt is vooral handig bij het werken met een API zoals GitHub die een fijnmaziger machtigingsmodel mist. Met het volgende IAM-beleid kan ik mijn API beperken om alleen de GET-methode toe te staan ​​op het eindpunt / repos / PokaInc / test-github-api / issues.

{
    "Versie": "2012-10-17",
    "Uitspraak": [
        {
            "Actie": [
                "Execute-api: Roep"
            ],
            "Bron": [
                "Arn: aws: uitvoeren-api: us-east-1: 123.456.789.010: w974f1rs6e / dev / GET / repos / PokaInc / test-GitHub-api / issues"
            ],
            "Effect": "Toestaan"
        }
    ]
}

Maar wacht, er is meer!

Andere voordelen van het gebruik van API Gateway als proxy

  • Gebruiksstatistieken. Dit kan handig zijn om trends te identificeren en snelheidsbeperking van services van derden te voorkomen.
  • Logging. Indien ingeschakeld, kunt u gedetailleerde logboeken van elke aanvraag hebben, inclusief de oorsprong en de gebruikte parameters.
  • Caching. Hebt u latentie- of snelheidsbeperkende problemen? Met drie regels CloudFormation-code kunt u een caching-backend aan uw proxy toevoegen.
  • Lokale ontwikkeling. Ontwikkelaars die lokaal een IAM-gebruiker gebruiken, hebben rechtstreeks toegang tot de proxy-services in plaats van te vertrouwen op gecodeerde referenties op hun computer.

Op dit punt ga ik ervan uit dat je het idee hebt verkocht en de methode zelf wilt proberen.

De code

Gezien het feit dat we hier bij Poka CloudFormation afi · cio · nados zijn, heb ik een proof-of-concept-sjabloon gemaakt die beschikbaar is op GitHub.

provisioning

Volg de instructies in README.md om de proxy te maken.

Gebruik van de proxy

Dit wordt ook beschreven in de leesmij, maar ik zal het hier insluiten, zodat ik je kan overtuigen dat het geen zwarte magie is.

Laten we dit codeblok eens bekijken:

retour AWSRequestsAuth (
      [...]
      ** boto_utils.get_credentials ()
)

Dit is waar we normaal gezien hard gecodeerde referenties, toegang tot een configuratiebestand of een query naar de omgeving zouden hebben gezien. In plaats daarvan vraagt ​​deze methode de metadataservice om tijdelijke sleutels. Als de rol van EC2-instantie voldoende machtigingen heeft, wordt de aanroep doorgestuurd naar GitHub, anders weigert API Gateway deze.

Gevolgtrekking

Ik hoop dat dit bericht heeft bijgedragen aan het vergroten van het bewustzijn van slecht beveiligde geheimen in applicatieservers en hoe het gebruik van API Gateway als proxy u verder kan helpen dan de toegevoegde beveiliging.

Voorbehoud (en hun tijdelijke oplossingen)

  • Wat als ik een interne service wil proxyen die niet is blootgesteld aan internet?

De verklaring kan zijn eigen specifieke blogpost hebben. Maar lang verhaal kort, u kunt een VPC Enabled AWS Lambda inrichten als het doel van uw API Gateway-proxy. De Lambda moet de headers, query-parameters en body doorgeven aan de interne service, het antwoord verzamelen en terugsturen naar API Gateway.

  • Dit werkt geweldig met REST API's, maar hoe zit het met TCP-services zoals relationele databases of cacheservers?

Nogmaals, dit zou een complete blogpost verdienen. Kortom, we kunnen een microservice maken (toegankelijk via, u raadt het al, een IAM-geverifieerde API-gateway) waarmee u meteen referenties kunt maken voor de gewenste services. Bijvoorbeeld: als de micro-service wordt gevraagd om PostgreSQL-referenties, kan deze een CREATE ROLE-opdracht geven met een willekeurig gegenereerd wachtwoord. Bovendien kan de rol een time-to-live hebben met behulp van de eigenschap VALID UNTIL.

alternatieven

U gebruikt uw productieworkload niet op AWS? Kan deze methode niet voor u werken? Er zijn andere tools die je kunnen helpen om geheimenbeheer aan te pakken.

  • http://engineering.nike.com/cerberus/
  • https://www.vaultproject.io/
  • https://docs.docker.com/engine/swarm/secrets/

Referenties voor dit artikel:

http://blog.arkency.com/2017/07/how-to-safely-store-api-keys-in-rails-apps/
https://blog.rackspace.com/securing-application-secrets-with-ec2-parameter-store
https://www.envkey.com/
https://www.hashicorp.com/blog/Vault-announcement/
https://docs.docker.com/engine/swarm/secrets/
http://docs.aws.amazon.com/apigateway/latest/developerguide/permissions.html
http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2.html
http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html

Speciale dank aan Tea Rudolf, Etienne Talbot, Simon-Pierre Gingras, Maxime Leblanc en Marilou Simard-Baril voor de correcties (Ja, ik heb zoveel mensen nodig om mijn Engels te beoordelen) en dank aan Julie Dorion-Bélanger voor de illustraties.

Heeft u vragen / suggesties over dit bericht? Schrijf hieronder een reactie en ik zal mijn best doen om deze te beantwoorden.