<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Guy Bowerman</title>
    <description>The latest articles on DEV Community by Guy Bowerman (@guybo).</description>
    <link>https://dev.to/guybo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1424716%2F3f62a14a-b44d-4dfb-a26d-7250d4448a94.jpg</url>
      <title>DEV Community: Guy Bowerman</title>
      <link>https://dev.to/guybo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/guybo"/>
    <language>en</language>
    <item>
      <title>Using CLI to deploy Postgres on Azure with Entra (AAD) Admin</title>
      <dc:creator>Guy Bowerman</dc:creator>
      <pubDate>Tue, 18 Feb 2025 05:00:08 +0000</pubDate>
      <link>https://dev.to/guybo/using-cli-to-deploy-postgres-on-azure-with-entra-aad-admin-1iad</link>
      <guid>https://dev.to/guybo/using-cli-to-deploy-postgres-on-azure-with-entra-aad-admin-1iad</guid>
      <description>&lt;p&gt;How do you use Azure CLI to create an &lt;a href="https://learn.microsoft.com/azure/postgresql/flexible-server/overview" rel="noopener noreferrer"&gt;Azure Database for PostgreSQL flexible server&lt;/a&gt; with an &lt;a href="https://learn.microsoft.com/azure/active-directory/fundamentals/active-directory-whatis" rel="noopener noreferrer"&gt;Entra (AAD)&lt;/a&gt; admin? Since many flexible server CLI deployment examples assume you're creating Postgres users rather than Entra, here's a walkthrough of deploying flexible server with an Entra admin role using Azure CLI.&lt;/p&gt;

&lt;p&gt;This example assumes you're running &lt;a href="https://azure.microsoft.com/get-started/azure-portal/cloud-shell/" rel="noopener noreferrer"&gt;Azure Cloud Shell&lt;/a&gt; in the Azure Portal. It would also work anywhere you've installed Azure CLI, but Cloud Shell makes for a useful sandbox as it always has the latest CLI version installed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Entra?&lt;/strong&gt;&lt;br&gt;
As network perimeters have become more porous with Bring Your Own Device, cloud apps and remote work, identity has increasingly become the most important security perimeter for a company. Using a centrally controlled identity service like &lt;a href="https://learn.microsoft.com/azure/active-directory/fundamentals/active-directory-whatis" rel="noopener noreferrer"&gt;Microsoft Entra ID&lt;/a&gt; allows greater control and better security. See also a great article called &lt;a href="https://learn.microsoft.com/azure/security/fundamentals/identity-management-best-practices" rel="noopener noreferrer"&gt;Azure Identity Management and access control security best practices&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's get started with a CLI walkthrough...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1) Set subscription and create resource group&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Set some variables and customize them for your purposes.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;myResourceGroup=my-entra-flex-rg&lt;br&gt;
myPGServer=my-entra-flex-server&lt;br&gt;
myLocation=westus3&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Set the subscription you're going to use in CLI.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az group set --name &amp;lt;your subscription name&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Create an Azure resource group.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az group create --name $myResourceGroup --location $myLocation&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2) Create the flexible server&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Deploy a flexible server. Set active-directory-auth to Enabled, and select whichever tier, tier, sku, location, version settings you need, e.g.,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az postgres flexible-server create -g $myResourceGroup \ &lt;br&gt;
  --name $myPGServer --tier Burstable --sku-name Standard_B1ms \ &lt;br&gt;
  --location $myLocation --create-default-database Enabled \ &lt;br&gt;
  --active-directory-auth Enabled --password-auth Disabled \ &lt;br&gt;
  --version 16&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You may see a random password being created in the CLI output, but you can ignore that, we'll be setting an Entra user as the admin.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3) Get the object ID for your Entra user and assign it as admin&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Setting an Entra admin user requires the Entra "object ID" of the user. You can query it using the "ad user show" CLI command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;objectId=`az ad user show --id myuser@mycompany.com --query "id" --output tsv&lt;/code&gt;`&lt;/p&gt;

