{"id":21244461,"url":"https://github.com/lunarway/postgresql-controller","last_synced_at":"2025-08-20T23:06:08.121Z","repository":{"id":37390634,"uuid":"218763003","full_name":"lunarway/postgresql-controller","owner":"lunarway","description":"PostgreSQL controller for managing database user access through kubernetes custom resources","archived":false,"fork":false,"pushed_at":"2025-08-10T19:19:31.000Z","size":908,"stargazers_count":9,"open_issues_count":9,"forks_count":2,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-08-10T21:14:46.968Z","etag":null,"topics":["golang","operator","operator-sdk","postgresql"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lunarway.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-10-31T12:40:38.000Z","updated_at":"2025-07-14T05:42:32.000Z","dependencies_parsed_at":"2023-02-19T05:31:01.717Z","dependency_job_id":"5518a9ab-2ffa-4be6-9c63-5e134b3d5241","html_url":"https://github.com/lunarway/postgresql-controller","commit_stats":{"total_commits":301,"total_committers":16,"mean_commits":18.8125,"dds":0.7408637873754154,"last_synced_commit":"9de02952115195e599c8e94de414992c617c4b1d"},"previous_names":[],"tags_count":74,"template":false,"template_full_name":null,"purl":"pkg:github/lunarway/postgresql-controller","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lunarway%2Fpostgresql-controller","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lunarway%2Fpostgresql-controller/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lunarway%2Fpostgresql-controller/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lunarway%2Fpostgresql-controller/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lunarway","download_url":"https://codeload.github.com/lunarway/postgresql-controller/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lunarway%2Fpostgresql-controller/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271400259,"owners_count":24752830,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-20T02:00:09.606Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang","operator","operator-sdk","postgresql"],"created_at":"2024-11-21T01:26:16.469Z","updated_at":"2025-08-20T23:06:08.101Z","avatar_url":"https://github.com/lunarway.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PostgreSQL controller\n\n**BE AWARE** This is under active development and not ready for production in any way.\nMore features described in this readme are goals more than implemented functionality of the controller at the moment.\n\nThis is a Kubernetes controller for managing users and their access rights to a PostgreSQL database instance.\nIts purpose is to make a codified description of what users have access to what databases and for what reason along with providing an auditable log of changes.\n\n# Design\n\nThe controller will handle user and database management on PostgreSQL instances with two Kubernetes [Custom Resource Definitions](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/).\n\nThe controller needs access to a role in PostreSQL privileged to create databases and roles.\n\n```sql\nCREATE USER iam_creator CREATEDB CREATEROLE PASSWORD 'strongpassword';\n```\n\n## Databases\n\nThe CRD `PostgreSQLDatabase` specified details about a database on a specific instance.\nIt is scoped as cluster wide ie. has no namespace.\n\nThe main purpose of this resource is to create databases on a specific host with a specific name used by application services.\nInstances of `PostgreSQLUser` can then give a specific developer access to the database by referencing the name.\n\n```yaml\napiVersion: lunar.bank/v1beta1\nkind: PostgreSQLDatabase\nmetadata:\n  name: user\nspec:\n  name: user\n  password:\n    value: \u003cstrong-password\u003e\n  host:\n    value: some.host.com\n```\n\nThe `password` and `host` fields are modelled like Kubernetes core's [`EnvVarSource`](https://github.com/kubernetes/api/blob/665c8a257c1af277521b08dd43d5c73570405ef0/core/v1/types.go#L1847-L1862), so it can specify raw values like above or reference ConfigMaps and Secrets.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample of a database referencing ConfigMap and Secret resource\u003c/summary\u003e\n\n```yaml\napiVersion: lunar.bank/v1beta1\nkind: PostgreSQLDatabase\nmetadata:\n  name: user\nspec:\n  name: user\n  password:\n    valueFrom:\n      secretKeyRef:\n        name: user-db\n        key: db.password\n  host:\n    valueFrom:\n      configMapKeyRef:\n        name: database\n        key: db.host\n```\n\n\u003c/details\u003e\n\nThe controller will ensure that a database exists on the host based on its configuration.  \nIf a resources is deleted we _might_ delete the database in the future, preferrable behind a flag to avoid loosing data.\n\nThere are created four roles for all databases.\nOne with login priviledges according to the custom resource name and password.\nThe other three are `read`, `readwrite` and `readowningwrite` roles used when granting users access to the database.\nThey are named as the database with a `_read`, `_readwrite` and `_readowningwrite` suffix and have the priviledge to `SELECT` and `SELECT, INSERT, UPDATE, DELETE` respectively.\nThe owning write role is also granted the owning role to allow using `DROP` and `ALTER`.\nDefault priviledges on the database ensures that each role have access to objects created by the service role.\n\n## Users\n\nThe CRD `PostgreSQLUser` contains metadata about the user along with its access rights to databases.\n\nThe access rights are devided into `read`, `write` and `owningWrite` and specifies a `host` and `reason` as a minimum.\nEither the `database` field or `allDatabases` must be set as well.\nIt is possible to set `start` and `stop` timestamps to limit the lifetime of capabilities e.g. automatic revocation after completing a support ticket.\n\nWe generally do not limit access to data but instead rely on strong audits.\n\nThis is an example of a user `bso` that has read access to all databases and write access to the `user` database in schema `user` between 10 AM to 2 PM on september 9th.\nThe read capability uses a static host name `some.host.com` and the write capability references a `database` ConfigMap on key `db.host`.\n\n```yaml\napiVersion: lunar.bank/v1\nkind: PostgreSQLUser\nmetadata:\n  name: bso\nspec:\n  name: bso\n  read:\n    - host:\n        value: some.host.com\n      reason: \"I am a developer\"\n  write:\n    - host:\n        valueFrom:\n          configMapKeyRef:\n            name: database\n            key: db.host\n      database:\n        value: user\n      schema:\n        value: user\n      reason: \"Related to support ticket LW-1234\"\n      start: 2019-09-16T10:00:00Z\n      stop: 2019-09-16T14:00:00Z\n```\n\nFrom the configuration the user will be created with a `\u003cname\u003e` user on the host and granted rights to access the required databases.\nThe flag `--user-role-prefix` can be used to prefix all created roles.\nThis can make it easier to see what roles are for human users and what are for services.\n\n```\n--user-role-prefix=iam_developer_\n```\n\nIt is also possible to add custom roles to all created users. This is useful for IAM authentication as roles with the `rds_iam` role can connect to the database using AWS IAM.\nFurther these roles can be used to group users created by specific controllers.\nBe aware that the controller will not create these roles.\nThey need to be available by other means.\n\n```\n--user-roles=rds_iam,iam_developer\n```\n\nThe `rds_iam` is the default value of the flag.\n\nA policy will also be added to AWS IAM for the specific user allowing it to connect to the host.\n\n```json\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\"rds-db:connect\"],\n      \"Resource\": [\n        \"arn:aws:rds-db:region:account:dbuser:*/iam_\u003cname\u003e\"\n      ],\n      \"Condition\": {\n        \"StringLike\": {\n          \"aws:userid\": \"*:\u003cname\u003e@lunar.app\"\n        }\n      }\n    }\n  ]\n}\n```\n\n# Development\n\nThis project uses the [Operator SDK framework](https://github.com/operator-framework/operator-sdk) and its associated CLI.  \nFollow the [offical installation instructions](https://github.com/operator-framework/operator-sdk/blob/master/doc/user/install-operator-sdk.md) to get started.\n\n## Testing\n\nUnit and integration tests are run with the make targets `test/unit` and `test/integration`.\n\nIntegration tests require a PostgreSQL instance to run against.\nIf you set environment variable `POSTGRESQL_CONTROLLER_INTEGRATION_HOST` to the hostname of the instance that will be used and the tests run.\nIf the flag is not set the tests are skipped.\n\n```\n$ make test/unit\nRunning tests:\ngo test -v -race -cover ./pkg/...\n?   \tgo.lunarway.com/postgresql-controller/pkg/apis\t[no test files]\n...\nPASS\ncoverage: 0.0% of statements\nok  \tgo.lunarway.com/postgresql-controller/pkg/controller/postgresqluser\t1.143s\tcoverage: 0.0% of statements\n\n\n$ make test/integration\nRunning integration tests against PostgreSQL instance on localhost:5432:\nPOSTGRESQL_CONTROLLER_INTEGRATION_HOST=localhost:5432 make test/unit\nRunning tests:\ngo test -v -race -cover ./pkg/...\n?   \tgo.lunarway.com/postgresql-controller/pkg/apis\t[no test files]\n...\nPASS\ncoverage: 34.7% of statements\nok  \tgo.lunarway.com/postgresql-controller/pkg/controller/postgresqluser\t1.232s\tcoverage: 34.7% of statements\n```\n\nTo spin up a local cluster with [kind](https://github.com/kubernetes-sigs/kind) ensure to have it installed on your local machine.\nYou can connect a local running operator by using kind's `KUBECONFIG` and applying the operators resources.\nBelow example will create a test cluster, apply CRD resources, start a PostgreSQL instance in the cluster and start the operator.\n\nMake sure to forward the postgresql pod for the\n\n```\n// Setup kind cluster (this will use KUBECONFIG=~/.kube/config to store the kubeconfig)\n$ make test/cluster\n\n// Apply kubernetes resources for the controller\n$ make test/cluster/resources\n\n// Forward PostgreSQL pod before starting the operator\n$ kubectl port-forward deploy/postgresql 5432\n\n// Start operator connecting to the cluster\n$ make run\n```\n\n# Releasing\n\nTo release a new version of the operator run `make release TAG=vx.x.x`.\nThis will ensure to update `deploy/operator.yaml` with the version, create a commit and push it.\nThe `Release` GitHub Action workflow is then triggered and pushes the Docker image to quay.io.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flunarway%2Fpostgresql-controller","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flunarway%2Fpostgresql-controller","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flunarway%2Fpostgresql-controller/lists"}