Skip to content

Commit 312dc94

Browse files
committed
grant create on Secrets through a namespaced Role in the operator namespace
The `create` verb was part of the ClusterRole of the `Role` controller, which allowed the operator to create Secrets in every namespace. It is only needed for the password fingerprint key Secret in the operator namespace. The Quarkus Kubernetes extension now generates a namespaced Role and RoleBinding for it. The default RoleBinding to the `view` ClusterRole is kept explicitly, because configured role bindings replace it.
1 parent 15cdd8f commit 312dc94

4 files changed

Lines changed: 26 additions & 3 deletions

File tree

docs/role.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ On each reconcile it compares the referenced Secret against that fingerprint. Wh
5656

5757
The fingerprint is an `HMAC-SHA256`. Its key is random and private to the operator.
5858
The operator generates the key once and stores it in a Secret named `postgresql-operator-password-fingerprint-key` in its own namespace. A reader of the `Role` status learns nothing about the password without that key.
59-
The Secret name is set by the configuration property `postgresql-operator.password-fingerprint.secret-name`, for example through the environment variable `POSTGRESQL_OPERATOR_PASSWORD_FINGERPRINT_SECRET_NAME`.
59+
The Secret name is set by the configuration property `postgresql-operator.password-fingerprint.secret-name`, for example through the environment variable `POSTGRESQL_OPERATOR_PASSWORD_FINGERPRINT_SECRET_NAME`.
60+
The Helm chart grants `create` on Secrets through a `Role` and `RoleBinding` in the operator namespace only. The `ClusterRole` of the operator keeps read access to Secrets.
6061

6162
**Consequences:**
6263

operator/src/main/java/it/aboutbits/postgresql/crd/role/RoleReconciler.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@
3737
@RBACRule(
3838
apiGroups = {""},
3939
resources = {"secrets"},
40-
// "create" is needed once for the password fingerprint key Secret in the operator namespace
41-
verbs = {"get", "list", "watch", "create"}
40+
// `create` for the password fingerprint key Secret is granted by a namespaced Role in the operator namespace,
41+
// see `quarkus.kubernetes.rbac` in application.yml. It does not belong in this ClusterRole.
42+
verbs = {"get", "list", "watch"}
4243
)
4344
})
4445
@RequiredArgsConstructor

operator/src/main/resources/application.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,22 @@ quarkus:
220220
QUARKUS_CONSOLE_COLOR: ${quarkus.console.color}
221221
QUARKUS_LOG_CONSOLE_JSON_ENABLED: ${quarkus.log.console.json.enabled}
222222
QUARKUS_LOG_CONSOLE_JSON_LOG_FORMAT: ${quarkus.log.console.json.log-format}
223+
rbac:
224+
# The operator creates the password fingerprint key Secret in its own namespace.
225+
# `create` on Secrets is granted through this namespaced Role only, not through the ClusterRole of the Role controller,
226+
# which would allow the operator to create Secrets in every namespace.
227+
# `api-groups` is omitted, so the rule targets the core API group.
228+
roles:
229+
postgresql-operator-password-fingerprint-key:
230+
policy-rules:
231+
create-secrets:
232+
resources: secrets
233+
verbs: create
234+
role-bindings:
235+
postgresql-operator-password-fingerprint-key:
236+
role-name: postgresql-operator-password-fingerprint-key
237+
# The kubernetes-client extension stops generating its default binding to the `view` ClusterRole as soon as
238+
# `role-bindings` are configured. This entry keeps that binding, so that the chart does not lose it.
239+
postgresql-operator-view:
240+
role-name: view
241+
cluster-wide: true

operator/src/test/java/it/aboutbits/postgresql/helm/HelmTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ void helmInstall_createsDeployment() throws IOException {
156156
assertThat(chartPath.resolve("templates/clusterrole.yaml")).exists();
157157
assertThat(chartPath.resolve("templates/clusterrolebinding.yaml")).exists();
158158
assertThat(chartPath.resolve("templates/deployment.yaml")).exists();
159+
// The namespaced Role that grants `create` on the password fingerprint key Secret
160+
assertThat(chartPath.resolve("templates/role.yaml")).exists();
159161
assertThat(chartPath.resolve("templates/rolebinding.yaml")).exists();
160162
assertThat(chartPath.resolve("templates/service.yaml")).exists();
161163
assertThat(chartPath.resolve("templates/serviceaccount.yaml")).exists();

0 commit comments

Comments
 (0)