
Azure Postgres
- 1 installs
- 404 repo stars
- Updated August 5, 2026
- aiskillstore/marketplace
azure-postgres is a Claude Code skill that configures Azure Database for PostgreSQL Flexible Server and passwordless Microsoft Entra ID authentication.
About
azure-postgres configures Azure Database for PostgreSQL Flexible Server and its passwordless authentication with Microsoft Entra ID. It sets up developer access, managed identities for apps, group-based permissions, and migration from password to Entra ID auth. A developer uses it when provisioning or securing an Azure-hosted PostgreSQL database.
- Configures passwordless Entra ID auth for Azure PostgreSQL Flexible Server
- Sets up developer, managed-identity and group-based access
- Ships az CLI scripts and SDK references for Python, TypeScript and .NET
Azure Postgres by the numbers
- 1 all-time installs (skills.sh)
- Ranked #765 of 911 Databases skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
azure-postgres capabilities & compatibility
- Capabilities
- azure postgres setup · passwordless auth · managed identity · database access control
- Works with
- azure · postgres
- Use cases
- database · devops · security audit
What azure-postgres says it does
Create new Azure Database for PostgreSQL Flexible Server instances and configure passwordless authentication with Microsoft Entra ID.
ALWAYS use passwordless authentication with Entra ID for production workloads.
npx skills add https://github.com/aiskillstore/marketplace --skill azure-postgresAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 404 |
| Last updated | August 5, 2026 |
| Repository | aiskillstore/marketplace ↗ |
What it does
Configure Azure PostgreSQL Flexible Server with passwordless Microsoft Entra ID authentication, managed identities and group-based access.
Who is it for?
Setting up passwordless Entra ID auth, managed identities and group access for Azure PostgreSQL.
Skip if: Non-Azure PostgreSQL hosting or general SQL query writing.
When should I use this skill?
A developer needs passwordless Postgres, Entra ID Postgres, or to migrate a Postgres server to managed identity auth on Azure.
What you get
A PostgreSQL server configured for passwordless Entra ID auth with the right user, app and group access.
- Entra ID authentication configuration
- managed identity and group access setup
- password-to-Entra migration
By the numbers
- 3 access patterns (developer, managed identity, group)
- 5 Azure MCP postgres commands listed
- supports PostgreSQL versions 11-16
Files
Azure Database for PostgreSQL
Configure passwordless authentication with Microsoft Entra ID for existing Azure Database for PostgreSQL Flexible Server. This skill focuses on setting up Entra ID authentication, managing user access, and migrating from password-based authentication.
Primary use cases:
- Migrating existing PostgreSQL databases from password to Entra ID authentication
- Setting up developer access with Azure identities
- Configuring managed identity access for Azure-hosted applications
- Managing group-based access control and permissions
---
MCP Tools (Preferred)
When Azure MCP is enabled, use these tools for PostgreSQL operations:
azure__postgreswith commandpostgres_server_list- List PostgreSQL serversazure__postgreswith commandpostgres_database_list- List databases on a serverazure__postgreswith commandpostgres_database_query- Execute SQL queriesazure__postgreswith commandpostgres_server_param_get- Get server parametersazure__postgreswith commandpostgres_server_param_set- Set server parameters
CLI Commands (Fallback)
az postgres flexible-server list --output table
az postgres flexible-server db list --server-name SERVER -g RG
az postgres flexible-server show --name SERVER -g RG
az postgres flexible-server create --name SERVER -g RG --location REGION --admin-user ADMIN --version 16---
Quick Reference
| Property | Value |
|---|---|
| CLI prefix | az postgres flexible-server |
| MCP tools | azure__postgres |
| Best for | Relational data, PostgreSQL compatibility, PostGIS |
| Engine versions | PostgreSQL 11, 12, 13, 14, 15, 16 (recommended) |
---
Working with Existing PostgreSQL Servers
This skill primarily focuses on configuring authentication for existing PostgreSQL servers. If you need to reference or create servers, use MCP tools or CLI commands, and provide Azure Portal links for easy access.
Portal Link Format:
https://portal.azure.com/#@{tenant-domain}/resource/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.DBforPostgreSQL/flexibleServers/{server-name}/overviewExample portal link:
View in Azure Portal:
https://portal.azure.com/#resource/subscriptions/abc123.../resourceGroups/myrg/providers/Microsoft.DBforPostgreSQL/flexibleServers/myserver/overview---
Microsoft Entra ID Authentication (Critical)
⚠️ ALWAYS use passwordless authentication with Entra ID for production workloads.
Complete Setup Guide
[→ Microsoft Entra ID Authentication Setup Guide](./references/entra-rbac-overview.md)
This guide covers:
- Enabling Entra ID authentication on PostgreSQL servers
- Creating PostgreSQL roles mapped to Azure identities
- Granting database permissions
- Connecting with access tokens instead of passwords
Quick Setup Patterns
Use these patterns based on your scenario:
| Scenario | Guide Link | Use When |
|---|---|---|
| Developer Access | Pattern 1 | Grant developers access with their Azure identity |
| App Authentication | Pattern 2 | Passwordless access for Azure-hosted apps (Container Apps, App Service, Functions) |
| Team Access | Pattern 3 | Manage permissions via Azure AD groups |
| Connection Issues | Troubleshooting | Diagnose authentication and connection failures |
| Migration | Pattern 5 | Transition from password to Entra ID authentication |
Service Tiers
| Tier | vCores | Memory | Use Case |
|---|---|---|---|
| Burstable | 1-20 | 0.5-4 GB/vCore | Dev/test, low traffic |
| General Purpose | 2-64 | 4 GB/vCore | Most production workloads |
| Memory Optimized | 2-64 | 8 GB/vCore | High-memory workloads |
Start with Burstable for dev/test, scale up as needed.
Common Issues
| Issue | Cause | Solution |
|---|---|---|
role does not exist | Role not created in database | Run pgaadauth_create_principal - see guide |
password authentication failed | Token expired (5-60 min validity) | Get fresh token: az account get-access-token --resource-type oss-rdbms |
permission denied | Role lacks permissions | Run GRANT statements - see templates |
| Connection timeout | Firewall blocking access | Add firewall rule: az postgres flexible-server firewall-rule create |
| Guest user login fails | Wrong UPN format | Use full UPN with #EXT# tag from Azure AD |
SDK Quick References
- PostgreSQL Client: TypeScript
- Azure Identity: Python | TypeScript
- PostgreSQL Mgmt: .NET
References
- Microsoft Entra ID Authentication Setup - Complete passwordless authentication guide
- SQL Functions - Entra ID role management functions
- Permission Templates - Common permission patterns
- Troubleshooting - Connection and auth issues
Azure PostgreSQL Entra ID RBAC Setup
This guide helps you set up Microsoft Entra ID (formerly Azure AD) authentication for Azure Database for PostgreSQL Flexible Server. It covers the confusing two-layer mapping: Azure Identity → PostgreSQL Role → Database Permissions.
When to Use This Guide
Use this guide when you need to:
- Set up Entra ID authentication for PostgreSQL
- Configure passwordless access to your PostgreSQL database
- Add a user/developer to Azure PostgreSQL using their Azure identity
- Set up managed identity for your app to access PostgreSQL
- Configure group-based access to PostgreSQL
- Troubleshoot authentication errors connecting to PostgreSQL with Entra
- Migrate from password authentication to Entra ID for PostgreSQL
Overview
Azure Database for PostgreSQL Flexible Server supports Microsoft Entra ID authentication, allowing users to connect using their Azure identities instead of passwords. This involves:
1. Enabling Entra authentication on the PostgreSQL server 2. Creating a PostgreSQL role mapped to an Azure identity 3. Granting database permissions to the PostgreSQL role 4. Connecting with an access token instead of a password
Identity Types Supported
| Identity Type | Use Case | SQL Function |
|---|---|---|
| User | Developer access, interactive queries | pgaadauth_create_principal |
| Group | Team-based access management | pgaadauth_create_principal_with_oid |
| Service Principal | Application authentication | pgaadauth_create_principal_with_oid |
| Managed Identity | Azure-hosted app passwordless access | pgaadauth_create_principal_with_oid |
Core Workflow
Step 1: Check Current Authentication Status
Verify if Entra authentication is enabled on the server. If empty, no Entra admin is configured yet.
Step 2: Add First Entra Administrator
Enable Entra authentication by adding the first admin using Azure CLI.
Step 3: Connect as Entra Admin
Get an access token and connect using psql with the token as password.
Step 4: Create PostgreSQL Roles for Identities
Once connected as admin, create roles for other identities using SQL functions.
Step 5: Grant Database Permissions
Grant appropriate permissions to the new roles using GRANT statements.
See: scripts/az-commands.sh for Azure CLI commands, references/sql-functions.md for SQL functions, and references/permission-templates.md for permission grants.
Setup Patterns
Pattern 1: Developer User Access
Set up a developer to access the database with their Azure identity.
Required Information:
- Developer's UPN (e.g.,
developer@company.com) - Target database name
- Permission level (read-only, read-write, admin)
Script: See scripts/setup-user.sh
Pattern 2: Managed Identity for Applications
Configure passwordless database access for Azure-hosted applications (Container Apps, App Service, Functions).
Required Information:
- Managed identity name and resource group
- Target database name
- Permission level needed
Steps:
1. Get managed identity object ID 2. Create PostgreSQL role using pgaadauth_create_principal_with_oid 3. Grant permissions 4. Configure application to use Azure Identity SDK
Script: See scripts/setup-managed-identity.sh
Pattern 3: Group-Based Access Control
Manage database permissions through Azure AD groups.
Required Information:
- Group display name and object ID
- Whether to enable group sync (
pgaadauth.enable_group_sync) - Permission level for the group
Group Sync Modes:
| Mode | Behavior | Use Case |
|---|---|---|
| OFF (default) | Members use group name as username | Simple setup, no individual tracking |
| ON | Individual member roles auto-created | Audit trails, per-user permissions |
Script: See scripts/setup-group.sh ---
Pattern 4: Troubleshooting Connection Failures
Diagnose and fix Entra authentication issues.
Common Errors:
role "user@domain.com" does not exist- Role not created in databasepassword authentication failed- Token expired or invalidFATAL: password authentication failed- Wrong username formatcould not connect to server- Network/firewall issues
See: troubleshooting.md for detailed diagnostic steps
---
Pattern 5: Migration from Password Auth
Transition existing password-based roles to Entra ID authentication.
Steps: 1. Enable "PostgreSQL and Microsoft Entra authentication" mode (parallel auth) 2. Map existing roles to Entra identities using SECURITY LABEL 3. Test Entra authentication for each migrated role 4. Disable passwords: ALTER ROLE "username" PASSWORD NULL 5. Switch to "Microsoft Entra authentication only" mode
Script: See scripts/migrate-to-entra.sh
MCP Tools Used
| Tool | Purpose |
|---|---|
postgres_server_list | List PostgreSQL servers in subscription |
postgres_database_list | List databases on a server |
postgres_database_query | Execute SQL (role creation, permissions) |
postgres_server_param_get | Get server parameter (e.g., group sync) |
postgres_server_param_set | Set server parameter |
Security Best Practices
| Practice | Recommendation |
|---|---|
| Least Privilege | Grant minimum required permissions; avoid admin roles for apps |
| Use Groups | Manage access via Entra groups for easier administration |
| Managed Identity | Always use managed identity for Azure-hosted apps |
| MFA for Admins | Set isMfa=true for admin roles if tenant supports optional MFA |
| Token Handling | Never store tokens; acquire fresh before each connection |
| Audit Access | Use pgaadauth_list_principals to review who has access |
| Private Endpoint | Use private endpoint for production; configure NSG for AzureActiveDirectory tag |
Common Issues
| Issue | Cause | Solution |
|---|---|---|
role does not exist | Role not created in database | Run pgaadauth_create_principal or pgaadauth_create_principal_with_oid |
password authentication failed | Token expired (5-60 min validity) | Get fresh token with az account get-access-token |
permission denied | Role exists but lacks permissions | Run GRANT statements for required access |
| Username case mismatch | Entra names are case-sensitive | Use exact case from Azure AD |
| Network timeout | Private endpoint missing NSG rule | Add outbound rule for AzureActiveDirectory service tag |
| Guest user login fails | Using wrong UPN format | Use full UPN with #EXT# tag |
References
- Azure CLI Commands - Token acquisition, identity lookups, admin management
- SQL Functions - Role creation, listing, security labels
- Permission Templates - Copy-paste SQL for common scenarios
- Group Sync Guide - Group sync configuration details
- Troubleshooting Guide - Detailed diagnostic steps
Azure PostgreSQL Group Sync Configuration
This guide explains how group-based access control works with Microsoft Entra ID authentication in Azure Database for PostgreSQL.
Overview
When you create a PostgreSQL role mapped to an Entra group, group members can access the database. There are two modes:
| Mode | Setting | Behavior | Best For |
|---|---|---|---|
| Sync Disabled | pgaadauth.enable_group_sync=OFF | Members use group name as username | Simple setups, shared audit trail |
| Sync Enabled | pgaadauth.enable_group_sync=ON | Individual member roles auto-created | Per-user auditing, fine-grained permissions |
Mode 1: Group Sync Disabled (Default)
How It Works
1. Create a group role in PostgreSQL 2. Grant permissions to the group 3. Group members sign in using the group name as their username 4. All members share the same PostgreSQL role
Setup
# Get group object ID
GROUP_ID=$(az ad group show --group "Database Readers" --query id -o tsv)
# Connect as admin
export PGPASSWORD=$(az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv)
psql "host=<server>.postgres.database.azure.com user=admin@domain.com dbname=postgres sslmode=require"-- Create group role
SELECT * FROM pgaadauth_create_principal_with_oid('Database Readers', '<group-id>', 'group', false, false);
-- Grant permissions
GRANT CONNECT ON DATABASE mydb TO "Database Readers";
GRANT USAGE ON SCHEMA public TO "Database Readers";
GRANT SELECT ON ALL TABLES IN SCHEMA public TO "Database Readers";Member Connection
Group members connect using the group name as their username:
# Bash
export PGPASSWORD=$(az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv)
psql "host=<server>.postgres.database.azure.com user='Database Readers' dbname=mydb sslmode=require"# PowerShell
$env:PGPASSWORD = az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv
psql "host=<server>.postgres.database.azure.com user='Database Readers' dbname=mydb sslmode=require"Note: For group names with spaces, escape or quote the name:
user='Database Readers'user=Database\ Readers
Pros and Cons
| Pros | Cons |
|---|---|
| Simple setup | Can't distinguish users in audit logs |
| Instant membership effect | Can't grant per-user permissions |
| Single role to manage | Username is the group name, not intuitive |
---
Mode 2: Group Sync Enabled
How It Works
1. Create a group role in PostgreSQL 2. Enable group sync server parameter 3. Individual PostgreSQL roles are auto-created for each group member 4. Sync runs automatically every 30 minutes 5. Members sign in with their own UPN
Setup
# Enable group sync
az postgres flexible-server parameter set \
--resource-group <rg> \
--server-name <server> \
--name pgaadauth.enable_group_sync \
--value ON
# Get group object ID
GROUP_ID=$(az ad group show --group "Database Readers" --query id -o tsv)
# Connect as admin
export PGPASSWORD=$(az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv)
psql "host=<server>.postgres.database.azure.com user=admin@domain.com dbname=postgres sslmode=require"-- Create group role
SELECT * FROM pgaadauth_create_principal_with_oid('Database Readers', '<group-id>', 'group', false, false);
-- Grant permissions to the group (inherited by synced members)
GRANT CONNECT ON DATABASE mydb TO "Database Readers";
GRANT USAGE ON SCHEMA public TO "Database Readers";
GRANT SELECT ON ALL TABLES IN SCHEMA public TO "Database Readers";
-- Trigger manual sync (optional, otherwise wait 30 min)
SELECT * FROM pgaadauth_sync_roles_for_group_members();Member Connection
With sync enabled, members connect using their own UPN:
# Bash
export PGPASSWORD=$(az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv)
psql "host=<server>.postgres.database.azure.com user=developer@company.com dbname=mydb sslmode=require"# PowerShell
$env:PGPASSWORD = az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv
psql "host=<server>.postgres.database.azure.com user=developer@company.com dbname=mydb sslmode=require"Pros and Cons
| Pros | Cons |
|---|---|
| Individual audit trails | 30-min sync delay for new members |
| Can grant per-user permissions | More roles to manage |
| Users sign in with their own name | Group role must NOT be deleted |
---
Important Considerations
Group Role Management
DO NOT delete the group role when sync is enabled. The group role is needed to maintain the member-group relationship.
-- WRONG: Don't do this
DROP ROLE "Database Readers"; -- Breaks sync!
-- CORRECT: Disable login if needed, but keep the role
ALTER ROLE "Database Readers" NOLOGIN;Manual Sync
Trigger sync immediately instead of waiting 30 minutes:
SELECT * FROM pgaadauth_sync_roles_for_group_members();Checking Sync Status
View all synced member roles:
SELECT * FROM pgaadauth_list_principals(false);Permission Inheritance
When sync is enabled:
- Permissions granted to the group are inherited by member roles
- You can also grant additional permissions to individual member roles
- Revoking from the group affects all synced members
Nested Groups
- Nested groups (groups within groups) are not supported
- Only direct members of the group are synced
- If you need hierarchical access, create separate group roles
---
Switching Modes
Enable Sync (OFF → ON)
az postgres flexible-server parameter set \
--resource-group <rg> \
--server-name <server> \
--name pgaadauth.enable_group_sync \
--value ONThen trigger sync:
SELECT * FROM pgaadauth_sync_roles_for_group_members();Disable Sync (ON → OFF)
az postgres flexible-server parameter set \
--resource-group <rg> \
--server-name <server> \
--name pgaadauth.enable_group_sync \
--value OFFNote: Existing synced member roles remain; they won't be deleted automatically.
---
Troubleshooting
New group member can't connect (sync enabled)
1. Wait up to 30 minutes, or trigger manual sync:
SELECT * FROM pgaadauth_sync_roles_for_group_members();2. Verify user is in the Azure AD group:
az ad group member list --group "Database Readers" --query "[].userPrincipalName"3. Check if role was created:
SELECT * FROM pgaadauth_list_principals(false) WHERE rolename = 'user@domain.com';Group login fails (sync disabled)
1. Ensure username is the group name, not individual UPN 2. Escape spaces in group name: user='Group Name' or user=Group\ Name 3. Check group role exists:
SELECT * FROM pgaadauth_list_principals(false) WHERE principaltype = 'group';Changes to group membership not reflected
1. Check the pgaadauth.enable_group_sync setting:
az postgres flexible-server parameter show \
--resource-group <rg> \
--server-name <server> \
--name pgaadauth.enable_group_sync2. If sync is OFF, changes are immediate (members use group name) 3. If sync is ON, wait 30 min or run manual sync
PostgreSQL Permission Templates
Copy-paste SQL templates for common permission scenarios when setting up Entra ID authentication.
Permission Levels
Read-Only Access
Grants SELECT access to all tables in the public schema.
-- Replace <database> and <role-name> with actual values
-- <role-name> should be the UPN (user@domain.com) or custom role name
GRANT CONNECT ON DATABASE <database> TO "<role-name>";
GRANT USAGE ON SCHEMA public TO "<role-name>";
GRANT SELECT ON ALL TABLES IN SCHEMA public TO "<role-name>";
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO "<role-name>";
-- Grant permissions on future tables
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO "<role-name>";
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON SEQUENCES TO "<role-name>";---
Read-Write Access
Grants SELECT, INSERT, UPDATE, DELETE on all tables.
GRANT CONNECT ON DATABASE <database> TO "<role-name>";
GRANT USAGE ON SCHEMA public TO "<role-name>";
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO "<role-name>";
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO "<role-name>";
-- Grant permissions on future tables
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "<role-name>";
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT USAGE, SELECT ON SEQUENCES TO "<role-name>";---
Full Admin Access
Grants all privileges including ability to create objects.
GRANT ALL PRIVILEGES ON DATABASE <database> TO "<role-name>";
GRANT ALL PRIVILEGES ON SCHEMA public TO "<role-name>";
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "<role-name>";
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO "<role-name>";
GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO "<role-name>";
-- Grant permissions on future objects
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO "<role-name>";
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO "<role-name>";
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON FUNCTIONS TO "<role-name>";
-- Add to azure_pg_admin role (Azure PostgreSQL admin group)
GRANT azure_pg_admin TO "<role-name>";---
Application-Specific Access
For applications that need access to specific tables only.
-- Connect permission
GRANT CONNECT ON DATABASE <database> TO "<role-name>";
GRANT USAGE ON SCHEMA public TO "<role-name>";
-- Specific tables only
GRANT SELECT, INSERT, UPDATE ON <table1> TO "<role-name>";
GRANT SELECT, INSERT, UPDATE, DELETE ON <table2> TO "<role-name>";
GRANT SELECT ON <readonly_table> TO "<role-name>";
-- Specific sequences
GRANT USAGE, SELECT ON <table1>_id_seq TO "<role-name>";
GRANT USAGE, SELECT ON <table2>_id_seq TO "<role-name>";---
Schema-Specific Access
For multi-tenant or multi-schema databases.
-- Grant access to a specific schema
GRANT CONNECT ON DATABASE <database> TO "<role-name>";
GRANT USAGE ON SCHEMA <schema-name> TO "<role-name>";
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA <schema-name> TO "<role-name>";
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA <schema-name> TO "<role-name>";
-- Future tables in that schema
ALTER DEFAULT PRIVILEGES IN SCHEMA <schema-name>
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "<role-name>";
ALTER DEFAULT PRIVILEGES IN SCHEMA <schema-name>
GRANT USAGE, SELECT ON SEQUENCES TO "<role-name>";---
Quick Copy Templates
For User (developer@company.com)
-- Read-Only
GRANT CONNECT ON DATABASE mydb TO "developer@company.com";
GRANT USAGE ON SCHEMA public TO "developer@company.com";
GRANT SELECT ON ALL TABLES IN SCHEMA public TO "developer@company.com";
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO "developer@company.com";
-- Read-Write
GRANT CONNECT ON DATABASE mydb TO "developer@company.com";
GRANT USAGE ON SCHEMA public TO "developer@company.com";
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO "developer@company.com";
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "developer@company.com";For Managed Identity (my-app-identity)
-- Read-Write (typical for applications)
GRANT CONNECT ON DATABASE mydb TO "my-app-identity";
GRANT USAGE ON SCHEMA public TO "my-app-identity";
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO "my-app-identity";
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO "my-app-identity";
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "my-app-identity";
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT ON SEQUENCES TO "my-app-identity";For Group (Database Readers)
-- Note: Group names with spaces must be quoted
GRANT CONNECT ON DATABASE mydb TO "Database Readers";
GRANT USAGE ON SCHEMA public TO "Database Readers";
GRANT SELECT ON ALL TABLES IN SCHEMA public TO "Database Readers";
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO "Database Readers";---
Revoking Permissions
Revoke All Permissions
-- Revoke grants
REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM "<role-name>";
REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM "<role-name>";
REVOKE USAGE ON SCHEMA public FROM "<role-name>";
REVOKE CONNECT ON DATABASE <database> FROM "<role-name>";
-- Remove default privileges
ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE ALL ON TABLES FROM "<role-name>";
ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE ALL ON SEQUENCES FROM "<role-name>";Drop Role Completely
-- First revoke all privileges
REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM "<role-name>";
REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM "<role-name>";
REVOKE ALL PRIVILEGES ON DATABASE <database> FROM "<role-name>";
REVOKE USAGE ON SCHEMA public FROM "<role-name>";
-- Then drop the role
DROP ROLE "<role-name>";---
Checking Existing Permissions
-- List all roles
\du
-- Show grants for a specific role
SELECT
grantee,
table_schema,
table_name,
privilege_type
FROM information_schema.role_table_grants
WHERE grantee = '<role-name>';
-- Show database-level permissions
SELECT datname, datacl FROM pg_database WHERE datname = '<database>';
-- Show schema permissions
SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'public';
-- List Entra-mapped roles with their properties
SELECT * FROM pgaadauth_list_principals(false);Authentication — Python SDK Quick Reference
Condensed from azure-identity-py. Full patterns (async,
ChainedTokenCredential, token caching, all credential types)
in the azure-identity-py plugin skill if installed.
Install
pip install azure-identityQuick Start
from azure.identity import DefaultAzureCredential
credential = DefaultAzureCredential()Best Practices
- Use DefaultAzureCredential for code that runs locally and in Azure
- Never hardcode credentials — use environment variables or managed identity
- Prefer managed identity in production Azure deployments
- Use ChainedTokenCredential when you need a custom credential order
- Close async credentials explicitly or use context managers
- Set AZURE_CLIENT_ID env var for user-assigned managed identities
- Exclude unused credentials to speed up authentication
Authentication — TypeScript SDK Quick Reference
Condensed from azure-identity-ts. Full patterns (sovereign clouds,
device code flow, custom credentials, bearer token provider)
in the azure-identity-ts plugin skill if installed.
Install
npm install @azure/identity
Quick Start
import { DefaultAzureCredential } from "@azure/identity";
const credential = new DefaultAzureCredential();Best Practices
- Use DefaultAzureCredential — works in development (CLI) and production (managed identity)
- Never hardcode credentials — use environment variables or managed identity
- Prefer managed identity — no secrets to manage in production
- Scope credentials appropriately — use user-assigned identity for multi-tenant scenarios
- Handle token refresh — Azure SDK handles this automatically
- Use ChainedTokenCredential for custom fallback scenarios
PostgreSQL — TypeScript SDK Quick Reference
Condensed from azure-postgres-ts. Full patterns (connection pooling,
transactions, Entra ID auth, parameterized queries)
in the azure-postgres-ts plugin skill if installed.
Install
npm install pg @azure/identity npm install -D @types/pg
Quick Start
import { Pool } from "pg";
const pool = new Pool({ host: process.env.AZURE_POSTGRESQL_HOST, database: process.env.AZURE_POSTGRESQL_DATABASE, port: 5432, ssl: { rejectUnauthorized: true } });Best Practices
- Always use connection pools for production applications
- Use parameterized queries — never concatenate user input
- Always close connections — use try/finally or connection pools
- Enable SSL — required for Azure (
ssl: { rejectUnauthorized: true }) - Handle token refresh — Entra ID tokens expire after ~1 hour
- Set connection timeouts — avoid hanging on network issues
- Use transactions for multi-statement operations
- Monitor pool metrics — track totalCount, idleCount, waitingCount
- Graceful shutdown — call
pool.end()on application termination - Use TypeScript generics — type your query results for safety
PostgreSQL Management — .NET SDK Quick Reference
Condensed from azure-resource-manager-postgresql-dotnet. Full patterns
(server creation, firewall rules, HA, backups, parameters, replicas)
in the azure-resource-manager-postgresql-dotnet plugin skill if installed.
Install
dotnet add package Azure.ResourceManager.PostgreSql dotnet add package Azure.Identity
Quick Start
using Azure.ResourceManager;
using Azure.Identity;
var armClient = new ArmClient(new DefaultAzureCredential());Best Practices
- Use Flexible Server — Single Server is deprecated
- Enable zone-redundant HA for production workloads
- Use DefaultAzureCredential — prefer over connection strings
- Configure Entra ID authentication — more secure than SQL auth alone
- Enable both auth methods — Entra ID + password for flexibility
- Set appropriate backup retention — 7-35 days based on compliance
- Use private endpoints for secure network access
- Tune server parameters based on workload characteristics
- Use read replicas for read-heavy workloads
- Stop dev/test servers to save costs when not in use
-- ============================================================================= -- SQL Functions for Azure PostgreSQL Entra ID Authentication -- Run these commands after connecting as an Entra admin -- =============================================================================
-- ============================================================================= -- CREATE ROLES -- =============================================================================
-- Create role for a user (by name - must match UPN exactly) SELECT * FROM pgaadauth_create_principal('user@domain.com', false, false); -- Arguments: -- 'user@domain.com' = roleName (must match Entra principal name exactly) -- false = isAdmin (true = azure_pg_admin member) -- false = isMfa (true = require MFA claim in token)
-- Create role for a user as admin SELECT * FROM pgaadauth_create_principal('admin@domain.com', true, false);
-- Create role using object ID (more reliable for managed identities, service principals, groups) SELECT * FROM pgaadauth_create_principal_with_oid( 'my-custom-role-name', -- roleName: any name you choose 'abc12345-1234-1234-1234-123456789012', -- objectId: Entra object ID (GUID) 'service', -- objectType: 'user', 'group', or 'service' false, -- isAdmin false -- isMfa );
-- Object Types: -- 'user' = Entra users (including guests) -- 'group' = Entra groups -- 'service' = Service principals and managed identities
-- ============================================================================= -- LIST ROLES -- =============================================================================
-- List all Entra-mapped roles SELECT * FROM pgaadauth_list_principals(false);
-- List only admin roles SELECT * FROM pgaadauth_list_principals(true);
-- Returns: rolename, principalType, objectId, tenantId, isMfa, isAdmin
-- ============================================================================= -- ENABLE ENTRA ON EXISTING ROLE (SECURITY LABEL) -- =============================================================================
-- Map an existing PostgreSQL role to an Entra identity SECURITY LABEL for "pgaadauth" on role "existing_role" is 'aadauth,oid=<object-id>,type=user';
-- With admin privileges SECURITY LABEL for "pgaadauth" on role "existing_admin" is 'aadauth,oid=<object-id>,type=user,admin';
-- For a group SECURITY LABEL for "pgaadauth" on role "existing_group_role" is 'aadauth,oid=<group-object-id>,type=group';
-- For a service principal or managed identity SECURITY LABEL for "pgaadauth" on role "existing_app_role" is 'aadauth,oid=<service-principal-object-id>,type=service';
-- ============================================================================= -- MANUAL GROUP SYNC -- =============================================================================
-- Trigger manual sync of group members (if group sync is enabled) SELECT * FROM pgaadauth_sync_roles_for_group_members();
-- ============================================================================= -- DROP ROLES -- =============================================================================
-- Drop an Entra-mapped role DROP ROLE "user@domain.com";
-- Note: For groups with sync enabled, do NOT delete the group role -- Instead, disable login if needed: ALTER ROLE "Group Name" NOLOGIN;
Troubleshooting Azure PostgreSQL Entra ID Authentication
This guide helps diagnose and resolve common authentication issues when connecting to Azure Database for PostgreSQL using Microsoft Entra ID.
Quick Diagnostic Checklist
Run through this checklist when authentication fails:
| Check | Command | Expected |
|---|---|---|
| Role exists in database | SELECT * FROM pgaadauth_list_principals(false); | Your role appears in list |
| Token is fresh | Check timestamp from az account get-access-token | expiresOn is in the future |
| Username format correct | Compare with role name in database | Exact match (case-sensitive) |
| Network connectivity | nslookup login.microsoftonline.com | Resolves to IP address |
| DNS for Graph API | nslookup graph.microsoft.com | Resolves to IP address |
| Entra admin exists | az postgres flexible-server microsoft-entra-admin list | At least one admin |
Common Errors and Solutions
Error: role "user@domain.com" does not exist
Cause: The PostgreSQL role hasn't been created for this Entra identity.
Solution:
1. Connect as an Entra admin:
export PGPASSWORD=$(az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv)
psql "host=<server>.postgres.database.azure.com user=admin@domain.com dbname=postgres sslmode=require"2. Create the role:
-- By name (for users)
SELECT * FROM pgaadauth_create_principal('user@domain.com', false, false);
-- By object ID (for managed identities/service principals)
SELECT * FROM pgaadauth_create_principal_with_oid('my-identity', '<object-id>', 'service', false, false);---
Error: password authentication failed for user "user@domain.com"
Cause: Token is expired, invalid, or wrong format.
Solution:
1. Get a fresh token:
# Bash
export PGPASSWORD=$(az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv)
# PowerShell
$env:PGPASSWORD = az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv2. Verify token validity:
az account get-access-token --resource-type oss-rdbms --query expiresOn -o tsv3. Ensure you're logged in as the correct user:
az account show --query user.name -o tsv---
Error: FATAL: password authentication failed (no username in error)
Cause: Username format is incorrect or doesn't match the database role.
Solution:
1. Check the exact role name in the database:
SELECT * FROM pgaadauth_list_principals(false);2. Use the exact role name (case-sensitive) in your connection:
# If role is "Developer@Company.com", use exactly that
psql "host=<server>.postgres.database.azure.com user=Developer@Company.com dbname=mydb sslmode=require"3. For guest users, use the full UPN with #EXT#:
psql "host=<server>.postgres.database.azure.com user=guest_user_example.com#EXT#@tenant.onmicrosoft.com dbname=mydb sslmode=require"---
Error: could not connect to server: Connection timed out
Cause: Network/firewall blocking connection or incorrect server name.
Solution:
1. Verify server FQDN:
az postgres flexible-server show --resource-group <rg> --name <server> --query fullyQualifiedDomainName -o tsv2. Check firewall rules:
az postgres flexible-server firewall-rule list --resource-group <rg> --name <server>3. For private endpoint, verify NSG allows outbound to AzureActiveDirectory service tag:
# Check NSG rules
az network nsg rule list --resource-group <rg> --nsg-name <nsg-name>4. Verify DNS resolution:
nslookup <server>.postgres.database.azure.com
nslookup login.microsoftonline.com
nslookup graph.microsoft.com---
Error: SSL SYSCALL error: Connection reset by peer
Cause: TLS/SSL connection issue, often network-related.
Solution:
1. Ensure sslmode=require is in connection string 2. Check if proxy/firewall is intercepting TLS traffic 3. For private endpoint, verify route table has AzureActiveDirectory → Internet
---
Error: Token acquisition fails
Cause: Not logged into Azure CLI or wrong account.
Solution:
1. Log in to Azure:
az login2. Select the correct subscription:
az account set --subscription <subscription-id>3. Verify you have access:
az account show4. For service principal authentication:
az login --service-principal -u <client-id> -p <client-secret> --tenant <tenant-id>---
Error: Cannot validate Microsoft Entra ID user because its name isn't unique
Cause: Multiple objects in Azure AD have the same display name.
Solution:
Use pgaadauth_create_principal_with_oid instead:
-- Get the object ID first
-- az ad user show --id user@domain.com --query id -o tsv
SELECT * FROM pgaadauth_create_principal_with_oid('unique-role-name', '<object-id>', 'user', false, false);---
Error: Group member can't connect (group sync enabled)
Cause: Group sync hasn't run yet (runs every 30 minutes).
Solution:
1. Manually trigger sync:
SELECT * FROM pgaadauth_sync_roles_for_group_members();2. Wait a few seconds and check roles:
SELECT * FROM pgaadauth_list_principals(false);3. Verify the user is actually in the Azure AD group:
az ad group member list --group "Group Name" --query "[].userPrincipalName" -o tsv---
Error: Managed identity can't connect from Azure-hosted app
Cause: Application not using Azure Identity SDK correctly.
Solution:
1. Verify managed identity is enabled on the app:
# For Container Apps
az containerapp identity show --name <app> --resource-group <rg>
# For App Service
az webapp identity show --name <app> --resource-group <rg>2. Ensure the correct role name is used (must match exactly what was created in PostgreSQL)
3. Check application code uses Azure Identity SDK
4. Verify managed identity object ID matches what's in PostgreSQL:
# Get MI object ID
az identity show --name <identity> --resource-group <rg> --query principalId -o tsv
# Compare with database
psql -c "SELECT * FROM pgaadauth_list_principals(false);"---
Diagnostic Commands Reference
Check Entra Admin Status
az postgres flexible-server microsoft-entra-admin list \
--resource-group <rg> \
--server-name <server>List All Entra-Mapped Roles
SELECT * FROM pgaadauth_list_principals(false);Check Role Permissions
-- List all roles
\du
-- Check grants on a database
\l
-- Check table permissions
\dp
-- Detailed permission check
SELECT * FROM information_schema.role_table_grants WHERE grantee = 'user@domain.com';Verify Token
# Get token and check expiration
az account get-access-token --resource-type oss-rdbms
# Decode token (optional, for debugging)
# The accessToken is a JWT - you can decode it at jwt.io to verify claimsTest Network Connectivity
# DNS resolution
nslookup <server>.postgres.database.azure.com
nslookup login.microsoftonline.com
nslookup graph.microsoft.com
# TCP connectivity (port 5432)
nc -zv <server>.postgres.database.azure.com 5432
# Or using telnet
telnet <server>.postgres.database.azure.com 5432Check Server Parameters
# Check group sync setting
az postgres flexible-server parameter show \
--resource-group <rg> \
--server-name <server> \
--name pgaadauth.enable_group_syncStill Having Issues?
1. Enable diagnostic logging on the PostgreSQL server in Azure Portal 2. Check Azure Monitor logs for authentication failures 3. Verify RBAC permissions - you may need Contributor or specific PostgreSQL roles 4. Contact support with diagnostic output from the commands above
#!/bin/bash
# Azure CLI commands for Azure PostgreSQL Entra ID authentication
# This file contains commonly used commands - copy/paste and modify as needed
# =============================================================================
# ENTRA ADMIN MANAGEMENT
# =============================================================================
# List Entra admins
# This will fail if Entra auth is not enabled yet
az postgres flexible-server microsoft-entra-admin list \
--resource-group <resource-group> \
--server-name <server-name>
# Get your own object ID (current signed-in user)
OBJECT_ID=$(az ad signed-in-user show --query id -o tsv)
# IMPORTANT: Must enable Entra auth before attempting to create an admin
az postgres flexible-server update \
--subscription <subscription-id> \
--resource-group <resource-group> \
--name <server-name> \
--microsoft-entra-auth Enabled
# Add Entra admin
# This will fail if Entra auth is not enabled yet
az postgres flexible-server microsoft-entra-admin create \
--resource-group <resource-group> \
--server-name <server-name> \
--display-name "admin@domain.com" \
--object-id $OBJECT_ID \
--type User
# Remove Entra admin
az postgres flexible-server microsoft-entra-admin delete \
--resource-group <resource-group> \
--server-name <server-name> \
--object-id <object-id>
# =============================================================================
# TOKEN ACQUISITION & CONNECTION
# =============================================================================
# Get access token (use as password)
az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv
# Connect to PostgreSQL with token
export PGPASSWORD=$(az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv)
psql "host=<server>.postgres.database.azure.com user=<user>@domain.com dbname=<database> sslmode=require"
# For sovereign clouds, find resource URL
az cloud show --query endpoints.ossrdbmsResourceId
# =============================================================================
# IDENTITY LOOKUPS
# =============================================================================
# Get user object ID
az ad user show --id user@domain.com --query id -o tsv
# Get group object ID
az ad group show --group "Group Name" --query id -o tsv
# Get managed identity object ID
az identity show --name <identity-name> --resource-group <rg> --query principalId -o tsv
# Get service principal object ID (use Enterprise App, not App Registration)
az ad sp show --id <app-id> --query id -o tsv
# =============================================================================
# SERVER PARAMETERS
# =============================================================================
# Enable group sync
az postgres flexible-server parameter set \
--resource-group <resource-group> \
--server-name <server-name> \
--source user-override \
--name pgaadauth.enable_group_sync \
--value ON
# Disable group sync
az postgres flexible-server parameter set \
--resource-group <resource-group> \
--server-name <server-name> \
--source user-override \
--name pgaadauth.enable_group_sync \
--value OFF
# Check current value
az postgres flexible-server parameter show \
--resource-group <resource-group> \
--server-name <server-name> \
--name pgaadauth.enable_group_sync
# =============================================================================
# AUTHENTICATION MODE
# =============================================================================
# !!!IMPORTANT: Must enable Entra auth before attempting to create an admin
# Enable Entra-only authentication (disable password auth)
az postgres flexible-server update \
--resource-group <resource-group> \
--name <server-name> \
--microsoft-entra-auth Enabled \
--password-auth Disabled
# Enable both Entra and password authentication
az postgres flexible-server update \
--resource-group <resource-group> \
--name <server-name> \
--microsoft-entra-auth Enabled \
--password-auth Enabled
# Disable Entra authentication (password-only)
az postgres flexible-server update \
--resource-group <resource-group> \
--name <server-name> \
--microsoft-entra-auth Disabled \
--password-auth Enabled
#!/bin/bash
# Migrate existing PostgreSQL roles from password auth to Entra ID
# Usage: ./migrate-to-entra.sh <resource-group> <server-name>
set -e
# Parameters
RESOURCE_GROUP="${1:?Resource group required}"
SERVER_NAME="${2:?Server name required}"
echo "=== Azure PostgreSQL Migration to Entra ID ==="
echo "Resource Group: $RESOURCE_GROUP"
echo "Server: $SERVER_NAME"
echo ""
echo "WARNING: This script will help migrate password-based roles to Entra ID."
echo "Please ensure you have tested Entra authentication before running this."
echo ""
# Step 1: Verify server exists and get FQDN
echo "[1/5] Verifying server..."
SERVER_FQDN=$(az postgres flexible-server show \
--resource-group "$RESOURCE_GROUP" \
--name "$SERVER_NAME" \
--query fullyQualifiedDomainName -o tsv)
if [ -z "$SERVER_FQDN" ]; then
echo "ERROR: Server not found or not accessible"
exit 1
fi
echo "Server FQDN: $SERVER_FQDN"
# Step 2: Check current authentication mode
echo ""
echo "[2/5] Checking authentication mode..."
AUTH_CONFIG=$(az postgres flexible-server show \
--resource-group "$RESOURCE_GROUP" \
--name "$SERVER_NAME" \
--query authConfig -o json)
echo "Current auth config:"
echo "$AUTH_CONFIG" | jq .
# Step 3: Get admin credentials
echo ""
echo "[3/5] Getting current user info..."
CURRENT_USER=$(az ad signed-in-user show --query userPrincipalName -o tsv)
echo "Current user (Entra admin): $CURRENT_USER"
export PGPASSWORD=$(az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv)
if [ -z "$PGPASSWORD" ]; then
echo "ERROR: Failed to acquire access token. Are you an Entra admin?"
exit 1
fi
echo "Token acquired"
# Step 4: List existing roles
echo ""
echo "[4/5] Listing existing PostgreSQL roles..."
echo ""
echo "=== Current PostgreSQL Roles ==="
psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=postgres sslmode=require" -c \
"SELECT rolname, rolcanlogin, rolsuper, rolcreatedb, rolcreaterole
FROM pg_roles
WHERE rolname NOT LIKE 'pg_%'
AND rolname NOT LIKE 'azure%'
AND rolname != 'replication'
ORDER BY rolname;"
echo ""
echo "=== Existing Entra-Mapped Roles ==="
psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=postgres sslmode=require" -c \
"SELECT * FROM pgaadauth_list_principals(false);" 2>/dev/null || echo "No Entra roles found"
# Step 5: Provide migration instructions
echo ""
echo "[5/5] Migration Instructions"
echo ""
echo "=== Migration Steps ==="
echo ""
echo "For EACH role you want to migrate to Entra ID:"
echo ""
echo "1. Find the Azure AD object ID for the user/group/service principal:"
echo " # For a user:"
echo " az ad user show --id user@domain.com --query id -o tsv"
echo ""
echo " # For a group:"
echo " az ad group show --group 'Group Name' --query id -o tsv"
echo ""
echo " # For a managed identity:"
echo " az identity show --name <identity-name> --resource-group <rg> --query principalId -o tsv"
echo ""
echo "2. Map the existing role to the Entra identity using SECURITY LABEL:"
echo " SECURITY LABEL for \"pgaadauth\" on role \"existing_role_name\" is 'aadauth,oid=<object-id>,type=user';"
echo ""
echo " Object types: user, group, service (for managed identities and service principals)"
echo ""
echo "3. Test Entra authentication for the migrated role:"
echo " export PGPASSWORD=\$(az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv)"
echo " psql \"host=$SERVER_FQDN user=user@domain.com dbname=<database> sslmode=require\""
echo ""
echo "4. After verifying Entra auth works, disable the password:"
echo " ALTER ROLE \"existing_role_name\" PASSWORD NULL;"
echo ""
echo "5. Once all roles are migrated, switch to 'Microsoft Entra authentication only' mode:"
echo " az postgres flexible-server update \\"
echo " --resource-group $RESOURCE_GROUP \\"
echo " --name $SERVER_NAME \\"
echo " --microsoft-entra-auth Enabled \\"
echo " --password-auth Disabled"
echo ""
echo "=== Example Migration Commands ==="
echo ""
echo "# Connect as Entra admin"
echo "export PGPASSWORD=\$(az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv)"
echo "psql \"host=$SERVER_FQDN user=$CURRENT_USER dbname=postgres sslmode=require\""
echo ""
echo "# Inside psql, run for each role:"
echo "-- Get object ID first: az ad user show --id developer@company.com --query id -o tsv"
echo "SECURITY LABEL for \"pgaadauth\" on role \"developer_role\" is 'aadauth,oid=abc12345-1234-1234-1234-123456789012,type=user';"
echo ""
echo "# Verify the mapping"
echo "SELECT * FROM pgaadauth_list_principals(false);"
echo ""
echo "# After testing Entra auth, disable password"
echo "ALTER ROLE \"developer_role\" PASSWORD NULL;"
#!/bin/bash
# Setup Group-based access for Azure PostgreSQL Flexible Server
# Usage: ./setup-group.sh <resource-group> <server-name> <group-name> <database> <permission-level> [enable-sync]
# Permission levels: readonly, readwrite, admin
# enable-sync: true/false (default: false)
set -e
# Parameters
RESOURCE_GROUP="${1:?Resource group required}"
SERVER_NAME="${2:?Server name required}"
GROUP_NAME="${3:?Group name required}"
DATABASE="${4:?Database name required}"
PERMISSION_LEVEL="${5:-readonly}"
ENABLE_SYNC="${6:-false}"
echo "=== Azure PostgreSQL Group Access Setup ==="
echo "Resource Group: $RESOURCE_GROUP"
echo "Server: $SERVER_NAME"
echo "Group: $GROUP_NAME"
echo "Database: $DATABASE"
echo "Permission Level: $PERMISSION_LEVEL"
echo "Enable Group Sync: $ENABLE_SYNC"
echo ""
# Step 1: Verify server exists and get FQDN
echo "[1/8] Verifying server..."
SERVER_FQDN=$(az postgres flexible-server show \
--resource-group "$RESOURCE_GROUP" \
--name "$SERVER_NAME" \
--query fullyQualifiedDomainName -o tsv)
if [ -z "$SERVER_FQDN" ]; then
echo "ERROR: Server not found or not accessible"
exit 1
fi
echo "Server FQDN: $SERVER_FQDN"
# Step 2: Get group details from Azure AD
echo ""
echo "[2/8] Getting group details from Azure AD..."
GROUP_INFO=$(az ad group show --group "$GROUP_NAME" --query "{id:id, displayName:displayName}" -o json 2>/dev/null || echo "")
if [ -z "$GROUP_INFO" ] || [ "$GROUP_INFO" = "" ]; then
echo "ERROR: Group '$GROUP_NAME' not found in Azure AD"
exit 1
fi
GROUP_ID=$(echo "$GROUP_INFO" | jq -r '.id')
GROUP_DISPLAY_NAME=$(echo "$GROUP_INFO" | jq -r '.displayName')
echo "Group ID: $GROUP_ID"
echo "Group Display Name: $GROUP_DISPLAY_NAME"
# List group members
echo ""
echo "Group members:"
az ad group member list --group "$GROUP_NAME" --query "[].{displayName:displayName, userPrincipalName:userPrincipalName}" -o table
# Step 3: Check if Entra admin exists
echo ""
echo "[3/8] Checking Entra admin status..."
ADMIN_COUNT=$(az postgres flexible-server microsoft-entra-admin list \
--resource-group "$RESOURCE_GROUP" \
--server-name "$SERVER_NAME" \
--query "length(@)" -o tsv)
if [ "$ADMIN_COUNT" -eq 0 ]; then
echo "ERROR: No Entra admin configured. Add an Entra admin first."
exit 1
fi
echo "Entra admin configured: $ADMIN_COUNT admin(s)"
# Step 4: Get current user info (must be Entra admin)
echo ""
echo "[4/8] Getting current user info..."
CURRENT_USER=$(az ad signed-in-user show --query userPrincipalName -o tsv)
echo "Current user: $CURRENT_USER"
# Step 5: Get access token
echo ""
echo "[5/8] Acquiring access token..."
export PGPASSWORD=$(az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv)
if [ -z "$PGPASSWORD" ]; then
echo "ERROR: Failed to acquire access token"
exit 1
fi
echo "Token acquired (valid for 5-60 minutes)"
# Step 6: Configure group sync parameter if requested
echo ""
echo "[6/8] Configuring group sync..."
if [ "$ENABLE_SYNC" = "true" ]; then
az postgres flexible-server parameter set \
--resource-group "$RESOURCE_GROUP" \
--server-name "$SERVER_NAME" \
--source user-override \
--name pgaadauth.enable_group_sync \
--value ON \
--output none
echo "Group sync ENABLED (members will get individual roles, auto-synced every 30 min)"
else
echo "Group sync DISABLED (members use group name as username)"
fi
# Step 7: Create PostgreSQL role for the group
echo ""
echo "[7/8] Creating PostgreSQL role for group..."
# Check if role already exists
ROLE_EXISTS=$(psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=postgres sslmode=require" -t -c \
"SELECT 1 FROM pgaadauth_list_principals(false) WHERE objectid = '$GROUP_ID';" 2>/dev/null | tr -d ' ')
if [ "$ROLE_EXISTS" = "1" ]; then
echo "Role already exists for group '$GROUP_DISPLAY_NAME'"
else
# Create role using object ID
psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=postgres sslmode=require" -c \
"SELECT * FROM pgaadauth_create_principal_with_oid('$GROUP_DISPLAY_NAME', '$GROUP_ID', 'group', false, false);"
echo "Role created successfully"
fi
# If sync is enabled, trigger manual sync
if [ "$ENABLE_SYNC" = "true" ]; then
echo ""
echo "Triggering manual group member sync..."
psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=postgres sslmode=require" -c \
"SELECT * FROM pgaadauth_sync_roles_for_group_members();" || echo "Note: Sync may take a moment to complete"
fi
# Step 8: Grant permissions based on level
echo ""
echo "[8/8] Granting $PERMISSION_LEVEL permissions on $DATABASE..."
# Escape the group name for PostgreSQL (handle spaces)
ESCAPED_GROUP_NAME=$(echo "$GROUP_DISPLAY_NAME" | sed 's/"/\\"/g')
case "$PERMISSION_LEVEL" in
readonly)
psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=$DATABASE sslmode=require" <<EOF
GRANT CONNECT ON DATABASE $DATABASE TO "$ESCAPED_GROUP_NAME";
GRANT USAGE ON SCHEMA public TO "$ESCAPED_GROUP_NAME";
GRANT SELECT ON ALL TABLES IN SCHEMA public TO "$ESCAPED_GROUP_NAME";
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO "$ESCAPED_GROUP_NAME";
EOF
;;
readwrite)
psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=$DATABASE sslmode=require" <<EOF
GRANT CONNECT ON DATABASE $DATABASE TO "$ESCAPED_GROUP_NAME";
GRANT USAGE ON SCHEMA public TO "$ESCAPED_GROUP_NAME";
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO "$ESCAPED_GROUP_NAME";
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "$ESCAPED_GROUP_NAME";
EOF
;;
admin)
psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=$DATABASE sslmode=require" <<EOF
GRANT ALL PRIVILEGES ON DATABASE $DATABASE TO "$ESCAPED_GROUP_NAME";
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "$ESCAPED_GROUP_NAME";
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO "$ESCAPED_GROUP_NAME";
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO "$ESCAPED_GROUP_NAME";
EOF
psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=postgres sslmode=require" -c \
"GRANT azure_pg_admin TO \"$ESCAPED_GROUP_NAME\";"
;;
*)
echo "ERROR: Invalid permission level. Use: readonly, readwrite, or admin"
exit 1
;;
esac
echo ""
echo "=== Setup Complete ==="
echo ""
echo "Group: $GROUP_DISPLAY_NAME"
echo "Group ID: $GROUP_ID"
echo "Group Sync: $ENABLE_SYNC"
echo ""
if [ "$ENABLE_SYNC" = "true" ]; then
echo "Group members can connect using their individual UPN:"
echo " export PGPASSWORD=\$(az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv)"
echo " psql \"host=$SERVER_FQDN user=member@domain.com dbname=$DATABASE sslmode=require\""
echo ""
echo "Note: New group members are synced automatically every 30 minutes."
echo "To force sync: SELECT * FROM pgaadauth_sync_roles_for_group_members();"
else
echo "Group members connect using the GROUP NAME as username:"
echo " export PGPASSWORD=\$(az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv)"
echo " psql \"host=$SERVER_FQDN user='$GROUP_DISPLAY_NAME' dbname=$DATABASE sslmode=require\""
echo ""
echo "Note: Spaces in group name must be escaped: 'Group\\ Name'"
fi
#!/bin/bash
# Setup Managed Identity access for Azure PostgreSQL Flexible Server
# Usage: ./setup-managed-identity.sh <resource-group> <server-name> <identity-name> <identity-resource-group> <database> <permission-level>
# Permission levels: readonly, readwrite, admin
set -e
# Parameters
RESOURCE_GROUP="${1:?Resource group required}"
SERVER_NAME="${2:?Server name required}"
IDENTITY_NAME="${3:?Managed identity name required}"
IDENTITY_RG="${4:?Identity resource group required}"
DATABASE="${5:?Database name required}"
PERMISSION_LEVEL="${6:-readwrite}"
echo "=== Azure PostgreSQL Managed Identity Setup ==="
echo "Resource Group: $RESOURCE_GROUP"
echo "Server: $SERVER_NAME"
echo "Managed Identity: $IDENTITY_NAME (in $IDENTITY_RG)"
echo "Database: $DATABASE"
echo "Permission Level: $PERMISSION_LEVEL"
echo ""
# Step 1: Verify server exists and get FQDN
echo "[1/7] Verifying server..."
SERVER_FQDN=$(az postgres flexible-server show \
--resource-group "$RESOURCE_GROUP" \
--name "$SERVER_NAME" \
--query fullyQualifiedDomainName -o tsv)
if [ -z "$SERVER_FQDN" ]; then
echo "ERROR: Server not found or not accessible"
exit 1
fi
echo "Server FQDN: $SERVER_FQDN"
# Step 2: Get managed identity details
echo ""
echo "[2/7] Getting managed identity details..."
IDENTITY_INFO=$(az identity show \
--name "$IDENTITY_NAME" \
--resource-group "$IDENTITY_RG" \
--query "{principalId:principalId, clientId:clientId}" -o json)
PRINCIPAL_ID=$(echo "$IDENTITY_INFO" | jq -r '.principalId')
CLIENT_ID=$(echo "$IDENTITY_INFO" | jq -r '.clientId')
if [ -z "$PRINCIPAL_ID" ] || [ "$PRINCIPAL_ID" = "null" ]; then
echo "ERROR: Managed identity not found"
exit 1
fi
echo "Principal ID (Object ID): $PRINCIPAL_ID"
echo "Client ID: $CLIENT_ID"
# Step 3: Check if Entra admin exists
echo ""
echo "[3/7] Checking Entra admin status..."
ADMIN_COUNT=$(az postgres flexible-server microsoft-entra-admin list \
--resource-group "$RESOURCE_GROUP" \
--server-name "$SERVER_NAME" \
--query "length(@)" -o tsv)
if [ "$ADMIN_COUNT" -eq 0 ]; then
echo "ERROR: No Entra admin configured. Add an Entra admin first."
exit 1
fi
echo "Entra admin configured: $ADMIN_COUNT admin(s)"
# Step 4: Get current user info (must be Entra admin)
echo ""
echo "[4/7] Getting current user info..."
CURRENT_USER=$(az ad signed-in-user show --query userPrincipalName -o tsv)
echo "Current user: $CURRENT_USER"
# Step 5: Get access token
echo ""
echo "[5/7] Acquiring access token..."
export PGPASSWORD=$(az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv)
if [ -z "$PGPASSWORD" ]; then
echo "ERROR: Failed to acquire access token"
exit 1
fi
echo "Token acquired (valid for 5-60 minutes)"
# Step 6: Create PostgreSQL role for the managed identity
echo ""
echo "[6/7] Creating PostgreSQL role for managed identity..."
# Check if role already exists
ROLE_EXISTS=$(psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=postgres sslmode=require" -t -c \
"SELECT 1 FROM pgaadauth_list_principals(false) WHERE objectid = '$PRINCIPAL_ID';" 2>/dev/null | tr -d ' ')
if [ "$ROLE_EXISTS" = "1" ]; then
echo "Role already exists for this managed identity"
ROLE_NAME=$(psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=postgres sslmode=require" -t -c \
"SELECT rolename FROM pgaadauth_list_principals(false) WHERE objectid = '$PRINCIPAL_ID';" | tr -d ' ')
else
# Create role using object ID (more reliable for managed identities)
psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=postgres sslmode=require" -c \
"SELECT * FROM pgaadauth_create_principal_with_oid('$IDENTITY_NAME', '$PRINCIPAL_ID', 'service', false, false);"
ROLE_NAME="$IDENTITY_NAME"
echo "Role created successfully"
fi
echo "PostgreSQL role name: $ROLE_NAME"
# Step 7: Grant permissions based on level
echo ""
echo "[7/7] Granting $PERMISSION_LEVEL permissions on $DATABASE..."
case "$PERMISSION_LEVEL" in
readonly)
psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=$DATABASE sslmode=require" <<EOF
GRANT CONNECT ON DATABASE $DATABASE TO "$ROLE_NAME";
GRANT USAGE ON SCHEMA public TO "$ROLE_NAME";
GRANT SELECT ON ALL TABLES IN SCHEMA public TO "$ROLE_NAME";
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO "$ROLE_NAME";
EOF
;;
readwrite)
psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=$DATABASE sslmode=require" <<EOF
GRANT CONNECT ON DATABASE $DATABASE TO "$ROLE_NAME";
GRANT USAGE ON SCHEMA public TO "$ROLE_NAME";
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO "$ROLE_NAME";
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "$ROLE_NAME";
EOF
;;
admin)
psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=$DATABASE sslmode=require" <<EOF
GRANT ALL PRIVILEGES ON DATABASE $DATABASE TO "$ROLE_NAME";
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "$ROLE_NAME";
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO "$ROLE_NAME";
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO "$ROLE_NAME";
EOF
psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=postgres sslmode=require" -c \
"GRANT azure_pg_admin TO \"$ROLE_NAME\";"
;;
*)
echo "ERROR: Invalid permission level. Use: readonly, readwrite, or admin"
exit 1
;;
esac
echo ""
echo "=== Setup Complete ==="
echo ""
echo "Managed Identity: $IDENTITY_NAME"
echo "PostgreSQL Role: $ROLE_NAME"
echo "Client ID: $CLIENT_ID"
echo ""
echo "Your application can now connect using Azure Identity SDK."
echo "See the examples/ folder for code samples in different languages."
echo ""
echo "Connection string format:"
echo " host=$SERVER_FQDN;database=$DATABASE;user=$ROLE_NAME;sslmode=require"
#!/bin/bash
# Setup Entra ID user access for Azure PostgreSQL Flexible Server
# Usage: ./setup-user.sh <resource-group> <server-name> <user-upn> <database> <permission-level>
# Permission levels: readonly, readwrite, admin
set -e
# Parameters
RESOURCE_GROUP="${1:?Resource group required}"
SERVER_NAME="${2:?Server name required}"
USER_UPN="${3:?User UPN required (e.g., user@domain.com)}"
DATABASE="${4:?Database name required}"
PERMISSION_LEVEL="${5:-readonly}"
echo "=== Azure PostgreSQL Entra User Setup ==="
echo "Resource Group: $RESOURCE_GROUP"
echo "Server: $SERVER_NAME"
echo "User: $USER_UPN"
echo "Database: $DATABASE"
echo "Permission Level: $PERMISSION_LEVEL"
echo ""
# Step 1: Verify server exists and get FQDN
echo "[1/6] Verifying server..."
SERVER_FQDN=$(az postgres flexible-server show \
--resource-group "$RESOURCE_GROUP" \
--name "$SERVER_NAME" \
--query fullyQualifiedDomainName -o tsv)
if [ -z "$SERVER_FQDN" ]; then
echo "ERROR: Server not found or not accessible"
exit 1
fi
echo "Server FQDN: $SERVER_FQDN"
# Step 2: Check if Entra admin exists
echo ""
echo "[2/6] Checking Entra admin status..."
ADMIN_COUNT=$(az postgres flexible-server microsoft-entra-admin list \
--resource-group "$RESOURCE_GROUP" \
--server-name "$SERVER_NAME" \
--query "length(@)" -o tsv)
if [ "$ADMIN_COUNT" -eq 0 ]; then
echo "ERROR: No Entra admin configured. Add an Entra admin first:"
echo " az postgres flexible-server microsoft-entra-admin create \\"
echo " --resource-group $RESOURCE_GROUP \\"
echo " --server-name $SERVER_NAME \\"
echo " --display-name <admin-upn> \\"
echo " --object-id <admin-object-id> \\"
echo " --type User"
exit 1
fi
echo "Entra admin configured: $ADMIN_COUNT admin(s)"
# Step 3: Get current user info (must be Entra admin)
echo ""
echo "[3/6] Getting current user info..."
CURRENT_USER=$(az ad signed-in-user show --query userPrincipalName -o tsv)
echo "Current user: $CURRENT_USER"
# Step 4: Get access token
echo ""
echo "[4/6] Acquiring access token..."
export PGPASSWORD=$(az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv)
if [ -z "$PGPASSWORD" ]; then
echo "ERROR: Failed to acquire access token"
exit 1
fi
echo "Token acquired (valid for 5-60 minutes)"
# Step 5: Create PostgreSQL role for the user
echo ""
echo "[5/6] Creating PostgreSQL role for $USER_UPN..."
# Check if role already exists
ROLE_EXISTS=$(psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=postgres sslmode=require" -t -c \
"SELECT 1 FROM pgaadauth_list_principals(false) WHERE rolename = '$USER_UPN';" 2>/dev/null | tr -d ' ')
if [ "$ROLE_EXISTS" = "1" ]; then
echo "Role already exists for $USER_UPN"
else
psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=postgres sslmode=require" -c \
"SELECT * FROM pgaadauth_create_principal('$USER_UPN', false, false);"
echo "Role created successfully"
fi
# Step 6: Grant permissions based on level
echo ""
echo "[6/6] Granting $PERMISSION_LEVEL permissions on $DATABASE..."
case "$PERMISSION_LEVEL" in
readonly)
psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=$DATABASE sslmode=require" <<EOF
GRANT CONNECT ON DATABASE $DATABASE TO "$USER_UPN";
GRANT USAGE ON SCHEMA public TO "$USER_UPN";
GRANT SELECT ON ALL TABLES IN SCHEMA public TO "$USER_UPN";
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO "$USER_UPN";
EOF
;;
readwrite)
psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=$DATABASE sslmode=require" <<EOF
GRANT CONNECT ON DATABASE $DATABASE TO "$USER_UPN";
GRANT USAGE ON SCHEMA public TO "$USER_UPN";
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO "$USER_UPN";
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "$USER_UPN";
EOF
;;
admin)
psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=$DATABASE sslmode=require" <<EOF
GRANT ALL PRIVILEGES ON DATABASE $DATABASE TO "$USER_UPN";
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "$USER_UPN";
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO "$USER_UPN";
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO "$USER_UPN";
EOF
psql "host=$SERVER_FQDN user=$CURRENT_USER dbname=postgres sslmode=require" -c \
"GRANT azure_pg_admin TO \"$USER_UPN\";"
;;
*)
echo "ERROR: Invalid permission level. Use: readonly, readwrite, or admin"
exit 1
;;
esac
echo ""
echo "=== Setup Complete ==="
echo ""
echo "User $USER_UPN can now connect using:"
echo ""
echo " # Get token"
echo " export PGPASSWORD=\$(az account get-access-token --resource-type oss-rdbms --query accessToken -o tsv)"
echo ""
echo " # Connect"
echo " psql \"host=$SERVER_FQDN user=$USER_UPN dbname=$DATABASE sslmode=require\""
{
"schema_version": "2.0",
"meta": {
"generated_at": "2026-02-21T08:39:29.657Z",
"slug": "microsoft-azure-postgres",
"source_url": "https://github.com/microsoft/github-copilot-for-azure/tree/main/plugin/skills/azure-postgres/",
"source_ref": "main",
"model": "claude",
"analysis_version": "3.0.0",
"source_type": "community",
"content_hash": "8b8a21bed230124b7d177b4bc5c4912494cb2b1c966c59e1f22b6ecb188eff97",
"tree_hash": "d0454cfebc9af09e059ead912e63e7d7c7117c4483f555ec19c14d5a250e741f"
},
"skill": {
"name": "azure-postgres",
"description": "Create new Azure Database for PostgreSQL Flexible Server instances and configure passwordless authentication with Microsoft Entra ID. Set up developer access, managed identities for apps, group-based permissions, and migrate from password-based to Entra ID authentication. Trigger phrases include \"passwordless for postgres\", \"entra id postgres\", \"azure ad postgres authentication\", \"postgres managed identity\", \"migrate postgres to passwordless\".",
"summary": "Configure passwordless Entra ID authentication for Azure PostgreSQL Flexible Server with managed identities and group-based access control",
"icon": "📦",
"version": "1.0.0",
"author": "microsoft",
"license": "MIT",
"tags": [
"azure",
"postgresql",
"entra-id",
"passwordless",
"managed-identity"
],
"supported_tools": [
"claude",
"codex",
"claude-code"
],
"risk_factors": [
"external_commands",
"filesystem",
"env_access",
"network"
]
},
"security_audit": {
"risk_level": "safe",
"is_blocked": false,
"safe_to_publish": true,
"summary": "This is an official Microsoft skill providing Azure PostgreSQL documentation. All static findings are false positives: the detected patterns are Azure CLI commands and SQL code examples in markdown documentation, not executable code. The 'Windows SAM database' alerts are triggered by PostgreSQL SECURITY LABEL syntax. No malicious intent detected.",
"critical_findings": [],
"high_findings": [],
"medium_findings": [],
"low_findings": [],
"dangerous_patterns": [],
"files_scanned": 15,
"total_lines": 1983,
"audit_model": "claude",
"audited_at": "2026-02-21T08:39:29.657Z",
"risk_factors": [
"scripts",
"network",
"filesystem",
"env_access",
"external_commands"
],
"risk_factor_evidence": [
{
"factor": "external_commands",
"evidence": [
{
"file": "SKILL.md",
"line_start": 22,
"line_end": 110
}
]
},
{
"factor": "filesystem",
"evidence": [
{
"file": "SKILL.md",
"line_start": 56,
"line_end": 62
}
]
},
{
"factor": "env_access",
"evidence": [
{
"file": "references/sdk/azure-postgres-ts.md",
"line_start": 14,
"line_end": 14
}
]
},
{
"factor": "network",
"evidence": [
{
"file": "SKILL.md",
"line_start": 56,
"line_end": 62
}
]
}
]
},
"content": {
"user_title": "Configure Azure PostgreSQL Passwordless Authentication",
"value_statement": "Set up Microsoft Entra ID authentication for Azure PostgreSQL Flexible Server to eliminate password-based access and enable secure, passwordless connections for applications and developers.",
"seo_keywords": [
"Azure PostgreSQL",
"passwordless authentication",
"Entra ID postgres",
"Microsoft Entra PostgreSQL",
"Azure AD authentication",
"postgres managed identity",
"Claude Codex postgres",
"claude-code azure postgres",
"Azure flexible server postgres",
"postgresql entra id setup"
],
"actual_capabilities": [
"Configure Entra ID authentication for existing Azure PostgreSQL Flexible Server instances",
"Set up managed identity access for Azure-hosted applications",
"Create user and group-based permissions using Microsoft Entra ID",
"Migrate existing password-based authentication to passwordless Entra ID",
"Execute SQL queries and manage database roles through Azure MCP tools or CLI",
"Troubleshoot Entra ID authentication issues with diagnostic commands"
],
"limitations": [
"Does not create new PostgreSQL servers - focuses on configuring authentication for existing servers",
"Requires Azure subscription with existing PostgreSQL Flexible Server",
"Entra ID admin must be set up on the server before other users can be configured",
"Does not manage PostgreSQL server provisioning or infrastructure"
],
"use_cases": [
{
"title": "Enable Passwordless Authentication for Development Team",
"description": "Configure Azure PostgreSQL to use Microsoft Entra ID so developers can connect without storing database passwords",
"target_user": "Development team leads and DevOps engineers"
},
{
"title": "Set Up Application Managed Identity Access",
"description": "Configure Azure-hosted applications to authenticate to PostgreSQL using managed identities instead of credentials",
"target_user": "Application developers and cloud architects"
},
{
"title": "Migrate from Password to Entra ID Authentication",
"description": "Move existing PostgreSQL users and applications from password-based auth to Microsoft Entra ID",
"target_user": "Database administrators and security teams"
}
],
"prompt_templates": [
{
"title": "List PostgreSQL Servers",
"prompt": "List all Azure Database for PostgreSQL Flexible Server instances in my subscription using the azure__postgres MCP tool",
"scenario": "Quick inventory check"
},
{
"title": "Configure Entra ID Admin",
"prompt": "Set up Microsoft Entra ID as the authentication method for my Azure PostgreSQL server named {server-name} in resource group {rg-name}",
"scenario": "Initial Entra ID setup"
},
{
"title": "Create User with Entra ID",
"prompt": "Create a new database user in Azure PostgreSQL for Entra ID user {user-email} with read-only access to database {db-name}",
"scenario": "Adding new team member"
},
{
"title": "Migrate to Passwordless Auth",
"prompt": "Help me migrate my Azure PostgreSQL database from password authentication to Microsoft Entra ID passwordless authentication. Current server is {server-name} in {resource-group}",
"scenario": "Authentication migration"
}
],
"output_examples": [
{
"input": "Configure Entra ID authentication for my Azure PostgreSQL server",
"output": "I can help you set up Microsoft Entra ID authentication for Azure PostgreSQL. Here are the steps:\n\n1. Set Entra ID admin on your server:\n az postgres flexible-server ad-admin create \\\n --server-name YOUR_SERVER \\\n --resource-group YOUR_RG \\\n --display-name YOUR_ADMIN \\\n --object-id ADMIN_OBJECT_ID\n\n2. Create database users from Entra identities:\n SELECT * FROM pgaadauth_create_principal('user@domain.com', false, false);\n\nWould you like me to help with any specific step?"
},
{
"input": "Set up managed identity for my app to access PostgreSQL",
"output": "To configure managed identity access:\n\n1. Enable managed identity on your Azure app service:\n az webapp identity assign --name APP_NAME --resource-group RG\n\n2. Create a database role for the managed identity:\n SELECT * FROM pgaadauth_create_principal_with_oid(\n 'app-name',\n 'MANAGED-IDENTITY-OBJECT-ID',\n 'service',\n false,\n false\n );\n\n3. Grant database permissions:\n GRANT CONNECT ON DATABASE yourdb TO \"app-name\";\n GRANT USAGE ON SCHEMA public TO \"app-name\";\n GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"app-name\";"
}
],
"best_practices": [
"Always use Microsoft Entra ID authentication instead of password-based access for production databases",
"Enable managed identities for Azure-hosted applications to avoid storing credentials",
"Use group-based access control in Entra ID to manage PostgreSQL permissions centrally",
"Configure MFA requirements in Entra ID for additional security on database access"
],
"anti_patterns": [
"Do not use password-based authentication in production - it exposes credentials in connection strings",
"Avoid creating individual database users for each application - use managed identities instead",
"Do not grant excessive privileges like azure_pg_admin to application service principals",
"Avoid hardcoding database credentials in application code - always use Entra ID or managed identities"
],
"faq": [
{
"question": "What is Entra ID authentication for Azure PostgreSQL?",
"answer": "Entra ID authentication is Microsoft's passwordless authentication method that allows users and applications to connect to Azure PostgreSQL using Azure AD identities instead of database passwords."
},
{
"question": "How do I enable Entra ID on my PostgreSQL server?",
"answer": "Use Azure CLI to create an Entra ID admin: az postgres flexible-server ad-admin create --server-name SERVER --resource-group RG --display-name ADMIN --object-id OBJECT_ID"
},
{
"question": "What are managed identities and why use them?",
"answer": "Managed identities are Azure-provided identities for Azure resources. They eliminate the need to store credentials in application code and automatically rotate, improving security."
},
{
"question": "Can I migrate existing password users to Entra ID?",
"answer": "Yes, you can map existing PostgreSQL roles to Entra identities using SECURITY LABEL commands, then drop the password authentication method."
},
{
"question": "What MCP tools are available for Azure PostgreSQL?",
"answer": "The azure__postgres MCP tool provides: postgres_server_list, postgres_database_list, postgres_database_query, postgres_server_param_get, and postgres_server_param_set."
},
{
"question": "Does this skill create new PostgreSQL servers?",
"answer": "No, this skill focuses on configuring authentication for existing Azure PostgreSQL Flexible Server instances. Server creation is handled separately."
}
]
},
"file_structure": [
{
"name": "references",
"type": "dir",
"path": "references",
"children": [
{
"name": "sdk",
"type": "dir",
"path": "references/sdk",
"children": [
{
"name": "azure-identity-py.md",
"type": "file",
"path": "references/sdk/azure-identity-py.md",
"lines": 26
},
{
"name": "azure-identity-ts.md",
"type": "file",
"path": "references/sdk/azure-identity-ts.md",
"lines": 23
},
{
"name": "azure-postgres-ts.md",
"type": "file",
"path": "references/sdk/azure-postgres-ts.md",
"lines": 28
},
{
"name": "azure-resource-manager-postgresql-dotnet.md",
"type": "file",
"path": "references/sdk/azure-resource-manager-postgresql-dotnet.md",
"lines": 29
}
]
},
{
"name": "entra-rbac-overview.md",
"type": "file",
"path": "references/entra-rbac-overview.md",
"lines": 172
},
{
"name": "group-sync.md",
"type": "file",
"path": "references/group-sync.md",
"lines": 256
},
{
"name": "permission-templates.md",
"type": "file",
"path": "references/permission-templates.md",
"lines": 205
},
{
"name": "sql-functions.md",
"type": "file",
"path": "references/sql-functions.md",
"lines": 82
},
{
"name": "troubleshooting.md",
"type": "file",
"path": "references/troubleshooting.md",
"lines": 301
}
]
},
{
"name": "scripts",
"type": "dir",
"path": "scripts",
"children": [
{
"name": "az-commands.sh",
"type": "file",
"path": "scripts/az-commands.sh",
"lines": 122
},
{
"name": "migrate-to-entra.sh",
"type": "file",
"path": "scripts/migrate-to-entra.sh",
"lines": 126
},
{
"name": "setup-group.sh",
"type": "file",
"path": "scripts/setup-group.sh",
"lines": 194
},
{
"name": "setup-managed-identity.sh",
"type": "file",
"path": "scripts/setup-managed-identity.sh",
"lines": 158
},
{
"name": "setup-user.sh",
"type": "file",
"path": "scripts/setup-user.sh",
"lines": 136
}
]
},
{
"name": "SKILL.md",
"type": "file",
"path": "SKILL.md",
"lines": 125
}
]
}
Related skills
FAQ
What authentication does it set up?
Passwordless authentication with Microsoft Entra ID for Azure Database for PostgreSQL Flexible Server.
Which access patterns are supported?
Developer user access, managed identity for applications, and group-based access control, plus migration from password auth.