Sorting OpenAPI 3 Specs by Paths

OpenAPI is a the new emerging standard in API definitions and documentations.

It’s based on a Specification File structured in Json, and a few editors and viewer tools are popping up here and there.

Unfortunately something that seems pretty inconsistent is the sorting of the paths in the viewer against the editor. The specifications leave to the writer to decide in which order the API Paths should be sorted, but most of the editors doesn’t allow to reorder the paths inside of the Json file.

So, I made this small-and-ugly script to sort the PATHS inside of an OpenAPI json file alphabetically, which seems a pretty practical approach even in documentations.

It reads a file called openapi.json and writes out a file called openapi_sorted.json.

Feel free to use it as you like.

<?php

##
## Small tool to sort the paths inside an OpenAPI definition file
## Taken from https://andrea.brancatelli.it/
##

$mainObject = json_decode(file_get_contents("openapi.json"));

$paths = get_object_vars($mainObject->paths);
ksort($paths);

$mainObject->paths = new StdClass();

foreach ($paths as $eachPath => $eachValue) {
	$mainObject->paths->$eachPath = $eachValue;
}

file_put_contents("openapi_sorted.json", json_encode($mainObject,
	JSON_PRETTY_PRINT |
	JSON_UNESCAPED_SLASHES |
	JSON_UNESCAPED_UNICODE));

Politiche di gestione dei Backup nel rispetto delle linee guida del GDPR

Un breve documento che presenta alcuni cambi di strategia adottati in Schema31 nella gestione dei backup per recepire e rispettare le nuove linee guida del GDPR.

Introduzione

Con l’introduzione delle linee guida per la Privacy diventate operative a partire dal 25 Maggio 2018, lo scenario della gestione dei dati personali nell’ambito dei processi informatici è notevolmente cambiato. 

Al proprietario del dato personale vengono infatti riconosciute una serie di tutele legate alle indicazioni di come i suoi dati vengano trattati e conservati da aziende terze che si trovino a gestirli.

Conseguentemente, l’intera filiera di gestione del dato personale viene impattata da una revisione sistematica che permetta di garantire una totale trasparenza ed un totale rispetto dei dati gestiti.

Nell’ambito del GDPR vengono introdotti 8 principi base nella gestione del dato personale :

  • Il diritto all’informativa: l’organizzazione che gestisca dei dati personali è tenuta ad informare l’utente di quali dati stia conservando, a che fine e per quanto tempo verranno conservati.
  • Il diritto all’accesso: l’organizzazione che gestisca dei dati personali è tenuta a garantire a fornire, entro un mese, una copia di tutti i dati personali in suo possesso ad un utente che ne richieda l’accesso.
  • Il diritto alla rettifica: l’organizzazione che gestisca dei dati personali è tenuta a correggere entro un mese dei dati che, secondo l’indicazione dell’utente risultino incompleti, parziali o errati.
  • Il diritto all’oblio: l’organizzazione che gestisca dei dati personali è tenuta a cancellarli qualora l’utente lo richieda o, comunque, ritiri il consenso al trattamento.
  • Il diritto a limitare il trattamento: l’organizzazione che gestisca dei dati personali è tenuta a limitare al minimo possibile il set dei dati che raccoglie o gestisce di un determinato utente.
  • Il diritto alla portabilità: l’organizzazione che gestisca dei dati personali è tenuta a rendere possibile la migrazione dei dati personali di un utente ad un’altra organizzazione nella maniera più semplice possibile.
  • Il diritto all’obiezione: l’organizzazione che gestisca dei dati personali è tenuta ad interrompere ogni trattamento dei dati dell’utente che obietti la legittimità al trattamento, fino a che non dimostrerà di essere titolata a trattarli.
  • Limiti alla profilazione: l’organizzazione che gestisca dei dati personali è tenuta a porre dei vincoli nei processi automatizzati di profilazione dell’utente, con specifico riferimento all’analisi incrociata dei dati di un utente ed alla definizione di ciò che potrebbe riguardarlo in maniera correlata a preferenze che abbia espresso.

