Comment SQL peut unifier l’accès aux API

Dans la proposition originale pour le World Wide Web, Tim Berners-Lee a écrit :

Un outil générique pourrait peut-être être créé pour permettre à toute base de données utilisant un SGBD commercial d’être affichée sous forme de vue hypertexte.

Nous avons obtenu ces vues hypertextes, sous la forme d’API, mais pas de manière générique. Les applications Web basées sur une base de données ont développé des API qui ont produit diverses sorties XML puis JSON. Les langages de programmation ont développé des bibliothèques pour aider les développeurs à consommer ces sorties. Apprendre à utiliser chaque API individuelle était un défi, joindre les sorties de plusieurs API encore plus.

En 2009, je construisais un système pour combiner des informations de calendrier provenant de nombreuses sources. Il leur a posé la même question à tous : quels événements sont programmés pour un lieu et une heure donnés ? Pour ce faire, il a dû utiliser une demi-douzaine d’API, chacune nécessitant une manière différente de faire une requête et de décompresser la réponse.

Donc, quand j’ai entendu parler du projet Astoria, j’étais un fan immédiat. Astoria était la vue hypertexte générique des bases de données dont nous avions besoin. Avec Astoria superposé, chaque base de données pourrait automatiquement fournir une API par défaut. Si la demi-douzaine de systèmes que j’interrogeais pour des événements supportaient quelque chose comme Astoria, aucun n’aurait eu besoin d’inventer des API sur mesure et tous seraient interrogeables de la même manière cohérente.

L’idée a mûri sous le nom d’Open Data, alias OData, une norme OASIS depuis 2014. En principe, toute application Web basée sur une base de données pourrait désormais arborer une “tête OData” qui fournirait une API par défaut, ne nécessitant aucun code à écrire par les développeurs de l’application. , et aucun nouveau protocole de demande/réponse à apprendre par les développeurs utilisant l’API.

Dans la pratique, cela ne s’est généralement pas produit.

Plus que jamais, la construction de logiciels oblige les développeurs à composer des solutions en utilisant une prolifération croissante d’API. Il existe souvent une bibliothèque pour envelopper chaque API dans le langage de programmation de votre choix, ce qui vous épargne l’effort d’effectuer des appels REST bruts et d’analyser les résultats. Mais chaque wrapper a sa propre façon de représenter les résultats, donc lors de la composition d’une solution multi-API, vous devez normaliser ces représentations. Étant donné que la combinaison des résultats se produit d’une manière spécifique à la langue, votre solution est liée à cette langue. Et si ce langage est JavaScript ou Python ou Java ou C #, ce n’est sans doute pas le moyen le plus universel et le plus puissant d’interroger (ou de mettre à jour) une base de données.

Quel est le meilleur moyen? Il s’est toujours caché à la vue de tous : SQL. Aguerri depuis des décennies et ayant évolué au-delà du modèle relationnel pur, SQL s’est réaffirmé comme l’interface prééminente avec les données. Et il est bien placé pour devenir l’unificateur d’API dont nous avons plus que jamais besoin.

Wrappers de données étrangères pour les API

Steampipe (steampipe.io) est un outil open source qui récupère les données de diverses API et les utilise pour remplir des tables dans une base de données. La base de données est Postgres, qui est, de nos jours, une plate-forme sur laquelle construire toutes sortes de systèmes de type base de données en créant des extensions qui personnalisent profondément le noyau. Une classe d’extension Postgres, le wrapper de données étrangères (FDW), crée des tables à partir de données externes. Steampipe intègre une instance de Postgres qui charge un wrapper de données étrangères orienté API. Le FDW communique à son tour avec une famille croissante de plug-ins qui consomment des API et alimentent les données via le FDW dans les tables Postgres.

Pour concrétiser ces abstractions, demandez-vous comment vous résoudriez le problème suivant. Vous exploitez des services AWS publics et vous souhaitez savoir si l’un de leurs points de terminaison apparaît comme vulnérable dans Shodan, un service qui analyse les points de terminaison publics. Votre solution ressemble probablement à ceci :

  1. Apprenez à utiliser l’API AWS qui trouve vos points de terminaison
  2. Apprenez à utiliser l’API Shodan pour vérifier vos points de terminaison
  3. Apprenez à combiner ces deux API pour répondre à la question

Voici la solution Steampipe.

