
Als wir anfingen, Open Source zu entwickeln cnquery und cnspec, wir wussten, dass wir eine einfache Abfrage- und Richtliniensprache brauchten. Wir haben nach einer vorhandenen Sprache gesucht, die wie folgt lautete:
- Hervorragend beim Suchen und Abrufen von Plattformdaten
- Fähig, Behauptungen auszudrücken
- Nutzbar für Plattform- und Sicherheitsexperten
Leichter gesagt als getan!
Wir haben unzählige Stacks untersucht (darunter Python, OPA/Rego und InSpec). Wir haben ihre Fähigkeiten bewertet und Usability-Studien mit vielen verschiedenen Sicherheitsexperten und Plattformingenieuren durchgeführt. Jeder hat mindestens eine unserer drei Kernanforderungen nicht erfüllt. Schließlich wurde uns klar, dass eine erweiterte Version von GraphQL sowohl bei Plattform- als auch bei Sicherheitsingenieuren und Entwicklern am erfolgreichsten sein würde.
Infrastruktursuche für Plattform- und Sicherheitsteams
Warum haben wir uns auf Plattform- und Sicherheitsexperten konzentriert?
Wir haben festgestellt, dass die Personen mit dem größten Einfluss auf die Infrastruktur und der tiefsten Erfahrung in der Infrastruktur in der Regel Plattform- und Sicherheitsteams. Diese Fachleute sind in den letzten zehn Jahren technischer geworden. Sie haben auch ein gesundes Maß an Entwicklerkenntnissen für die Automatisierung von Infrastrukturen (wie Kubernetes, Terraform und Ansible) erworben.
Plattform- und Sicherheitsingenieure verbringen jedoch nicht den Großteil ihrer Tage damit, mit C++, Java und dergleichen zu entwickeln. Sie wollen sich nicht mit den Feinheiten von Programmiersprachen und seltsamen Speicheroptimierungen beschäftigen. Für sie geht es darum, die Arbeit zu erledigen.
Leider sind fast alle vorhandenen Lösungen für Entwickler konzipiert.
Unser vorrangiges Ziel bestand darin, Plattform- und Sicherheitsteams in die Lage zu versetzen, Infrastruktursuchen und -aussagen zu erstellen. Wir wollten ihnen etwas bieten, das die Arbeit erledigt, ohne ihnen einen übermäßig komplizierten Stapel aufzuwerfen. Denken Sie an Python, nicht C++. Bash, nicht Java.
Find and fix the security risks that pose the biggest threat to your business.
Warum GraphQL?
Wenn Sie eine Sicherheitsaussage schreiben möchten, benötigen Sie als Erstes Daten.
Wie kommen Sie an Daten?
Abgesehen von Abstraktionen in Programmiersprachen sind die bekanntesten Methoden zum Abrufen von Daten SQL, GraphQL, und RESTful-APIs. Ersteres wird normalerweise direkt auf Datenbanken verwendet, während letzteres besser als Serviceschnittstelle bekannt ist.
Wir wollten keine neue Art des Datenzugriffs entwickeln, da bereits bestehende Muster verfügbar waren (was eine niedrigere Lernkurve und weniger Wegwerfwissen bedeutet). Angesichts dessen fragen Sie sich vielleicht:
Warum nicht SQL?
In den letzten zehn Jahren gab es eine sehr wichtige Veränderung: Die Plattformressourcen wurden immer stärker miteinander verbunden. Zum Beispiel ist es heute wichtig, nicht nur einen offenen Port zu finden, sondern auch zu verstehen:
- Welcher Prozess führt es aus
- Welcher Benutzer hat es gestartet
- Welcher Service ist verantwortlich
- Aus welchem Paket wurde es installiert
Mit SQL ist es einfach, einzelne Zeilen aus einer Datenbank abzurufen, aber es ist ein ganz anderes Unterfangen, sie zu verbinden und miteinander zu verketten. Erinnerst du dich an all die lustigen JOIN-Anweisungen, die du am Ende deiner ersten Datenbank-Vorlesung verflucht hast? Wenn Sie versuchen, Fragen wie die obige Liste zu beantworten, werden Sie sich in einem tiefen Gewirr von JOINs wiederfinden.
Letztlich ist SQL sehr komplex und schwieriger zu verwalten. Aus diesem Grund verlassen sich so viele graphbasierte Lösungen nicht auf herkömmliches SQL.
GraphQL für Graph-Traversal
GraphQL ist JSON auf Steroiden. Es ist sehr einfach zu lernen und zu verstehen. JSON ist praktisch überall und wurde durch seine Verwendung in RESTful-APIs und JavaScript populär. Der Übergang von JSON zu GraphQL ist ein Kinderspiel.
GraphQL macht es einfach, verwandte Datenobjekte zu untersuchen. Sie können Verbindungen zwischen Ressourcen untersuchen, indem Sie der Abfrage nur eine weitere Zeile hinzufügen. Aufgrund seiner Fähigkeit, Ressourcen zu verketten und schnell die wichtigsten Felder auszuwählen, ist es in vielen Diensten zu einer leistungsstarken Alternative zu RESTful-APIs geworden.
processes { // list of processes on this system
pid // the process PID
user { // list the user that runs this process
name // grab the user's name...
uid // ... and UID
}
}
Warum GraphQL erweitern?
Ich habe Ihnen vielleicht den Eindruck vermittelt, dass wir in GraphQL die perfekte Lösung gefunden haben. Es war zwar sehr knapp, entsprach aber nicht ganz den Anforderungen unserer Anwendungsfälle. Also haben wir MQL als Erweiterung von GraphQL entwickelt.
GraphQL-Erweiterungen wie MQL sind weit verbreitet. Diese Graphdatenbanken sind Modifikationen von GraphQL, die auf eine bestimmte Umgebung zugeschnitten sind.
Dies sind einige der aufregendsten Möglichkeiten, wie MQL GraphQL erweitert:
- Filter universell machen
- Wählen Sie*
- Behauptungen
- Leichte Skripte
Lassen Sie uns jeden einzelnen untersuchen.
Filter universell machen
GraphQL übergibt normalerweise Filter an das Backend. Filter sind auf Ressourcen zugeschnitten. Sie geben sie direkt nach dem Abfragefeld in Klammern an:
users(uid: 0) {
name
}
GraphQL funktioniert gut genug für einfachere Probleme, erlaubt aber oft keine leistungsfähigeren Suchen. Da wir nicht alle Fragen, die unsere Benutzer stellen könnten, vorhersehen konnten (und auch nicht einschränken wollten), brauchten wir einen besseren Ansatz.
Geben Sie die Filter von MQL ein:
users.where( uid > 0 && uid < 1000 ) {
name
}
In diesen Fällen sind Anweisungen für alle MQL-Ressourcen zugänglich und ermöglichen es Ihnen, auf der Grundlage eines beliebigen Felds einer Ressource zu filtern, einschließlich regulärer Ausdrücke und Zeitprüfungen:
accounts.where(
email == /gmail.com$/ &&
lastLogin > time.today
)
Wählen Sie*
Wir verstehen warum GraphQL das generell nicht unterstützt. Für unseren Anwendungsfall war es jedoch sehr sinnvoll, * auszuwählen und Daten freier zu untersuchen. Wir vergessen oft, welche Felder unterstützt werden. Selbst mit der automatischen Vervollständigung in der CLI und den Editoren ist es oft einfacher, einfach alle Daten zu erfassen und später aufzuschlüsseln. In einigen Fällen möchten Benutzer auch einfach alles über eine Ressource sammeln, was sie können.
Diese Abfrage gibt beispielsweise alle Felder in der Datenstruktur des Benutzers zurück:
users{*}
users: [
0: {
uid: 0
gid: 0
shell: "/bin/bash"
home: "/root"
name: "root"
group: group name="root" gid=0
sshkeys: []
...
}
Behauptungen
Wie ich am Anfang dieses Artikels erwähnt habe, beinhalteten die Designziele für MQL sowohl die Datenextraktion als auch die Richtlinie als Code. Wir wollten sicherstellen, dass MQL ressourcenübergreifend nach Sicherheit und Best Practices suchen kann, aber wir wollten nicht, dass es so kompliziert ist wie so viele andere Lösungen für Plattform- und Sicherheitsingenieure.
Im Mittelpunkt jedes Tests stehen Aussagen: Verhält sich etwas so, wie Sie es erwarten?
Als reine Abfragesprache unterstützt GraphQL standardmäßig keine Assertions. Dies war eine großartige Gelegenheit, es zu erweitern und Prüfungen für einfache und komplizierte Tests hinzuzufügen.
Die einfachsten Tests laufen auf boolesche Aussagen hinaus wie:
user.name == "Alice"
tls.versions == ["tls1.3"]
uid > 1000 && uid < 9999
Für Listen haben wir es noch einfacher gemacht. In unserer bisherigen Erfahrung haben wir gesehen, dass die meisten Benutzer sehr komplizierte Schleifen konstruierten, die nach der Verkettung fast unmöglich zu verwalten waren. Mit MQL ist das viel einfacher:
// no user should have a uid smaller than 0
users.none( uid < 0 )
// a package with the regex /ssh/ in its name should be installed
packages.contains( name == /ssh/ && installed )
// all listening ports should have a port number smaller than 1000
ports.listening.all( port < 1000 )
Leichte Skripte
Um MQL flexibel zu machen, haben wir sehr einfache Skriptelemente hinzugefügt. Sie ermöglichen es Ihnen, Variablen zuzuweisen und zu verwenden oder Werte zu kombinieren.
myFile = user.home + "/my.file"
MQL-Abfragen sind vorkompiliert und folgen einem Schema. Dadurch können wir Fehler frühzeitig finden und sicherstellen, dass die Typen korrekt verwendet werden. Es führt auch zu einer unglaublich schnellen Ausführung.
Darüber hinaus wird MQL standardmäßig gleichzeitig und parallel ausgeführt. Das bedeutet, dass komplexe Abfragen in mehrere Streams mit separaten I/O-Anforderungen aufgeteilt werden, die dann gleichzeitig ausgeführt werden.
Ein offener Standard
MQL eröffnet Plattform- und Sicherheitsingenieuren neue Möglichkeiten, ihre Fragen und Behauptungen auszudrücken. Es wurde als flexibles Framework entwickelt, das nicht an ein bestimmtes Tool oder eine bestimmte Zieltechnologie gebunden ist.
MQL ist erweiterbar, sodass jederzeit neue Ressourcen und Felder hinzugefügt werden können. Aufgrund seiner hohen Leistungsfähigkeit eignet es sich ideal als eingebettete Engine für eine noch bessere Automatisierung.
Wir haben die Vorteile gesehen, die MQL sowohl modernen als auch etablierten Plattformteams und Umgebungen bietet. Es ermöglicht unsere Full-Stack-Sicherheitslösung und findet überall Konfigurations- und Sicherheitsprobleme.
Wir hoffen es gefällt euch auch! Scannen Sie weiter und entdecken Sie neue Dinge über Ihre Flotte. Wenn Sie Fragen oder Ideen haben, würden wir uns freuen, Sie in unserem zu sehen Gemeinschaft!