Nella loro applicazione, questi 8 principi base impattano in maniera diversa su fasi diverse della gestione di un processo informatico. Taluni di essi, infatti, saranno recepiti in fase di definizione della comunicazione verso l’utente (Diritto all’informativa), taluni saranno recepiti in fase di design dei sistemi informatici software che gestiscano i dati (Diritto alla rettifica, diritto alla limitazione del trattamento, diritto alla portabilità, limiti alla profilazione), taluni saranno recepiti in fase di esercizio del sistema informatico (Diritto all’accesso, diritto all’oblio, diritto a limitare il trattamento, diritto all’obiezione).

Implementazione delle logiche di backup

Ognuno di questi aspetti cardine viene recepito in maniera più o meno complessa nell’ambito di un sistema informatico – quello di maggiore impatto, ed oggetto di questo documento – è senza dubbio l’infrastruttura volta a garantire il backup dei dati gestiti dall’applicazione. Essa infatti viene impattata in maniera diretta dal diritto all’oblio, che riguarda fondamentalmente tutte quelle strategie da adottare nel momento in cui sia necessario cancellare un determinato dato su richiesta di un utente, nonché dai normali parametri di riservatezza e confidenzialità.

Da un punto di vista dell’applicativo in esecuzione e della sua base dati, l’implementazione di funzionalità di sicurezza e di cancellazione dei dati stanno oramai diventando funzionalità de-facto, che possono apparire abbastanza semplici da implementare: per garantire il diritto all’oblio, ad esempio, sarà sufficiente cancellare il tracciato dati relativo all’utente che ne abbia richiesto la cancellazione, mentre per garantire la confidenzialità del dato (e quindi indirettamente il diritto alla limitazione al trattamento) sarà sufficiente adottare dovute precauzioni nella gestione dei privilegi di accesso all’applicazioni ed eventuali politiche di cifratura dei dati su disco nella base dati (cifratura dati a riposo).

Raramente, invece, si focalizzano le problematiche dei dati degli utenti nell’ambito dell’ecosistema di Backup. Ogni dato trattato e gestito lascia alle sue spalle una proiezione della sua presenza sia all’interno dei sistemi informatici che lo hanno gestito, sia nei sistemi di backup.

Il GDPR, invece, richiede in maniera molto formale che ogni istanza dei dati dell’utente che chieda la cancellazione debba essere rimossa; è, quindi, assolutamente necessario prendere in considerazione anche delle strategie volte alla rimozione dalla stessa dai sistemi di backup.

Su Internet è possibile trovare della bibliografia  sul tema nel quale viene suggerito di adottare delle strategie volte a pianificare delle politiche di backup tramite le quali i dati di ogni utente siano collocati in un archivio a se stante – da cancellare quindi integralmente su richiesta dell’utente. Per quanto apparentemente risolutivo della problematica generale, questo approccio risulta decisamente di difficile applicazione in uno scenario applicativo che debba gestire dati di migliaia di utenti, sparsi in una base dati organizzata per gestire dei dati specifici di un determinato dominio applicativo.

Sarebbe altresì possibile progettare dei sistemi di backup che, invece di esportare la base dati in maniera diretta, la trasformino in un’estrazione aggregata dedicata, ma questo creerebbe degli enormi effort operativi nel mantenere la procedura di backup allineata con l’evoluzione della base dati, nonché un enorme incremento delle tempistiche di ripristino della base dati a fronte di un’anomalia hardware o applicativa (in altre parole, invece che limitarsi a ripristinare la base dati bisognerebbe avviare delle complesse procedure di re-importazione dei dati stessi) .

Tolta la possibilità di gestire in maniera automatizzata questa operazione, è necessario ridisegnare le procedure di backup affinché soddisfino i requisiti del GDPR.

In ambito SCHEMA31 stiamo pertanto adottando le seguenti linee guida:

