Skip to content

Commit

Permalink
Merge branch 'master' into fix-keep-secret-values
Browse files Browse the repository at this point in the history
  • Loading branch information
hitman99 authored Feb 25, 2024
2 parents 2f7e59c + 1d9e64b commit 595d62f
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 38 deletions.
39 changes: 18 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,5 @@
# External PostgreSQL server operator for Kubernetes

---------------------------------------------------------
### IMPORTANT UPDATE

### Restoring pushes to DockerHub repository `movetokube/postgres-operator`

Some history about this:

About 10 days after announcing the decition to sunset free organisations in dockerhub and receiving heavily negative community feedback
Docker revoked their decision, did a 180-degree turn and did not sunset free legacy organisations.

Thus, new images of this operator will be pushed to both `movetokube/postgres-operator` and `ghcr.io/movetokube/postgres-operator` for your convenience.

Starting with ext-postgres-operator Helm chart version **1.2.3** images will be pulled from ghcr by default, you can change this if you like.

Here's how to install it (please install with care according to your configuration):
```shell
helm repo add ext-postgres-operator https://movetokube.github.io/postgres-operator/
helm upgrade --install -n operators ext-postgres-operator ext-postgres-operator/ext-postgres-operator --version 1.2.3
```

----------------------------------------------------------
## Sponsors

Please consider sponsoring my work
Expand All @@ -39,6 +18,7 @@ None
* Creates Kubernetes secret with postgres_uri in the same namespace as CR
* Support for AWS RDS and Azure Database for PostgresSQL
* Support for managing CRs in dynamically created namespaces
* Template secret values

## Cloud specific configuration

