{"id":3741,"date":"2021-10-29T13:59:00","date_gmt":"2021-10-29T11:59:00","guid":{"rendered":"https:\/\/blog.besharp.it\/?p=3741"},"modified":"2021-10-28T12:47:02","modified_gmt":"2021-10-28T10:47:02","slug":"installare-plug-in-custom-su-rds-con-le-custom-resources-di-cloudformation","status":"publish","type":"post","link":"https:\/\/blog.besharp.it\/it\/installare-plug-in-custom-su-rds-con-le-custom-resources-di-cloudformation\/","title":{"rendered":"Installare plug-in custom su RDS con le Custom Resources di CloudFormation"},"content":{"rendered":"\n

La gestione e l’amministrazione dei database<\/strong> sono sempre stati compiti molto delicati sia per server on premise, sia sul cloud. Lo sforzo richiesto per configurare e mantenere un database \u00e8 molto alto: dalla configurazione della rete, alla restrizione dei permessi per i vari utenti, gruppi e ruoli. Backup e aggiornamenti, inoltre, richiedono anch\u2019essi tempo. C\u2019\u00e8 anche da considerare il fatto che le varie configurazioni di un database possono cambiare nel tempo<\/strong> e richiedere quindi revisioni e modifiche, anche sostanziali. <\/p>\n\n\n\n

Sfruttare i database managed<\/em><\/strong> diminuisce considerevolmente lo sforzo di gestione e amministrazione aggiungendo anche caratteristiche fondamentali come scalabilit\u00e0<\/strong>, alta disponibilit\u00e0<\/strong>, fault-tolerance<\/strong> e sicurezza<\/strong>.<\/p>\n\n\n\n

Ma non basta: in molti casi pu\u00f2 sopraggiungere per un amministratore di databases la necessit\u00e0 di installare uno o pi\u00f9 plug-in<\/strong> (o estensioni) per incrementare le potenzialit\u00e0 del database o aggiungere funzionalit\u00e0. Alcuni esempi relativi al mondo PostgreSQL, possono essere l\u2019installazione di PostGis per query che includono informazioni geografiche, o PGCrypto per avere funzionalit\u00e0 crittografiche come la generazione del salt o l\u2019hashing di stringhe. Queste sono operazioni manuali e ricorrenti che richiedono tempo e attenzione gi\u00e0 per un singolo database. Oggi, per\u00f2, anche le aziende pi\u00f9 piccole necessitano di pi\u00f9 database, a seconda del numero di servizi e\/o applicazioni che offrono. Ripetere le stesse azioni per configurare correttamente molti databases \u00e8 un’operazione time-consuming e rischiosa: la ripetizione manuale<\/strong> delle stesse configurazioni ha un’alta probabilit\u00e0 di incappare in errori<\/strong>. <\/p>\n\n\n\n

Per queste ragioni, la nuova sfida \u00e8 trovare un modo per schierare molteplici database con un dato set di configurazioni, in modo automatico<\/strong>. In tutto questo, l\u2019Infrastructure as Code (IaC)<\/strong> ci viene in aiuto: strumenti come Terraform o Pulumi, ad esempio, possono essere usati per automatizzare la creazione di svariate risorse in ambienti diversi, sia in locale, sia sui Cloud providers supportati, il tutto descrivendo l\u2019infrastruttura desiderata tramite codice. Solitamente, i cloud providers offrono le loro soluzioni proprietarie per lo IaC. La soluzione di AWS \u00e8 AWS CloudFormation<\/strong>.<\/p>\n\n\n\n

Utilizzando i servizi cloud combinati con templates IaC, possiamo costruire una soluzione riutilizzabile che, con poche azioni manuali, pu\u00f2 creare svariati databases, completamente gestiti, in modo automatico. <\/p>\n\n\n\n

Rimane comunque la necessit\u00e0 dell\u2019azione manuale per l\u2019installazione di plugin <\/strong>specifici.<\/p>\n\n\n\n

A questo problema non c\u2019\u00e8 una soluzione standard a seconda del motore: scegliendo, ad esempio, tra PostgreSQL o MySQL, ci si trova di fronte a differenti versioni, ognuna delle quali supporta un insieme differente di plugins, ognuno, a sua volta, con diverse versioni. <\/p>\n\n\n\n

In pratica, serve trovare un set di configurazioni compatibili<\/strong> che lavori insieme. Una volta trovato questo set, potremo sfruttare lo IaC per automatizzare completamente la creazione dei databases.<\/p>\n\n\n\n

In questo articolo, proponiamo una possibile soluzione a questo problema, automatizzando la creazione di database con conseguente installazione di plug-ins a bordo di essi. Per gli esempi contenuti in questo articolo useremo AWS<\/strong> come cloud provider e RDS<\/strong>, con PostgreSQL<\/strong>, come servizio database.<\/p>\n\n\n\n

Prima di sporcarci le mani con il codice CloudFormation, ci sono alcune cose che dobbiamo tenere in considerazione. Diamo per assunto che tutte le configurazioni relative all\u2019ambiente in cui il database verr\u00e0 messo siano gi\u00e0 state fatte, non essendo centrali in questo articolo. In particolare, diamo per scontato che VPC, sottoreti, tabelle di routing e security groups siano gi\u00e0 pronti. Verranno presi come parametri in input nel nostro codice per l\u2019infrastruttura.<\/strong><\/p>\n\n\n\n

Partendo dalla creazione del database, ci sono tre risorse principali che sono necessarie alla creazione dell\u2019istanza: un subnet group<\/strong> per gestire il networking del database, un parameter group<\/strong> per definire alcuni parametri specifici della famiglia di database scelta e un option group<\/strong> per configurare alcune caratteristiche specifiche del dato engine del database.<\/p>\n\n\n\n

DBSubnetGroup:\n   Type: 'AWS::RDS::DBSubnetGroup'\n   Properties:\n     DBSubnetGroupDescription: !Sub \"${DBName}-db-subnet-group\"\n     SubnetIds: [!Ref PrivateSubnetA, !Ref PrivateSubnetB, !Ref PrivateSubnetC]\n     Tags:\n       - Key: Name\n         Value: !Sub \"${DBName}-db-subnet-group\"\n<\/code><\/pre>\n\n\n\n

Come possiamo vedere dal codice, utilizzando il subnet group, abbiamo messo il nostro database nelle sottoreti private e abbiamo configurato l\u2019uso di Postgres13 con l\u2019option group. Nel mentre, tramite il parameter group, abbiamo configurato un singolo parametro, ai fini della spiegazione, impostando il massimo numero di connessioni al database, limitandolo a 30.<\/p>\n\n\n\n

DBOptionGroup:\n   Type: \"AWS::RDS::OptionGroup\"\n   Properties:\n     EngineName: \"postgres\"\n     MajorEngineVersion: 13\n     # OptionConfigurations: [] # no options needed for PostgreSQL\n     OptionGroupDescription: !Sub \"${DBName}-db-option-group\"\n     Tags:\n       - Key: Name\n         Value: !Sub \"${DBName}-db-option-group\"\n<\/code><\/pre>\n\n\n\n

Ora \u00e8 il momento dell\u2019istanza per il database. Dato che questo \u00e8 un semplice esempio, possiamo rimanere su configurazioni di base, utilizzando un\u2019istanza db.m5.large con 20 GBs per lo storage (gp2). Poi possiamo configurare altri parametri addizionali quali: nome dell\u2019istanza, nome dell\u2019utente master e la relativa password, i parametri relativi alla cifratura dello storage, come la chiave KMS e le finestre di backup e manutenzione preferite.<\/p>\n\n\n\n

Insieme all’istanza del DB, ci sono alcune risorse aggiuntive che possiamo utilizzare per migliorare la sicurezza del nostro database. Abbiamo definito una chiave KMS, insieme al relativo alias, per criptare lo storage e un segreto dentro al Secrets Manager per contenere le credenziali di admin per l\u2019accesso al DB. Inoltre, come ulteriore layer di sicurezza, potremmo anche impostare un meccanismo che fa ruotare la password molto frequentemente, ad esempio ogni singolo giorno. Anche queste risorse possono essere create tramite CloudFormation. Non entreremo, per\u00f2, nei dettagli di ci\u00f2 dato che non \u00e8 l\u2019oggetto principale di questo articolo.<\/p>\n\n\n\n

Giusto un\u2019ultima aggiunta riguardo l\u2019accesso al DB: in AWS c\u2019\u00e8 anche la possibilit\u00e0, per i database che lo supportano, di utilizzare le credenziali IAM per accedere alle istanze di database. Ci\u00f2 potrebbe risultare particolarmente utile per incrementare la sicurezza dell\u2019infrastruttura dato che verrebbe ridotto drasticamente il numero di credenziali di accesso.<\/p>\n\n\n\n

DBInstance:\n   Type: 'AWS::RDS::DBInstance'\n   Properties:\n     DBInstanceIdentifier: !Ref DBName\n     Engine: \"postgres\"\n     DBInstanceClass: \"db.m5.large\"\n     StorageType: \"gp2\"\n     AllocatedStorage: 20\n     DBParameterGroupName: !Ref DBParameterGroup\n     OptionGroupName: !Ref DBOptionGroup\n     DBSubnetGroupName: !Ref DBSubnetGroup\n     VPCSecurityGroups: [!Ref DBSecurityGroup]\n     MasterUsername: !Ref DBMasterUser\n     MasterUserPassword: !Ref DBMasterUserPassword\n     DBName: !Ref DBName\n     Port: 5432\n     AutoMinorVersionUpgrade: true\n     CopyTagsToSnapshot: true\n     Tags:\n       - Key: Name\n         Value: !Sub \"${DBName}-db\"\n<\/code><\/pre>\n\n\n\n

Ora che abbiamo lanciato il nostro template  CloudFormation e il nostro database \u00e8 stato creato, possiamo provare a connetterci e fare alcune queries. Per esempio, possiamo controllare il set di plug-ins installati con<\/p>\n\n\n\n

SELECT * FROM pg_extension;<\/pre>\n\n\n\n

<\/p>\n\n\n\n

\"\"<\/figure>\n\n\n\n

<\/p>\n\n\n\n

Un\u2019altra cosa utile \u00e8 controllare il set di estensioni permesse che pu\u00f2 essere installato anche senza i permessi di amministratore. Possiamo controllarlo in due modi, il pi\u00f9 semplice, dato che siamo gi\u00e0 connessi al database, \u00e8 la seguente query:<\/p>\n\n\n\n

SHOW rds.extensions;<\/pre>\n\n\n\n

Altrimenti, se abbiamo la necessit\u00e0 di un plugin specifico, probabilmente \u00e8 meglio verificare prima se \u00e8 supportato o meno. Possiamo vedere la lista completa di plugin supportati a questo link<\/a>.<\/p>\n\n\n\n

<\/p>\n\n\n\n

\"\"<\/figure>\n\n\n\n

<\/p>\n\n\n\n

Come possiamo vedere, abbiamo la lista completa di plug-ins, insieme alla lista delle estensioni permesse che possiamo installare semplicemente con i normali permessi utente.<\/p>\n\n\n\n

Dallo screenshot notiamo che abbiamo installato solo un plug-in nel nostro database, ma potremmo volerne aggiungere altri, come PostGis e PGCrypto. Per fare ci\u00f2 potremmo lanciare semplicemente due queries:<\/p>\n\n\n\n

CREATE EXTENSION IF NOT EXISTS postgis VERSION '3.0.3' CASCADE;<\/pre>\n\n\n\n
CREATE EXTENSION IF NOT EXISTS pgcrypto VERSION '1.3' CASCADE;<\/pre>\n\n\n\n

Come spiegato nell’introduzione, per\u00f2, questo approccio non \u00e8 scalabile<\/strong>. Un amministratore di databases pu\u00f2 farlo per alcuni DB, ma al crescere del numero di plug-in da installare, il task richiederebbe troppo tempo e sforzo. In aggiunta, l\u2019uomo \u00e8 naturalmente pi\u00f9 propenso a commettere errori. Un approccio manuale \u00e8, quindi, sempre sconsigliato per questo tipo di operazioni, sempre molto delicate.<\/p>\n\n\n\n

Entriamo quindi nel vivo della nostra soluzione a questo problema: l’utilizzo delle Custom Resource di CloudFormation<\/strong>. Le Custom resources sono un modo per implementare logiche personalizzate di provisioning nel nostro codice IaC. Queste logiche vengono eseguite a ogni cambiamento dello stato di uno stack (creazione, aggiornamento, cancellazione). Nello specifico, queste risorse personalizzare eseguono i loro compiti tramite una funzione Lambda o un topic SNS. Per i nostri scopi, implementeremo la logica tramite una Lambda<\/strong>.<\/p>\n\n\n\n

La Custom resource richiede semplicemente un identificatore della funzione<\/strong> che dovr\u00e0 eseguire, ovvero il lambda ARN, e alcuni parametri aggiuntivi che verranno passati alla funzione per definire o modificare il suo comportamento. Si pu\u00f2 decidere di avere pi\u00f9 lambda a seconda del tipo di database che si sta creando, ad esempio, che sia un MySQL o un PostgreSQL, poich\u00e9 il codice SQL effettivo e il set di plug-ins che dobbiamo installare possono essere diversi.<\/p>\n\n\n\n

Detto questo, dobbiamo gi\u00e0 avere la lambda creata, insieme al suo codice, poich\u00e9 verr\u00e0 eseguita non appena il database verr\u00e0 creato. Anche la lambda potrebbe essere descritta nel nostro template IaC ma per semplicit\u00e0 la creeremo utilizzando la console AWS. Questo \u00e8 utile perch\u00e9 siamo in grado di testare e verificare il codice prima di utilizzarlo effettivamente nella custom resource<\/strong>.<\/p>\n\n\n\n

La lambda richiede alcune configurazioni: partendo dalle basi, la lambda stessa deve gestire un compito molto semplice quindi 512MB per la memoria saranno sufficienti. Implementeremo il codice utilizzando Python3.8 come linguaggio e aggiungeremo un lambda layer per utilizzare la dipendenza psycopg2 per gestire la connessione con il database.<\/p>\n\n\n\n

Ora ci sono ancora 3 parti fondamentali per finalizzare la lambda: permessi, rete e il codice vero e proprio. Partendo dal primo elemento della lista, dobbiamo solo creare il ruolo IAM per la lambda in grado di gestire il networking (in pratica, utilizzare le interfacce di rete) e leggere alcuni segreti all’interno del Secrets Manager.<\/p>\n\n\n\n

Per connettersi al database, la lambda deve essere eseguita nella stessa rete in cui \u00e8 il database<\/strong>, ovvero la VPC, e deve avere un modo per comunicare con esso. A tal fine, abbiamo bisogno di impostare alcuni parametri aggiuntivi<\/strong> nel nostro template CloudFormation. Dobbiamo posizionare la nostra custom resource in una sottorete pubblica, o meglio, con un NAT in modo tale che, non appena si avvier\u00e0, avr\u00e0 un IP collegato che potr\u00e0 essere utilizzato per comunicare con le altre risorse nella VPC. L’ultima cosa che dobbiamo configurare per quanto riguarda la rete sono i security groups: dobbiamo creare un security group per la lambda e poi consentire la comunicazione con il database utilizzando una regola in ingresso all’interno del nostro template CloudFormation per automatizzare questo processo per ogni database che verr\u00e0 essere creato. <\/p>\n\n\n\n

Finalmente, tutto ci\u00f2 che riguarda la rete \u00e8 impostato correttamente!<\/p>\n\n\n\n

Ora la lambda pu\u00f2 connettersi all’istanza del database. Prima di iniziare l’automazione della creazione del database insieme all’installazione dei plug-ins, iniziamo a scrivere il codice per il suo comportamento e verificare che tutto funzioni correttamente. Possiamo iniziare creando un metodo che elenchi le estensioni nel database, utilizzando la query di prima:<\/p>\n\n\n\n

def get_extensions(cursor):\n   extensions_query = \"SELECT * FROM pg_extension\"\n   cursor.execute(extensions_query)\n   return [row[1] for row in cursor.fetchall()]\n<\/code><\/pre>\n\n\n\n

Questo sar\u00e0 utile per verificare effettivamente se abbiamo installato correttamente i plugin. Come possiamo vedere, nell’output c’\u00e8 lo stesso plug-in che abbiamo visto in precedenza. Ora che siamo sicuri che la nostra custom resource \u00e8 in grado di interagire con il database, possiamo creare il metodo che installer\u00e0 effettivamente i plug-ins.<\/p>\n\n\n\n

def create_extension(cursor, extension, version):\n   extensions_query = 'CREATE EXTENSION IF NOT EXISTS \"%s\" VERSION \"%s\" CASCADE;'\n   cursor.execute(extensions_query, (AsIs(extension), AsIs(version),))\n<\/code><\/pre>\n\n\n\n

Possiamo passare le estensioni, insieme alle loro versioni, alla lambda come mappa attraverso l’uso di un parametro nella definizione della custom resource nello IaC che vedremo in seguito.<\/p>\n\n\n\n

L’ultima cosa che dobbiamo fare per finalizzare il nostro codice della lambda \u00e8 inviare una risposta a un endpoint CloudFormation per informarlo della corretta esecuzione della custom resource. Ci\u00f2 \u00e8 necessario perch\u00e9 CloudFormation deve sapere quando termina la custom resource e, quindi, quando pu\u00f2 continuare a creare le altre risorse nello IaC. Possiamo vedere l’implementazione in questa parte di codice:<\/p>\n\n\n\n

def send_response(event: dict, context, response_status: str, response_data: dict, no_echo=False, reason=None):\n   logical_id = event.get('LogicalResourceId')\n   digest = hashlib.sha256(logical_id.encode('utf-8')).hexdigest()\n   physical_resource_id = logical_id + digest[:8]\n\n   response_body = {\n       'Status': response_status,\n       'Reason': reason or f\"See the details in CloudWatch Log Stream: {context.log_stream_name}\",\n       'PhysicalResourceId': physical_resource_id or context.log_stream_name,\n       'StackId': event['StackId'],\n       'RequestId': event['RequestId'],\n       'LogicalResourceId': logical_id,\n       'NoEcho': no_echo,\n       'Data': response_data\n   }\n   try:\n       response = http.request('PUT', event['ResponseURL'], body=json.dumps(response_body))\n   except Exception as e:\n       logger.error(f\"send_response failed executing http.request(..): {e}\")\n<\/code><\/pre>\n\n\n\n

Solo un commento su questa implementazione: per quanto riguarda i parametri di input per la funzione, abbiamo l’event e il context della funzione lambda, abbiamo poi lo stato della risposta che pu\u00f2 essere “SUCCESS” o “FAILED”. Poi possiamo avere i response data se dobbiamo inviare qualcosa a CloudFormation. Infine, abbiamo il parametro no echo<\/em> in caso di informazioni sensibili e il parametro reason<\/em> per commentare l’esecuzione della custom resource.<\/p>\n\n\n\n

Ora possiamo finalizzare il nostro IaC con l’implementazione della custom resource. Qui il frammento di codice:<\/p>\n\n\n\n

InstallPlugins:\n   Type: Custom::ExecuteSQL\n   Properties:\n     ServiceToken: 'arn:aws:lambda:eu-west-2:364050767034:function:custom-resource-demo'\n     DBSecret: !Ref DBSecret\n     PluginsMap:\n       \"PostGIS\": '3.0.3'\n       \"pgcrypto\": '1.3'\n<\/code><\/pre>\n\n\n\n

Si noti l’utilizzo del segreto DBSecret come parametro di input per la custom resource che contiene, in modo sicuro, tutte le informazioni necessarie per la connessione al database.<\/p>\n\n\n\n

Ora che tutto \u00e8 impostato correttamente, possiamo eseguire un test e creare il nostro database insieme alla custom resource che installer\u00e0 i vari plug-ins. Iniziamo con un singolo database chiamato “demo1”.<\/p>\n\n\n\n

Non appena CloudFormation termina la creazione dello stack, abbiamo due modi per verificare l’installazione dei plug-ins. Possiamo provare a connetterci all’istanza ed eseguire la nostra query:<\/p>\n\n\n\n

SELECT * FROM pg_extension;<\/pre>\n\n\n\n

oppure, se li abbiamo stampati nel codice della custom resource, possiamo semplicemente controllare i suoi log.<\/p>\n\n\n\n

BEFORE:  ['plpgsql']\nInstalling plugin PostGIS version 3.0.3 ...\nInstalling plugin pgcrypto version 1.3 ...\nAFTER:  ['plpgsql', 'postgis', 'pgcrypto']\n<\/code><\/pre>\n\n\n\n

Una volta verificato che tutto funzioni correttamente, possiamo iniziare a testare le altre caratteristiche di questa soluzione.<\/p>\n\n\n\n

Innanzitutto, possiamo testare la sua capacit\u00e0 di scalare. Usiamo lo stesso IaC che abbiamo creato per creare due altri database: “demo2” e “demo3”.<\/p>\n\n\n\n

Come possiamo vedere dai logs della lambda, tutto funziona correttamente. Bene!<\/p>\n\n\n\n

Ora possiamo testare un’altra caratteristica: la possibilit\u00e0 di recuperare il database. Possiamo creare uno snapshot utilizzando la console AWS e, non appena lo snapshot viene creato, possiamo provare a creare un database partendo da esso e verificare se abbiamo ancora i plug-ins. (Spoiler: s\u00ec, li abbiamo!)<\/p>\n\n\n\n

Dopo che il database \u00e8 stato ripristinato da un errore fittizio, abbiamo ancora i nostri dati e i nostri plug-ins!<\/p>\n\n\n\n

Riassumendo<\/h2>\n\n\n\n

In questo articolo abbiamo visto come creare pi\u00f9 database e installare su di essi alcune estensioni\/plug-in, automatizzando il tutto tramite IaC, usando CloudFormation. Nel mentre, abbiamo scoperto la potenza e la facilit\u00e0 di utilizzo dei servizi Cloud per creare questo tipo di componenti infrastrutturali e, conseguentemente, per ottenere molte belle funzionalit\u00e0 quali alta disponibilit\u00e0, scalabilit\u00e0, backup automatici, fault-tolerance e sicurezza con uno sforzo minimo. <\/p>\n\n\n\n

Per installare plug-ins\/estensioni nel database, abbiamo esplorato il mondo delle custom resources per l’automazione delle azioni manuali tramite IaC. La speranza \u00e8 di aver aperto uno spiraglio di luce su questo argomento che di solito viene visto come oscuro e difficile. Nel frattempo, abbiamo spiegato come scrivere una lambda e come utilizzarla all’interno della rete per accedere ai vari databases.<\/p>\n\n\n\n

In conclusione, abbiamo ottenuto la creazione automatizzata di una o pi\u00f9 istanze di database nel cloud, con plug-ins pre-installati che possono essere piuttosto utili ai DBA.<\/p>\n\n\n\n

Nella speranza che questo articolo sia stato abbastanza chiaro e uno spunto di ragionamento o discussione per qualcuno, se avete commenti o suggerimenti, non esitare a scriverci!<\/p>\n","protected":false},"excerpt":{"rendered":"

La gestione e l’amministrazione dei database sono sempre stati compiti molto delicati sia per server on premise, sia sul cloud. […]<\/p>\n","protected":false},"author":16,"featured_media":3748,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[241],"tags":[537,356,263,539,541,253],"yoast_head":"\nInstallare plug-in custom su RDS con le Custom Resources di CloudFormation - Proud2beCloud Blog<\/title>\n<meta name=\"description\" content=\"Abbiamo esplorato il mondo delle CloudFormation custom resources per automatizzare l'installazione di plug-ins ed estensioni nel database.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blog.besharp.it\/it\/installare-plug-in-custom-su-rds-con-le-custom-resources-di-cloudformation\/\" \/>\n<meta property=\"og:locale\" content=\"it_IT\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Installare plug-in custom su RDS con le Custom Resources di CloudFormation\" \/>\n<meta property=\"og:description\" content=\"Automatizzare la creazione dei database e l'installazione di estensioni e plugin con CloudFormation Custom resources.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blog.besharp.it\/it\/installare-plug-in-custom-su-rds-con-le-custom-resources-di-cloudformation\/\" \/>\n<meta property=\"og:site_name\" content=\"Proud2beCloud Blog\" \/>\n<meta property=\"article:published_time\" content=\"2021-10-29T11:59:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-10-28T10:47:02+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/blog.besharp.it\/wp-content\/uploads\/2021\/10\/Copertina-blog-29-10-21-social-ita.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"628\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Matteo Goretti\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:title\" content=\"Installare plug-in custom su RDS con le Custom Resources di CloudFormation\" \/>\n<meta name=\"twitter:description\" content=\"Automatizzare la creazione dei database e l'installazione di estensioni e plugin con CloudFormation Custom resources.\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/blog.besharp.it\/wp-content\/uploads\/2021\/10\/Copertina-blog-29-10-21-social-ita.png\" \/>\n<meta name=\"twitter:label1\" content=\"Scritto da\" \/>\n\t<meta name=\"twitter:data1\" content=\"Matteo Goretti\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tempo di lettura stimato\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minuti\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blog.besharp.it\/it\/installare-plug-in-custom-su-rds-con-le-custom-resources-di-cloudformation\/\",\"url\":\"https:\/\/blog.besharp.it\/it\/installare-plug-in-custom-su-rds-con-le-custom-resources-di-cloudformation\/\",\"name\":\"Installare plug-in custom su RDS con le Custom Resources di CloudFormation - Proud2beCloud Blog\",\"isPartOf\":{\"@id\":\"https:\/\/blog.besharp.it\/it\/#website\"},\"datePublished\":\"2021-10-29T11:59:00+00:00\",\"dateModified\":\"2021-10-28T10:47:02+00:00\",\"author\":{\"@id\":\"https:\/\/blog.besharp.it\/it\/#\/schema\/person\/45f6a2847f73cbac9f3a563f80e22ae5\"},\"description\":\"Abbiamo esplorato il mondo delle CloudFormation custom resources per automatizzare l'installazione di plug-ins ed estensioni nel database.\",\"breadcrumb\":{\"@id\":\"https:\/\/blog.besharp.it\/it\/installare-plug-in-custom-su-rds-con-le-custom-resources-di-cloudformation\/#breadcrumb\"},\"inLanguage\":\"it-IT\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blog.besharp.it\/it\/installare-plug-in-custom-su-rds-con-le-custom-resources-di-cloudformation\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blog.besharp.it\/it\/installare-plug-in-custom-su-rds-con-le-custom-resources-di-cloudformation\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/blog.besharp.it\/it\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Installare plug-in custom su RDS con le Custom Resources di CloudFormation\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blog.besharp.it\/it\/#website\",\"url\":\"https:\/\/blog.besharp.it\/it\/\",\"name\":\"Proud2beCloud Blog\",\"description\":\"il blog di beSharp\",\"alternateName\":\"Proud2beCloud Blog\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blog.besharp.it\/it\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"it-IT\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/blog.besharp.it\/it\/#\/schema\/person\/45f6a2847f73cbac9f3a563f80e22ae5\",\"name\":\"Matteo Goretti\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\/\/blog.besharp.it\/it\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/77ecb0a249254473a8e5ea8f8fd0de24?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/77ecb0a249254473a8e5ea8f8fd0de24?s=96&d=mm&r=g\",\"caption\":\"Matteo Goretti\"},\"description\":\"DevOps Engineer @ beSharp. Passionate about Artificial Intelligence, in particular, Machine Learning and Deep Learning, and interested in Cloud Computing. I love trekking and nature in general. I relax with my guitar, play video games, and watch TV series.\",\"url\":\"https:\/\/blog.besharp.it\/it\/author\/matteo-goretti\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Installare plug-in custom su RDS con le Custom Resources di CloudFormation - Proud2beCloud Blog","description":"Abbiamo esplorato il mondo delle CloudFormation custom resources per automatizzare l'installazione di plug-ins ed estensioni nel database.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blog.besharp.it\/it\/installare-plug-in-custom-su-rds-con-le-custom-resources-di-cloudformation\/","og_locale":"it_IT","og_type":"article","og_title":"Installare plug-in custom su RDS con le Custom Resources di CloudFormation","og_description":"Automatizzare la creazione dei database e l'installazione di estensioni e plugin con CloudFormation Custom resources.","og_url":"https:\/\/blog.besharp.it\/it\/installare-plug-in-custom-su-rds-con-le-custom-resources-di-cloudformation\/","og_site_name":"Proud2beCloud Blog","article_published_time":"2021-10-29T11:59:00+00:00","article_modified_time":"2021-10-28T10:47:02+00:00","og_image":[{"width":1200,"height":628,"url":"https:\/\/blog.besharp.it\/wp-content\/uploads\/2021\/10\/Copertina-blog-29-10-21-social-ita.png","type":"image\/png"}],"author":"Matteo Goretti","twitter_card":"summary_large_image","twitter_title":"Installare plug-in custom su RDS con le Custom Resources di CloudFormation","twitter_description":"Automatizzare la creazione dei database e l'installazione di estensioni e plugin con CloudFormation Custom resources.","twitter_image":"https:\/\/blog.besharp.it\/wp-content\/uploads\/2021\/10\/Copertina-blog-29-10-21-social-ita.png","twitter_misc":{"Scritto da":"Matteo Goretti","Tempo di lettura stimato":"12 minuti"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/blog.besharp.it\/it\/installare-plug-in-custom-su-rds-con-le-custom-resources-di-cloudformation\/","url":"https:\/\/blog.besharp.it\/it\/installare-plug-in-custom-su-rds-con-le-custom-resources-di-cloudformation\/","name":"Installare plug-in custom su RDS con le Custom Resources di CloudFormation - Proud2beCloud Blog","isPartOf":{"@id":"https:\/\/blog.besharp.it\/it\/#website"},"datePublished":"2021-10-29T11:59:00+00:00","dateModified":"2021-10-28T10:47:02+00:00","author":{"@id":"https:\/\/blog.besharp.it\/it\/#\/schema\/person\/45f6a2847f73cbac9f3a563f80e22ae5"},"description":"Abbiamo esplorato il mondo delle CloudFormation custom resources per automatizzare l'installazione di plug-ins ed estensioni nel database.","breadcrumb":{"@id":"https:\/\/blog.besharp.it\/it\/installare-plug-in-custom-su-rds-con-le-custom-resources-di-cloudformation\/#breadcrumb"},"inLanguage":"it-IT","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blog.besharp.it\/it\/installare-plug-in-custom-su-rds-con-le-custom-resources-di-cloudformation\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/blog.besharp.it\/it\/installare-plug-in-custom-su-rds-con-le-custom-resources-di-cloudformation\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blog.besharp.it\/it\/"},{"@type":"ListItem","position":2,"name":"Installare plug-in custom su RDS con le Custom Resources di CloudFormation"}]},{"@type":"WebSite","@id":"https:\/\/blog.besharp.it\/it\/#website","url":"https:\/\/blog.besharp.it\/it\/","name":"Proud2beCloud Blog","description":"il blog di beSharp","alternateName":"Proud2beCloud Blog","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blog.besharp.it\/it\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"it-IT"},{"@type":"Person","@id":"https:\/\/blog.besharp.it\/it\/#\/schema\/person\/45f6a2847f73cbac9f3a563f80e22ae5","name":"Matteo Goretti","image":{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/blog.besharp.it\/it\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/77ecb0a249254473a8e5ea8f8fd0de24?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/77ecb0a249254473a8e5ea8f8fd0de24?s=96&d=mm&r=g","caption":"Matteo Goretti"},"description":"DevOps Engineer @ beSharp. Passionate about Artificial Intelligence, in particular, Machine Learning and Deep Learning, and interested in Cloud Computing. I love trekking and nature in general. I relax with my guitar, play video games, and watch TV series.","url":"https:\/\/blog.besharp.it\/it\/author\/matteo-goretti\/"}]}},"_links":{"self":[{"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/posts\/3741"}],"collection":[{"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/users\/16"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/comments?post=3741"}],"version-history":[{"count":0,"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/posts\/3741\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/media\/3748"}],"wp:attachment":[{"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/media?parent=3741"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/categories?post=3741"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/tags?post=3741"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}