Skip to content

Commit a063b96

Browse files
authored
Merge pull request #112 from cybertec-postgresql/tde-improvements
Tde improvements
2 parents 0f35e8a + 5612e00 commit a063b96

10 files changed

Lines changed: 191 additions & 39 deletions

File tree

charts/postgres-operator/crds/postgresqls.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,19 @@ spec:
694694
type: string
695695
recoveryEventType:
696696
type: string
697+
tde:
698+
nullable: true
699+
properties:
700+
enable:
701+
type: boolean
702+
keybits:
703+
type: integer
704+
format: int32
705+
default: 128
706+
enum:
707+
- 128
708+
- 192
709+
- 256
697710
teamId:
698711
type: string
699712
tls:

docs/hugo/content/en/crd/crd-postgresql.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ weight: 331
5757
| spiloRunAsUser | int | false | Sets the user ID which should be used in the container to run the process. This must be set to run the container without root. |
5858
| [standby](#standby) | map | false | Enables the creation of a standby cluster at the time of the creation of a new cluster |
5959
| [streams](#streams) | array | false | Enables change data capture streams for defined database tables |
60-
| [tde](#tde) | map | false | Enables the activation of TDE if a new cluster is created |
60+
| [tde](#tde) | map | false | Enables TDE and allows you to define options such as key bits. |
6161
| teamId | string | true | name of the team the cluster belongs to. Will be removed soon |
6262
| [tls](#tls) | map | false | Custom TLS certificate |
6363
| [tolerations](#tolerations) | array | false | a list of tolerations that apply to the cluster pods. Each element of that list is a dictionary with the following fields:
@@ -256,9 +256,10 @@ key, operator, value, effect and tolerationSeconds |
256256

257257
#### tde
258258

259-
| Name | Type | required | Description |
260-
| ------------------------------ |:-------:| ---------:| ------------------:|
261-
| enable | boolean | true | enable TDE during initDB |
259+
| Name | Type | default | Description |
260+
| ------------------------------ |:-------:| ---------:| -------------------------:|
261+
| enable | boolean | false | enable TDE during initDB |
262+
| keybits | integer | 256 | used to specify the key length in bits. Accepted values are 128, 192 and 256 (default). More Informations: [PGEE-Documentation](https://repository.cybertec.at/doc/18ee/encryption.html) |
262263

263264
{{< back >}}
264265

docs/hugo/content/en/tde/_index.md

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Further information on TDE and PGEE can be found here: [CYBERTEC TDE](https://ww
2727

2828
## Securing clusters with TDE
2929

30-
The CYBERTEC pg operator, together with Patroni, takes over the setup and administration of the TDE functionality in conjunction with the cost-effective PGEE containers
30+
The CYBERTEC-pg-operator, together with Patroni, takes over the setup and administration of the TDE functionality in conjunction with the cost-effective PGEE containers
3131

3232
### Preconditions
3333
- CYBERTEC-pgee-container
@@ -36,7 +36,7 @@ The CYBERTEC pg operator, together with Patroni, takes over the setup and admini
3636
### Deploy a TDE-Cluster
3737

3838
Setting up a TDE cluster is basically the same as setting up a conventional cluster.
39-
The only difference is the defined Postgres. container and the object TDE.enabled: true, which instructs the operator to initialise the database with the TDE functionality.
39+
The only difference is the defined Postgres-container and the object TDE.enabled: true, which instructs the operator to initialise the database with the TDE functionality.
4040

4141
```yaml
4242
apiVersion: cpo.opensource.cybertec.at/v1
@@ -58,20 +58,65 @@ spec:
5858
memory: 500Mi
5959
tde:
6060
enable: true
61+
keybits: 256
6162
teamId: acid
6263
volume:
6364
size: 5Gi
6465
```
6566
- `dockerImage` - Must contain a PostgreSQL image of the pgee container suite
6667
- `tde.enabled`- initialises the DB with TDE
68+
- `tde.keybits`- Defines keylength in bits. Possible Values: 128,192,256 Default: 256
6769

6870
{{< hint type=important >}} Please note that the activation of TDE is only possible when creating new clusters. Subsequent activation is not possible. {{< /hint >}}
6971

72+
### Key-Management
73+
74+
For TDE, we or the operator must work with the required encryption key. The key is transferred to the Postgres containers using a secret. There are two basic options for the necessary key management.
75+
76+
#### Automatic key generation (default)
77+
If no existing secret is provided, the operator automatically generates a cryptographically secure key when creating a new cluster. This is stored in the secret in the cluster's namespace.
78+
79+
It is important to note for key management that TDE allows you to choose from the available key lengths (128 bit, 192 bit, 256 bit). By default, the operator chooses 256 bit. The keybits parameter allows you to adjust this if desired. See [CRD](crd/crd-postgresql).
80+
Further information on TDE can also be found in the [PGEE-Documentation](https://repository.cybertec.at/doc/18ee/encryption.html)
81+
82+
#### Use of your own keys (Bring Your Own Key)
83+
You have the option of defining your own encryption key before the cluster is created.
84+
To do this, create a secret with the desired key in advance.
85+
When starting, the operator checks whether a corresponding secret already exists and uses this instead of a newly generated key.
86+
Use case: This enables the integration of external secret store solutions (e.g. HashiCorp Vault) to stream or synchronise keys directly into the Kubernetes secret.
87+
88+
{{< hint type=important >}} If you provide your own key, you must ensure that the length of the key (in bytes) matches the configured keybits exactly.
89+
| keybits | Keylength (Byte) | Notes |
90+
| -------- |:----------------:| --------------:|
91+
| 128 | 16 Byte | |
92+
| 192 | 24 Byte | |
93+
| 256 | 32 Byte | (Default) |
94+
95+
A discrepancy between the configured bit length and the actual byte length of the provided key will result in errors when starting the database.
96+
{{< /hint >}}
97+
98+
The secret name follows the following fixed naming convention: [CLUSTERNAME]-tde
99+
100+
```yaml
101+
kind: Secret
102+
apiVersion: v1
103+
metadata:
104+
name: [CLUSTERNAME]-tde
105+
stringData:
106+
key: [TDE-KEY]
107+
type: Opaque
108+
```
109+
70110
### Check TDE-Status
71111

72112
```sh
113+
114+
sh-5.1$ /usr/pgsql-17/bin/pg_controldata | grep -i "Encryption"
115+
Data encryption: on
116+
Encryption key length: 128
117+
73118
[postgres@tde-cluster-1-0 ~]$ psql
74-
psql (17.4 EE 1.4.1)
119+
psql (18.1 EE 1.5.0, server 17.7 EE 1.4.4)
75120
____ ____ _____ _____
76121
| _ \ / ___| ____| ____|
77122
| |_) | | _| _| | _|

manifests/postgresql.crd.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,20 @@ spec:
692692
type: string
693693
recoveryEventType:
694694
type: string
695+
tde:
696+
nullable: true
697+
properties:
698+
enable:
699+
type: boolean
700+
keybits:
701+
type: integer
702+
format: int32
703+
default: 128
704+
enum:
705+
- 128
706+
- 192
707+
- 256
708+
type: object
695709
teamId:
696710
type: string
697711
tls:

pkg/apis/cpo.opensource.cybertec.at/v1/crds.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,6 +1444,18 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{
14441444
"enable": {
14451445
Type: "boolean",
14461446
},
1447+
"keybits": {
1448+
Type: "integer",
1449+
Format: "int32",
1450+
Enum: []apiextv1.JSON{
1451+
{Raw: []byte("128")},
1452+
{Raw: []byte("192")},
1453+
{Raw: []byte("256")},
1454+
},
1455+
Default: &apiextv1.JSON{
1456+
Raw: []byte("128"),
1457+
},
1458+
},
14471459
},
14481460
},
14491461
"monitor": {

pkg/apis/cpo.opensource.cybertec.at/v1/postgresql_type.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,8 @@ type Configuration struct {
316316
}
317317

318318
type TDE struct {
319-
Enable bool `json:"enable"`
319+
Enable bool `json:"enable"`
320+
Keybits *int32 `json:"keybits"`
320321
}
321322

322323
// Monitoring Sidecar defines a container to be run in the same pod as the Postgres container.

pkg/apis/cpo.opensource.cybertec.at/v1/zz_generated.deepcopy.go

Lines changed: 6 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/cluster/k8sres.go

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ type spiloConfiguration struct {
8383
Bootstrap pgBootstrap `json:"bootstrap"`
8484
}
8585

86+
type TDEConfig struct {
87+
Enabled bool
88+
KeyBits string
89+
}
90+
8691
func (c *Cluster) statefulSetName() string {
8792
return c.Name
8893
}
@@ -327,7 +332,7 @@ func (c *Cluster) generateResourceRequirements(
327332
return &result, nil
328333
}
329334

330-
func generateSpiloJSONConfiguration(pg *cpov1.PostgresqlParam, patroni *cpov1.Patroni, opConfig *config.Config, enableTDE bool, logger *logrus.Entry) (string, error) {
335+
func generateSpiloJSONConfiguration(pg *cpov1.PostgresqlParam, patroni *cpov1.Patroni, opConfig *config.Config, tdeOptions TDEConfig, logger *logrus.Entry) (string, error) {
331336
config := spiloConfiguration{}
332337

333338
config.Bootstrap = pgBootstrap{}
@@ -350,8 +355,9 @@ func generateSpiloJSONConfiguration(pg *cpov1.PostgresqlParam, patroni *cpov1.Pa
350355
map[string]string{"auth-local": "trust"}}
351356
}
352357

353-
if enableTDE {
358+
if tdeOptions.Enabled {
354359
config.Bootstrap.Initdb = append(config.Bootstrap.Initdb, map[string]string{"encryption-key-command": "/tmp/tde.sh"})
360+
config.Bootstrap.Initdb = append(config.Bootstrap.Initdb, map[string]string{"key-bits": tdeOptions.KeyBits})
355361
}
356362

357363
initdbOptionNames := []string{}
@@ -878,17 +884,16 @@ func (c *Cluster) generatePodTemplate(
878884
podSpec.PriorityClassName = priorityClassName
879885
}
880886

881-
if c.Postgresql.Spec.Monitoring != nil {
882-
addEmptyDirVolume(&podSpec, "exporter-tmp", "postgres-exporter", "/tmp")
883-
}
884-
885-
if c.OpConfig.ReadOnlyRootFilesystem != nil && *c.OpConfig.ReadOnlyRootFilesystem && !isRepoHost {
887+
if c.OpConfig.ReadOnlyRootFilesystem != nil && *c.OpConfig.ReadOnlyRootFilesystem && spiloContainer.Name == "postgres" {
886888
addRunVolume(&podSpec, "postgres-run", "postgres", "/run")
887889
addEmptyDirVolume(&podSpec, "postgres-tmp", "postgres", "/tmp")
890+
if c.Postgresql.Spec.Monitoring != nil {
891+
addEmptyDirVolume(&podSpec, "exporter-tmp", "postgres-exporter", "/tmp")
892+
}
888893
}
889894

890-
if c.OpConfig.ReadOnlyRootFilesystem != nil && *c.OpConfig.ReadOnlyRootFilesystem && isRepoHost {
891-
addEmptyDirVolume(&podSpec, "pgbackrest-tmp", "pgbackrest", "/tmp")
895+
if c.OpConfig.ReadOnlyRootFilesystem != nil && *c.OpConfig.ReadOnlyRootFilesystem && strings.Contains(spiloContainer.Name, "pgbackrest") {
896+
addEmptyDirVolume(&podSpec, "pgbackrest-tmp", spiloContainer.Name, "/tmp")
892897
}
893898

894899
if sharePgSocketWithSidecars != nil && *sharePgSocketWithSidecars {
@@ -1393,11 +1398,20 @@ func (c *Cluster) generateStatefulSet(spec *cpov1.PostgresSpec) (*appsv1.Statefu
13931398
}
13941399
}
13951400

1396-
enableTDE := false
1401+
// Keybits must be converted to strings for initdb processing.
1402+
tdeOptions := TDEConfig{Enabled: false}
13971403
if spec.TDE != nil && spec.TDE.Enable {
1398-
enableTDE = true
1404+
tdeOptions.Enabled = true
1405+
tdeOptions.KeyBits = strconv.Itoa(256)
1406+
ptr := c.Postgresql.Spec.TDE.Keybits
1407+
if ptr != nil {
1408+
val := *ptr
1409+
if val == 128 || val == 192 {
1410+
tdeOptions.KeyBits = fmt.Sprintf("%d", val)
1411+
}
1412+
}
13991413
}
1400-
spiloConfiguration, err := generateSpiloJSONConfiguration(&spec.PostgresqlParam, &spec.Patroni, &c.OpConfig, enableTDE, c.logger)
1414+
spiloConfiguration, err := generateSpiloJSONConfiguration(&spec.PostgresqlParam, &spec.Patroni, &c.OpConfig, tdeOptions, c.logger)
14011415
if err != nil {
14021416
return nil, fmt.Errorf("could not generate Spilo JSON configuration: %v", err)
14031417
}

0 commit comments

Comments
 (0)