Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,15 @@ spec:
rule.verbs != null &&
rule.verbs.all(v, v in ['create', 'delete', 'get', 'list', 'patch', 'update', 'watch'])
) ||
(
rule.apiGroups.size() == 1 &&
rule.apiGroups[0] == 'openbao.org' &&
rule.resources != null &&
rule.resources.size() == 1 &&
rule.resources[0] == 'openbaoclusters' &&
rule.verbs != null &&
rule.verbs.all(v, v in ['usecustomexecutables', 'useimagetrustroots'])
) ||
(
rule.apiGroups.size() == 1 &&
rule.apiGroups[0] == 'apps' &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,35 @@ spec:
- name: rolling_upgrade_progress_started
expression: >-
oldObject != null && has(oldObject.status) && has(oldObject.status.upgrade) && (oldObject.status.upgrade.currentPartition < oldObject.spec.replicas || (has(oldObject.status.upgrade.completedPods) && size(oldObject.status.upgrade.completedPods) > 0))
- name: custom_executables_authorized
expression: >-
authorizer.group("openbao.org").resource("openbaoclusters").namespace(request.namespace).name(object.metadata.name).check("usecustomexecutables").allowed() ||
authorizer.group("openbao.org").resource("openbaoclusters").namespace(request.namespace).name(object.metadata.name).check("usehelperimages").allowed()
- name: image_trust_roots_authorized
expression: >-
authorizer.group("openbao.org").resource("openbaoclusters").namespace(request.namespace).name(object.metadata.name).check("useimagetrustroots").allowed()
- name: has_custom_main_image_trust_roots
expression: >-
has(object.spec.imageVerification) &&
(
(has(object.spec.imageVerification.publicKey) && object.spec.imageVerification.publicKey.trim() != "") ||
(has(object.spec.imageVerification.issuer) && object.spec.imageVerification.issuer.trim() != "") ||
(has(object.spec.imageVerification.subject) && object.spec.imageVerification.subject.trim() != "") ||
(has(object.spec.imageVerification.issuerRegExp) && object.spec.imageVerification.issuerRegExp.trim() != "") ||
(has(object.spec.imageVerification.subjectRegExp) && object.spec.imageVerification.subjectRegExp.trim() != "") ||
(has(object.spec.imageVerification.ignoreTlog) && object.spec.imageVerification.ignoreTlog == true)
)
- name: has_custom_operator_image_trust_roots
expression: >-
has(object.spec.operatorImageVerification) &&
(
(has(object.spec.operatorImageVerification.publicKey) && object.spec.operatorImageVerification.publicKey.trim() != "") ||
(has(object.spec.operatorImageVerification.issuer) && object.spec.operatorImageVerification.issuer.trim() != "") ||
(has(object.spec.operatorImageVerification.subject) && object.spec.operatorImageVerification.subject.trim() != "") ||
(has(object.spec.operatorImageVerification.issuerRegExp) && object.spec.operatorImageVerification.issuerRegExp.trim() != "") ||
(has(object.spec.operatorImageVerification.subjectRegExp) && object.spec.operatorImageVerification.subjectRegExp.trim() != "") ||
(has(object.spec.operatorImageVerification.ignoreTlog) && object.spec.operatorImageVerification.ignoreTlog == true)
)
- name: requested_below_current_version
expression: >-
variables.current_version_valid &&
Expand Down Expand Up @@ -374,18 +403,26 @@ spec:
object.spec.profile != "Hardened" ||
object.spec.replicas >= 3
message: "Hardened profile requires at least 3 replicas for Raft quorum HA. Use Profile=Development for non-HA deployments."
# Confused-deputy protection: custom backup helper images run with backup credentials.
# Confused-deputy protection: CR-selected custom executables run with operator-managed identities,
# OpenBao runtime mounts, or both. Existing usehelperimages grants are accepted as a compatibility alias.
- expression: >-
!has(object.spec.backup) ||
!has(object.spec.backup.image) ||
object.spec.backup.image == "" ||
(request.operation == "UPDATE" &&
oldObject != null &&
has(oldObject.spec.backup) &&
has(oldObject.spec.backup.image) &&
oldObject.spec.backup.image == object.spec.backup.image) ||
authorizer.group("openbao.org").resource("openbaoclusters").namespace(request.namespace).name(object.metadata.name).check("usehelperimages").allowed()
message: "Users configuring custom backup helper images must be authorized to use helper image overrides on this OpenBaoCluster."
(
(!has(object.spec.initContainer) || !has(object.spec.initContainer.image) || object.spec.initContainer.image == "") &&
(!has(object.spec.backup) || !has(object.spec.backup.image) || object.spec.backup.image == "") &&
(!has(object.spec.upgrade) || !has(object.spec.upgrade.image) || object.spec.upgrade.image == "") &&
(!has(object.spec.upgrade) || !has(object.spec.upgrade.blueGreen) || !has(object.spec.upgrade.blueGreen.verification) || !has(object.spec.upgrade.blueGreen.verification.prePromotionHook)) &&
(!has(object.spec.plugins) || object.spec.plugins.all(p, (!has(p.image) || p.image == "") && (!has(p.command) || p.command == "")))
) ||
variables.custom_executables_authorized
message: "Users configuring CR-selected custom executables (custom init, backup, upgrade, blue/green hook, or plugin executable configuration) must be authorized to use custom executables on this OpenBaoCluster."
# Supply-chain protection: Hardened image verification may use official defaults without extra RBAC,
# but CR-selected trust roots require a separate delegation.
- expression: >-
!has(object.spec.profile) ||
object.spec.profile != "Hardened" ||
!(variables.has_custom_main_image_trust_roots || variables.has_custom_operator_image_trust_roots) ||
variables.image_trust_roots_authorized
message: "Users configuring custom image verification trust roots in Hardened profile must be authorized to use image trust roots on this OpenBaoCluster."
# Confused-deputy protection: users configuring unseal Secret credentials must be able to read that Secret.
- expression: >-
!has(object.spec.unseal) ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ spec:
- name: restore_endpoint_is_in_cluster_service
expression: >-
variables.restore_endpoint_hostname_normalized.matches("^[a-z0-9]([-a-z0-9]*[a-z0-9])?\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?\\.svc(\\.cluster\\.local)?$")
- name: custom_executables_authorized
expression: >-
authorizer.group("openbao.org").resource("openbaoclusters").namespace(request.namespace).name(object.spec.cluster).check("usecustomexecutables").allowed() ||
authorizer.group("openbao.org").resource("openbaoclusters").namespace(request.namespace).name(object.spec.cluster).check("usehelperimages").allowed()
validations:
# API contract: restore specs are immutable after creation.
- expression: >-
Expand Down Expand Up @@ -86,15 +90,12 @@ spec:
(variables.restore_endpoint_scheme == "http" && variables.restore_endpoint_is_in_cluster_service)))
message: "Restore endpoint must use HTTPS or S3 scheme, unless it targets an in-cluster Service (*.svc)."
# Confused-deputy protection: custom restore helper images run with restore credentials.
# Existing usehelperimages grants are accepted as a compatibility alias.
- expression: >-
!has(object.spec.image) ||
object.spec.image == "" ||
(request.operation == "UPDATE" &&
oldObject != null &&
has(oldObject.spec.image) &&
oldObject.spec.image == object.spec.image) ||
authorizer.group("openbao.org").resource("openbaoclusters").namespace(request.namespace).name(object.spec.cluster).check("usehelperimages").allowed()
message: "Users configuring custom restore helper images must be authorized to use helper image overrides on the target OpenBaoCluster."
variables.custom_executables_authorized
message: "Users configuring custom restore helper images must be authorized to use custom executables on the target OpenBaoCluster."
# Confused-deputy protection: users configuring restore Secret credentials must be able to read those Secrets.
- expression: >-
(!has(object.spec.source.target.credentialsSecretRef) ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,26 @@ rules:
- openbaoclusters
verbs:
- get
- usecustomexecutables
- usehelperimages
---

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
{{- include "openbao-operator.labels" . | nindent 4 }}
name: {{ include "openbao-operator.fullname" . }}-openbaocluster-image-trust-roots
rules:
- apiGroups:
- openbao.org
resources:
- openbaoclusters
verbs:
- get
- useimagetrustroots
---

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ rules:
- patch
- update
- watch
- apiGroups:
- openbao.org
resources:
- openbaoclusters
verbs:
- usecustomexecutables
- useimagetrustroots
- apiGroups:
- openbao.org
resources:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ rules:
- delete
- get
- patch
- apiGroups:
- openbao.org
resources:
- openbaoclusters
verbs:
- usecustomexecutables
- useimagetrustroots
- apiGroups:
- openbao.org
resources:
Expand Down
7 changes: 7 additions & 0 deletions config/overlays/single-tenant/single_tenant_clusterrole.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ rules:
- delete
- get
- patch
- apiGroups:
- openbao.org
resources:
- openbaoclusters
verbs:
- usecustomexecutables
- useimagetrustroots
- apiGroups:
- openbao.org
resources:
Expand Down
9 changes: 9 additions & 0 deletions config/policy/openbao-restrict-provisioner-rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ spec:
rule.verbs != null &&
rule.verbs.all(v, v in ['create', 'delete', 'get', 'list', 'patch', 'update', 'watch'])
) ||
(
rule.apiGroups.size() == 1 &&
rule.apiGroups[0] == 'openbao.org' &&
rule.resources != null &&
rule.resources.size() == 1 &&
rule.resources[0] == 'openbaoclusters' &&
rule.verbs != null &&
rule.verbs.all(v, v in ['usecustomexecutables', 'useimagetrustroots'])
) ||
(
rule.apiGroups.size() == 1 &&
rule.apiGroups[0] == 'apps' &&
Expand Down
59 changes: 48 additions & 11 deletions config/policy/openbao-validate-openbaocluster.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,35 @@ spec:
- name: rolling_upgrade_progress_started
expression: >-
oldObject != null && has(oldObject.status) && has(oldObject.status.upgrade) && (oldObject.status.upgrade.currentPartition < oldObject.spec.replicas || (has(oldObject.status.upgrade.completedPods) && size(oldObject.status.upgrade.completedPods) > 0))
- name: custom_executables_authorized
expression: >-
authorizer.group("openbao.org").resource("openbaoclusters").namespace(request.namespace).name(object.metadata.name).check("usecustomexecutables").allowed() ||
authorizer.group("openbao.org").resource("openbaoclusters").namespace(request.namespace).name(object.metadata.name).check("usehelperimages").allowed()
- name: image_trust_roots_authorized
expression: >-
authorizer.group("openbao.org").resource("openbaoclusters").namespace(request.namespace).name(object.metadata.name).check("useimagetrustroots").allowed()
- name: has_custom_main_image_trust_roots
expression: >-
has(object.spec.imageVerification) &&
(
(has(object.spec.imageVerification.publicKey) && object.spec.imageVerification.publicKey.trim() != "") ||
(has(object.spec.imageVerification.issuer) && object.spec.imageVerification.issuer.trim() != "") ||
(has(object.spec.imageVerification.subject) && object.spec.imageVerification.subject.trim() != "") ||
(has(object.spec.imageVerification.issuerRegExp) && object.spec.imageVerification.issuerRegExp.trim() != "") ||
(has(object.spec.imageVerification.subjectRegExp) && object.spec.imageVerification.subjectRegExp.trim() != "") ||
(has(object.spec.imageVerification.ignoreTlog) && object.spec.imageVerification.ignoreTlog == true)
)
- name: has_custom_operator_image_trust_roots
expression: >-
has(object.spec.operatorImageVerification) &&
(
(has(object.spec.operatorImageVerification.publicKey) && object.spec.operatorImageVerification.publicKey.trim() != "") ||
(has(object.spec.operatorImageVerification.issuer) && object.spec.operatorImageVerification.issuer.trim() != "") ||
(has(object.spec.operatorImageVerification.subject) && object.spec.operatorImageVerification.subject.trim() != "") ||
(has(object.spec.operatorImageVerification.issuerRegExp) && object.spec.operatorImageVerification.issuerRegExp.trim() != "") ||
(has(object.spec.operatorImageVerification.subjectRegExp) && object.spec.operatorImageVerification.subjectRegExp.trim() != "") ||
(has(object.spec.operatorImageVerification.ignoreTlog) && object.spec.operatorImageVerification.ignoreTlog == true)
)
- name: requested_below_current_version
expression: >-
variables.current_version_valid &&
Expand Down Expand Up @@ -371,18 +400,26 @@ spec:
object.spec.profile != "Hardened" ||
object.spec.replicas >= 3
message: "Hardened profile requires at least 3 replicas for Raft quorum HA. Use Profile=Development for non-HA deployments."
# Confused-deputy protection: custom backup helper images run with backup credentials.
# Confused-deputy protection: CR-selected custom executables run with operator-managed identities,
# OpenBao runtime mounts, or both. Existing usehelperimages grants are accepted as a compatibility alias.
- expression: >-
!has(object.spec.backup) ||
!has(object.spec.backup.image) ||
object.spec.backup.image == "" ||
(request.operation == "UPDATE" &&
oldObject != null &&
has(oldObject.spec.backup) &&
has(oldObject.spec.backup.image) &&
oldObject.spec.backup.image == object.spec.backup.image) ||
authorizer.group("openbao.org").resource("openbaoclusters").namespace(request.namespace).name(object.metadata.name).check("usehelperimages").allowed()
message: "Users configuring custom backup helper images must be authorized to use helper image overrides on this OpenBaoCluster."
(
(!has(object.spec.initContainer) || !has(object.spec.initContainer.image) || object.spec.initContainer.image == "") &&
(!has(object.spec.backup) || !has(object.spec.backup.image) || object.spec.backup.image == "") &&
(!has(object.spec.upgrade) || !has(object.spec.upgrade.image) || object.spec.upgrade.image == "") &&
(!has(object.spec.upgrade) || !has(object.spec.upgrade.blueGreen) || !has(object.spec.upgrade.blueGreen.verification) || !has(object.spec.upgrade.blueGreen.verification.prePromotionHook)) &&
(!has(object.spec.plugins) || object.spec.plugins.all(p, (!has(p.image) || p.image == "") && (!has(p.command) || p.command == "")))
) ||
variables.custom_executables_authorized
message: "Users configuring CR-selected custom executables (custom init, backup, upgrade, blue/green hook, or plugin executable configuration) must be authorized to use custom executables on this OpenBaoCluster."
# Supply-chain protection: Hardened image verification may use official defaults without extra RBAC,
# but CR-selected trust roots require a separate delegation.
- expression: >-
!has(object.spec.profile) ||
object.spec.profile != "Hardened" ||
!(variables.has_custom_main_image_trust_roots || variables.has_custom_operator_image_trust_roots) ||
variables.image_trust_roots_authorized
message: "Users configuring custom image verification trust roots in Hardened profile must be authorized to use image trust roots on this OpenBaoCluster."
# Confused-deputy protection: users configuring unseal Secret credentials must be able to read that Secret.
- expression: >-
!has(object.spec.unseal) ||
Expand Down
13 changes: 7 additions & 6 deletions config/policy/openbao-validate-openbaorestore.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ spec:
- name: restore_endpoint_is_in_cluster_service
expression: >-
variables.restore_endpoint_hostname_normalized.matches("^[a-z0-9]([-a-z0-9]*[a-z0-9])?\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?\\.svc(\\.cluster\\.local)?$")
- name: custom_executables_authorized
expression: >-
authorizer.group("openbao.org").resource("openbaoclusters").namespace(request.namespace).name(object.spec.cluster).check("usecustomexecutables").allowed() ||
authorizer.group("openbao.org").resource("openbaoclusters").namespace(request.namespace).name(object.spec.cluster).check("usehelperimages").allowed()
validations:
# API contract: restore specs are immutable after creation.
- expression: >-
Expand Down Expand Up @@ -83,15 +87,12 @@ spec:
(variables.restore_endpoint_scheme == "http" && variables.restore_endpoint_is_in_cluster_service)))
message: "Restore endpoint must use HTTPS or S3 scheme, unless it targets an in-cluster Service (*.svc)."
# Confused-deputy protection: custom restore helper images run with restore credentials.
# Existing usehelperimages grants are accepted as a compatibility alias.
- expression: >-
!has(object.spec.image) ||
object.spec.image == "" ||
(request.operation == "UPDATE" &&
oldObject != null &&
has(oldObject.spec.image) &&
oldObject.spec.image == object.spec.image) ||
authorizer.group("openbao.org").resource("openbaoclusters").namespace(request.namespace).name(object.spec.cluster).check("usehelperimages").allowed()
message: "Users configuring custom restore helper images must be authorized to use helper image overrides on the target OpenBaoCluster."
variables.custom_executables_authorized
message: "Users configuring custom restore helper images must be authorized to use custom executables on the target OpenBaoCluster."
# Confused-deputy protection: users configuring restore Secret credentials must be able to read those Secrets.
- expression: >-
(!has(object.spec.source.target.credentialsSecretRef) ||
Expand Down
1 change: 1 addition & 0 deletions config/rbac/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@ resources:
- openbaocluster_admin_role.yaml
- openbaocluster_editor_role.yaml
- openbaocluster_helper_image_role.yaml
- openbaocluster_image_trust_roots_role.yaml
- openbaocluster_maintenance_role.yaml
- openbaocluster_viewer_role.yaml
Loading
Loading