From da44625664982d7af54b57af13be67597e2a416b Mon Sep 17 00:00:00 2001 From: Thomas Sapelza Date: Mon, 26 Jan 2026 13:23:04 +0100 Subject: [PATCH 1/7] polish the README.md and add new docs --- .editorconfig | 1 + README.md | 282 ++++++++++-------- docs/cluster-connection.md | 51 ++++ docs/database.md | 46 +++ docs/default-privilege.md | 70 +++++ docs/docker-environment.md | 114 +++++++ docs/grant.md | 75 +++++ .../{ => images}/apply-cluster-connection.png | Bin docs/{ => images}/created-role.png | Bin .../established-cluster-connection.png | Bin docs/{ => images}/role-in-table-pg-authid.png | Bin docs/role.md | 87 ++++++ docs/schema.md | 46 +++ 13 files changed, 643 insertions(+), 129 deletions(-) create mode 100644 docs/cluster-connection.md create mode 100644 docs/database.md create mode 100644 docs/default-privilege.md create mode 100644 docs/docker-environment.md create mode 100644 docs/grant.md rename docs/{ => images}/apply-cluster-connection.png (100%) rename docs/{ => images}/created-role.png (100%) rename docs/{ => images}/established-cluster-connection.png (100%) rename docs/{ => images}/role-in-table-pg-authid.png (100%) create mode 100644 docs/role.md create mode 100644 docs/schema.md diff --git a/.editorconfig b/.editorconfig index 718060d..838d8cf 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,6 +15,7 @@ indent_size = 2 [*.md] max_line_length = off +indent_size = 2 [Makefile*] indent_style = tab diff --git a/README.md b/README.md index 25bca81..70ba19c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,133 @@ # AboutBits PostgreSQL Operator -## Getting started +AboutBits PostgreSQL Operator is a Kubernetes operator that helps you manage PostgreSQL databases, roles (users), and privileges in a declarative way using Custom Resource Definitions (CRDs). + +## Usage + +This operator allows you to manage PostgreSQL resources using Kubernetes manifests. +Further documentation of each Custom Resource can be found here: + +- [ClusterConnection](docs/cluster-connection.md) – Define a connection to a PostgreSQL cluster. +- [Database](docs/database.md) - Manage databases. +- [Role](docs/role.md) - Manage roles (users). +- [Schema](docs/schema.md) - Manage schemas. +- [Grant](docs/grant.md) - Manage privileges. +- [DefaultPrivilege](docs/default-privilege.md) - Manage default privileges. + +### Showcase + +The following example shows how to set up a connection to a PostgreSQL cluster, create a database and schema, a login role (user), and configure permissions. + +```yaml +# Define a ClusterConnection resource to connect to a PostgreSQL cluster. +--- +apiVersion: v1 +kind: Secret +metadata: + name: my-postgres-secret +type: kubernetes.io/basic-auth +stringData: + username: postgres + password: password +--- +apiVersion: postgresql.aboutbits.it/v1 +kind: ClusterConnection +metadata: + name: my-postgres-connection +spec: + host: postgres-host + port: 5432 + database: postgres + adminSecretRef: + name: my-postgres-secret + +# Create a Database +--- +apiVersion: postgresql.aboutbits.it/v1 +kind: Database +metadata: + name: my-database +spec: + clusterRef: + name: my-postgres-connection + name: my_app_db + reclaimPolicy: Retain + owner: dba_user + +# Create a Schema +--- +apiVersion: postgresql.aboutbits.it/v1 +kind: Schema +metadata: + name: my-schema +spec: + clusterRef: + name: my-postgres-connection + name: my_app_schema + reclaimPolicy: Retain + owner: dba_user + +# Create a Login Role (User) +--- +apiVersion: v1 +kind: Secret +metadata: + name: my-app-user-secret +type: kubernetes.io/basic-auth +stringData: + password: secret_password +--- +apiVersion: postgresql.aboutbits.it/v1 +kind: Role +metadata: + name: my-role +spec: + clusterRef: + name: my-postgres-connection + name: my_app_user + passwordSecretRef: + name: my-app-user-secret + flags: + createdb: false + +# Configure Permissions +--- +apiVersion: postgresql.aboutbits.it/v1 +kind: Grant +metadata: + name: my-grant +spec: + clusterRef: + name: my-postgres-connection + database: my_app_db + role: my_app_user + objectType: schema + schema: my_app_schema + privileges: + - usage + +# Configure Default Privileges +--- +apiVersion: postgresql.aboutbits.it/v1 +kind: DefaultPrivilege +metadata: + name: my-default-privilege +spec: + clusterRef: + name: my-postgres-connection + database: my_app_db + role: my_app_user + owner: shared_developer_user + objectType: table + schema: my_app_schema + privileges: + - select + - insert + - update + - delete +``` + +## Contribute These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. @@ -12,7 +139,7 @@ To build the project, the following prerequisites must be met: - [Gradle](https://gradle.org/) (Optional) - [Docker](https://www.docker.com/) -### Setup configuration +### Setup To get started, call: @@ -20,11 +147,11 @@ To get started, call: make init ``` -### Running the project in the console +### Development You can run your application in dev mode that enables live coding and continuous testing using: -```shell script +```bash make run # or @@ -45,131 +172,22 @@ make test ./gradlew :operator:test ``` -### Run the project as a service in IntelliJ +#### Run the project as a service in IntelliJ 1. Open the `Services` tool on the left side of the IDE 2. Click on "+" and select "Quarkus" Afterward, the project can be started in IntelliJ by navigating to `Run` -> `Run '...'`. -## Test the CRD on the ephemeral Dev Services cluster +### Docker Environment -This example demonstrates how to set up a local development environment using Quarkus Dev Services to test the Operator manually. -As the K3s cluster port and the secrets change on every `./gradlew :operator:quarkusDev` run, you will have to manually update the port and secrets in the `~/.kube/config` every time. +See [Docker Environment](docs/docker-environment.md) for setting up a local development environment using Quarkus Dev Services. -### 1. Configure Kubeconfig from Dev Services - -When running in dev mode (`make run` or via IntelliJ), Quarkus starts the pre-configured K3s and PostgreSQL Dev Services. - -1. Access the Quarkus Dev UI at [http://localhost:8080/q/dev-ui/dev-services](http://localhost:8080/q/dev-ui/dev-services). -2. Locate the properties for the `kubernetes-client` Dev Service. -3. Convert these properties into a **Kubeconfig YAML** format, see the example below. -4. Merge this configuration into your local `~/.kube/config`. This allows your local environment to communicate with the ephemeral Kubernetes cluster provided by Dev Services. - -```yml -apiVersion: v1 -kind: Config -current-context: quarkus-cluster -clusters: -- cluster: - certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkekNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdGMyVnkKZG1WeUxXTmhRREUzTmpjNU56UTFNREF3SGhjTk1qWXdNVEE1TVRZd01UUXdXaGNOTXpZd01UQTNNVFl3TVRRdwpXakFqTVNFd0h3WURWUVFEREJock0zTXRjMlZ5ZG1WeUxXTmhRREUzTmpjNU56UTFNREF3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFRYlpRQmgzdlNXMVExd1pST0tBQ1NlY3dreXhQUXVjVm9FN0tVM1MrQnYKZ1hJYzdCREQrb2JqTXFETXZuRkpNUlBCYUw0R2RDVVNsRDM3QzJUV01DNjlvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVURPdkI4eWt1VFJBTDRjRjhNOUo4Cit3STh5U2t3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnQWlZb0RsR2txUXd6WXVzcno5V3RMcUdEMXE2SmR6TVYKdW1nTFFPeFdNTEFDSVFDenQyMmxVTXJMNm1zMnBSRTBpQmZ3azNLbGdKSmJzZkp0YlI0bW9mRE16UT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K - server: https://localhost:53658 - name: quarkus-cluster -# ... more clusters -contexts: -- context: - cluster: quarkus-cluster - namespace: default - user: quarkus-user - name: quarkus-context -# ... more contexts -users: -- name: quarkus-user - user: - client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJrakNDQVRlZ0F3SUJBZ0lJTlpCUDhySWZaTlV3Q2dZSUtvWkl6ajBFQXdJd0l6RWhNQjhHQTFVRUF3d1kKYXpOekxXTnNhV1Z1ZEMxallVQXhOelkzT1RjME5UQXdNQjRYRFRJMk1ERXdPVEUyTURFME1Gb1hEVEkzTURFdwpPVEUyTURFME1Gb3dNREVYTUJVR0ExVUVDaE1PYzNsemRHVnRPbTFoYzNSbGNuTXhGVEFUQmdOVkJBTVRESE41CmMzUmxiVHBoWkcxcGJqQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJIdnE1UWxVWVBFRldvYXEKRTJNRXI1cUM4TjBFMVkyRTJBTDcrYUl0a1YzYWZHRkkyMGtBODl1eEorc1phQ0ZzblJzYmE1ZmtuVEhPaGJtOApYZGpSeERxalNEQkdNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFmCkJnTlZIU01FR0RBV2dCUWJ3RktrRXhOaitCZjl2YVVNSGxtUi9oeC9PekFLQmdncWhrak9QUVFEQWdOSkFEQkcKQWlFQXlncll6eFIrZWoxWk5CdGdsZW5WT01HWWYrRWlPbkR6L1dzK1dQc1hnd0VDSVFEcEZhMlJ2RkRIVXhLMwpEODkzcGNLUkt1eU5MdXp6ZVZGODNlMURpckF1ZXc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlCZGpDQ0FSMmdBd0lCQWdJQkFEQUtCZ2dxaGtqT1BRUURBakFqTVNFd0h3WURWUVFEREJock0zTXRZMnhwClpXNTBMV05oUURFM05qYzVOelExTURBd0hoY05Nall3TVRBNU1UWXdNVFF3V2hjTk16WXdNVEEzTVRZd01UUXcKV2pBak1TRXdId1lEVlFRRERCaHJNM010WTJ4cFpXNTBMV05oUURFM05qYzVOelExTURBd1dUQVRCZ2NxaGtqTwpQUUlCQmdncWhrak9QUU1CQndOQ0FBVGNWU1NCOHdNakJIbHVOekVZb2krUUU1di9iUWl3cS81d2Jtb2hKU0FGCmZ2aE95eUhCcDBweDRRR0l6YU5BVm9kdkFIazRFV0ViMy9sMWpZVXNCSGlTbzBJd1FEQU9CZ05WSFE4QkFmOEUKQkFNQ0FxUXdEd1lEVlIwVEFRSC9CQVV3QXdFQi96QWRCZ05WSFE0RUZnUVVHOEJTcEJNVFkvZ1gvYjJsREI1WgprZjRjZnpzd0NnWUlLb1pJemowRUF3SURSd0F3UkFJZ2FJemlrUzN6THNSakZTdit1Ny9BbmRNQzdDWTZaREF4Ckp4T1pKbzJVTmVRQ0lFaVlLQlpEVjhVZDZHN3BGU2doSVU5UVZYQ3FYSmx6MHNRbWpnRTJUeUZHCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K - client-key-data: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUFuN1dTOWJGZUhlaUpKMmJHcHFFTjBJc28vQzR3VEVNRFBSdENRNzNYMmhvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFZStybENWUmc4UVZhaHFvVFl3U3Ztb0x3M1FUVmpZVFlBdnY1b2kyUlhkcDhZVWpiU1FEegoyN0VuNnhsb0lXeWRHeHRybCtTZE1jNkZ1YnhkMk5IRU9nPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo= -# ... more users -``` - -### 2. Create PostgreSQL Connection and Secret - -For the `postgresql` Dev Service, you can generate the necessary Custom Resources to test the Operator: - -1. From the Dev UI, get the `postgresql` Dev Service properties (username, password, host, port). -2. Convert the `postgresql` Dev Service properties to a **Basic Auth Secret** and a **ClusterConnection** CR instance. - For more details see class `ClusterConnectionSpec` or the `ClusterConnection` CRD definition from `build/kubernetes/clusterconnections.postgresql.aboutbits.it-v1.yml` as a reference. -3. Apply the generated files using IntelliJ or `kubectl`. - ![Apply Cluster Connection](docs/apply-cluster-connection.png) - -**Example Secret (`secret.yml`):** - -```yaml -apiVersion: v1 -kind: Secret -metadata: - name: quarkus-db-secret - labels: - app.kubernetes.io/name: quarkus-postgres -type: kubernetes.io/basic-auth -stringData: - # extracted from quarkus.datasource.username - username: root - # extracted from quarkus.datasource.password - password: password -``` - -**Example ClusterConnection (`cluster-connection.yml`):** - -```yaml -apiVersion: postgresql.aboutbits.it/v1 -kind: ClusterConnection -metadata: - name: quarkus-postgres-connection -spec: - adminSecretRef: - name: quarkus-db-secret - host: localhost - port: 5432 - database: postgres -``` - -![Established Cluster Connection](docs/established-cluster-connection.png) - -### 3. Create a Role - -Similarly, you can create a `Role` resource: - -1. Manually create a **Role** CR instance. - For more details see class `RoleSpec` or the `Role` CRD definition from `build/kubernetes/roles.postgresql.aboutbits.it-v1.yml` as a reference. -2. Apply the file using IntelliJ or `kubectl`. - -**Example Role (`role.yml`):** - -```yaml -apiVersion: postgresql.aboutbits.it/v1 -kind: Role -metadata: - name: test-role-from-crd -spec: - # The actual name of the role to be created in the PostgreSQL database - name: test-role-from-crd - comment: It simply works - # Connects this role definition to the specific Postgres ClusterConnection CR instance - clusterRef: - name: quarkus-postgres-connection - flags: - createdb: true - validUntil: "2026-12-31T23:59:59Z" -``` - -![Created Role](docs/created-role.png) -![Role in pg_authid](docs/role-in-table-pg-authid.png) - -## Packaging and running the application +## Build The application can be packaged using: -```shell script +```bash ./gradlew :operator:build ``` @@ -180,34 +198,40 @@ The application is now runnable using `java -jar build/quarkus-app/quarkus-run.j If you want to build an _über-jar_, execute the following command: -```shell script +```bash ./gradlew :operator:build -Dquarkus.package.jar.type=uber-jar ``` The application, packaged as an _über-jar_, is now runnable using `java -jar build/*-runner.jar`. -## Creating a native executable +### Creating a native executable You can create a native executable using: -```shell script +```bash ./gradlew :operator:build -Dquarkus.native.enabled=true ``` Or, if you don't have GraalVM installed, you can run the native executable build in a container using: -```shell script +```bash ./gradlew :operator:build -Dquarkus.native.enabled=true -Dquarkus.native.container-build=true ``` You can then execute your native executable with: `./build/postgresql-operator-1.0.0-SNAPSHOT-runner` -If you want to learn more about building native executables, please consult . +## Information + +About Bits is a company based in South Tyrol, Italy. You can find more information about us on [our website](https://aboutbits.it). + +### Support + +For support, please contact [info@aboutbits.it](mailto:info@aboutbits.it). + +### Credits + +- [All Contributors](https://github.com/aboutbits/postgresql-operator/graphs/contributors) -## Related Guides +### License -- Operator SDK ([guide](https://docs.quarkiverse.io/quarkus-operator-sdk/dev/index.html)): Quarkus extension for the Java Operator SDK (https://javaoperatorsdk.io) -- Helm ([guide](https://docs.quarkiverse.io/quarkus-helm/dev/index.html)): Quarkus extension for Kubernetes Helm charts -- SmallRye Health ([guide](https://quarkus.io/guides/smallrye-health)): Monitor service health -- Micrometer metrics ([guide](https://quarkus.io/guides/micrometer)): Instrument the runtime and your application with dimensional metrics using Micrometer. -- YAML Configuration ([guide](https://quarkus.io/guides/config-yaml)): Use YAML to configure your Quarkus application +The MIT License (MIT). Please see the [license file](LICENSE) for more information. diff --git a/docs/cluster-connection.md b/docs/cluster-connection.md new file mode 100644 index 0000000..d48d29e --- /dev/null +++ b/docs/cluster-connection.md @@ -0,0 +1,51 @@ +# ClusterConnection + +The `ClusterConnection` Custom Resource Definition (CRD) defines the connection details for a PostgreSQL cluster. +It specifies the host, port, database, and the credentials to use for administrative operations. + +Other Custom Resources (like `Database`, `Role`, `Schema`, `Grant`, `DefaultPrivilege`) reference to a specify target PostgreSQL cluster using `clusterRef` to be able to execute the operations on. + +## Spec + +| Field | Type | Description | Required | +|------------------|---------------------|-----------------------------------------------------------------------|----------| +| `host` | `string` | The hostname of the PostgreSQL instance. | Yes | +| `port` | `integer` | The port of the PostgreSQL instance (1-65535). | Yes | +| `database` | `string` | The database to connect to (usually `postgres` for admin operations). | Yes | +| `adminSecretRef` | `SecretRef` | Reference to the secret containing admin credentials. | Yes | +| `parameters` | `map[string]string` | Additional connection parameters. | No | + +### SecretRef + +| Field | Type | Description | Required | +|-------------|----------|---------------------------------------------------------------------|----------| +| `name` | `string` | Name of the secret. | Yes | +| `namespace` | `string` | Namespace of the secret. If not specified, uses the CR's namespace. | No | + +The referenced secret must be of type `kubernetes.io/basic-auth` and contain the keys `username` and `password`. + +### Example + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: my-db-secret +type: kubernetes.io/basic-auth +stringData: + username: postgres + password: password +``` + +```yaml +apiVersion: postgresql.aboutbits.it/v1 +kind: ClusterConnection +metadata: + name: my-postgres-connection +spec: + adminSecretRef: + name: my-db-secret + host: localhost + port: 5432 + database: postgres +``` diff --git a/docs/database.md b/docs/database.md new file mode 100644 index 0000000..4f4a88c --- /dev/null +++ b/docs/database.md @@ -0,0 +1,46 @@ +# Database + +The `Database` Custom Resource Definition (CRD) is responsible for managing PostgreSQL databases. + +## Spec + +| Field | Type | Description | Required | Immutable | +|-----------------|--------------------|------------------------------------------------------------------------------------------------------|----------|-----------| +| `clusterRef` | `ClusterReference` | Reference to the `ClusterConnection` to use. | Yes | No | +| `name` | `string` | The name of the database to create. | Yes | Yes | +| `owner` | `string` | The owner of the database. | No | No | +| `reclaimPolicy` | `string` | The policy for reclaiming the database when the CR is deleted. Values: `Retain` (Default), `Delete`. | No | No | + +### ClusterReference + +| Field | Type | Description | Required | +|-------------|----------|----------------------------------------------------------------------------------|----------| +| `name` | `string` | Name of the `ClusterConnection`. | Yes | +| `namespace` | `string` | Namespace of the `ClusterConnection`. If not specified, uses the CR's namespace. | No | + +### Reclaim Policy + +The `reclaimPolicy` controls what happens to the PostgreSQL database when the Custom Resource is deleted from Kubernetes. + +- `Retain` (Default): The database remains in the PostgreSQL cluster. Only the Kubernetes Custom Resource is deleted. This prevents accidental data loss. +- `Delete`: The database is dropped from the PostgreSQL cluster. **Warning:** This will permanently delete the database and all its data. + +## Example + +```yaml +apiVersion: postgresql.aboutbits.it/v1 +kind: Database +metadata: + name: my-database +spec: + clusterRef: + name: my-postgres-connection + name: my_database + owner: my_role + reclaimPolicy: Retain +``` + +## Official Documentation + +- [CREATE DATABASE](https://www.postgresql.org/docs/current/sql-createdatabase.html) +- [ALTER DATABASE](https://www.postgresql.org/docs/current/sql-alterdatabase.html) diff --git a/docs/default-privilege.md b/docs/default-privilege.md new file mode 100644 index 0000000..073700d --- /dev/null +++ b/docs/default-privilege.md @@ -0,0 +1,70 @@ +# DefaultPrivilege + +The `DefaultPrivilege` Custom Resource Definition (CRD) manages default privileges (ALTER DEFAULT PRIVILEGES) for objects created in the future. + +## Spec + +| Field | Type | Description | Required | Immutable | +|--------------|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------|-------------|-----------| +| `clusterRef` | `ClusterReference` | Reference to the `ClusterConnection` to use. | Yes | No | +| `database` | `string` | The database where default privileges apply. | Yes | Yes | +| `role` | `string` | The role to which default privileges are granted. | Yes | Yes | +| `owner` | `string` | The role that owns the objects (the creator). Default privileges apply to objects created by this role. | Yes | Yes | +| `objectType` | `string` | The type of object. | Yes | Yes | +| `schema` | `string` | The schema where default privileges apply. Required if `objectType` is `sequence` or `table`. Must NOT be set if `objectType` is `schema`. | Conditional | Yes | +| `privileges` | `array[string]` | List of privileges to grant. | Yes | No | + +### Object Types + +Supported object types: + +- `schema` +- `sequence` +- `table` + +### Privileges + +Supported privileges depend on the `objectType`: + +- `connect` +- `create` +- `delete` +- `insert` +- `maintain` +- `references` +- `select` +- `temporary` +- `trigger` +- `truncate` +- `update` +- `usage` + +### ClusterReference + +| Field | Type | Description | Required | +|-------------|----------|----------------------------------------------------------------------------------|----------| +| `name` | `string` | Name of the `ClusterConnection`. | Yes | +| `namespace` | `string` | Namespace of the `ClusterConnection`. If not specified, uses the CR's namespace. | No | + +## Example + +```yaml +apiVersion: postgresql.aboutbits.it/v1 +kind: DefaultPrivilege +metadata: + name: default-privileges-tables +spec: + clusterRef: + name: my-postgres-connection + database: my_database + role: read_only_role + owner: app_user + objectType: table + schema: public + privileges: + - select +``` + +## Official Documentation + +- [ALTER DEFAULT PRIVILEGES](https://www.postgresql.org/docs/current/sql-alterdefaultprivileges.html) diff --git a/docs/docker-environment.md b/docs/docker-environment.md new file mode 100644 index 0000000..5eff244 --- /dev/null +++ b/docs/docker-environment.md @@ -0,0 +1,114 @@ +# Docker Environment + +This example demonstrates how to set up a local development environment using Quarkus Dev Services to test the Operator manually. +As the K3s cluster port and the secrets change on every `./gradlew :operator:quarkusDev` run, you will have to manually update the port and secrets in the `~/.kube/config` every time. + +## 1. Configure Kubeconfig from Dev Services + +When running in dev mode (`make run` or via IntelliJ), Quarkus starts the pre-configured K3s and PostgreSQL Dev Services. + +1. Access the Quarkus Dev UI at [http://localhost:8080/q/dev-ui/dev-services](http://localhost:8080/q/dev-ui/dev-services). +2. Locate the properties for the `kubernetes-client` Dev Service. +3. Convert these properties into a **Kubeconfig YAML** format, see the example below. +4. Merge this configuration into your local `~/.kube/config`. This allows your local environment to communicate with the ephemeral Kubernetes cluster provided by Dev Services. + +```yml +apiVersion: v1 +kind: Config +current-context: quarkus-cluster +clusters: + - cluster: + certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkekNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdGMyVnkKZG1WeUxXTmhRREUzTmpjNU56UTFNREF3SGhjTk1qWXdNVEE1TVRZd01UUXdXaGNOTXpZd01UQTNNVFl3TVRRdwpXakFqTVNFd0h3WURWUVFEREJock0zTXRjMlZ5ZG1WeUxXTmhRREUzTmpjNU56UTFNREF3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFRYlpRQmgzdlNXMVExd1pST0tBQ1NlY3dreXhQUXVjVm9FN0tVM1MrQnYKZ1hJYzdCREQrb2JqTXFETXZuRkpNUlBCYUw0R2RDVVNsRDM3QzJUV01DNjlvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVURPdkI4eWt1VFJBTDRjRjhNOUo4Cit3STh5U2t3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnQWlZb0RsR2txUXd6WXVzcno5V3RMcUdEMXE2SmR6TVYKdW1nTFFPeFdNTEFDSVFDenQyMmxVTXJMNm1zMnBSRTBpQmZ3azNLbGdKSmJzZkp0YlI0bW9mRE16UT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + server: https://localhost:53658 + name: quarkus-cluster +# ... more clusters +contexts: + - context: + cluster: quarkus-cluster + namespace: default + user: quarkus-user + name: quarkus-context +# ... more contexts +users: + - name: quarkus-user + user: + client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJrakNDQVRlZ0F3SUJBZ0lJTlpCUDhySWZaTlV3Q2dZSUtvWkl6ajBFQXdJd0l6RWhNQjhHQTFVRUF3d1kKYXpOekxXTnNhV1Z1ZEMxallVQXhOelkzT1RjME5UQXdNQjRYRFRJMk1ERXdPVEUyTURFME1Gb1hEVEkzTURFdwpPVEUyTURFME1Gb3dNREVYTUJVR0ExVUVDaE1PYzNsemRHVnRPbTFoYzNSbGNuTXhGVEFUQmdOVkJBTVRESE41CmMzUmxiVHBoWkcxcGJqQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJIdnE1UWxVWVBFRldvYXEKRTJNRXI1cUM4TjBFMVkyRTJBTDcrYUl0a1YzYWZHRkkyMGtBODl1eEorc1phQ0ZzblJzYmE1ZmtuVEhPaGJtOApYZGpSeERxalNEQkdNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFmCkJnTlZIU01FR0RBV2dCUWJ3RktrRXhOaitCZjl2YVVNSGxtUi9oeC9PekFLQmdncWhrak9QUVFEQWdOSkFEQkcKQWlFQXlncll6eFIrZWoxWk5CdGdsZW5WT01HWWYrRWlPbkR6L1dzK1dQc1hnd0VDSVFEcEZhMlJ2RkRIVXhLMwpEODkzcGNLUkt1eU5MdXp6ZVZGODNlMURpckF1ZXc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlCZGpDQ0FSMmdBd0lCQWdJQkFEQUtCZ2dxaGtqT1BRUURBakFqTVNFd0h3WURWUVFEREJock0zTXRZMnhwClpXNTBMV05oUURFM05qYzVOelExTURBd0hoY05Nall3TVRBNU1UWXdNVFF3V2hjTk16WXdNVEEzTVRZd01UUXcKV2pBak1TRXdId1lEVlFRRERCaHJNM010WTJ4cFpXNTBMV05oUURFM05qYzVOelExTURBd1dUQVRCZ2NxaGtqTwpQUUlCQmdncWhrak9QUU1CQndOQ0FBVGNWU1NCOHdNakJIbHVOekVZb2krUUU1di9iUWl3cS81d2Jtb2hKU0FGCmZ2aE95eUhCcDBweDRRR0l6YU5BVm9kdkFIazRFV0ViMy9sMWpZVXNCSGlTbzBJd1FEQU9CZ05WSFE4QkFmOEUKQkFNQ0FxUXdEd1lEVlIwVEFRSC9CQVV3QXdFQi96QWRCZ05WSFE0RUZnUVVHOEJTcEJNVFkvZ1gvYjJsREI1WgprZjRjZnpzd0NnWUlLb1pJemowRUF3SURSd0F3UkFJZ2FJemlrUzN6THNSakZTdit1Ny9BbmRNQzdDWTZaREF4Ckp4T1pKbzJVTmVRQ0lFaVlLQlpEVjhVZDZHN3BGU2doSVU5UVZYQ3FYSmx6MHNRbWpnRTJUeUZHCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + client-key-data: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUFuN1dTOWJGZUhlaUpKMmJHcHFFTjBJc28vQzR3VEVNRFBSdENRNzNYMmhvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFZStybENWUmc4UVZhaHFvVFl3U3Ztb0x3M1FUVmpZVFlBdnY1b2kyUlhkcDhZVWpiU1FEegoyN0VuNnhsb0lXeWRHeHRybCtTZE1jNkZ1YnhkMk5IRU9nPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo= +# ... more users +``` + +## 2. Create PostgreSQL Connection and Secret + +For the `postgresql` Dev Service, you can generate the necessary Custom Resources to test the Operator: + +1. From the Dev UI, get the `postgresql` Dev Service properties (username, password, host, port). +2. Convert the `postgresql` Dev Service properties to a **Basic Auth Secret** and a **ClusterConnection** CR instance. + For more details see the [ClusterConnection](cluster-connection.md) CRD definition. +3. Apply the generated files using IntelliJ or `kubectl`. + ![Apply Cluster Connection](images/apply-cluster-connection.png) + +**Example Secret (`secret.yml`):** + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: quarkus-db-secret + labels: + app.kubernetes.io/name: quarkus-postgres +type: kubernetes.io/basic-auth +stringData: + # extracted from quarkus.datasource.username + username: root + # extracted from quarkus.datasource.password + password: password +``` + +**Example ClusterConnection (`cluster-connection.yml`):** + +```yaml +apiVersion: postgresql.aboutbits.it/v1 +kind: ClusterConnection +metadata: + name: quarkus-postgres-connection +spec: + adminSecretRef: + name: quarkus-db-secret + host: localhost + port: 5432 + database: postgres +``` + +![Established Cluster Connection](images/established-cluster-connection.png) + +## 3. Create a Role + +Similarly, you can create a `Role` resource: + +1. Manually create a **Role** CR instance. + For more details see the [Role](role.md) CRD definition. +2. Apply the file using IntelliJ or `kubectl`. + +**Example Role (`role.yml`):** + +```yaml +apiVersion: postgresql.aboutbits.it/v1 +kind: Role +metadata: + name: test-role-from-crd +spec: + # The actual name of the role to be created in the PostgreSQL database + name: test-role-from-crd + comment: It simply works + # Connects this role definition to the specific Postgres ClusterConnection CR instance + clusterRef: + name: quarkus-postgres-connection + flags: + createdb: true + validUntil: "2026-12-31T23:59:59Z" +``` + +![Created Role](images/created-role.png) +![Role in pg_authid](images/role-in-table-pg-authid.png) + +The same principle applies to other CRDs. diff --git a/docs/grant.md b/docs/grant.md new file mode 100644 index 0000000..1377e1f --- /dev/null +++ b/docs/grant.md @@ -0,0 +1,75 @@ +# Grant + +The `Grant` Custom Resource Definition (CRD) is responsible for managing privileges (GRANT/REVOKE) on PostgreSQL objects. + +## Spec + +| Field | Type | Description | Required | Immutable | +|--------------|--------------------|--------------------------------------------------------------------------------------------------|-------------|-----------| +| `clusterRef` | `ClusterReference` | Reference to the `ClusterConnection` to use. | Yes | No | +| `database` | `string` | The database containing the objects. | Yes | Yes | +| `role` | `string` | The role to which privileges are granted. | Yes | Yes | +| `objectType` | `string` | The type of object. | Yes | Yes | +| `objects` | `array[string]` | List of object names. Required if `objectType` is `sequence` or `table`. | Conditional | No | +| `schema` | `string` | The schema containing the objects. Required if `objectType` is `sequence`, `table`, or `schema`. | Conditional | Yes | +| `privileges` | `array[string]` | List of privileges to grant. | Yes | No | + +### Object Types + +Supported object types: + +- `database` +- `schema` +- `sequence` +- `table` + +### Privileges + +Supported privileges depend on the `objectType`: + +- `connect` +- `create` +- `delete` +- `insert` +- `maintain` +- `references` +- `select` +- `temporary` +- `trigger` +- `truncate` +- `update` +- `usage` + +### ClusterReference + +| Field | Type | Description | Required | +|-------------|----------|----------------------------------------------------------------------------------|----------| +| `name` | `string` | Name of the `ClusterConnection`. | Yes | +| `namespace` | `string` | Namespace of the `ClusterConnection`. If not specified, uses the CR's namespace. | No | + +## Example + +```yaml +apiVersion: postgresql.aboutbits.it/v1 +kind: Grant +metadata: + name: grant-select-tables +spec: + clusterRef: + name: my-postgres-connection + database: my_database + role: my_role + objectType: table + schema: public + objects: + - my_table + - another_table + privileges: + - select + - insert +``` + +## Official Documentation + +- [GRANT](https://www.postgresql.org/docs/current/sql-grant.html) +- [REVOKE](https://www.postgresql.org/docs/current/sql-revoke.html) diff --git a/docs/apply-cluster-connection.png b/docs/images/apply-cluster-connection.png similarity index 100% rename from docs/apply-cluster-connection.png rename to docs/images/apply-cluster-connection.png diff --git a/docs/created-role.png b/docs/images/created-role.png similarity index 100% rename from docs/created-role.png rename to docs/images/created-role.png diff --git a/docs/established-cluster-connection.png b/docs/images/established-cluster-connection.png similarity index 100% rename from docs/established-cluster-connection.png rename to docs/images/established-cluster-connection.png diff --git a/docs/role-in-table-pg-authid.png b/docs/images/role-in-table-pg-authid.png similarity index 100% rename from docs/role-in-table-pg-authid.png rename to docs/images/role-in-table-pg-authid.png diff --git a/docs/role.md b/docs/role.md new file mode 100644 index 0000000..d6b6c0c --- /dev/null +++ b/docs/role.md @@ -0,0 +1,87 @@ +# Role + +The `Role` Custom Resource Definition (CRD) manages PostgreSQL roles (users). + +## Spec + +| Field | Type | Description | Required | Immutable | +|---------------------|--------------------|-------------------------------------------------------------|----------|-----------| +| `clusterRef` | `ClusterReference` | Reference to the `ClusterConnection` to use. | Yes | No | +| `name` | `string` | The name of the role to create in the database. | Yes | Yes | +| `comment` | `string` | A comment to add to the role. | No | No | +| `flags` | `RoleFlags` | Flags and attributes for the role. | No | No | +| `passwordSecretRef` | `SecretRef` | Reference to a secret containing the password for the role. | No | No | + +### ClusterReference + +| Field | Type | Description | Required | +|-------------|----------|----------------------------------------------------------------------------------|----------| +| `name` | `string` | Name of the `ClusterConnection`. | Yes | +| `namespace` | `string` | Namespace of the `ClusterConnection`. If not specified, uses the CR's namespace. | No | + +### RoleFlags + +| Field | Type | Default | Description | +|-------------------|-----------------|---------|------------------------------------------------------------------------| +| `bypassrls` | `boolean` | `false` | Bypass Row Level Security. | +| `connectionLimit` | `integer` | `-1` | Maximum number of concurrent connections. | +| `createdb` | `boolean` | `false` | Ability to create databases. | +| `createrole` | `boolean` | `false` | Ability to create new roles. | +| `inRole` | `array[string]` | `[]` | List of roles this role should be added to. | +| `inherit` | `boolean` | `true` | Whether to inherit privileges from roles it is a member of by default. | +| `replication` | `boolean` | `false` | Ability to initiate replication. | +| `role` | `array[string]` | `[]` | List of roles that should be members of this role. | +| `superuser` | `boolean` | `false` | Superuser status. | +| `validUntil` | `string` | `null` | Date and time until the password is valid (ISO 8601). | + +### SecretRef + +| Field | Type | Description | Required | +|-------------|----------|---------------------------------------------------------------------|----------| +| `name` | `string` | Name of the secret. | Yes | +| `namespace` | `string` | Namespace of the secret. If not specified, uses the CR's namespace. | No | + +The referenced secret must be of type `kubernetes.io/basic-auth`. + +**Note**: The `username` key in the secret is not strictly required, as the role name is specified by the `name` field in the CRD. Only the `password` key is used. + +### Login vs No-Login Roles + +The operator uses the presence of the `passwordSecretRef` field to determine if the role should have the `LOGIN` privilege (User) or not (Group). + +- **Login Role (User)**: If `passwordSecretRef` is specified, the role is created with the `LOGIN` attribute. It uses the password from the referenced secret. +- **No-Login Role (Group)**: If `passwordSecretRef` is omitted, the role is created with the `NOLOGIN` attribute. This is useful for creating roles that serve as groups for permissions. + +### Example + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: test-role-secret +type: kubernetes.io/basic-auth +stringData: + password: securepassword +``` + +```yaml +apiVersion: postgresql.aboutbits.it/v1 +kind: Role +metadata: + name: test-role +spec: + name: test_role + comment: "A test role" + clusterRef: + name: my-postgres-connection + flags: + createdb: true + validUntil: "2026-12-31T23:59:59Z" + passwordSecretRef: + name: test-role-secret +``` + +## Official Documentation + +- [CREATE ROLE](https://www.postgresql.org/docs/current/sql-createrole.html) +- [ALTER ROLE](https://www.postgresql.org/docs/current/sql-alterrole.html) diff --git a/docs/schema.md b/docs/schema.md new file mode 100644 index 0000000..3fd7509 --- /dev/null +++ b/docs/schema.md @@ -0,0 +1,46 @@ +# Schema + +The `Schema` Custom Resource Definition (CRD) is responsible for managing PostgreSQL schemas. + +## Spec + +| Field | Type | Description | Required | Immutable | +|-----------------|--------------------|----------------------------------------------------------------------------------------------------|----------|-----------| +| `clusterRef` | `ClusterReference` | Reference to the `ClusterConnection` to use. | Yes | No | +| `name` | `string` | The name of the schema to create. | Yes | Yes | +| `owner` | `string` | The owner of the schema. | No | No | +| `reclaimPolicy` | `string` | The policy for reclaiming the schema when the CR is deleted. Values: `Retain` (Default), `Delete`. | No | No | + +### ClusterReference + +| Field | Type | Description | Required | +|-------------|----------|----------------------------------------------------------------------------------|----------| +| `name` | `string` | Name of the `ClusterConnection`. | Yes | +| `namespace` | `string` | Namespace of the `ClusterConnection`. If not specified, uses the CR's namespace. | No | + +### Reclaim Policy + +The `reclaimPolicy` controls what happens to the PostgreSQL schema when the Custom Resource is deleted from Kubernetes. + +- `Retain` (Default): The schema remains in the PostgreSQL database. Only the Kubernetes Custom Resource is deleted. This prevents accidental data loss. +- `Delete`: The schema is dropped from the PostgreSQL database. **Warning:** This will permanently delete the schema and all objects (tables, views, etc.) within it. + +## Example + +```yaml +apiVersion: postgresql.aboutbits.it/v1 +kind: Schema +metadata: + name: my-schema +spec: + clusterRef: + name: my-postgres-connection + name: my_schema + owner: my_role + reclaimPolicy: Retain +``` + +## Official Documentation + +- [CREATE SCHEMA](https://www.postgresql.org/docs/current/sql-createschema.html) +- [ALTER SCHEMA](https://www.postgresql.org/docs/current/sql-alterschema.html) From 2b133c71c3ed4a41b4966cba1155edf47dd7c5d0 Mon Sep 17 00:00:00 2001 From: Thomas Sapelza Date: Mon, 26 Jan 2026 14:15:24 +0100 Subject: [PATCH 2/7] fix wording --- docs/cluster-connection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cluster-connection.md b/docs/cluster-connection.md index d48d29e..7675137 100644 --- a/docs/cluster-connection.md +++ b/docs/cluster-connection.md @@ -3,7 +3,7 @@ The `ClusterConnection` Custom Resource Definition (CRD) defines the connection details for a PostgreSQL cluster. It specifies the host, port, database, and the credentials to use for administrative operations. -Other Custom Resources (like `Database`, `Role`, `Schema`, `Grant`, `DefaultPrivilege`) reference to a specify target PostgreSQL cluster using `clusterRef` to be able to execute the operations on. +Other Custom Resources (like `Database`, `Role`, `Schema`, `Grant`, `DefaultPrivilege`) reference a specific target PostgreSQL cluster using `clusterRef` on which to execute the operations. ## Spec From ba4d296dc2800b0f5eccbac9d6418bdc2ff072bc Mon Sep 17 00:00:00 2001 From: Thomas Sapelza Date: Mon, 26 Jan 2026 14:34:53 +0100 Subject: [PATCH 3/7] polish the docs --- docs/cluster-connection.md | 5 +++++ docs/default-privilege.md | 18 +++++++++--------- docs/grant.md | 18 +++++++++--------- docs/role.md | 38 +++++++++++++++++++------------------- 4 files changed, 42 insertions(+), 37 deletions(-) diff --git a/docs/cluster-connection.md b/docs/cluster-connection.md index 7675137..d65f2ae 100644 --- a/docs/cluster-connection.md +++ b/docs/cluster-connection.md @@ -48,4 +48,9 @@ spec: host: localhost port: 5432 database: postgres + # Example parameters + parameters: + ApplicationName: "k8s-operator" # Helps identify this connection in Postgres logs + #sslmode: "require" # Enforce SSL encryption + #connectTimeout: "10" # Timeout in seconds for connection attempts ``` diff --git a/docs/default-privilege.md b/docs/default-privilege.md index 073700d..e532671 100644 --- a/docs/default-privilege.md +++ b/docs/default-privilege.md @@ -4,15 +4,15 @@ The `DefaultPrivilege` Custom Resource Definition (CRD) manages default privileg ## Spec -| Field | Type | Description | Required | Immutable | -|--------------|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------|-------------|-----------| -| `clusterRef` | `ClusterReference` | Reference to the `ClusterConnection` to use. | Yes | No | -| `database` | `string` | The database where default privileges apply. | Yes | Yes | -| `role` | `string` | The role to which default privileges are granted. | Yes | Yes | -| `owner` | `string` | The role that owns the objects (the creator). Default privileges apply to objects created by this role. | Yes | Yes | -| `objectType` | `string` | The type of object. | Yes | Yes | -| `schema` | `string` | The schema where default privileges apply. Required if `objectType` is `sequence` or `table`. Must NOT be set if `objectType` is `schema`. | Conditional | Yes | -| `privileges` | `array[string]` | List of privileges to grant. | Yes | No | +| Field | Type | Description | Required | Immutable | +|--------------|--------------------|---------------------------------------------------------------------------------------------------------|-------------|-----------| +| `clusterRef` | `ClusterReference` | Reference to the `ClusterConnection` to use. | Yes | No | +| `database` | `string` | The database where default privileges apply. | Yes | Yes | +| `role` | `string` | The role to which default privileges are granted. | Yes | Yes | +| `owner` | `string` | The role that owns the objects (the creator). Default privileges apply to objects created by this role. | Yes | Yes | +| `schema` | `string` | The schema where default privileges apply. Required, unless `objectType` is `schema`. | Conditional | Yes | +| `objectType` | `string` | The type of object. | Yes | Yes | +| `privileges` | `array[string]` | List of privileges to grant. | Yes | No | ### Object Types diff --git a/docs/grant.md b/docs/grant.md index 1377e1f..1517d1f 100644 --- a/docs/grant.md +++ b/docs/grant.md @@ -4,15 +4,15 @@ The `Grant` Custom Resource Definition (CRD) is responsible for managing privile ## Spec -| Field | Type | Description | Required | Immutable | -|--------------|--------------------|--------------------------------------------------------------------------------------------------|-------------|-----------| -| `clusterRef` | `ClusterReference` | Reference to the `ClusterConnection` to use. | Yes | No | -| `database` | `string` | The database containing the objects. | Yes | Yes | -| `role` | `string` | The role to which privileges are granted. | Yes | Yes | -| `objectType` | `string` | The type of object. | Yes | Yes | -| `objects` | `array[string]` | List of object names. Required if `objectType` is `sequence` or `table`. | Conditional | No | -| `schema` | `string` | The schema containing the objects. Required if `objectType` is `sequence`, `table`, or `schema`. | Conditional | Yes | -| `privileges` | `array[string]` | List of privileges to grant. | Yes | No | +| Field | Type | Description | Required | Immutable | +|--------------|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------|-------------|-----------| +| `clusterRef` | `ClusterReference` | Reference to the `ClusterConnection` to use. | Yes | No | +| `database` | `string` | The database containing the objects. | Yes | Yes | +| `role` | `string` | The role to which privileges are granted. | Yes | Yes | +| `schema` | `string` | The schema containing the objects. Required, unless `objectType` is `database`. | Conditional | Yes | +| `objectType` | `string` | The type of object. | Yes | Yes | +| `objects` | `array[string]` | List of object names. If empty, all objects of this `objectType` will be granted. Required, unless `objectType` is `database` or `schema`. | Conditional | No | +| `privileges` | `array[string]` | List of privileges to grant. | Yes | No | ### Object Types diff --git a/docs/role.md b/docs/role.md index d6b6c0c..75ee361 100644 --- a/docs/role.md +++ b/docs/role.md @@ -4,13 +4,13 @@ The `Role` Custom Resource Definition (CRD) manages PostgreSQL roles (users). ## Spec -| Field | Type | Description | Required | Immutable | -|---------------------|--------------------|-------------------------------------------------------------|----------|-----------| -| `clusterRef` | `ClusterReference` | Reference to the `ClusterConnection` to use. | Yes | No | -| `name` | `string` | The name of the role to create in the database. | Yes | Yes | -| `comment` | `string` | A comment to add to the role. | No | No | -| `flags` | `RoleFlags` | Flags and attributes for the role. | No | No | -| `passwordSecretRef` | `SecretRef` | Reference to a secret containing the password for the role. | No | No | +| Field | Type | Description | Required | Immutable | +|---------------------|--------------------|-------------------------------------------------------------------------------------|----------|-----------| +| `clusterRef` | `ClusterReference` | Reference to the `ClusterConnection` to use. | Yes | No | +| `name` | `string` | The name of the role to create in the database. | Yes | Yes | +| `comment` | `string` | A comment to add to the role. | No | No | +| `passwordSecretRef` | `SecretRef` | Reference to a secret containing the password for the role to make it a LOGIN role. | No | No | +| `flags` | `RoleFlags` | Flags and attributes for the role. | No | No | ### ClusterReference @@ -21,18 +21,18 @@ The `Role` Custom Resource Definition (CRD) manages PostgreSQL roles (users). ### RoleFlags -| Field | Type | Default | Description | -|-------------------|-----------------|---------|------------------------------------------------------------------------| -| `bypassrls` | `boolean` | `false` | Bypass Row Level Security. | -| `connectionLimit` | `integer` | `-1` | Maximum number of concurrent connections. | -| `createdb` | `boolean` | `false` | Ability to create databases. | -| `createrole` | `boolean` | `false` | Ability to create new roles. | -| `inRole` | `array[string]` | `[]` | List of roles this role should be added to. | -| `inherit` | `boolean` | `true` | Whether to inherit privileges from roles it is a member of by default. | -| `replication` | `boolean` | `false` | Ability to initiate replication. | -| `role` | `array[string]` | `[]` | List of roles that should be members of this role. | -| `superuser` | `boolean` | `false` | Superuser status. | -| `validUntil` | `string` | `null` | Date and time until the password is valid (ISO 8601). | +| Field | Type | Default | Description | +|-------------------|-----------------|---------|-------------------------------------------------------------------------| +| `bypassrls` | `boolean` | `false` | Bypass Row Level Security. | +| `connectionLimit` | `integer` | `-1` | Maximum number of concurrent connections. A value of -1 means no limit. | +| `createdb` | `boolean` | `false` | Ability to create databases. | +| `createrole` | `boolean` | `false` | Ability to create new roles. | +| `inRole` | `array[string]` | `[]` | List of roles this role should be added to. | +| `inherit` | `boolean` | `true` | Whether to inherit privileges from roles it is a member of by default. | +| `replication` | `boolean` | `false` | Ability to initiate replication. | +| `role` | `array[string]` | `[]` | List of roles that should be members of this role. | +| `superuser` | `boolean` | `false` | Superuser status. | +| `validUntil` | `string` | `null` | Date and time until the password is valid (ISO 8601). | ### SecretRef From e6feade2092cc61d9a67eabc59d5163d1be8d222 Mon Sep 17 00:00:00 2001 From: Thomas Sapelza Date: Mon, 26 Jan 2026 14:50:13 +0100 Subject: [PATCH 4/7] improve the docs --- README.md | 8 ++++++-- docs/docker-environment.md | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 70ba19c..08c93ff 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ Further documentation of each Custom Resource can be found here: The following example shows how to set up a connection to a PostgreSQL cluster, create a database and schema, a login role (user), and configure permissions. +If you want to try this out locally, you can follow the [Docker Environment](docs/docker-environment.md) guide. + ```yaml # Define a ClusterConnection resource to connect to a PostgreSQL cluster. --- @@ -159,8 +161,10 @@ make run ./gradlew :operator:quarkusDev ``` -The app service will be available at http://localhost:8080, -and you can also use the Dev UI (available in dev mode only) at . +The app service will be available at [http://localhost:8080](http://localhost:8080). + +You can also use the Dev UI (available in dev mode only) at [http://localhost:8080/q/dev-ui/welcome](http://localhost:8080/q/dev-ui/welcome). +There you can find a set of guides for the used extensions in this project to get up-to-speed faster. To execute the test without continuous testing in the dev mode, you can run the following command: diff --git a/docs/docker-environment.md b/docs/docker-environment.md index 5eff244..37cf7cb 100644 --- a/docs/docker-environment.md +++ b/docs/docker-environment.md @@ -1,6 +1,6 @@ # Docker Environment -This example demonstrates how to set up a local development environment using Quarkus Dev Services to test the Operator manually. +This example demonstrates how to set up a local development environment using Quarkus Dev Services to test the Operator manually. As the K3s cluster port and the secrets change on every `./gradlew :operator:quarkusDev` run, you will have to manually update the port and secrets in the `~/.kube/config` every time. ## 1. Configure Kubeconfig from Dev Services From 67ae42d9292856435c21c6b84cb14db564bdd559 Mon Sep 17 00:00:00 2001 From: Thomas Sapelza Date: Mon, 26 Jan 2026 14:55:40 +0100 Subject: [PATCH 5/7] also run the tests against the main branch, not only PR branches --- .github/workflows/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 34aec92..cc34a7f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,6 +1,9 @@ name: Test on: + push: + branches: + - main pull_request: types: [ opened, reopened, synchronize ] From a03b95176dc5934c1bc0729e4afd061c99ff7010 Mon Sep 17 00:00:00 2001 From: Thomas Sapelza Date: Mon, 26 Jan 2026 15:10:34 +0100 Subject: [PATCH 6/7] add ASCII architecture chart --- README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/README.md b/README.md index 08c93ff..7b826b4 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,36 @@ AboutBits PostgreSQL Operator is a Kubernetes operator that helps you manage PostgreSQL databases, roles (users), and privileges in a declarative way using Custom Resource Definitions (CRDs). +## Architecture + +``` +┌──────────────────────────────────────────────────────────────────────────┐ +│ Kubernetes Cluster │ +│ ┌────────────────────────┐ ┌────────────────────────────────────────┐ │ +│ │ PostgreSQL │ │ PostgreSQL Operator │ │ +│ │ Operator CRDs │──▶│ ┌──────────────────────────────────┐ │ │ +│ │ │ │ │ ClusterConnection Controller │ │ │ +│ │ ┌────────────────────┐ │ │ ├──────────────────────────────────┤ │ │ +│ │ │ ClusterConnection │ │ │ │ Database Controller │ │ │ +│ │ └──────────▲─────────┘ │ │ ├──────────────────────────────────┤ │ │ +│ │ │ │ │ │ Role Controller │ │ │ +│ │ ┌──────────┴─────────┐ │ │ ├──────────────────────────────────┤ │ │ +│ │ │ - Database │ │ │ │ Schema Controller │ │ │ +│ │ │ - Schema │ │ │ ├──────────────────────────────────┤ │ │ +│ │ │ - Role │ │ │ │ Grant Controller │ │ │ +│ │ │ - Grant │ │ │ ├──────────────────────────────────┤ │ │ +│ │ │ - DefaultPrivilege │ │ │ │ DefaultPrivilege Controller │ │ │ +│ │ └────────────────────┘ │ │ └──────────────────────────────────┘ │ │ +│ └────────────────────────┘ └────────────────────┬───────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌──────────────────────────────────┐ │ +│ │ PostgreSQL Server │ │ +│ │ (SQL) │ │ +│ └──────────────────────────────────┘ │ +└──────────────────────────────────────────────────────────────────────────┘ +``` + ## Usage This operator allows you to manage PostgreSQL resources using Kubernetes manifests. From a7bd4638a563753f50b9cade858a99cf5a27d184 Mon Sep 17 00:00:00 2001 From: Thomas Sapelza Date: Tue, 27 Jan 2026 07:26:34 +0100 Subject: [PATCH 7/7] =?UTF-8?q?the=20Operator=20arrow=20should=20touch=20t?= =?UTF-8?q?he=20PostgreSQL=20server=20=F0=9F=98=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 7b826b4..ff182fa 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,7 @@ AboutBits PostgreSQL Operator is a Kubernetes operator that helps you manage Pos │ │ └────────────────────┘ │ │ └──────────────────────────────────┘ │ │ │ └────────────────────────┘ └────────────────────┬───────────────────┘ │ │ │ │ -│ ▼ │ -│ ┌──────────────────────────────────┐ │ +│ ┌─────────────────▼────────────────┐ │ │ │ PostgreSQL Server │ │ │ │ (SQL) │ │ │ └──────────────────────────────────┘ │