{"id":35976,"date":"2024-12-01T21:10:49","date_gmt":"2024-12-01T20:10:49","guid":{"rendered":"https:\/\/www.dbi-services.com\/blog\/?p=35976"},"modified":"2025-03-04T11:03:39","modified_gmt":"2025-03-04T10:03:39","slug":"offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens","status":"publish","type":"post","link":"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/","title":{"rendered":"Offloading PostgreSQL Backups to Azure Blob Storage Using PGBackRest, Managed Identity, and SAS Tokens"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\" id=\"h-introduction\">Introduction<\/h2>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"533\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/12\/image.png\" alt=\"\" class=\"wp-image-35998\" style=\"width:336px;height:auto\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/12\/image.png 1024w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/12\/image-300x156.png 300w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/12\/image-768x400.png 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>One of the nice things with cloud providers is the low costs of their storage. Whenever you want to optimize your long-term backups and push them on Azure, you might face a wall of questions on how to do it with PostgreSQL securely and whether it would align with disaster recovery plans.<br>The following setup is an example of how you could manage having local PITR backups and offload your long-term full backups on Azure Blob Storage securely to reduce storage costs and extend your backup infrastructure to the cloud.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-architecture-overview\">Architecture Overview<\/h2>\n\n\n\n<p>The architecture consists of the following components:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>PostgreSQL Standalone Server (PG1):<\/strong> An Azure VM hosting PostgreSQL 17.2<\/li>\n\n\n\n<li><strong>Local PGBackRest Repository:<\/strong> Stores backups locally on the PG1 server for quick access.<\/li>\n\n\n\n<li><strong>Azure Blob Storage Account:<\/strong> Acts as a secondary, offsite repository for backups.<\/li>\n\n\n\n<li><strong>Managed Identity:<\/strong> Enables the VM to authenticate with Azure services without storing credentials on the VM.<\/li>\n\n\n\n<li><strong>SAS Token:<\/strong> Provides secure, time-limited access to the Blob Storage container.<\/li>\n\n\n\n<li><strong>Azure Key Vault:<\/strong> Securely stores sensitive information like the SAS token (optional but recommended).<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\n+--------------------+       +------------------------+\n|  Azure VM (PG1)    |       |  Azure Blob Storage    |\n|  PostgreSQL 17     |&lt;------&gt;  Repo 2 (Remote Backup)|\n|                    |       |   (Secondary Storage)  |\n|  +--------------+  |       +------------------------+\n|  | PGBackRest   |  |\n|  |  Repo 1      |  |                     ^\n|  | (Local       |  |                     |\n|  |  Storage)    |  |                     |\n|  +--------------+  |                     |\n|                    |                     |\n|                    |                     |\n|  +---------------+ | Managed Identity    |\n|  | Azure CLI     |&lt;----------------------+\n|  +---------------+ |\n|  | SAS Token     | |\n|  +---------------+ |\n+--------------------+\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"h-prerequisites\">Prerequisites<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Azure Subscription:<\/strong> Active subscription to deploy resources.<\/li>\n\n\n\n<li><strong>Azure VM (PG1):<\/strong> Running compatible Linux distribution with PostgreSQL installed.<\/li>\n\n\n\n<li><strong>PGBackRest Installed:<\/strong> On the server.<\/li>\n\n\n\n<li><strong>Azure CLI Installed:<\/strong> Version 2.0 or higher on the server.<\/li>\n\n\n\n<li><strong>Managed Identity Enabled:<\/strong> On the Azure VM.<\/li>\n\n\n\n<li><strong>Azure Blob Storage Account and Container:<\/strong> Created for storing backups.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-step-1-assign-a-managed-identity-to-the-pg1-vm\">Step 1: Assign a Managed Identity to the PG1 VM<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Navigate to Your VM in Azure Portal:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Go to <strong>Azure Portal<\/strong> &gt; <strong>Virtual Machines<\/strong> &gt; <strong>Your VM (PG1)<\/strong>.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Enable System-Assigned Managed Identity:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Click on <strong>Identity<\/strong> in the left-hand menu.<\/li>\n\n\n\n<li>Under the <strong>System assigned<\/strong> tab, set the status to <strong>On<\/strong>.<\/li>\n\n\n\n<li>Click <strong>Save<\/strong>.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-step-2-set-up-azure-blob-storage\">Step 2: Set Up Azure Blob Storage<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Create a Storage Account:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Go to <strong>Azure Portal<\/strong> &gt; <strong>Storage Accounts<\/strong> &gt; <strong>Create<\/strong>.<\/li>\n\n\n\n<li>Provide a unique <strong>Storage Account Name<\/strong><\/li>\n\n\n\n<li>Choose the appropriate <strong>Subscription<\/strong>, <strong>Resource Group<\/strong>, and <strong>Location<\/strong>.<\/li>\n\n\n\n<li>Select <strong>Standard<\/strong> performance and <strong>BlobStorage<\/strong> account kind.<\/li>\n\n\n\n<li>Click <strong>Review + create<\/strong> and then <strong>Create<\/strong>.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Create a Blob Container:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Navigate to your storage account.<\/li>\n\n\n\n<li>Under <strong>Data storage<\/strong>, select <strong>Containers<\/strong>.<\/li>\n\n\n\n<li>Click <strong>+ Container<\/strong>.<\/li>\n\n\n\n<li>Name the container<\/li>\n\n\n\n<li>Set the <strong>Public access level<\/strong> to <strong>Private<\/strong>.<\/li>\n\n\n\n<li>Click <strong>Create<\/strong>.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-step-3-grant-permissions-to-the-managed-identity\">Step 3: Grant Permissions to the Managed Identity<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Assign Role to Managed Identity:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Go to your <strong>Storage Account<\/strong> &gt; <strong>Access Control (IAM)<\/strong>.<\/li>\n\n\n\n<li>Click <strong>+ Add<\/strong> &gt; <strong>Add role assignment<\/strong>.<\/li>\n\n\n\n<li>In the <strong>Role<\/strong> dropdown, select <strong>Storage Blob Data Contributor<\/strong>.<\/li>\n\n\n\n<li>In the <strong>Assign access to<\/strong> dropdown, select <strong>Managed identity<\/strong>.<\/li>\n\n\n\n<li>Click <strong>+ Select members<\/strong>, search for your VM&#8217;s name, and select it.<\/li>\n\n\n\n<li>Click <strong>Select<\/strong> and then <strong>Review + assign<\/strong>.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-step-4-adapt-the-backup-script\">Step 4: Adapt the Backup Script<\/h2>\n\n\n\n<p>According your infrastructure, change the required parameters.<br>This works well for standalone servers, it can also serve as a base for a Patroni setup, in that case, you would need to modify the local pgBackRest configuration and push it to the other nodes as well with a &#8220;scp&#8221; command.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-script\">Script<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\n#!\/bin\/bash\n\n## Renew Azure Blob Storage SAS Token for PGBackRest\n\n# Authenticate Azure CLI\naz login --identity\n\n# Variables\nSTORAGE_ACCOUNT_NAME=&quot;storage-account&quot;\nCONTAINER_NAME=&quot;container-name&quot;\nPG_BACKREST_CONF=&quot;\/etc\/pgbackrest.conf&quot;\nEXPIRY_DATE=$(date -u -d &quot;+6 hours&quot; +&quot;%Y-%m-%dT%H:%M:%SZ&quot;)\n\n# Retrieve the Storage Account Key\nACCOUNT_KEY=$(az storage account keys list \\\n    --resource-group &quot;cloud-shell-storage-westeurope&quot; \\\n    --account-name &quot;$STORAGE_ACCOUNT_NAME&quot; \\\n    --query &quot;&#x5B;0].value&quot; \\\n    --output tsv)\n\nif &#x5B; -z &quot;$ACCOUNT_KEY&quot; ]; then\n    echo &quot;Failed to retrieve storage account key.&quot;\n    exit 1\nfi\n\n# Generate SAS Token\nSAS_TOKEN=$(az storage container generate-sas \\\n    --account-name &quot;$STORAGE_ACCOUNT_NAME&quot; \\\n    --name &quot;$CONTAINER_NAME&quot; \\\n    --permissions acdlrw \\\n    --expiry &quot;$EXPIRY_DATE&quot; \\\n    --https-only \\\n    --account-key &quot;$ACCOUNT_KEY&quot; \\\n    --output tsv)\n\nif &#x5B; -z &quot;$SAS_TOKEN&quot; ]; then\n    echo &quot;Failed to generate SAS token.&quot;\n    exit 1\nfi\n\necho &quot;SAS Token generated successfully. It will expire on $EXPIRY_DATE.&quot;\n\n# Update PGBackRest configuration with the SAS token\necho &quot;Updating PGBackRest configuration on backup server...&quot;\n\nsudo awk -v sas_token=&quot;$SAS_TOKEN&quot; &#039;\/^repo2-azure-key=\/ {$0=&quot;repo2-azure-key=&quot; sas_token} {print}&#039; &quot;$PG_BACKREST_CONF&quot; &gt; \/tmp\/pgbackrest.conf.tmp &amp;&amp; sudo mv \/tmp\/pgbackrest.conf.tmp &quot;$PG_BACKREST_CONF&quot;\n\nif &#x5B; $? -eq 0 ]; then\n    echo &quot;PGBackRest configuration updated successfully.&quot;\nelse\n    echo &quot;Failed to update PGBackRest configuration.&quot;\n    exit 1\nfi\n\necho &quot;SAS token update completed.&quot;\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"h-step-5-configure-pgbackrest-for-azure-blob-storage\">Step 5: Configure PGBackRest for Azure Blob Storage<\/h2>\n\n\n\n<p>Update your <code>\/etc\/pgbackrest.conf<\/code> file to include the Azure Blob Storage as a secondary repository.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\n&#x5B;global]\nrepo1-path=\/u99\/pgbackrest\nrepo1-retention-full=2\n\nrepo2-type=azure\nrepo2-path=\/\nrepo2-azure-container=backups\nrepo2-azure-account=pgbackreststorage\nrepo2-azure-key=se=2024-12-02T05%3A36%3A34Z&amp;sp=racwdl&amp;spr=https&amp;sv=2022-11-02&amp;sr=c&amp;sig=d16aYx67bpUT\/MVNerRQG9cnIQYJ46%2Bggt3jeEC8fnQ%3D\nrepo2-azure-key-type=sas\nrepo2-retention-full=2\n\n&#x5B;pg17]\npg1-path=\/u02\/pgdata\/17\/PG17 \npg1-port=5435 \ndb-socket-path=\/tmp\n<\/pre><\/div>\n\n\n<p><\/p>\n\n\n\n<p><strong>Note:<\/strong> The <code>&lt;Your_SAS_Token&gt;<\/code> value will be dynamically updated by your script.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-step-6-test-the-backup-process\">Step 6: Test the Backup Process<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Create your stanza and run a Manual Backup:<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>postgres@PG1:\/home\/postgres\/renewSAS\/ &#091;PG17] pgbackrest --config=\/etc\/pgbackrest.conf --stanza=pg17 --log-level-console=info stanza-create\n2024-12-01 17:36:56.834 P00   INFO: stanza-create command begin 2.54.0: --config=\/etc\/pgbackrest.conf --exec-id=10839-70ab76ac --log-level-console=info --pg1-path=\/u02\/pgdata\/17\/PG17 --pg1-port=5435 --pg1-socket-path=\/tmp --repo2-azure-account=&lt;redacted&gt; --repo2-azure-container=backups --repo2-azure-key=&lt;redacted&gt; --repo2-azure-key-type=sas --repo1-path=\/u99\/pgbackrest --repo2-path=\/ --repo2-type=azure --stanza=pg17\n2024-12-01 17:36:56.844 P00   INFO: stanza-create for stanza 'pg17' on repo1\n2024-12-01 17:36:56.844 P00   INFO: stanza 'pg17' already exists on repo1 and is valid\n2024-12-01 17:36:56.844 P00   INFO: stanza-create for stanza 'pg17' on repo2\n2024-12-01 17:36:57.473 P00   INFO: stanza-create command end: completed successfully (642ms)\n\npostgres@PG1:\/home\/postgres\/renewSAS\/ &#091;PG17] pgbackrest --config=\/etc\/pgbackrest.conf --stanza=pg17 --log-level-console=info --repo=2 --archive-copy backup\n2024-12-01 17:37:22.303 P00   INFO: backup command begin 2.54.0: --archive-copy --config=\/etc\/pgbackrest.conf --exec-id=10844-31614f9c --log-level-console=info --pg1-path=\/u02\/pgdata\/17\/PG17 --pg1-port=5435 --pg1-socket-path=\/tmp --repo=2 --repo2-azure-account=&lt;redacted&gt; --repo2-azure-container=backups --repo2-azure-key=&lt;redacted&gt; --repo2-azure-key-type=sas --repo1-path=\/u99\/pgbackrest --repo2-path=\/ --repo1-retention-full=2 --repo2-retention-full=2 --repo2-type=azure --stanza=pg17\n2024-12-01 17:37:22.550 P00   WARN: no prior backup exists, incr backup has been changed to full\n2024-12-01 17:37:22.550 P00   INFO: execute non-exclusive backup start: backup begins after the next regular checkpoint completes\n2024-12-01 17:37:22.793 P00   INFO: backup start archive = 00000001000000010000008F, lsn = 1\/8F000028\n2024-12-01 17:37:22.793 P00   INFO: check archive for prior segment 00000001000000010000008E\n2024-12-01 17:39:10.512 P00   INFO: execute non-exclusive backup stop and wait for all WAL segments to archive\n2024-12-01 17:39:10.685 P00   INFO: backup stop archive = 00000001000000010000008F, lsn = 1\/8F000158\n2024-12-01 17:39:10.727 P00   INFO: check archive for segment(s) 00000001000000010000008F:00000001000000010000008F\n2024-12-01 17:39:11.750 P00   INFO: new backup label = 20241201-173722F\n2024-12-01 17:39:12.556 P00   INFO: full backup size = 1.5GB, file total = 1592\n2024-12-01 17:39:12.556 P00   INFO: backup command end: completed successfully (110257ms)\n2024-12-01 17:39:12.556 P00   INFO: expire command begin 2.54.0: --config=\/etc\/pgbackrest.conf --exec-id=10844-31614f9c --log-level-console=info --repo=2 --repo2-azure-account=&lt;redacted&gt; --repo2-azure-container=backups --repo2-azure-key=&lt;redacted&gt; --repo2-azure-key-type=sas --repo1-path=\/u99\/pgbackrest --repo2-path=\/ --repo1-retention-full=2 --repo2-retention-full=2 --repo2-type=azure --stanza=pg17\n2024-12-01 17:39:12.708 P00   INFO: expire command end: completed successfully (152ms)\n\npostgres@PG1:\/home\/postgres\/renewSAS\/ &#091;PG17] pgbackrest --config=\/etc\/pgbackrest.conf --stanza=pg17 --log-level-console=info --repo=1 backup\n2024-12-01 17:45:32.275 P00   INFO: backup command begin 2.54.0: --config=\/etc\/pgbackrest.conf --exec-id=10957-81c3e6e7 --log-level-console=info --pg1-path=\/u02\/pgdata\/17\/PG17 --pg1-port=5435 --pg1-socket-path=\/tmp --repo=1 --repo2-azure-account=&lt;redacted&gt; --repo2-azure-container=backups --repo2-azure-key=&lt;redacted&gt; --repo2-azure-key-type=sas --repo1-path=\/u99\/pgbackrest --repo2-path=\/ --repo1-retention-full=2 --repo2-retention-full=2 --repo2-type=azure --stanza=pg17\n2024-12-01 17:45:32.300 P00   INFO: last backup label = 20241201-164054F_20241201-164358I, version = 2.54.0\n2024-12-01 17:45:32.300 P00   INFO: execute non-exclusive backup start: backup begins after the next regular checkpoint completes\n2024-12-01 17:45:32.564 P00   INFO: backup start archive = 000000010000000100000091, lsn = 1\/91000028\n2024-12-01 17:45:32.564 P00   INFO: check archive for prior segment 000000010000000100000090\n2024-12-01 17:45:34.211 P00   INFO: execute non-exclusive backup stop and wait for all WAL segments to archive\n2024-12-01 17:45:34.392 P00   INFO: backup stop archive = 000000010000000100000091, lsn = 1\/91000120\n2024-12-01 17:45:34.422 P00   INFO: check archive for segment(s) 000000010000000100000091:000000010000000100000091\n2024-12-01 17:45:34.790 P00   INFO: new backup label = 20241201-164054F_20241201-174532I\n2024-12-01 17:45:35.022 P00   INFO: incr backup size = 605.7KB, file total = 1591\n2024-12-01 17:45:35.022 P00   INFO: backup command end: completed successfully (2750ms)\n2024-12-01 17:45:35.022 P00   INFO: expire command begin 2.54.0: --config=\/etc\/pgbackrest.conf --exec-id=10957-81c3e6e7 --log-level-console=info --repo=1 --repo2-azure-account=&lt;redacted&gt; --repo2-azure-container=backups --repo2-azure-key=&lt;redacted&gt; --repo2-azure-key-type=sas --repo1-path=\/u99\/pgbackrest --repo2-path=\/ --repo1-retention-full=2 --repo2-retention-full=2 --repo2-type=azure --stanza=pg17\n2024-12-01 17:45:35.023 P00   INFO: expire command end: completed successfully (1ms)\n\n\n<\/code><\/pre>\n\n\n\n<p><br><strong>Note :<\/strong><em> I use the &#8220;&#8211;archive-copy&#8221; command here to backup the required WAL with the FULL backup for repo 2. This avoids having parts of the WAL chain on both repositories. The idea here is that you would do your local (repo 1) backup for PITR purposes and your long-term backups on repo 2 (weekly\/monthly\/yearly).<\/em><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>Verify Backups:<\/strong><\/p>\n\n\n\n<p><em>You can note here that each backup set has a repo line specifying where the files are stored.<\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>postgres@PG1:\/home\/postgres\/renewSAS\/ &#091;PG17] pgbackrest --config=\/etc\/pgbackrest.conf --stanza=pg17 --log-level-console=info info\nstanza: pg17\nstatus: ok\ncipher: none\n\ndb (current)\n    wal archive min\/max (17): 000000010000000100000087\/000000010000000100000091\n\n    full backup: 20241201-164054F\n        timestamp start\/stop: 2024-12-01 16:40:54+00 \/ 2024-12-01 16:41:49+00\n        wal start\/stop: 000000010000000100000089 \/ 000000010000000100000089\n        database size: 1.5GB, database backup size: 1.5GB\n        repo1: backup set size: 91MB, backup size: 91MB\n\n    incr backup: 20241201-164054F_20241201-164358I\n        timestamp start\/stop: 2024-12-01 16:43:58+00 \/ 2024-12-01 16:44:00+00\n        wal start\/stop: 00000001000000010000008D \/ 00000001000000010000008D\n        database size: 1.5GB, database backup size: 604.5KB\n        repo1: backup set size: 91MB, backup size: 27.6KB\n        backup reference total: 1 full\n\n    full backup: 20241201-173722F\n        timestamp start\/stop: 2024-12-01 17:37:22+00 \/ 2024-12-01 17:39:10+00\n        wal start\/stop: 00000001000000010000008F \/ 00000001000000010000008F\n        database size: 1.5GB, database backup size: 1.5GB\n        repo2: backup set size: 91MB, backup size: 91MB\n\n    incr backup: 20241201-164054F_20241201-174532I\n        timestamp start\/stop: 2024-12-01 17:45:32+00 \/ 2024-12-01 17:45:34+00\n        wal start\/stop: 000000010000000100000091 \/ 000000010000000100000091\n        database size: 1.5GB, database backup size: 605.7KB\n        repo1: backup set size: 91MB, backup size: 27.7KB\n        backup reference total: 1 full, 1 incr\n\n\n<\/code><\/pre>\n\n\n\n<p><strong>Verify Remote files Backups:<\/strong><\/p>\n\n\n\n<p>Use Azure Portal or Azure CLI to check the Blob Storage container for uploaded backup files.<br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>az storage blob list --account-name pgbackreststorage --container-name backups --output table<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 7: Automate the Script Execution<\/h2>\n\n\n\n<p>Schedule the script to run periodically to renew the SAS token before it expires.<\/p>\n\n\n\n<p><strong>Edit Crontab:<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>  sudo crontab -e<\/code><\/pre>\n\n\n\n<p><strong>Add Cron Job<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\n    0 *\/11 * * * \/path\/to\/renew_sas_token.sh &gt;&gt; \/var\/log\/pgbackrest_sas_renew.log 2&gt;&amp;1\n  \n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Runs the script every 11 hours.<\/li>\n\n\n\n<li>Redirects output to a log file for troubleshooting.<br>You can also trigger the script from any automation platform you&#8217;d like.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-why-use-managed-identity-with-short-lived-sas-tokens\"><strong>Why Use Managed Identity with Short-Lived SAS Tokens?<\/strong><\/h2>\n\n\n\n<p>While there are alternative methods, using Managed Identity to generate short-lived SAS tokens provides a balance between security and manageability.<br>pgBackRest does not support managed Identity yet, it might not be a priority for the project (<a href=\"https:\/\/github.com\/pgbackrest\/pgbackrest\/issues\/2023\" target=\"_blank\" rel=\"noreferrer noopener\">link<\/a>) but this solution is valid and secure from a compliance point of view.<br>This solution offers seamless integration with pgBackRest no code changes are required it is pretty flexible since you can adjust your token validity to when you push towards Azure Blob Storage and permissions are customizable. Automation is easy with a crontab or AAP\u2026etc.<br>The management is simplified since the token generation is automated, the access control is centralized (with Azure AD RBAC policies) and the administrative overhead is reduced by avoiding key management.<br>Regarding security standards, using short-lived tokens and Managed Identities aligns with security best practices and standards like <strong>ISO 27001<\/strong>, <strong>SOC 2<\/strong>, <strong>GDPR,<\/strong> and <strong>revDSG\/nLPD<\/strong>. Additionally, actions performed using Managed Identity are logged in Azure AD providing the audit logs for compliance and security reviews and access to Blob Storage Account can be monitored using Azure Storage analytics to detect unauthorized access attempts.<br>Obviously, some enhancement could be done, you could configure SSL for pgBackRest and backup encryption even though there is a limited added value here (the connection is local and Azure Blob Storage is already encrypted). But, overall I feel this offers a good foundation to help you setup and offload on Azure your backup repository.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">References<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/pgbackrest.org\/\">PGBackRest Documentation<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/active-directory\/managed-identities-azure-resources\/overview\">Azure Managed Identities<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/storage\/common\/storage-sas-overview\">Azure Blob Storage SAS Tokens<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/key-vault\/general\/overview\">Azure Key Vault<\/a><\/li>\n<\/ul>\n\n\n\n<p><strong>Appendix: Full Script and config<br><\/strong><br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>17:45:39 postgres@PG1:\/home\/postgres\/renewSAS\/ &#091;PG17] cat renewSASToken.bash\n#!\/bin\/bash\n\n## Renew Azure Blob Storage SAS Token for PGBackRest\n\n# Authenticate Azure CLI\naz login --identity\n\n# Variables\nSTORAGE_ACCOUNT_NAME=\"pgbackreststorage\"\nCONTAINER_NAME=\"backups\"\nPG_BACKREST_CONF=\"\/etc\/pgbackrest.conf\"\nEXPIRY_DATE=$(date -u -d \"+12 hours\" +\"%Y-%m-%dT%H:%M:%SZ\")\n\n# Retrieve the Storage Account Key\nACCOUNT_KEY=$(az storage account keys list \\\n    --resource-group \"cloud-shell-storage-westeurope\" \\\n    --account-name \"$STORAGE_ACCOUNT_NAME\" \\\n    --query \"&#091;0].value\" \\\n    --output tsv)\n\nif &#091; -z \"$ACCOUNT_KEY\" ]; then\n    echo \"Failed to retrieve storage account key.\"\n    exit 1\nfi\n\n# Generate SAS Token\nSAS_TOKEN=$(az storage container generate-sas \\\n    --account-name \"$STORAGE_ACCOUNT_NAME\" \\\n    --name \"$CONTAINER_NAME\" \\\n    --permissions acdlrw \\\n    --expiry \"$EXPIRY_DATE\" \\\n    --https-only \\\n    --account-key \"$ACCOUNT_KEY\" \\\n    --output tsv)\n\nif &#091; -z \"$SAS_TOKEN\" ]; then\n    echo \"Failed to generate SAS token.\"\n    exit 1\nfi\n\necho \"SAS Token generated successfully. It will expire on $EXPIRY_DATE.\"\n\n# Update PGBackRest configuration with the SAS token\necho \"Updating PGBackRest configuration on backup server...\"\n\nsudo awk -v sas_token=\"$SAS_TOKEN\" '\/^repo2-azure-key=\/ {$0=\"repo2-azure-key=\" sas_token} {print}' \"$PG_BACKREST_CONF\" &gt; \/tmp\/pgbackrest.conf.tmp &amp;&amp; sudo mv \/tmp\/pgbackrest.conf.tmp \"$PG_BACKREST_CONF\"\n\nif &#091; $? -eq 0 ]; then\n    echo \"PGBackRest configuration updated successfully.\"\nelse\n    echo \"Failed to update PGBackRest configuration.\"\n    exit 1\nfi\n\necho \"SAS token update completed.\"\n\n18:16:54 postgres@PG1:\/home\/postgres\/renewSAS\/ &#091;PG17] cat \/etc\/pgbackrest.conf\n&#091;global]\nrepo1-path=\/u99\/pgbackrest\nrepo1-retention-full=2\n\nrepo2-type=azure\nrepo2-path=\/\nrepo2-azure-container=backups\nrepo2-azure-account=pgbackreststorage\nrepo2-azure-key=se=2024-12-02T05%3A36%3A34Z&amp;sp=racwdl&amp;spr=https&amp;sv=2022-11-02&amp;sr=c&amp;sig=d16aYx67bpUT\/MVNerRQG9cnIQYJ46%2Bggt3jeEC8fnQ%3D\nrepo2-azure-key-type=sas\nrepo2-retention-full=2\n\n&#091;pg17]\npg1-path=\/u02\/pgdata\/17\/PG17\npg1-port=5435\ndb-socket-path=\/tmp\n18:17:19 postgres@PG1:\/home\/postgres\/renewSAS\/ &#091;PG17] sqh\npsql (17.2 dbi services build)\nType \"help\" for help.\n\npostgres=# show archive_mode;\n archive_mode\n--------------\n on\n(1 row)\n\npostgres=# show archive_command;\n                            archive_command\n------------------------------------------------------------------------\n pgbackrest --config=\/etc\/pgbackrest.conf --stanza=pg17 archive-push %p\n(1 row)<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Introduction One of the nice things with cloud providers is the low costs of their storage. Whenever you want to optimize your long-term backups and push them on Azure, you might face a wall of questions on how to do it with PostgreSQL securely and whether it would align with disaster recovery plans.The following setup [&hellip;]<\/p>\n","protected":false},"author":153,"featured_media":35997,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[955,83,149],"tags":[1338,3474,1293],"type_dbi":[2749],"class_list":["post-35976","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cloud","category-postgresql","category-security","tag-azure","tag-managed-identity","tag-pgbackrest","type-postgresql"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.2 (Yoast SEO v27.2) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Offloading PostgreSQL Backups to Azure Blob Storage Using PGBackRest, Managed Identity, and SAS Tokens - dbi Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Offloading PostgreSQL Backups to Azure Blob Storage Using PGBackRest, Managed Identity, and SAS Tokens\" \/>\n<meta property=\"og:description\" content=\"Introduction One of the nice things with cloud providers is the low costs of their storage. Whenever you want to optimize your long-term backups and push them on Azure, you might face a wall of questions on how to do it with PostgreSQL securely and whether it would align with disaster recovery plans.The following setup [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/\" \/>\n<meta property=\"og:site_name\" content=\"dbi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-12-01T20:10:49+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-03-04T10:03:39+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/12\/DBAlanscape.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1344\" \/>\n\t<meta property=\"og:image:height\" content=\"768\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Adrien Obernesser\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Adrien Obernesser\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/\"},\"author\":{\"name\":\"Adrien Obernesser\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/fd2ab917212ce0200c7618afaa7fdbcd\"},\"headline\":\"Offloading PostgreSQL Backups to Azure Blob Storage Using PGBackRest, Managed Identity, and SAS Tokens\",\"datePublished\":\"2024-12-01T20:10:49+00:00\",\"dateModified\":\"2025-03-04T10:03:39+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/\"},\"wordCount\":933,\"commentCount\":0,\"image\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/12\/DBAlanscape.jpg\",\"keywords\":[\"Azure\",\"Managed-Identity\",\"pgbackrest\"],\"articleSection\":[\"Cloud\",\"PostgreSQL\",\"Security\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/\",\"name\":\"Offloading PostgreSQL Backups to Azure Blob Storage Using PGBackRest, Managed Identity, and SAS Tokens - dbi Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/12\/DBAlanscape.jpg\",\"datePublished\":\"2024-12-01T20:10:49+00:00\",\"dateModified\":\"2025-03-04T10:03:39+00:00\",\"author\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/fd2ab917212ce0200c7618afaa7fdbcd\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/#primaryimage\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/12\/DBAlanscape.jpg\",\"contentUrl\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/12\/DBAlanscape.jpg\",\"width\":1344,\"height\":768},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\/\/www.dbi-services.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Offloading PostgreSQL Backups to Azure Blob Storage Using PGBackRest, Managed Identity, and SAS Tokens\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#website\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/\",\"name\":\"dbi Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/fd2ab917212ce0200c7618afaa7fdbcd\",\"name\":\"Adrien Obernesser\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/dc9316c729e50107159e0a1e631b9c1742ce8898576887d0103c83b1ca3bc9e6?s=96&d=mm&r=g\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/dc9316c729e50107159e0a1e631b9c1742ce8898576887d0103c83b1ca3bc9e6?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/dc9316c729e50107159e0a1e631b9c1742ce8898576887d0103c83b1ca3bc9e6?s=96&d=mm&r=g\",\"caption\":\"Adrien Obernesser\"},\"url\":\"https:\/\/www.dbi-services.com\/blog\/author\/adrienobernesser\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Offloading PostgreSQL Backups to Azure Blob Storage Using PGBackRest, Managed Identity, and SAS Tokens - dbi Blog","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:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/","og_locale":"en_US","og_type":"article","og_title":"Offloading PostgreSQL Backups to Azure Blob Storage Using PGBackRest, Managed Identity, and SAS Tokens","og_description":"Introduction One of the nice things with cloud providers is the low costs of their storage. Whenever you want to optimize your long-term backups and push them on Azure, you might face a wall of questions on how to do it with PostgreSQL securely and whether it would align with disaster recovery plans.The following setup [&hellip;]","og_url":"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/","og_site_name":"dbi Blog","article_published_time":"2024-12-01T20:10:49+00:00","article_modified_time":"2025-03-04T10:03:39+00:00","og_image":[{"width":1344,"height":768,"url":"http:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/12\/DBAlanscape.jpg","type":"image\/jpeg"}],"author":"Adrien Obernesser","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Adrien Obernesser","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/#article","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/"},"author":{"name":"Adrien Obernesser","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/fd2ab917212ce0200c7618afaa7fdbcd"},"headline":"Offloading PostgreSQL Backups to Azure Blob Storage Using PGBackRest, Managed Identity, and SAS Tokens","datePublished":"2024-12-01T20:10:49+00:00","dateModified":"2025-03-04T10:03:39+00:00","mainEntityOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/"},"wordCount":933,"commentCount":0,"image":{"@id":"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/#primaryimage"},"thumbnailUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/12\/DBAlanscape.jpg","keywords":["Azure","Managed-Identity","pgbackrest"],"articleSection":["Cloud","PostgreSQL","Security"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/","url":"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/","name":"Offloading PostgreSQL Backups to Azure Blob Storage Using PGBackRest, Managed Identity, and SAS Tokens - dbi Blog","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/#primaryimage"},"image":{"@id":"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/#primaryimage"},"thumbnailUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/12\/DBAlanscape.jpg","datePublished":"2024-12-01T20:10:49+00:00","dateModified":"2025-03-04T10:03:39+00:00","author":{"@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/fd2ab917212ce0200c7618afaa7fdbcd"},"breadcrumb":{"@id":"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/#primaryimage","url":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/12\/DBAlanscape.jpg","contentUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/12\/DBAlanscape.jpg","width":1344,"height":768},{"@type":"BreadcrumbList","@id":"https:\/\/www.dbi-services.com\/blog\/offloading-postgresql-backups-to-azure-blob-storage-using-pgbackrest-managed-identity-and-sas-tokens\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/www.dbi-services.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Offloading PostgreSQL Backups to Azure Blob Storage Using PGBackRest, Managed Identity, and SAS Tokens"}]},{"@type":"WebSite","@id":"https:\/\/www.dbi-services.com\/blog\/#website","url":"https:\/\/www.dbi-services.com\/blog\/","name":"dbi Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/fd2ab917212ce0200c7618afaa7fdbcd","name":"Adrien Obernesser","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/dc9316c729e50107159e0a1e631b9c1742ce8898576887d0103c83b1ca3bc9e6?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/dc9316c729e50107159e0a1e631b9c1742ce8898576887d0103c83b1ca3bc9e6?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/dc9316c729e50107159e0a1e631b9c1742ce8898576887d0103c83b1ca3bc9e6?s=96&d=mm&r=g","caption":"Adrien Obernesser"},"url":"https:\/\/www.dbi-services.com\/blog\/author\/adrienobernesser\/"}]}},"_links":{"self":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/35976","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/users\/153"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/comments?post=35976"}],"version-history":[{"count":31,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/35976\/revisions"}],"predecessor-version":[{"id":36009,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/35976\/revisions\/36009"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media\/35997"}],"wp:attachment":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media?parent=35976"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/categories?post=35976"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/tags?post=35976"},{"taxonomy":"type","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/type_dbi?post=35976"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}