Skip to content

Commit 2fb0189

Browse files
gbartolinisxdjbattiato
authored
docs: add "CNCF Project Integration" section for External Secrets (cloudnative-pg#7294)
Introduce a new documentation section detailing the integration between CloudNativePG and the `external-secrets` project. This covers automated password rotation and secret management for PostgreSQL users using External Secrets and using Vault to store the secrets. Closes cloudnative-pg#7286 Signed-off-by: Gabriele Bartolini <gabriele.bartolini@enterprisedb.com> Signed-off-by: Jonathan Gonzalez V. <jonathan.gonzalez@enterprisedb.com> Signed-off-by: Jonathan Battiato <jonathan.battiato@enterprisedb.com> Co-authored-by: Jonathan Gonzalez V. <jonathan.gonzalez@enterprisedb.com> Co-authored-by: Jonathan Battiato <jonathan.battiato@enterprisedb.com>
1 parent 56daaad commit 2fb0189

File tree

3 files changed

+267
-0
lines changed

3 files changed

+267
-0
lines changed

.wordlist-en-custom.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ EDB
144144
EKS
145145
EOF
146146
EOL
147+
ESO
147148
EmbeddedObjectMetadata
148149
EnablePDB
149150
EncryptionType
@@ -210,6 +211,7 @@ Istio's
210211
JSON
211212
Jihyuk
212213
Jitendra
214+
KV
213215
Karpenter
214216
KinD
215217
Krew
@@ -365,6 +367,7 @@ PublicationTargetAllTables
365367
PublicationTargetObject
366368
PublicationTargetTable
367369
PullPolicy
370+
PushSecret
368371
QoS
369372
Quaresima
370373
QuickStart
@@ -429,6 +432,7 @@ Seccomp
429432
SeccompProfile
430433
SecretKeySelector
431434
SecretRefs
435+
SecretStore
432436
SecretVersion
433437
SecretsResourceVersion
434438
SecurityProfiles

docs/mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,7 @@ nav:
7474
- supported_releases.md
7575
- preview_version.md
7676
- release_notes.md
77+
- CNCF Projects Integrations:
78+
- cncf-projects/external-secrets.md
7779
- Appendixes:
7880
- appendixes/object_stores.md
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
# External Secrets
2+
3+
[External Secrets](https://external-secrets.io/latest/) is a CNCF Sandbox
4+
project, accepted in 2022 under the sponsorship of TAG Security.
5+
6+
## About
7+
8+
The **External Secrets Operator (ESO)** is a Kubernetes operator that enhances
9+
secret management by decoupling the storage of secrets from Kubernetes itself.
10+
It enables seamless synchronization between external secret management systems
11+
and native Kubernetes `Secret` resources.
12+
13+
ESO supports a wide range of backends, including:
14+
15+
- [HashiCorp Vault](https://www.vaultproject.io/)
16+
- [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/)
17+
- [Google Secret Manager](https://cloud.google.com/secret-manager)
18+
- [Azure Key Vault](https://azure.microsoft.com/en-us/services/key-vault/)
19+
- [IBM Cloud Secrets Manager](https://www.ibm.com/cloud/secrets-manager)
20+
21+
…and many more. For a full and up-to-date list of supported providers, refer to
22+
the [official External Secrets documentation](https://external-secrets.io/latest/).
23+
24+
## Integration with PostgreSQL and CloudNativePG
25+
26+
When it comes to PostgreSQL databases, External Secrets integrates seamlessly
27+
with [CloudNativePG](https://cloudnative-pg.io/) in two major use cases:
28+
29+
- **Automated password management:** ESO can handle the automatic generation
30+
and rotation of database user passwords stored in Kubernetes `Secret`
31+
resources, ensuring that applications running inside the cluster always have
32+
access to up-to-date credentials.
33+
34+
- **Cross-platform secret access:** It enables transparent synchronization of
35+
those passwords with an external Key Management Service (KMS) via a
36+
`SecretStore` resources. This allows applications and developers outside the
37+
Kubernetes cluster—who may not have access to Kubernetes secrets—to retrieve
38+
the database credentials directly from the external KMS.
39+
40+
## Example: Automated Password Management with External Secrets
41+
42+
Let’s walk through how to automatically rotate the password of the `app` user
43+
every 24 hours in the `cluster-example` Postgres cluster from the
44+
[quickstart guide](../quickstart.md#part-3-deploy-a-postgresql-cluster).
45+
46+
!!! Important
47+
Before proceeding, ensure that the `cluster-example` Postgres cluster is up
48+
and running in your environment.
49+
50+
By default, CloudNativePG generates and manages a Kubernetes `Secret` named
51+
`cluster-example-app`, which contains the credentials for the `app` user in the
52+
`cluster-example` cluster. You can read more about this in the
53+
[“Connecting from an application” section](../applications.md#secrets).
54+
55+
With External Secrets, the goal is to:
56+
57+
1. Define a `Password` generator that specifies how to generate the password.
58+
2. Create an `ExternalSecret` resource that keeps the `cluster-example-app`
59+
secret in sync by updating only the `password` and `pgpass` fields.
60+
61+
### Creating the Password Generator
62+
63+
The following example creates a
64+
[`Password` generator](https://external-secrets.io/main/api/generator/password/)
65+
resource named `pg-password-generator` in the `default` namespace. You can
66+
customize the name and properties to suit your needs:
67+
68+
```yaml
69+
apiVersion: generators.external-secrets.io/v1alpha1
70+
kind: Password
71+
metadata:
72+
name: pg-password-generator
73+
spec:
74+
length: 42
75+
digits: 5
76+
symbols: 5
77+
symbolCharacters: "-_$@"
78+
noUpper: false
79+
allowRepeat: true
80+
```
81+
82+
This specification defines the characteristics of the generated password,
83+
including its length and the inclusion of digits, symbols, and uppercase
84+
letters.
85+
86+
### Creating the External Secret
87+
88+
The example below creates an `ExternalSecret` resource named
89+
`cluster-example-app-secret`, which refreshes the password every 24 hours. It
90+
uses a `Merge` policy to update only the specified fields (`password`, `pgpass`,
91+
`jdbc-uri` and `uri`) in the `cluster-example-app` secret.
92+
93+
```yaml
94+
apiVersion: external-secrets.io/v1beta1
95+
kind: ExternalSecret
96+
metadata:
97+
name: cluster-example-app-secret
98+
spec:
99+
refreshInterval: "24h"
100+
target:
101+
name: cluster-example-app
102+
creationPolicy: Merge
103+
template:
104+
metadata:
105+
labels:
106+
cnpg.io/reload: "true"
107+
data:
108+
password: "{{ .password }}"
109+
pgpass: "cluster-example-rw:5432:app:app:{{ .password }}"
110+
jdbc-uri: "jdbc:postgresql://cluster-example-rw.default:5432/app?password={{ .password }}&user=app"
111+
uri: "postgresql://app:{{ .password }}@cluster-example-rw.default:5432/app"
112+
dataFrom:
113+
- sourceRef:
114+
generatorRef:
115+
apiVersion: generators.external-secrets.io/v1alpha1
116+
kind: Password
117+
name: pg-password-generator
118+
```
119+
120+
The label `cnpg.io/reload: "true"` ensures that CloudNativePG triggers a reload
121+
of the user password in the database when the secret changes.
122+
123+
### Verifying the Configuration
124+
125+
To check that the `ExternalSecret` is correctly synchronizing:
126+
127+
```sh
128+
kubectl get es cluster-example-app-secret
129+
```
130+
131+
To observe the password being refreshed in real time, temporarily reduce the
132+
`refreshInterval` to `30s` and run the following command repeatedly:
133+
134+
```sh
135+
kubectl get secret cluster-example-app \
136+
-o jsonpath="{.data.password}" | base64 -d
137+
```
138+
139+
You should see the password change every 30 seconds, confirming that the
140+
rotation is working correctly.
141+
142+
### There's More
143+
144+
While the example above focuses on the default `cluster-example-app` secret
145+
created by CloudNativePG, the same approach can be extended to manage any
146+
custom secrets or PostgreSQL users you create to regularly rotate their
147+
password.
148+
149+
150+
## Example: Integration with an External KMS
151+
152+
A widely used Key Management Service (KMS) provider in the CNCF ecosystem is
153+
[HashiCorp Vault](https://www.vaultproject.io/).
154+
155+
In this example, we'll demonstrate how to integrate CloudNativePG,
156+
External Secrets Operator, and HashiCorp Vault to automatically rotate
157+
a PostgreSQL password and securely store it in Vault.
158+
159+
!!! Important
160+
This example assumes that HashiCorp Vault is already installed and properly
161+
configured in your environment, and that your team has the necessary expertise
162+
to operate it. There are various ways to deploy Vault, and detailing them is
163+
outside the scope of CloudNativePG. While it's possible to run Vault inside
164+
Kubernetes, it is more commonly deployed externally. For detailed instructions,
165+
consult the [HashiCorp Vault documentation](https://www.vaultproject.io/docs).
166+
167+
Continuing from the previous example, we will now create the necessary
168+
`SecretStore` and `PushSecret` resources to complete the integration with
169+
Vault.
170+
171+
### Creating the `SecretStore`
172+
173+
In this example, we assume that HashiCorp Vault is accessible from within the
174+
namespace at `http://vault.vault.svc:8200`, and that a Kubernetes `Secret`
175+
named `vault-token` exists in the same namespace, containing the token used to
176+
authenticate with Vault.
177+
178+
```yaml
179+
apiVersion: external-secrets.io/v1beta1
180+
kind: SecretStore
181+
metadata:
182+
name: vault-backend
183+
spec:
184+
provider:
185+
vault:
186+
server: "http://vault.vault.svc:8200"
187+
path: "secrets"
188+
# Specifies the Vault KV secret engine version ("v1" or "v2").
189+
# Defaults to "v2" if not set.
190+
version: "v2"
191+
auth:
192+
# References a Kubernetes Secret that contains the Vault token.
193+
# See: https://www.vaultproject.io/docs/auth/token
194+
tokenSecretRef:
195+
name: "vault-token"
196+
key: "token"
197+
---
198+
apiVersion: v1
199+
kind: Secret
200+
metadata:
201+
name: vault-token
202+
data:
203+
token: aHZzLioqKioqKio= # hvs.*******
204+
```
205+
206+
This configuration creates a `SecretStore` resource named `vault-backend`.
207+
208+
!!! Important
209+
This example uses basic token-based authentication, which is suitable for
210+
testing API, and CLI use cases. While it is the default method enabled in
211+
Vault, it is not recommended for production environments. For production,
212+
consider using more secure authentication methods.
213+
Refer to the [External Secrets Operator documentation](https://external-secrets.io/latest/provider/hashicorp-vault/)
214+
for a full list of supported authentication mechanisms.
215+
216+
!!! Info
217+
HashiCorp Vault must have a KV secrets engine enabled at the `secrets` path
218+
with version `v2`. If your Vault instance uses a different path or
219+
version, be sure to update the `path` and `version` fields accordingly.
220+
221+
### Creating the `PushSecret`
222+
223+
The `PushSecret` resource is used to push a Kubernetes `Secret` to HashiCorp
224+
Vault. In this simplified example, we'll push the credentials for the `app`
225+
user of the sample cluster `cluster-example`.
226+
227+
For more details on configuring `PushSecret`, refer to the
228+
[External Secrets Operator documentation](https://external-secrets.io/latest/api/pushsecret/).
229+
230+
```yaml
231+
apiVersion: external-secrets.io/v1alpha1
232+
kind: PushSecret
233+
metadata:
234+
name: pushsecret-example
235+
spec:
236+
deletionPolicy: Delete
237+
refreshInterval: 24h
238+
secretStoreRefs:
239+
- name: vault-backend
240+
kind: SecretStore
241+
selector:
242+
secret:
243+
name: cluster-example-app
244+
data:
245+
- match:
246+
remoteRef:
247+
remoteKey: cluster-example-app
248+
```
249+
250+
In this example, the `PushSecret` resource instructs the External Secrets
251+
Operator to push the Kubernetes `Secret` named `cluster-example-app` to
252+
HashiCorp Vault (from the previous example). The `remoteKey` defines the name
253+
under which the secret will be stored in Vault, using the `SecretStore` named
254+
`vault-backend`.
255+
256+
### Verifying the Configuration
257+
258+
To verify that the `PushSecret` is functioning correctly, navigate to the
259+
HashiCorp Vault UI. In the `kv` secrets engine at the path `secrets`, you
260+
should find a secret named `cluster-example-app`, corresponding to the
261+
`remoteKey` defined above.

0 commit comments

Comments
 (0)