PostgreSQL integration
PostgreSQL is an open-source object-relational database management system.
Windmill provides a framework to support PostgreSQL databases, either with native SQL scripts or through TypeScript for raw queries.
Please refer to the SQL Getting started section.
IAM authentication for AWS RDS and Aurora
This feature is available on Windmill Enterprise Edition only.
Instead of using static passwords, you can authenticate to AWS RDS or Aurora PostgreSQL databases using IAM database authentication. Windmill workers generate short-lived authentication tokens automatically, so no database password needs to be stored in the resource.
This works with any of the standard AWS credential methods:
- IRSA (IAM Roles for Service Accounts)
- EKS Pod Identity
- EC2 Instance Profiles
Setup
-
Enable IAM authentication on your RDS instance. In the AWS console, go to your RDS instance settings and enable IAM database authentication.
-
Create a database user with the
rds_iamrole:
CREATE USER myuser WITH LOGIN;
GRANT rds_iam TO myuser;
- Grant IAM permissions to your worker. The IAM principal attached to your Windmill worker (via IRSA, Pod Identity, or Instance Profile) needs the
rds-db:connectaction. Example IAM policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "rds-db:connect",
"Resource": "arn:aws:rds-db:<region>:<account-id>:dbuser:<dbi-resource-id>/<db-user-name>"
}
]
}
- Create a PostgreSQL resource with IAM auth enabled. Set
use_iam_authtotrueand fill inhost,user, anddbname. Thepasswordfield is ignored when IAM auth is enabled.
{
"host": "mydb.cluster-abc123.us-east-1.rds.amazonaws.com",
"port": 5432,
"user": "myuser",
"dbname": "mydb",
"sslmode": "require",
"use_iam_auth": true,
"region": "us-east-1"
}
The region field is optional if the AWS_REGION environment variable is set on the worker. SSL is enforced automatically for IAM connections.
Azure workload identity for Azure Database for PostgreSQL
This feature is available on Windmill Enterprise Edition only.
On AKS, workers can authenticate to Azure Database for PostgreSQL Flexible Server as their own workload identity instead of with a password. The pod's projected service account token is exchanged with Microsoft Entra ID for a short-lived access token, so no database password is stored in the resource.
Setup
- Give the worker a workload identity. Enable the OIDC issuer and the workload identity add-on on the cluster, create a user-assigned managed identity, and add a federated credential binding it to the worker's Kubernetes service account:
az identity federated-credential create \
--name windmill-worker \
--identity-name <managed-identity-name> \
--resource-group <resource-group> \
--issuer "$(az aks show -n <cluster> -g <resource-group> --query oidcIssuerProfile.issuerUrl -o tsv)" \
--subject "system:serviceaccount:<namespace>:<worker-service-account>" \
--audience api://AzureADTokenExchange
Annotate the service account with azure.workload.identity/client-id: <client-id> and label the worker pods with azure.workload.identity/use: "true". The webhook then injects AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_FEDERATED_TOKEN_FILE and AZURE_AUTHORITY_HOST into the worker, which is where Windmill reads the identity from. Nothing about the identity is configured on the resource, so a worker reaching two databases as two different identities needs two worker groups.
- Create the database principal. Connect as the server's Entra administrator and map the managed identity:
SELECT * FROM pgaadauth_create_principal('<managed-identity-name>', false, false);
- Create a PostgreSQL resource with
ms_entraidas the password. That value is a sentinel rather than a real password: it tells the worker to authenticate as its workload identity.usermust be the Entra principal name created above.
{
"host": "myserver.postgres.database.azure.com",
"port": 5432,
"user": "<managed-identity-name>",
"dbname": "mydb",
"sslmode": "require",
"password": "ms_entraid"
}
SSL is enforced automatically for these connections, and the job logs state Using Azure Workload Identity whenever the sentinel takes effect. A resource whose password happens to be literally ms_entraid is treated the same way, so pick a different password if that ever collides.