```
select
  a.instance_id,
  s.ports,
  s.vulns,
  a.security_groups
from
  aws_ec2_instance a
left join
  shodan_host s on a.public_ip_address = s.ip
where
  a.public_ip_address is not null;
```
```
+---------------------+----------+--------------------+-------------------------------------------------------------+
| instance_id         | ports    | vulns              | security_groups                                             |
+---------------------+----------+--------------------+-------------------------------------------------------------+
| i-0dc60dd191cb84239 |    |              | [{"GroupId":"sg-042fe79169eb42818","GroupName":"lockdown"}] |
| i-042a51a815773780d | [80,22]  |              | [{"GroupId":"sg-042042bac705630f4","GroupName":"bastion"}]  |
| i-00cf426db9b8a58b6 | [22]     |              | [{"GroupId":"sg-0423f79169eb42818","GroupName":"default"}]  |
| i-0e97f373db42dfa3f | [22,111] | ["CVE-2018-15919"] | [{"GroupId":"sg-0423f79169eb42818","GroupName":"default"}]  |
+---------------------+----------+--------------------+-------------------------------------------------------------+
```

Les deux tables jointes ici sont fournies par les plug-ins Steampipe pour AWS et Shodan. Le premier mappe le catalogue tentaculaire des API AWS sur (actuellement) 269 tables ; le second propose une dizaine de tables Shodan.

Vous configurez ces plug-ins pour vous authentifier auprès des API avec les mêmes informations d’identification dont vous auriez besoin si vous utilisiez directement les API. Mais vous n’avez pas besoin de savoir quoi que ce soit d’autre sur les appels REST sous-jacents ou sur les bibliothèques qui les entourent. La solution est composée de tables qui fonctionnent de la même manière dans et entre les API. Vous les inspectez (aws_ec2_instance, shodan_host) pour découvrir les noms de leurs colonnes, et vous les joignez à la manière SQL traditionnelle.

Un plug-in pour chaque API

Il est clair que cette solution à deux API dépend de l’existence de plug-ins pour mapper les deux API aux tables. Si les deux services implémentaient OData, cela ne serait pas nécessaire. Les API seraient automatiquement interrogeables, bien que sans doute non joignables avec l’élégance qu’offre SQL. Mais ces deux services, comme la plupart, ne présentent pas d’interface unifiée avec leurs API. Donc, cette unification doit être superposée à eux. Le SDK de plug-in de Steampipe facilite la tâche aux auteurs de plug-in en faisant abstraction de la gestion des connexions, de la logique de nouvelle tentative, de la mise en cache et, bien sûr, du mappage des résultats de l’API aux tables.

Les plug-ins Steampipe sont écrits en Go. Ils exploitent le catalogue complet de bibliothèques Go qui enveloppent les API. Mais seuls les auteurs de plug-ins doivent le savoir. En tant que développeur travaillant avec Steampipe, vous ne voyez que des tables et vous n’écrivez que du SQL. De nos jours, parce que SQL a évolué, cela inclut des fonctionnalités telles que les expressions de table communes (alias CTE ou WITH clauses) et les colonnes JSON. Mais ce n’est toujours que SQL.

De tels plug-ins peuvent-ils être créés pour chaque API ? Eh bien, Steampipe a été lancé début 2021 avec une poignée de plug-ins, aujourd’hui il y en a plus de 60, et le nombre augmente rapidement. Jusqu’à présent, la plupart ont été écrits par l’équipe principale, mais les contributions externes se multiplient. Grâce au plug-in SDK, qui fait le gros du travail, il est simple de créer un plug-in qui associe une API à un ensemble de tables.

Debout sur les épaules de Postgres

En intégrant Postgres, Steampipe hérite de toutes ses capacités. Ainsi, par exemple, vous pouvez joindre des tables étrangères provenant de l’API avec des tables Postgres natives. Et bien que le principal avantage de Steampipe soit l’interrogation en direct des API, vous pouvez créer des vues matérialisées pour conserver ces données et écrire des fonctions Postgres pour les exploiter. Vous pouvez même charger d’autres extensions Postgres et les utiliser avec les tables Steampipe. L’extension tablefunc intégrée de Postgres, par exemple, peut faire des tableaux croisés, en SQL, avec des données de feuille de calcul du plug-in Google Sheets de Steampipe.

Un autre avantage de l’intégration de Postgres : n’importe quel client API compatible avec Postgres peut se connecter à Steampipe. Cela inclut des outils de ligne de commande comme psql et ceux basés sur une interface graphique comme Tableau, Power BI, Metabase et Superset qui apportent visualisation et interaction aux données API en direct.

La publication ne sera peut-être jamais aussi largement intégrée que l’omniprésent SQLite, mais elle est plus performante et son écosystème développé est utilisé pour alimenter des outils interopérables pour travailler avec des données. Steampipe étend Postgres pour fournir un accès unifié aux API et un environnement SQL commun dans lequel raisonner sur les données qu’elles fournissent.

Copyright © 2022 IDG Communications, Inc.

Leave a Comment