&lt;p&gt;Now you can set this Entra user as the flexible server admin user.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az postgres flexible-server ad-admin create -g $myResourceGroup \ &lt;br&gt;
  -s $myPGServer --type User --object-id $objectId \ &lt;br&gt;
  -u myuser@mycompany.com&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4) Connect to your server as your Entra Admin user&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of a password you'll be using your Entra access token. Get the current token by running this command and assigning it to a variable $currentToken:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az account get-access-token --resource-type oss-rdbms --output tsv --query accessToken&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now connect to your flexible server using this access token as the PostgreSQL "password" via any Postgres admin tool.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;psql "host=$myPGserver.postgres.database.azure.com port=5432 dbname=postgres user=myuser@mycompany.com password=$currentToken"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;One thing to keep in mind is that you're effectively using an Entra token as a password for PostgreSQL. Note that Entra tokens expire so you'll need to think about how you refresh them. I'm hoping future versions of open-source PostgreSQL will have a more implicit approach to centralized identity management with built-in OAUTH and Entra support.&lt;/p&gt;

&lt;p&gt;Next I plan to look into using Entra IDs with the &lt;a href="https://www.postgresql.org/docs/current/contrib-dblink-function.html" rel="noopener noreferrer"&gt;dblink&lt;/a&gt; extension.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>azure</category>
      <category>cli</category>
      <category>aad</category>
    </item>
    <item>
      <title>Setting up Postgres on Azure private endpoints using CLI</title>
      <dc:creator>Guy Bowerman</dc:creator>
      <pubDate>Mon, 02 Sep 2024 07:12:34 +0000</pubDate>
      <link>https://dev.to/guybo/setting-up-postgres-on-azure-private-endpoints-using-cli-3g27</link>
      <guid>https://dev.to/guybo/setting-up-postgres-on-azure-private-endpoints-using-cli-3g27</guid>
      <description>&lt;p&gt;Previously I wrote about &lt;a href="https://dev.to/guybo/securing-postgres-on-azure-with-a-private-endpoint-connection-3gmf"&gt;Securing Postgres on Azure with a private endpoint&lt;/a&gt; to ensure a Postgres server can only be connected from a specific subnet, via the private Azure backbone network. &lt;/p&gt;

&lt;p&gt;Suppose you want to set up a Postgres flexible server instance with private endpoints using Azure CLI instead of the Portal? This article walks through a CLI script to do that. &lt;/p&gt;