Riduzione delle tempistiche di permanenza dei backup

Nel precedente approccio alla gestione dei Backup si era usata una filosofia secondo cui la situazione migliore possibile fosse quella di far perdurare il dato “più a lungo possibile” nel sistema di Backup.

Le così-dette policy di retention del sistema di backup erano pertanto disegnate per “riempire” totalmente il sistema di backup con la maggiore profondità storica possibile. All’esaurimento dello spazio nel sistema di backup, i nuovi backup avrebbero sovrascritto i più vecchi generando uno svecchiamento dei dati conservati. Nei casi degli applicativi con basi dati più contenute, questo poteva portare con semplicità ad una profondità storica di 5, 6, fino anche 10 anni di backup.

Questa scelta, “garantista” nei confronti della parte tecnologica, però risulta stridere fortemente con il diritto all’oblio (dato che una cancellazione nella base dati poteva far perdurare il dato nei backup anche per dieci anni), con il diritto alla limitazione del trattamento (dato che anche una riduzione del set dei dati trattati poteva richiedere decine di anni ad essere applicata), e con il diritto all’informativa (dato che non essendo pianificata in maniera preventiva una politica temporale di backup essa era di difficile formalizzazione nell’informativa all’utente).

A valle del ridisegno delle politiche di Backup in ottica GDPR si è deciso di modificare le policy di retention del sistema di backup affinché nessun dato storico venga conservato per più di due mesi dalla data in cui viene estratto dalla base dati.

Definire in maniera rigorosa questa metrica permette di comunicare questo dato in maniera chiara all’utenza (nel rispetto quindi del diritto all’informativa) e permette di garantire che a fronte di un utente che richieda una rettifica dei propri dati o la cancellazione dei propri dati, essa possa essere effettuata in maniera deterministica sia sulla base dati (in tempo reale) sia sulla base storica dei dati sulla piattaforma di backup (entro un massimo di due mesi).

Cifratura delle informazioni all’interno del sistema di backup

Un altro aspetto focale emerso durante la revisione delle politiche di Backup in un’ottica di rispetto delle linee guida del GDPR è relativo agli ulteriori step che è necessario adottare per garantire la tutela delle informazioni trattate dell’utenza, nell’ottica di limitare più possibile il trattamento delle stesse da parte sia di persone autorizzate che di persone non autorizzate che si trovino involontariamente a gestire i dati.

Detto altrimenti, la necessità – anche ai fini del rispetto delle norme ISO27001 e derivati – di definire il perimetro di confidenzialità di trattamento dei dati rende improvvisamente il sistema di backup il punto nevralgico della sicurezza all’interno dell’infrastruttura informatica: da una parte un utente malintenzionato non ha la necessità di superare gli elevati sbarramenti di sicurezza di un sistema disegnato per trattare dati riservati, quando può accedere ad una copia della base dati su un sistema con parametri di sicurezza inferiore (e solitamente aperto a molteplici sistemi diversi) quale il sistema di backup. D’altra parte qualsiasi operatore del sistema di Backup risulta involontariamente esposto a tutte le responsabilità di confidenzialità dei dati contenuti all’interno delle basi dati, spesso senza esserne neanche conscio.

Per aggirare questo problema si è deciso di definire delle logiche di cifratura delle basi dati esportate prima del loro invio verso il sistema di backup.

Specificamente, vi è da garantire una serie di aspetti fondamentali:

  • Il rispetto dei migliori RTO (Recovery Time Objective)  – pertanto la procedura di ripristino di un backup deve essere mantenuta più “fruibile” possibile.
  • Il rispetto della confidenzialità dei dati – pertanto la procedura di backup deve impedire il ripristino del backup da parte di un utente non designato all’operazione.
  • Il rispetto dell’isolamento dei dati in chiaro dagli operatori del sistema di backup – pertanto la procedura di Backup non deve prevedere chiavi di decifrazione all’interno del sistema di Backup.