Expand Down Expand Up @@ -173,6 +153,8 @@ spec:
privileges: OWNER # Can be OWNER/READ/WRITE
annotations: # Annotations to be propagated to the secrets metadata section (optional)
foo: "bar"
secretTemplate: # Output secrets can be customized using standard Go templates
PQ_URL: "host={{.Host}} user={{.Role}} password={{.Password}} dbname={{.Database}}"
```

This creates a user role `username-<hash>` and grants role `test-db-group`, `test-db-writer` or `test-db-reader` depending on `privileges` property. Its credentials are put in secret `my-secret-my-db-user` (unless `KEEP_SECRET_NAME` is enabled).
Expand Down Expand Up @@ -203,6 +185,21 @@ With the help of annotations it is possible to create annotation-based copies of

For more information and an example, see [kubernetes-replicator#pull-based-replication](https://github.com/mittwald/kubernetes-replicator#pull-based-replication)

#### Template Use Case

Users can specify the structure and content of secrets based on their unique requirements using standard
[Go templates](https://pkg.go.dev/text/template#hdr-Actions). This flexibility allows for a more tailored approach to
meeting the specific needs of different applications.

Available context:

| Variable | Meaning |
|-------------|--------------------------|
| `.Host` | Database host |
| `.Role` | Generated user/role name |
| `.Database` | Referenced database name |
| `.Password` | Generated role password |

### Contribution

You can contribute to this project by opening a PR to merge to `master`, or one of the `vX.X.X` branches.
Expand Down
4 changes: 2 additions & 2 deletions charts/ext-postgres-operator/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 1.2.3
version: 1.2.5

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.2.3"
appVersion: "1.3.2"
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ spec:
spec:
description: PostgresUserSpec defines the desired state of PostgresUser
properties:
annotations:
additionalProperties:
type: string
type: object
database:
type: string
privileges:
Expand All @@ -39,6 +43,10 @@ spec:
type: string
secretName:
type: string
secretTemplate:
additionalProperties:
type: string
type: object
required:
- database
- role
Expand Down
2 changes: 1 addition & 1 deletion charts/ext-postgres-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ image:
repository: ghcr.io/movetokube/postgres-operator
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: "latest"
tag: ""

# Override chart name, defaults to Chart.name
nameOverride: ""
Expand Down
8 changes: 8 additions & 0 deletions deploy/crds/db.movetokube.com_postgresusers_crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ spec:
spec:
description: PostgresUserSpec defines the desired state of PostgresUser
properties:
annotations:
additionalProperties:
type: string
type: object
database:
type: string
privileges:
Expand All @@ -39,6 +43,10 @@ spec:
type: string
secretName:
type: string
secretTemplate:
additionalProperties:
type: string
type: object
required:
- database
- role
Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/db/v1alpha1/postgresuser_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ type PostgresUserSpec struct {
Database string `json:"database"`
SecretName string `json:"secretName"`
// +optional
SecretTemplate map[string]string `json:"secretTemplate,omitempty"` // key-value, where key is secret field, value is go template
// +optional
Privileges string `json:"privileges"`
// +optional
Annotations map[string]string `json:"annotations,omitempty"`
Expand Down
17 changes: 16 additions & 1 deletion pkg/apis/db/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

73 changes: 60 additions & 13 deletions pkg/controller/postgresuser/postgresuser_controller.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package postgresuser

import (
"bytes"
"context"
goerr "errors"
"fmt"
"text/template"

"github.com/movetokube/postgres-operator/pkg/config"

Expand Down Expand Up @@ -221,7 +223,10 @@ func (r *ReconcilePostgresUser) Reconcile(request reconcile.Request) (reconcile.
return r.requeue(instance, err)
}

secret := r.newSecretForCR(instance, role, password, login)
secret, err := r.newSecretForCR(instance, role, password, login)
if err != nil {
return r.requeue(instance, err)
}

// Set PostgresUser instance as the owner and controller
if err := controllerutil.SetControllerReference(instance, secret, r.scheme); err != nil {
Expand Down Expand Up @@ -270,7 +275,7 @@ func (r *ReconcilePostgresUser) addFinalizer(reqLogger logr.Logger, m *dbv1alpha
return nil
}

func (r *ReconcilePostgresUser) newSecretForCR(cr *dbv1alpha1.PostgresUser, role, password, login string) *corev1.Secret {
func (r *ReconcilePostgresUser) newSecretForCR(cr *dbv1alpha1.PostgresUser, role, password, login string) (*corev1.Secret, error) {
pgUserUrl := fmt.Sprintf("postgresql://%s:%s@%s/%s", role, password, r.pgHost, cr.Status.DatabaseName)
pgJDBCUrl := fmt.Sprintf("jdbc:postgresql://%s/%s", r.pgHost, cr.Status.DatabaseName)
pgDotnetUrl := fmt.Sprintf("User ID=%s;Password=%s;Host=%s;Port=5432;Database=%s;", role, password, r.pgHost, cr.Status.DatabaseName)
Expand All @@ -283,24 +288,40 @@ func (r *ReconcilePostgresUser) newSecretForCR(cr *dbv1alpha1.PostgresUser, role
name = cr.Spec.SecretName
}

templateData, err := renderTemplate(cr.Spec.SecretTemplate, templateContext{
Role: role,
Host: r.pgHost,
Database: cr.Status.DatabaseName,
Password: password,
})
if err != nil {
return nil, fmt.Errorf("render templated keys: %w", err)
}

data := map[string][]byte{
"POSTGRES_URL": []byte(pgUserUrl),
"POSTGRES_JDBC_URL": []byte(pgJDBCUrl),
"POSTGRES_DOTNET_URL": []byte(pgDotnetUrl),
"HOST": []byte(r.pgHost),
"DATABASE_NAME": []byte(cr.Status.DatabaseName),
"ROLE": []byte(role),
"PASSWORD": []byte(password),
"LOGIN": []byte(login),
}
// templates may override standard keys
for k, v := range templateData {
data[k] = v
}

return &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: cr.Namespace,
Labels: labels,
Annotations: annotations,
},
Data: map[string][]byte{
"POSTGRES_URL": []byte(pgUserUrl),
"POSTGRES_JDBC_URL": []byte(pgJDBCUrl),
"POSTGRES_DOTNET_URL": []byte(pgDotnetUrl),
"HOST": []byte(r.pgHost),
"DATABASE_NAME": []byte(cr.Status.DatabaseName),
"ROLE": []byte(role),
"PASSWORD": []byte(password),
"LOGIN": []byte(login),
},
}
Data: data,
}, nil
}

func (r *ReconcilePostgresUser) requeue(cr *dbv1alpha1.PostgresUser, reason error) (reconcile.Result, error) {
Expand Down Expand Up @@ -354,3 +375,29 @@ func (r *ReconcilePostgresUser) addOwnerRef(reqLogger logr.Logger, instance *dbv
err = r.client.Update(context.TODO(), instance)
return err
}

type templateContext struct {
Host string
Role string
Database string
Password string
}

func renderTemplate(data map[string]string, tc templateContext) (map[string][]byte, error) {
if len(data) == 0 {
return nil, nil
}
var out = make(map[string][]byte, len(data))
for key, templ := range data {
parsed, err := template.New("").Parse(templ)
if err != nil {
return nil, fmt.Errorf("parse template %q: %w", key, err)
}
var content bytes.Buffer
if err := parsed.Execute(&content, tc); err != nil {
return nil, fmt.Errorf("execute template %q: %w", key, err)
}
out[key] = content.Bytes()
}
return out, nil
}

0 comments on commit 595d62f

Please sign in to comment.