&lt;p&gt;Firstly, set up a few variables (assuming it's running as a bash script):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;#!/usr/bin/bash&lt;br&gt;
resourceGroup="my-private-rg"&lt;br&gt;
location="westus3"&lt;br&gt;
vnetName="my-private-vnet"&lt;br&gt;
subnetName="my-private-subnet"&lt;br&gt;
dnsZoneName="privatelink.postgres.database.azure.com"&lt;br&gt;
connectionName="privatelink"&lt;br&gt;
privateEndpointName="myPrivateEndpoint"&lt;br&gt;
privateLinkName="privatelink"&lt;br&gt;
serverName="my-private-pg-server"&lt;br&gt;
adminUser="myuser"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next create an Azure resource group, and a Virtual Network with a subnet:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az group create --name $resourceGroup --location $location&lt;br&gt;
az network vnet create --resource-group $resourceGroup --name $vnetName --subnet-name $subnetName --subnet-prefixes 10.0.0.0/24&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now create a new PostgreSQL flexible server instance. &lt;br&gt;
Note: Setting public access to None, and assuming you've set an environment variable $password for the admin password:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az postgres flexible-server create --resource-group $resourceGroup --name $serverName --tier Burstable --sku-name Standard_B1ms --public-access None --admin-user $adminUser --admin-password $password&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once the flexible server instance is running, create a private endpoint, and attach it to the flexible server resource id by dynamically calling "az resource show" to get the resource id:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az network private-endpoint create --name $privateEndpointName --connection-name $connectionName --resource-group $resourceGroup --vnet $vnetName --subnet $subnetName --private-connection-resource-id $(az resource show -g $resourceGroup -n $serverName --resource-type "Microsoft.DBforPostgreSQL/flexibleServers" --query "id" -o tsv) --group-id postgresqlServer&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next create a private DNS zone and link it to the virtual network. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;az network private-dns zone create --resource-group $resourceGroup --name $dnsZoneName &lt;br&gt;
az network private-dns link vnet create --resource-group $resourceGroup --zone-name $dnsZoneName --name $privateLinkName --virtual-network $vnetName --registration-enabled false&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Lastly, get the private IP address of the private endpoint, and create a private DNS record to point the Postgres server name to this address:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;networkInterfaceId=$(az network private-endpoint show --name $privateEndpointName --resource-group $resourceGroup --query 'networkInterfaces[0].id' -o tsv)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;privateIP=$(az resource show --ids $networkInterfaceId --api-version 2019-04-01 -o json | grep privateIPAddress\" |  grep -oP '(?&amp;lt;="privateIPAddress": ")[^"]+')&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az network private-dns record-set a create --name $serverName --zone-name $dnsZoneName --resource-group $resourceGroup  &lt;br&gt;
az network private-dns record-set a add-record --record-set-name $serverName --zone-name $dnsZoneName --resource-group $resourceGroup -a $privateIP&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once it's set up, you can create resource in the subnet that can now connect privately to the database server.&lt;/p&gt;

&lt;p&gt;One thing worth noting. If you look at the Postgres server network properties after running this script, "Public access" is checked:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5t9z8vxjq903b3vw3h06.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5t9z8vxjq903b3vw3h06.png" alt="Postgres flexible server network properties" width="800" height="231"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It doesn't mean the server can be accessed other than via the private endpoint, as there are no firewall rules in place. You can safely uncheck this box. (And I need to tinker with the CLI some more so this box isn't checked.)&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>azure</category>
      <category>cli</category>
      <category>security</category>
    </item>
    <item>
      <title>Securing Postgres on Azure with a Private Endpoint</title>
      <dc:creator>Guy Bowerman</dc:creator>
      <pubDate>Sun, 01 Sep 2024 03:05:27 +0000</pubDate>
      <link>https://dev.to/guybo/securing-postgres-on-azure-with-a-private-endpoint-connection-3gmf</link>
      <guid>https://dev.to/guybo/securing-postgres-on-azure-with-a-private-endpoint-connection-3gmf</guid>
      <description>&lt;p&gt;Here's a quick guide to setting up secure access to &lt;em&gt;Azure Database for PostgreSQL flexible server&lt;/em&gt;, AKA &lt;strong&gt;Postgres on Azure&lt;/strong&gt;, using a &lt;strong&gt;private endpoint&lt;/strong&gt;, so the PostgreSQL server is only accessible from a specified subnet, which connects privately over the Microsoft backbone network. In this example a Linux VM will be created in the subnet to act as a database client. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcym31qc7xz0l4t6fx0tb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcym31qc7xz0l4t6fx0tb.png" alt="Image description" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Basic steps&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an Azure Virtual Network (VNET) with a default subnet.&lt;/li&gt;
&lt;li&gt;Create an Azure Database for PostgreSQL flexible server instance (with a private endpoint and private DNS integration).&lt;/li&gt;
&lt;li&gt;Create a VM with a PostgreSQL client in the subnet.&lt;/li&gt;
&lt;li&gt;Install psql on the VM.&lt;/li&gt;
&lt;li&gt;Connect to the Postgres instance from the VM.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;BTW if you want to do steps 1-3 purely in Azure CLI, see &lt;a href="https://dev.to/guybo/setting-up-postgres-on-azure-private-endpoints-using-cli-3g27"&gt;Setting up Postgres on Azure private endpoints using CLI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Create a VNET&lt;/strong&gt;&lt;br&gt;
Create an Azure Resource Group and a VNET in the Azure portal or using Azure CLI.&lt;/p&gt;

&lt;p&gt;E.g., with CLI:&lt;br&gt;
&lt;code&gt;az group create --name myPrivateRG --location westus3&lt;br&gt;
az network vnet create --resource-group myPrivateRG --name myPrivateVNet --subnet-name myPrivateSubnet --subnet-prefixes 10.0.0.0/24&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Create an Azure Database for PostgreSQL flexible server instance&lt;/strong&gt;&lt;br&gt;
The Microsoft docs also has a tutorial for this part. See: &lt;a href="https://learn.microsoft.com/azure/postgresql/flexible-server/how-to-manage-virtual-network-private-endpoint-portal" rel="noopener noreferrer"&gt;Create and manage virtual networks with Private Link for Azure Database for PostgreSQL - Flexible Server by using the Azure portal&lt;/a&gt;. In this article I'll go into a little more detail on the networking options.&lt;/p&gt;

&lt;p&gt;In the Azure portal, create a new Azure Database for PostgreSQL flexible server instance, picking the default settings for Development workload type (Burstable compute SKU):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm9pbmc2kqafhdbwn82cs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm9pbmc2kqafhdbwn82cs.png" alt="Azure portal panel for creating a PostgreSQL flexible server" width="751" height="883"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the Networking panel select Public access as the connectivity method, but uncheck the "Public access" checkbox. This means only private endpoint connections will be allowed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs66og09354v9f1pg79so.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs66og09354v9f1pg79so.png" alt="Flexible server networking panel" width="733" height="936"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then on the same panel click "Add private endpoint". In the "Create private endpoint" panel create a new private endpoint which points to the virtual network and subnet created earlier, and select "Enable Private DNS integration" to enable private host resolution from the client.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvrqmujmg9p0ej9fmc2mo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvrqmujmg9p0ej9fmc2mo.png" alt="Private endpoint configuration panel" width="800" height="1031"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you create the PostgreSQL server you'll get a warning saying that no firewall rule has been added so you won't be able to connect to it over the internet, which is good, because you only want to connect via private endpoint over the Azure backbone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Create a VM with a PostgreSQL client in the subnet&lt;/strong&gt;&lt;br&gt;
Create a VM in the subnet referenced by the private endpoint, which will be the only client resource allowed to connect to the PostgreSQL server.&lt;/p&gt;

&lt;p&gt;Here's an example of creating an Ubuntu VM in the Azure Portal, choosing the default settings, in the VNET created in step 1.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fckqb3op9fcpzc7jnpr44.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fckqb3op9fcpzc7jnpr44.png" alt="Azure portal panel for creating a VM" width="800" height="947"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use an SSH key to connect, and if you're generating a new key pair you'll have the option to save the PEM file (which contains your private key) locally when creating the VM.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F329rv4vv3l9oha5eo6et.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F329rv4vv3l9oha5eo6et.png" alt="Azure portal panel for creating a VM with SSH connection" width="784" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the Networking panel confirm the VNET and Subnet match the one created earlier for the private endpoint:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5uua6atlblj7g7jgyazd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5uua6atlblj7g7jgyazd.png" alt="Networking panel when creating a VM" width="800" height="947"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Install psql on the VM&lt;/strong&gt; &lt;br&gt;
Once the VM is running, SSH to the VM using the locally saved key. In this case I ran ssh from a Debian instance running in WSL (Windows Subsystem for Linux) to the public IP address of the VM. I saved the PEM file in a .ssh directory and set the file permissions to 600 (chmod 600 .ssl/myPrivateVM_key.pem):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ssh -i .ssh/myPrivateVM_key.pem azureuser@nn.nn.nn.nnn&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Use the Ubuntu package manager to install the Postgres client tool psql on the vM:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo apt-get update&lt;br&gt;
sudo apt-get upgrade&lt;br&gt;
sudo apt install postgresql-client&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Connect to the Postgres instance from the VM&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With the postgresql-client package installed you can use the &lt;em&gt;psql&lt;/em&gt; tool to connect to the database server via the private endpoint. Note "myuser" is the name of the admin user you specified when you created the PostgreSQL server (this example assumes you specified a regular user/password, not an Entra ID).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;psql -h my-private-pg-server.postgres.database.azure.com -U myuser -d postgres&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj5oytdqqflisntlqbh63.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj5oytdqqflisntlqbh63.png" alt="PostgreSQL psql client tool connection" width="800" height="99"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Any resource you create in this subnet, for example a web app, will be able to connect to the PostgreSQL server via the private endpoint using Azure's private backbone network. No resources outside this subnet will be able to connect.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>azure</category>
      <category>networking</category>
      <category>security</category>
    </item>
    <item>
      <title>Postgres on Debian in WSL</title>
      <dc:creator>Guy Bowerman</dc:creator>
      <pubDate>Mon, 15 Apr 2024 04:16:48 +0000</pubDate>
      <link>https://dev.to/guybo/postgresql-on-wsl-debian-1lkh</link>
      <guid>https://dev.to/guybo/postgresql-on-wsl-debian-1lkh</guid>
      <description>&lt;p&gt;This article covers the basics of installing and running PostgreSQL on Debian in &lt;a href="https://learn.microsoft.com/windows/wsl/about" rel="noopener noreferrer"&gt;Windows subsystem for Linux&lt;/a&gt; (WSL).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Updated &lt;strong&gt;June 15 2025&lt;/strong&gt; (to include running Postgres 18 on WSL, and connecting with the VS Code Postgres extension).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;WSL makes for a great development environment if you're running Windows and want to use Linux locally. It's also a very convenient platform run to a local PostgreSQL server, and integrates nicely with dev tools like VS Code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Linux distro?
&lt;/h2&gt;

&lt;p&gt;You can choose from many Linux distributions to run on WSL (run &lt;em&gt;wsl -l -o&lt;/em&gt; to see a list or import any distro using a TAR file). I like to use &lt;strong&gt;Debian&lt;/strong&gt; as it's a popular, stable, general purpose distro with good support. You can install Debian to WSL directly from the &lt;a href="https://apps.microsoft.com/detail/9msvkqc78pk6?hl=en-US&amp;amp;gl=US" rel="noopener noreferrer"&gt;Microsoft Store&lt;/a&gt;, and use &lt;a href="https://learn.microsoft.com/windows/wsl/setup/environment#set-up-windows-terminal" rel="noopener noreferrer"&gt;Windows Terminal&lt;/a&gt; to log on to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Postgres version?
&lt;/h2&gt;

&lt;p&gt;Ignore this step if you want want the default Postgres version that comes with your distro packages. &lt;/p&gt;

&lt;p&gt;See the postgresql.org &lt;a href="https://wiki.postgresql.org/wiki/Apt/FAQ#I_want_to_try_the_beta_version_of_the_next_PostgreSQL_release" rel="noopener noreferrer"&gt;Apt/FAQ&lt;/a&gt; for guidance on how to install the latest released or development PostgreSQL version. For example, edit &lt;em&gt;/etc/apt/sources.list.d/pgdg.list&lt;/em&gt; to point to the latest version 18 pre-release by adding this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;deb http://apt.postgresql.org/pub/repos/apt/ bookworm-pgdg main 18 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install Postgres
&lt;/h2&gt;

&lt;p&gt;The first thing to do is make sure you're up to date with the latest patches. On the Debian command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt update
sudo apt upgrade
sudo apt autoremove # to free up space if needed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're installing the latest released version (e.g., 17), install with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install postgresql postgresql-contrib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See &lt;a href="https://learn.microsoft.com/windows/wsl/tutorials/wsl-database#install-postgresql" rel="noopener noreferrer"&gt;Install PostgreSQL&lt;/a&gt; in the WSL docs for more details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installing a development release. E.g., postgresql-18&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Alternatively, install a specific version like 18 with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install postgresql-18
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set a password for the postgres user with &lt;em&gt;sudo passwd postgres&lt;/em&gt; and then start the service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo passwd postgres
sudo service postgresql start
sudo systemctl enable postgresql # to start service automatically
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: If you previously had an earlier version of PostgreSQL installed and the version you want isn't starting, you can explicitly initialize it. You can then run both versions (listening on different ports), or you can drop the older cluster if you don't need it. Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo pg_createcluster 18 main --start
pg_lsclusters
sudo pg_dropcluster 17 main --stop
sudo service postgresql start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Connecting to PostgreSQL
&lt;/h2&gt;

&lt;p&gt;You can then enter the PostgreSQL shell with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo -u postgres psql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;..and from there run SQL commands, e.g. create PostgreSQL users with &lt;em&gt;CREATE USER&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Or run SQL commands directly, e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo -i -u postgres psql &amp;lt; create_db.sql
sudo -i -u postgre psql -d mydb &amp;lt; create_schema.sql
# list databases
sudo -i postgres psql --list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Connecting with VS Code
&lt;/h2&gt;

&lt;p&gt;VS Code has become a great way to connect to a Postgres instance since the &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-ossdata.vscode-pgsql" rel="noopener noreferrer"&gt;PostgreSQL for Visual Studio Code extension&lt;/a&gt; was released in May 2025. &lt;/p&gt;

&lt;p&gt;Create a new connection, use 127.0.0.1 as the "SERVER NAME" and check in "Advanced Connection Settings" to make sure 5432 is the listening port (unless you're using a different listening port - you can check in Debian with pg_lsclusters).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flv90req104007d68w3xm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flv90req104007d68w3xm.png" alt="Image description" width="800" height="912"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting with pgAdmin
&lt;/h2&gt;

&lt;p&gt;You can install &lt;a href="https://www.pgadmin.org/" rel="noopener noreferrer"&gt;pgAdmin&lt;/a&gt; on Windows and connect the GUI Admin/developer tool directly to your Postgres server running in WSL.&lt;/p&gt;

&lt;p&gt;In pgAdmin, create a new server with the name of your choice, Host name/address: 127.0.0.1 and a valid PostgreSQL user/password.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztthuzw4l7j5acqx390q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztthuzw4l7j5acqx390q.png" alt="A screen shot of a pgAdmin new server definition panel" width="703" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fha0cvbdustsmrdoutgv2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fha0cvbdustsmrdoutgv2.png" alt="A screen shot of pgAdmin server view" width="457" height="478"&gt;&lt;/a&gt;&lt;br&gt;
Once I've done my local development it's very straightforward to export a database from WSL to a Postgres cloud service or other production destination.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>wsl</category>
      <category>debian</category>
    </item>
  </channel>
</rss>