Per garantire il rispetto di questi fattori si è optato per effettuare una cifratura a chiave asimmetrica (chiave RSA da 2Kb con cifratura AES-256) della base dati esportata prima che essa venga inviata al sistema centrale di gestione di backup .

Specificamente l’esportazione della base dati provvederà a cifrare il backup stesso tramite una duplice chiave pubblica:

  • La chiave pubblica del Server che sta effettuando il backup – di modo da garantire che in qualsiasi momento il Server che sta effettuando il backup sia in grado di ripristinare il proprio backup. Questo tipo di vincolo non introduce ulteriori falle ai principi di confidenzialità del dato, in quanto il codice che si occupa di effettuare il Backup ha già accesso alla base dati – conseguentemente qualsiasi violazione del Server da parte di un utente malintenzionato renderebbe accessibile la base dati nella sua interezza e non solo il suo stesso Backup. Al contempo questa scelta permette di garantire il miglior RTO possibile in quando un operatore correttamente abilitato all’accesso al Server potrà sempre effettuare il ripristino dello stesso (tramite l’accesso al backup con la chiave privata del Server stesso) qualora questo sia necessario. Parallelamente un operatore che abbia già accesso al Server, si può già considerare informato e conscio dei principi di confidenzialità dei dati che il Server stesso contiene.
  • La chiave pubblica del Responsabile della Privacy dell’azienda – di modo da garantire che a fronte di un evento disastroso che corrompa in maniera irreversibile il Server, il backup dei suoi dati sia comunque accessibile su una piattaforma terza (piattaforma sostitutiva del Server o piattaforma esterna) fornendo tutte le adeguate garanzie di continuità del business. Questo tipo di vincolo non introduce ulteriori falle ai principi di confidenzialità del dato, dato che l’unico a poter accedere ai dati stessi è il Responsabile della Privacy tramite la sua chiave privata – quindi persona già titolata a farlo. Al contempo permette di garantire degli RTO adeguati semplicemente coinvolgendo il Responsabile della Privacy nella fase di ripristino dei dati stessi, anche a fronte di attività di personale operativo sistemistico non necessariamente designato per operare sulla base dati in questione (ad esempio operatori della nuova infrastruttura) e che quindi potrebbero non essere coscienti dei livelli di confidenzialità necessari nel trattamento dei dati in questione (a differenza del Responsabile della Privacy che a questo punto è necessariamente coinvolto).

Il sistema di backup centralizzato a questo punto si limiterà a copiare i file cifrati all’interno del sistema di Storage storicizzato senza possibilità da parte degli operatori del sistema di Backup o di terzi malintenzionati che vi abbiano accesso, di leggere alcun dato contenuto al suo interno.

Riferimenti



CouchDB Replication Scheduler – tweak and tuning

A few tweaking hints for the Replication Scheduler in CouchDB 2.x

Lately we’ve been experimenting a lot with CouchDB an its replication features.

It’s a very cool paradigm that allows you to hide many layer of complexity related to data synchronisation between different systems into an automated and almost-instant replication process.

Basically CouchDB implements two kind of replications, a “one-shot” replication and a “continuous” replication. In the first case there’s a process that starts, replicate an entire DB and then goes in a “Completed” state, while in the second case there’s an always-on iterating process that, using some kind of internal sequence numbers (something conceptually close to a Journal Log of a filesystem), keeps the slave database continuously in sync with the master one.

When dealing with many databases and replication processes it’s pretty easy to reach a point where you have many Replication Processes running on a single server and that may lead to slowness and, in general, a high load of (effectively idle) activities on the machines.

To avoid such circumstances CouchDB, since version 2.1, implements a replication scheduler that is able to cycle trough all the replication jobs in some sort of circular fashion pausing and restarting all the jobs to avoid resources exhaustion.

