Rotate Authentication of PostgerSQL
Rotate Authentication is a feature of the KubeDB Ops-Manager that allows you to rotate a Postgres
user’s authentication credentials using a PostgresOpsRequest
. There are two ways to perform this rotation.
- Operator Generated: The KubeDB operator automatically generates a random credential, updates the existing secret with the new credential The KubeDB operator automatically generates a random credential and updates the existing secret with the new credential..
- User Defined: The user can create their own credentials by defining a Secret of type
kubernetes.io/basic-auth
containing the desiredusername
andpassword
, and then reference this Secret in thePostgresOpsRequest
.
Before You Begin
You should be familiar with the following
KubeDB
concepts:At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using kind.
Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps here.
To keep things isolated, this tutorial uses a separate namespace called
demo
throughout this tutorial.$ kubectl create ns demo namespace/demo created
Create a PostgreSQL database
KubeDB implements a Postgres CRD to define the specification of a PostgreSQL database.
You can apply this yaml file:
apiVersion: kubedb.com/v1
kind: Postgres
metadata:
name: quick-postgres
namespace: demo
spec:
version: "13.13"
storageType: Durable
storage:
storageClassName: "standard"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
deletionPolicy: DoNotTerminate
Command:
$ kubectl apply -f postgres.yaml
postgres.kubedb.com/quick-postgres created
Or, you can deploy by using command:
$ kubectl create -f https://github.com/kubedb/docs/raw/{{ .version }}/docs/examples/postgres/quickstart/quick-postgres-v1.yaml
postgres.kubedb.com/quick-postgres created
Now, wait until quick-postgres has status Ready. i.e,
$ kubectl get pg -n demo -w
NAME VERSION STATUS AGE
quick-postgres 13.13 Ready 7m36s
Verify authentication
The user can verify whether they are authorized by executing a query directly in the database. To do this, the user needs username
and password
in order to connect to the database using the kubectl exec
command. Below is an example showing how to retrieve the credentials from the Secret.
$ kubectl get pg -n demo quick-postgres -ojson | jq .spec.authSecret.name
"quick-postgres-auth"
$ kubectl get secret -n demo quick-postgres-auth -o jsonpath='{.data.username}' | base64 -d
postgres
$ kubectl get secret -n demo quick-postgres-auth -o jsonpath='{.data.password}' | base64 -d
yFj_WnVA9rxfQlLt
Now, you can exec into the pod quick-postgres-0
and connect to database using username
and password
$ kubectl exec -it -n demo quick-postgres-0 -- bash
Defaulted container "postgres" out of: postgres, postgres-init-container (init)
quick-postgres-0:/$ PGPASSWORD=yFj_WnVA9rxfQlLt psql -U postgres -d postgres -p 5432 -h quick-postgres.demo.svc
psql (13.13)
Type "help" for help.
postgres=# \dt
List of relations
Schema | Name | Type | Owner
--------+--------------------+-------+----------
public | kubedb_write_check | table | postgres
(1 row)
If you can access the data table and run queries, it means the secrets are working correctly.
Create RotateAuth PostgresOpsRequest
1. Using operator generated credentials:
In order to rotate authentication to the Postgres using operator generated, we have to create a PostgresOpsRequest
CRO with RotateAuth
type. Below is the YAML of the PostgresOpsRequest
CRO that we are going to create,
apiVersion: ops.kubedb.com/v1alpha1
kind: PostgresOpsRequest
metadata:
name: pgops-rotate-auth-generated
namespace: demo
spec:
type: RotateAuth
databaseRef:
name: quick-postgres
timeout: 5m
apply: IfReady
Here,
spec.databaseRef.name
specifies that we are performing rotate authentication operation onquick-postgres
cluster.spec.type
specifies that we are performingRotateAuth
on Postgres.
Let’s create the PostgresOpsRequest
CR we have shown above,
$ kubectl apply -f https://github.com/kubedb/docs/raw/{{ .version }}/docs/examples/postgres/rotate-auth/postgres-rotate-auth-generated.yaml
postgresopsrequest.ops.kubedb.com/pgops-rotate-auth-generated created
Let’s wait for PostgresOpsrequest
to be Successful
. Run the following command to watch PostgresOpsrequest
CRO
$ kubectl get postgresopsrequest -n demo
NAME TYPE STATUS AGE
pgops-rotate-auth-generated RotateAuth Successful 7m47s
If we describe the PostgresOpsRequest
we will get an overview of the steps that were followed.
$ kubectl describe postgresopsrequest -n demo pgops-rotate-auth-generated
Name: pgops-rotate-auth-generated
Namespace: demo
Labels: <none>
Annotations: <none>
API Version: ops.kubedb.com/v1alpha1
Kind: PostgresOpsRequest
Metadata:
Creation Timestamp: 2025-07-08T11:24:10Z
Generation: 1
Resource Version: 546623
UID: 97a07133-c98e-457c-9249-85c0c690a82e
Spec:
Apply: IfReady
Database Ref:
Name: quick-postgres
Timeout: 5m
Type: RotateAuth
Status:
Conditions:
Last Transition Time: 2025-07-08T11:24:10Z
Message: Postgres ops request has started to rotate auth for postgres
Observed Generation: 1
Reason: RotateAuth
Status: True
Type: RotateAuth
Last Transition Time: 2025-07-08T11:24:13Z
Message: Successfully generated new credentials
Observed Generation: 1
Reason: UpdateCredential
Status: True
Type: UpdateCredential
Last Transition Time: 2025-07-08T11:24:15Z
Message: Successfully updated petsets for rotate auth type
Observed Generation: 1
Reason: UpdatePetSets
Status: True
Type: UpdatePetSets
Last Transition Time: 2025-07-08T11:24:55Z
Message: Successfully restarted all the nodes
Observed Generation: 1
Reason: RestartNodes
Status: True
Type: RestartNodes
Last Transition Time: 2025-07-08T11:24:20Z
Message: evict pod; ConditionStatus:True
Observed Generation: 1
Status: True
Type: EvictPod
Last Transition Time: 2025-07-08T11:24:20Z
Message: check pod ready; ConditionStatus:False; PodName:quick-postgres-0
Observed Generation: 1
Status: False
Type: CheckPodReady--quick-postgres-0
Last Transition Time: 2025-07-08T11:24:55Z
Message: check pod ready; ConditionStatus:True
Observed Generation: 1
Status: True
Type: CheckPodReady
Last Transition Time: 2025-07-08T11:24:56Z
Message: Successfully Rotated Postgres Auth Secret
Observed Generation: 1
Reason: Successful
Status: True
Type: Successful
Observed Generation: 1
Phase: Successful
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal PauseDatabase 20m KubeDB Ops-manager Operator Pausing Postgres demo/quick-postgres
Normal PauseDatabase 20m KubeDB Ops-manager Operator Successfully paused Postgres demo/quick-postgres
Normal VersionUpdate 20m KubeDB Ops-manager Operator Updating PetSets
Normal VersionUpdate 20m KubeDB Ops-manager Operator Successfully Updated PetSets
Warning evict pod; ConditionStatus:True 20m KubeDB Ops-manager Operator evict pod; ConditionStatus:True
Warning check pod ready; ConditionStatus:False; PodName:quick-postgres-0 20m KubeDB Ops-manager Operator check pod ready; ConditionStatus:False; PodName:quick-postgres-0
Warning check pod ready; ConditionStatus:True 19m KubeDB Ops-manager Operator check pod ready; ConditionStatus:True
Normal RestartNodes 19m KubeDB Ops-manager Operator Successfully restarted all the nodes
Normal ResumeDatabase 19m KubeDB Ops-manager Operator Resuming PostgreSQL demo/quick-postgres
Normal ResumeDatabase 19m KubeDB Ops-manager Operator Successfully resumed PostgreSQL demo/quick-postgres
Normal Successful 19m KubeDB Ops-manager Operator Successfully Rotated Postgres Auth Secret for demo/quick-postgres
Verify Auth is rotated
$ kubectl get pg -n demo quick-postgres -ojson | jq .spec.authSecret.name
"quick-postgres-auth"
$ kubectl get secret -n demo quick-postgres-auth -o=jsonpath='{.data.username}' | base64 -d
postgres
$ kubectl get secret -n demo quick-postgres-auth -o jsonpath='{.data.password}' | base64 -d
zGB9GF!NXwI.2HP9⏎
Also, there will be two more new keys in the secret that stores the previous credentials. The keys are username.prev
and password.prev
. You can find the secret and its data by running the following command:
$ kubectl get secret -n demo quick-postgres-auth -o go-template='{{ index .data "username.prev" }}' | base64 -d
postgres
$ kubectl get secret -n demo quick-postgres-auth -o go-template='{{ index .data "password.prev" }}' | base64 -d
yFj_WnVA9rxfQlLt
The above output shows that the password has been changed successfully. The previous username & password is stored for rollback purpose.
2. Using user created credentials
At first, we need to create a secret with kubernetes.io/basic-auth type using custom username and password. Below is the command to create a secret with kubernetes.io/basic-auth type,
$ kubectl create secret generic quick-postgres-user-auth -n demo \
--type=kubernetes.io/basic-auth \
--from-literal=username=admin \
--from-literal=password=postgres-secret
secret/quick-postgres-user-auth created
Now create a PostgresOpsRequest
with RotateAuth
type. Below is the YAML of the PostgresOpsRequest
that we are going to create,
apiVersion: ops.kubedb.com/v1alpha1
kind: PostgresOpsRequest
metadata:
name: pgops-rotate-auth-user
namespace: demo
spec:
type: RotateAuth
databaseRef:
name: quick-postgres
authentication:
secretRef:
name: quick-postgres-user-auth
timeout: 5m
apply: IfReady
Here,
spec.databaseRef.name
specifies that we are performing rotate authentication operation onquick-postgres
cluster.spec.type
specifies that we are performingRotateAuth
on postgres.spec.authentication.secretRef.name
specifies that we are usingquick-postgres-user-auth
asspec.authSecret.name
for authentication.
Let’s create the PostgresOpsRequest
CR we have shown above,
$ kubectl apply -f https://github.com/kubedb/docs/raw/{{ .version }}/docs/examples/postgres/rotate-auth/rotate-auth-user.yaml
postgresopsrequest.ops.kubedb.com/pgops-rotate-auth-user created
Let’s wait for PostgresOpsRequest
to be Successful. Run the following command to watch PostgresOpsRequest
CRO:
$ kubectl get postgresopsrequest -n demo
NAME TYPE STATUS AGE
pgops-rotate-auth-generated RotateAuth Successful 19h
pgops-rotate-auth-user RotateAuth Successful 7m44s
We can see from the above output that the PostgresOpsRequest
has succeeded. If we describe the PostgresOpsRequest
we will get an overview of the steps that were followed.
$ kubectl describe postgresopsrequest -n demo pgops-rotate-auth-user
Name: pgops-rotate-auth-user
Namespace: demo
Labels: <none>
Annotations: <none>
API Version: ops.kubedb.com/v1alpha1
Kind: PostgresOpsRequest
Metadata:
Creation Timestamp: 2025-07-09T06:45:44Z
Generation: 1
Resource Version: 562328
UID: d25c3d36-cc15-4c82-8fe4-64e5ffc1467c
Spec:
Apply: IfReady
Authentication:
Secret Ref:
Name: quick-postgres-user-auth
Database Ref:
Name: quick-postgres
Timeout: 5m
Type: RotateAuth
Status:
Conditions:
Last Transition Time: 2025-07-09T06:45:44Z
Message: Postgres ops request has started to rotate auth for postgres
Observed Generation: 1
Reason: RotateAuth
Status: True
Type: RotateAuth
Last Transition Time: 2025-07-09T06:45:47Z
Message: Successfully referenced the user provided authSecret
Observed Generation: 1
Reason: UpdateCredential
Status: True
Type: UpdateCredential
Last Transition Time: 2025-07-09T06:45:50Z
Message: Successfully updated petsets for rotate auth type
Observed Generation: 1
Reason: UpdatePetSets
Status: True
Type: UpdatePetSets
Last Transition Time: 2025-07-09T06:46:30Z
Message: Successfully restarted all the nodes
Observed Generation: 1
Reason: RestartNodes
Status: True
Type: RestartNodes
Last Transition Time: 2025-07-09T06:45:55Z
Message: evict pod; ConditionStatus:True
Observed Generation: 1
Status: True
Type: EvictPod
Last Transition Time: 2025-07-09T06:45:55Z
Message: check pod ready; ConditionStatus:False; PodName:quick-postgres-0
Observed Generation: 1
Status: False
Type: CheckPodReady--quick-postgres-0
Last Transition Time: 2025-07-09T06:46:30Z
Message: check pod ready; ConditionStatus:True
Observed Generation: 1
Status: True
Type: CheckPodReady
Last Transition Time: 2025-07-09T06:46:30Z
Message: Successfully Rotated Postgres Auth Secret
Observed Generation: 1
Reason: Successful
Status: True
Type: Successful
Observed Generation: 1
Phase: Successful
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal PauseDatabase 10m KubeDB Ops-manager Operator Pausing Postgres demo/quick-postgres
Normal PauseDatabase 10m KubeDB Ops-manager Operator Successfully paused Postgres demo/quick-postgres
Normal VersionUpdate 10m KubeDB Ops-manager Operator Updating PetSets
Normal VersionUpdate 10m KubeDB Ops-manager Operator Successfully Updated PetSets
Warning evict pod; ConditionStatus:True 10m KubeDB Ops-manager Operator evict pod; ConditionStatus:True
Warning check pod ready; ConditionStatus:False; PodName:quick-postgres-0 10m KubeDB Ops-manager Operator check pod ready; ConditionStatus:False; PodName:quick-postgres-0
Warning check pod ready; ConditionStatus:True 9m58s KubeDB Ops-manager Operator check pod ready; ConditionStatus:True
Normal RestartNodes 9m58s KubeDB Ops-manager Operator Successfully restarted all the nodes
Normal ResumeDatabase 9m58s KubeDB Ops-manager Operator Resuming PostgreSQL demo/quick-postgres
Normal ResumeDatabase 9m58s KubeDB Ops-manager Operator Successfully resumed PostgreSQL demo/quick-postgres
Normal Successful 9m58s KubeDB Ops-manager Operator Successfully Rotated Postgres Auth Secret for demo/quick-postgres
Verify auth is rotate
$ kubectl get pg -n demo quick-postgres -ojson | jq .spec.authSecret.name
"quick-postgres-user-auth"
$ kubectl get secret -n demo quick-postgres-user-auth-new -o=jsonpath='{.data.username}' | base64 -d
admin
$ kubectl get secret -n demo quick-postgres-user-auth-new -o=jsonpath='{.data.password}' | base64 -d
postgres-secret
Also, there will be two more new keys in the secret that stores the previous credentials. The keys are username.prev
and password.prev
. You can find the secret and its data by running the following command:
$ kubectl get secret -n demo quick-postgres-user-auth -o go-template='{{ index .data "username.prev" }}' | base64 -d
postgres
$ kubectl get secret -n demo quick-postgres-user-auth -o go-template='{{ index .data "password.prev" }}' | base64 -d
zGB9GF!NXwI.2HP9
The above output shows that the password has been changed successfully. The previous username & password is stored in the secret for rollback purpose.
Cleaning up
To clean up the Kubernetes resources you can delete the CRD or namespace. Or, you can delete one by one resource by their name by this tutorial, run:
$ kubectl delete postgresopsrequest pgops-rotate-auth-generated pgops-rotate-auth-user -n demo
postgresopsrequest.ops.kubedb.com "pgops-rotate-auth-generated" "pgops-rotate-auth-user" deleted
$ kubectl delete secret -n demo quick-postgres-user-auth
secret "quick-postgres-user-auth" deleted
$ kubectl delete secret -n demo quick-postgres-auth
secret "quick-postgres-auth" deleted
Next Steps
- Learn about backup and restore PostgreSQL database using Stash.
- Learn about initializing PostgreSQL with Script.
- Learn about custom PostgresVersions.
- Want to setup PostgreSQL cluster? Check how to configure Highly Available PostgreSQL Cluster
- Monitor your PostgreSQL database with KubeDB using built-in Prometheus.
- Monitor your PostgreSQL database with KubeDB using Prometheus operator.
- Detail concepts of Postgres object.
- Use private Docker registry to deploy PostgreSQL with KubeDB.
- Want to hack on KubeDB? Check our contribution guidelines.