Buongiorno a tutti. Mi chiamo Nathan Clark. Utilizzo JMP da 22 anni e lavoro presso IDEXX Laboratories. Parlerò della gestione dei segreti con la mia co-relatrice, Sage Darling.
Ciao. Sono Sage. Lavoro anche io in IDEXX con Nathan. Qui sono un ingegnere analitico senior e parleremo di segreti.
Ottimo. Cominciamo a parlare un po' di cosa si intende per segreto. In genere, almeno dal punto di vista del codice, un segreto è una sorta di credenziale che serve a far funzionare il codice per accedere a qualcosa, ma che allo stesso tempo non dovrebbe essere rivelata ad altri. È molto simile alle password con cui accedi al computer. Devi usarla spesso, ma non dovresti rivelarla ad altri.
I segreti sono metodi sviluppati da diverse piattaforme per consentire a queste credenziali di esistere in modo tale che non siano visibili una volta disponibili. In questo modo, diventano molto più sicuri da utilizzare nelle attività in background. JMP non ha questa funzionalità integrata. Ma man mano che iniziamo a lavorare di più con il codice e con attività in background o dietro le quinte in JSL, abbiamo voluto che questa possibilità fosse presente per condividere le nostre attività con altri, accedendo a cose diverse senza dare accidentalmente a nessuno le chiavi del proverbiale regno.
In una discussione che ho avuto con il supporto JMP qualche tempo fa, ho ricevuto questo piccolo pezzo di codice scritto da, credo fosse Evan McCorkle, che lo avrebbe messo insieme come un modo per mascherare questi segreti e qualcosa in cui potrebbe esistere come stiamo vedendo qui, ma poi è possibile crittografare lo script e poi utilizzarlo.
Fondamentalmente, utilizza una funzione che contiene i segreti, ma richiede un segreto secondario o una frase di accesso di cui si conosce l'esistenza, che tutte le funzioni all'interno di questo codice crittografato contengono, ma che nessun altro saprà di cosa si tratta. Anche se sanno che use secret A è la funzione che vogliono provare a chiamare o qualcosa del genere, non possono accedere direttamente a questi segreti senza sapere di cosa si tratta. Una volta crittografato, è possibile includerlo come script segreto e quindi accedere a queste informazioni senza saperlo. Finora, quando ho parlato con il supporto JMP, nonostante i tentativi, non erano riusciti a trovare un modo per esporre il segreto durante i test. Con il materiale su cui ho lavorato, non ci sono riuscito nemmeno io. Sembra un framework davvero valido da cui partire per sviluppare il modo in cui si desidera poter archiviare i segreti in modo sicuro, consentendo comunque agli utenti di utilizzarli per svolgere varie attività di codice.
Oggi abbiamo due esempi. Parlerò di come abbiamo implementato tutto questo per Snowflake. Quello che ho qui è, scusate, il modello di connessione di Snowflake che trovate qui. Questa è fondamentalmente la funzione che ho scritto, con tutti i dettagli nascosti.
Lo renderò un po' più grande. Vedete, ho la funzione get_secrets che indica dove si trovano i segreti. Nel mio caso, per quello che stiamo cercando di fare, ho bisogno solo di un nome utente e di una password per accedere a Snowflake, con la configurazione attuale. Questo è un array di password relativamente semplice da avere qui.
Ma poi ho altre funzioni di supporto per utilizzarle. La prima crea una connessione effettiva al database e restituisce semplicemente il nuovo connettore dati. Questa è una stringa che dovresti mettere insieme. È qualcosa in cui hai il connettore dati e si connette a tutti i componenti specifici della tua azienda. L'unica cosa che devi avere è il driver Snowflake installato. Questo è il nome del driver Snowflake quando lo installi dal sito web di Snowflake sul tuo computer. In questo modo puoi stabilire la connessione ODBC. Ma il tuo database sarà specifico per le tue aziende. Tuttavia, i server della tua azienda sono connessi a Snowflake, eccetera. Quindi la password è dove la prende da quest'altro array che abbiamo qui. La inserisce, quindi hai qui gli altri componenti a cui puoi connetterti.
L'ultima funzione che ho implementato fa un ulteriore passo avanti. Questa, infatti, acquisisce la stringa della query che si desidera eseguire, crea tutte le connessioni presenti ed esegue la query in questa funzione. Quindi, alla fine, elimina tutti gli script di tabella che provengono da quella tabella. Ne parlerò quando farò l'esempio, spiegando perché potrebbe essere utile. In pratica, si tratta di un ulteriore livello di protezione, in modo che le credenziali non vengano condivise o esposte accidentalmente.
Detto questo, ho qui un esempio davvero semplice. Nel primo esempio, si tratta fondamentalmente di eseguire una query raw, e sto eseguendo SQL personalizzato e inserendo semplicemente la versione stringa di ciò che dovrebbe essere la query. Se lo eseguo, ottengo una tabella da Snowflake. Assomiglia moltissimo a Big Class perché lo è. Ne ho appena caricato una copia su Snowflake. Questo vi fornisce la tabella esattamente come la desiderate. Include alcune informazioni di origine. Questo può essere utile. Ho notato che quando lo faccio, maschera il nome utente e la password, che è quello che mi aspetterei. Ho notato che, mentre sperimentavo in molti modi diversi, ho avuto un paio di esempi, casuali o meno, in cui la password non era esposta, ma l'ID utente sì. A seconda di quanto strettamente si debba monitorare queste credenziali, ecco perché ho creato la funzione aggiuntiva che rimuove queste informazioni.
Se commento questa sezione qui e ora la eseguo, si crea semplicemente una nuova tabella con quest'altra funzione in cui inserisco questo come query, e ora crea la stessa cosa. Solo che ora ci si trova in una situazione in cui la tabella non ha nessuno di questi script di tabella. Ottimo. Per approfondire ulteriormente il funzionamento, ad esempio, se voglio eliminare questo e selezionare solo questo grafico a stella, tutte le colonne, questo dovrebbe ora funzionare e includerle tutte. Lo stesso vale se si desidera aggiungere alcune funzionalità di filtro. È possibile farlo qui. Funziona proprio come il linguaggio SQL standard quando si eseguono queste query. Basta passare la stringa a questo e si ottiene la tabella dei dati di pulizia. Questo è un esempio relativamente semplice. Vorrei ora passare la parola a Sage, che ha una versione più complessa di come questo può funzionare insieme alla stratificazione della funzione. Ora passo la parola a Sage.
Fox Drive è un percorso di salvataggio di cartelle online in cui è possibile inserire informazioni. Noi lo usiamo per molte cose diverse e quindi volevo iniziare chiedendomi come autenticarmi in Box per trasferire i file localmente da Box al mio computer. Questo richiede la creazione di un'app tramite Box Developers che possa poi autenticare. Quindi, per fare ciò, l'app richiede di fornire un JWT, ovvero un token web JSON, e questo token web JSON può essere utilizzato, tramite pipeline, per ottenere un token di accesso che posso utilizzare per accedere effettivamente a Box. Qui la mia situazione si è rivelata un po' più complessa, perché non avevo mai avuto a che fare con JSON o token web JSON prima, JWT, ed è qui che ho dovuto implementare questa funzionalità.
Come descriveva Nathan, questo è l'esempio a destra di come appare il mio file secrets.jsl. Al momento non è crittografato, quindi potete vedere come appare all'interno. Il mio inizia anche con una funzione get secrets o ha una funzione per ottenere i segreti. Qui è dove vanno tutte le informazioni del mio JWT. Il JWT contiene informazioni come ID client, segreto client, elementi univoci per quell'applicazione. Li inserisco in questo array associativo in modo che siano i segreti che verranno poi estratti. Quindi, per accedere a ciascuno di questi elementi, ho altre funzioni che accedono ai componenti all'interno di quegli array associativi a partire dall'ID client.
Ne mostrerò solo uno perché se li esaminassi tutti, vedreste tutti i pezzi dell'array associativo e sarebbe probabilmente noioso. Questo è un esempio di come ottenere solo l'ID client. Al suo interno, uso i segreti per ottenere i segreti, che sono la mia chiave di accesso Box, che mi fornisce l'ID client. Di nuovo, questo sistema mantiene tutto segreto per poter estrarre i dati da quella funzione perché è crittografato.
La cosa che ho dovuto aggiungere, un po' diversa, riguarda il token JWT di Get Box. Questo richiede un po' di finezza diversa, perché i JWT richiedono asserzioni per ottenere un nuovo token di accesso, che a sua volta richiede un componente di firma. Trattandosi di un componente di firma, è in realtà considerato materiale sensibile. Il mio file secrets.jsl include funzioni che elaborano ulteriormente per ottenere queste informazioni da Box. In questo caso, la mia funzione JWT... la riassumo in modo che sia più facile da vedere. La mia funzione JWT crea quell'asserzione con Box per poter ottenere l'impegno da inviare per ottenere il token di accesso. Per fare ciò, devo ottenere le informazioni esplicite che ho anche sopra per i miei segreti, ovvero il mio ID aziendale Get Box, il mio ID client Get Box, la mia chiave pubblica Box, la mia chiave privata e la mia parafrasi univoca per la mia app.
Da lì ho un po' di materiale per la risoluzione dei problemi, ad esempio se mancano delle chiavi, cosa è veramente importante, e poi per eseguire l'asserzione JWT ho dovuto farlo tramite Python. Questo include anche un altro esempio di utilizzo di un altro linguaggio all'interno di secrets.jsl, che è stato anch'esso un aspetto che ho dovuto gestire per assicurarmi che i dati potessero essere stampati. Ecco perché risiede in secrets.jsl in termini di crittografia e non solo nello script che sto usando per utilizzare le informazioni che sono le mie informazioni JWT. Questa è anche un'opportunità unica per vedere Python integrato in quel JSL, il che è davvero fantastico.
Invio quindi queste informazioni allo script Python, che le estrae per ottenere una firma specifica per quel JWT, e da lì crea quelle credenziali e poi restituisce quell'asserzione JWT in modo che io possa utilizzarla in seguito. Ora che ho quell'asserzione JWT, posso ottenere il mio token di accesso. Da lì, fondamentalmente ottengo il mio box o il token JWT del mio box, che hai appena visto sopra, e poi uso il mio client_ID e il mio client_secret per creare un token prendendo quella JWT_assertion, prendendo il mio client_ID, prendendo i miei client secret e usando una richiesta HTTP per inviarli a Box. Da lì sono in grado di ottenere il mio nuovo token di accesso.
Ho anche inserito un po' di air-catching per coloro che sono interessati ad approfondire, ma poi invierà le mie informazioni relative al fatto che ho effettivamente ricevuto o meno il token di accesso e poi restituirà il token di accesso all'utente.
Dove viene utilizzato? Come viene utilizzato? Mostrerò il mio esempio perché ci sono alcune conversazioni interessanti che potremmo avere ulteriormente sui token di accesso stessi. Per integrare questo, ho una cartella generica che vi mostrerò come esempio, ma per il mio codice effettivo qui mostrerò solo alcuni input.
Includo la connessione Box, che nel mio caso è crittografata, perché è quello che si vuole fare dopo aver terminato la gestione del file secrets. Box ha una posizione o un modo per gestire le proprie cartelle, ovvero ha dei codici ID, e questo è un modo per sapere in modo univoco in quale cartella si sta cercando un file da cercare. È lì che si inserisce l'ID univoco della cartella. In particolare, sto estraendo solo file JMP. Potrebbe essere molto più complesso in termini di ciò che si vuole fare, ma il mio esempio riguardava solo file JMP.
Ho anche incluso un parametro qui per valutare la profondità di ricorsione. Box è interessante perché funziona in modo orientato agli oggetti. Si ha un ID cartella, quindi si possono avere ID all'interno di quell'ID cartella, quindi si deve cercare ricorsivamente nelle cartelle. Permetto al mio script di accedere a tutti i livelli che ritengo opportuni, che in questo caso sono cinque. Poi ho una posizione in cui scaricare i file e un modo per rinominarli. Quello che farò in questo esempio, dopo aver spiegato come funziona effettivamente e alcune delle complessità relative al token di accesso per motivi di sicurezza, vi mostrerò il mio esempio: estrarrò alcuni file JMP da Box.
Ci sono alcune funzioni qui per la ricerca ricorsiva nei file JSL. Non parlerò di queste o dei download di Python, ma parlerò della connessione principale di Box. In questo caso, è qui che stavamo parlando in termini di alcuni aspetti di sicurezza che potrebbero essere un po' interessanti in termini di dove sia il posto migliore per ogni azienda/persona dove inserirlo. Il posto in cui potresti inserirlo è leggermente diverso e in termini di sicurezza varia a seconda del posto di cui stai parlando, ma nel mio caso è qui che mi sono fermato. Questa funzione principale, per iniziare subito, mi serve per ottenere le informazioni da Box. Per farlo devo ottenere il mio token di accesso. Ottenere il mio token di accesso fa parte di quel file secrets.jsl che hai visto che era crittografato. In questo caso, ciò che fa è fornirmi questo token di accesso. Questa è una variabile che esiste in questo JSL.
In questo JSL, poiché sto ottenendo questo token di accesso qui, se dovessi aggiungere un'istruzione di stampa, ad esempio alla riga 583, saresti in grado di vedere il token di accesso. Ora, la cosa interessante, o il bello di Box, è che quei token di accesso scadono. Non c'è davvero alcun rischio che qualcuno possa usarli in seguito. Si riduce, ma è comunque potenzialmente un rischio per la sicurezza se si stampa questo token di accesso o si ottiene lo script, lo si esegue e si stampa in quella posizione.
Idealmente o potenzialmente, quello che potresti fare è, invece di quello che ho fatto qui, ovvero inserire il token di accesso Box, spostare le parti di autenticazione, sia il test che la ricerca, nel mio secret.jsl per poi crittografarle. In tal caso, non sarebbero più accessibili e gli altri non sarebbero in grado di vederle. Un caso d'uso leggermente diverso, un po' diverso, che puoi usare a tuo piacimento, a seconda di come vuoi posizionarlo. Il modo più sicuro sarebbe quello di inserire il token di accesso Box all'interno del secret.jsl e crittografarlo in modo che nessuno possa vederlo. Ma in questo caso, questo è un buon spunto di discussione, è così che l'ho lasciato, quindi ecco come appare. Possiamo parlarne da lì.
Poi passa e ottiene il token di accesso Box e da lì posso effettivamente cercare i file di accesso Box perché ora ho il mio modulo di autenticazione che dice che sono chi sono e che dovresti farmi entrare. Nel mio caso, ho una demo, e nella mia demo ho un esempio in cui sto estraendo dati da un file che ho sul mio disco Box. Quell'area file si presenta così, ed è Secrets_JMP Discovery, File Examples_Secrets e ho alcune tabelle JMP che sto per estrarre e concatenare da questa posizione. Per farlo, eseguirò questo. Poi faremo la tragica musica di attesa perché è quello che succede a volte quando si esegue uno script. A volte ci vuole un secondo.
Autenticazione, dimmi chi sono, dimmi chi sei. Eccoci qui. Questo è il file che ho ottenuto. Puoi vedere le mie tabelle sorgente, quelli erano i nomi delle tabelle JMP che avevo in quella posizione di Box e queste sono le tabelle che sono state concatenate insieme. Solo un mucchio di battute divertenti.
Ecco cosa ho fatto con i miei token di accesso Box e l'integrazione con i JWT. Ora lo passerò a Nathan.
Con tutto ciò che Sage ha mostrato, e che io ho mostrato, come possiamo implementarlo e come possiamo fare in modo che, ora che abbiamo fatto questo, più di me e Sage possano svolgere parte di questo lavoro? Quello che abbiamo fatto è stato caricarlo su GitHub. Ecco uno sguardo a GitHub. Abbiamo il repository. Questo è anche collegato alla presentazione, e qui abbiamo i nostri esempi.
Ora, questo è qualcosa in cui, a seconda di come si desidera organizzarlo, ci sono molte opzioni a disposizione. Ma la cosa principale che abbiamo messo insieme è il modello dei segreti. Questo è ciò che vi avevo mostrato prima con quel valore di base. Poi abbiamo i nostri diversi esempi. All'interno di questi esempi, abbiamo fondamentalmente tre file principali in cui abbiamo, ecco il nostro modello che mostreremmo contenente tutte le nostre informazioni. Qui è dove potete compilarlo con le vostre informazioni personali o aziendali, ed è questo che si ottiene per la crittografia. Ciò che rende tutto questo sicuro è ciò che vi consigliamo di fare: prendete questo modello e salvatelo nel vostro repository o nel vostro clone, sostituendo "template" con la parola "raw". In questo modo, è lì che vengono nascoste tutte le informazioni veramente importanti. Quello che abbiamo fatto è che in questo gitignore ignoreremo il file raw.jsl. In questo modo, questi file rimangono locali e potete lavorarci sopra. Avete le vostre credenziali. Mantenete le vostre credenziali. Quindi crittografi il tuo file raw e lo carichi come versione crittografata di quel file.
Ora, l'unica cosa presente su GitHub dovrebbe essere la versione crittografata funzionante. In ciascuna di queste cartelle, abbiamo documenti specifici per il loro utilizzo. Quanto si desidera condividere nel file README principale o nella documentazione dipende in realtà da cosa si desidera che le persone sappiano in termini di utilizzo di queste informazioni. Se si dispone di qualcosa, o si sta utilizzando qualcosa come Project Jab, di cui Sage e io abbiamo parlato l'anno scorso, questo è un modo per creare componenti aggiuntivi e consente potenzialmente di estrarre file da singoli repository. In questo modo è possibile estrarre semplicemente i file segreti necessari per poter fare ciò che si desidera. È un ottimo modo per mantenere queste informazioni disponibili, ma anche per mantenere diversi livelli di segretezza.
Come ha accennato Sage, se ti trovi in una situazione in cui il tuo codice sta diventando un po' più complicato, potresti ritrovarti nella situazione in cui, per mantenere quel livello di segretezza, finisci per inserire sempre più informazioni in questo file crittografato.
Come diceva Sage nel suo modello, ha tutte queste funzioni che svolgono molto lavoro, ma è quando è entrata nel suo esempio che ha sottolineato quel token di accesso molto specifico. Non ricordo esattamente dove si trovi nella funzione, ma è qualcosa che, se non si vuole che gli altri vedano nell'esempio principale, si può semplicemente aggiungere quella funzione al modello o al file raw del modello, crittografarlo e nasconderlo. I livelli da attraversare, credo, dipenderanno dai casi d'uso e da cosa si vuole fare. In Snowflake, si è rivelato relativamente semplice perché ho potuto usare la connessione direttamente o semplicemente pulire una tabella. Quindi, le difficoltà possono variare e a cosa è necessario connettersi, che si tratti di API o cose del genere.
Ma penso che sia un modo relativamente facile da digerire e utilizzare per analizzare i propri segreti ed essere in grado di offrire molti livelli per migliorare la propria codifica di base, mantenendo comunque solide pratiche di sicurezza informatica per mantenere le cose pulite e a norma.
Credo che questo sia tutto ciò di cui volevamo parlare oggi. Grazie di cuore a tutti al JMP per averci dato questa opportunità e grazie a tutti gli spettatori per aver dato un'occhiata.
Sono assolutamente d'accordo. Spero che tu stia tenendo al sicuro i tuoi segreti. Se vuoi, puoi venirci a trovare al JMP Discovery di quest'anno, perché noi saremo lì.
Sì, lo faremo. Grazie.