The Replication Scheduler is controlled by a few tuneable parameters (see http://docs.couchdb.org/en/stable/config/replicator.html#replicator for more details). Three of those parameters are the real deal of the situation as they control the basic aspects of the scheduler:

  • max_jobs – which controls the threshold of max simultaneously running jobs;
  • interval – which controls how often the scheduler is invoked to rearrange replication jobs, pausing some jobs and starting some others;
  • max_churn – which controls the maximum number of jobs to be “replaced” (read: one job is paused, another one is started) in any single execution of the scheduler.

This is a basic diagram outlining the Replication Scheduler process:

Untitled Diagram

So, basically, with “max_jobs” you control how much you want to stress your server, with “interval” you control how often you want to shuffle things up, and with “max_churn” you control how violently the scheduler will act.

  • If max_jobs is too high your server load will increase (a lot!).
  • If max_jobs is too low your replication will be less “realtime” as there is an higher chance that a replication job could be paused.
  • If interval is too high a paused replication job could stay paused for way too long.
  • If interval is too low a running replication job could be paused to early, before it could actually catch up with it’s queued activities.
  • If max_churn is too high there may be an high expense in setup and kick off timings (when a replication process is started up it has to connect to the server, authenticate, check that everything is aligned and so on…)
  • If max_churn is too low the amount of time a process could stay paused may be pretty long.

As usual, your working environment – I mean, database size, hardware performances, document sizes, whatever – has a huge impact on how you tweak those parameters.

My only personal consideration is that the default value of max_jobs (500) seems to me a pretty high value for a common server. After some tweaking, on a “small” Virtual Machine we use for development we’ve settled with max_jobs set to 20, interval set to 60000 (60 seconds) and max_churn set to 10. On the Production server, with better Hardware (Real HW instead of VM, SSD drives, more CPU cores, and whatever) we expect an higher value for max_jobs – but in the 2x/3x range, so maybe something like 40/60 max_jobs – I strongly doubt we could ever reach a max_jobs value of 500.

Have fun.

PHP Proc_Open and STDIN – STDOUT – STDERR

In gCloud Storage, our Storage-as-a-Service system, we developed some years ago some chain technologies that allowed us to expand dynamically the features of the Storage subsystem allowing it to translate incoming or outgoing files.

Some while ago we developed a chain that allows our users to securely store a file by ciphering it when it enters in the system and decipher it when it’s fetched, without our party saving the password.

After some thinking we decided to embrace already existing technologies for the purpose, and we decided to rely on openssl for the purpose.

So we had to wrap some code that was able to interact with a spawned openssl process. We did some try-and-guess and surely we did our research on google. After various attempts we found this code that proved to be pretty reliable:

http://omegadelta.net/2012/02/08/stdin-stdout-stderr-with-proc_open-in-php/

We tried first on our Mac OS machines, then on our FreeBSD server and it worked flawlessly for a couple of years. Recently one of our customer asked for a on-premises installation of a stripped-down clone of gCloud Storage, that had to run on Linux (CentOS if that’s relevant). We were pretty confident that everything would go smoothly but that wasn’t the case. When the system went live we found out that when deciphering the files it would lose some ending blocks.

Long story short we found that on Linux a child process can finish while leaving data still in the stdout buffer while – apparently – it can’t on FreeBSD.

The code we adopted had a specific control to make sure that it wasn’t trying to interact with a dead process. Specifically:

if (!is_resource($process)) break;

was the guilty portion of the code. What was happening was that openssl was closing, the code was detecting it and bailing out before fetching the whole stdout/stderr.

So in the end we came out with this:

public function procOpenHandler($command = '', $stdin = '', $maxExecutionTime = 30) {

    $timeLimit = (time() + $maxExecutionTime);

    $descriptorSpec = array(
        0 => array("pipe", "r"),
        1 => array('pipe', 'w'),
        2 => array('pipe', 'w')
    );

    $pipes = array();

    $response = new stdClass();
    $response->status = TRUE;
    $response->stdOut = '';
    $response->stdErr = '';
    $response->exitCode = '';

    $process = proc_open($command, $descriptorSpec, $pipes);
    if (!$process) {
        // could not exec command
        $response->status = FALSE;
        return $response;
    }

    $txOff = 0;
    $txLen = strlen($stdin);
    $stdoutDone = FALSE;
    $stderrDone = FALSE;

    // Make stdin/stdout/stderr non-blocking
    stream_set_blocking($pipes[0], 0);
    stream_set_blocking($pipes[1], 0);
    stream_set_blocking($pipes[2], 0);

    if ($txLen == 0) {
        fclose($pipes[0]);
    }

    while (TRUE) {

        if (time() > $timeLimit) {
            // max execution time reached
            // echo 'MAX EXECUTION TIME REACHED'; die;
            @proc_close($process);
            $response->status = FALSE;
            break;
        }

        $rx = array(); // The program's stdout/stderr

        if (!$stdoutDone) {
            $rx[] = $pipes[1];
        }

        if (!$stderrDone) {
            $rx[] = $pipes[2];
        }

        $tx = array(); // The program's stdin

        if ($txOff < $txLen) {
              $tx[] = $pipes[0];
          }
          $ex = NULL;
          stream_select($rx, $tx, $ex, NULL, NULL); // Block til r/w possible
          if (!empty($tx)) {
              $txRet = fwrite($pipes[0], substr($stdin, $txOff, 8192));
              if ($txRet !== FALSE) {
                  $txOff += $txRet;
              }
              if ($txOff >= $txLen) {
                fclose($pipes[0]);
            }
        }

        foreach ($rx as $r) {

            if ($r == $pipes[1]) {

                $response->stdOut .= fread($pipes[1], 8192);

                if (feof($pipes[1])) {

                    fclose($pipes[1]);
                    $stdoutDone = TRUE;
                }
            } else if ($r == $pipes[2]) {

                $response->stdErr .= fread($pipes[2], 8192);

                if (feof($pipes[2])) {

                    fclose($pipes[2]);
                    $stderrDone = TRUE;
                }
            }
        }
        if (!is_resource($process)) {
            $txOff = $txLen;
        }

        $processStatus = proc_get_status($process);
        if (array_key_exists('running', $processStatus) && !$processStatus['running']) {
            $txOff = $txLen;
        }

        if ($txOff >= $txLen && $stdoutDone && $stderrDone) {
            break;
        }
    }

    // Ok - close process (if still running)
    $response->exitCode = @proc_close($process);

    return $response;
}

Have Fun! 😉

FreeBSD 10.0 bhyve – VMWare ESXi 5.5 comparison – part 2

A few days ago I posted a comparison between FreeBSD’s bhyve and VMWare ESXi 5.5. I received a lot of feedbacks from the result of our test, so we decided to investigate further with a new round of tests, in a more scientific approach.

As in previous test, we used a standard “empty” FreeBSD 10 machine + latest portsnap that we used as our main “template”. The VM was using “ahci-hd” as the storage backend and the tests were run in SSH, not local console. We always started from this template for every test and run the same test in different scenarios. The hardware was the same one as the previous tests.

Note: I didn’t write it in the past post, but our first round of test was run on a ZFS filesystem with both compression and deduplication enabled.

Continua a leggere “FreeBSD 10.0 bhyve – VMWare ESXi 5.5 comparison – part 2”

FreeBSD 10.0 BHyVe – VMWare ESXi 5.5 comparison

Hey, I wrote a “part 2” to this article, you may want to check it out!

Hello,

recently FreeBSD10 has come out and one of the most intresting new features was the introduction of bhyve, a “type 2 hypervisor” that allow you to easily create a Virtual Machine inside of a FreeBSD Host.

As with every new technology, it is yet very rough, but the first “driving” experience was very good. Recently we had a new project starting, some new hardware still unused and in general I’m not very fond of VMWare so we decided to do a comparison between VMWare and bhyve to understand what would be the real performance downfall of using a new technology.

Continua a leggere “FreeBSD 10.0 BHyVe – VMWare ESXi 5.5 comparison”