Skip to content
Open
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
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,17 @@ test-unit: test-forwarder-generator test-unit-api
test-unit-api:
@cd ./api/observability && go test -coverprofile=test.cov ./...

# Validates the protected-SA ValidatingAdmissionPolicies' CEL against a real
# kube-apiserver via envtest (no cluster needed). setup-envtest downloads the
# apiserver/etcd binaries; its version tracks controller-runtime (release-0.23).
# The admission suite skips these specs when KUBEBUILDER_ASSETS is unset, so
# test-unit is unaffected.
ENVTEST_K8S_VERSION ?= 1.31.0
.PHONY: test-admission-envtest
test-admission-envtest:
KUBEBUILDER_ASSETS="$$(go run sigs.k8s.io/controller-runtime/tools/setup-envtest@release-0.23 use $(ENVTEST_K8S_VERSION) -p path)" \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing we could use this for our other admissions tests?

go test -count=1 -run TestAdmission ./internal/admission/...

.PHONY: coverage
coverage: test-unit
go tool cover -html=test.cov -o $${ARTIFACTS_DIR:-.}/coverage.html
Expand Down
15 changes: 14 additions & 1 deletion bundle/manifests/cluster-logging.clusterserviceversion.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ metadata:
categories: OpenShift Optional, Logging & Tracing, Observability
certified: "false"
containerImage: quay.io/openshift-logging/cluster-logging-operator:latest
createdAt: "2026-07-15T11:39:59Z"
createdAt: "2026-08-12T13:43:48Z"
description: The Red Hat OpenShift Logging Operator for OCP provides a means for
configuring and managing log collection and forwarding.
features.operators.openshift.io/cnf: "false"
Expand Down Expand Up @@ -2495,6 +2495,19 @@ spec:
- subjectaccessreviews
verbs:
- create
- apiGroups:
- admissionregistration.k8s.io
resources:
- validatingadmissionpolicies
- validatingadmissionpolicybindings
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- apps
resources:
Expand Down
16 changes: 16 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import (
"strings"
"time"

internaladmission "github.com/openshift/cluster-logging-operator/internal/admission"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should think if this should be in the controller package? Maybe that package is only for our resources?

internalcontext "github.com/openshift/cluster-logging-operator/internal/api/context"
"github.com/openshift/cluster-logging-operator/internal/collector"
admissioncontroller "github.com/openshift/cluster-logging-operator/internal/controller/admission"
internaltls "github.com/openshift/cluster-logging-operator/internal/tls"
"sigs.k8s.io/controller-runtime/pkg/metrics/filters"

Expand Down Expand Up @@ -258,8 +260,22 @@ func main() {
os.Exit(1)
}

operatorNS := internaladmission.OperatorNamespace()
if err = (&admissioncontroller.ProtectedSAReconciler{
Client: mgr.GetClient(),
OperatorNS: operatorNS,
}).SetupWithManager(mgr); err != nil {
Comment thread
vparfonov marked this conversation as resolved.
log.Error(err, "unable to create controller", "controller", "ProtectedServiceAccounts")
os.Exit(1)
}

//+kubebuilder:scaffold:builder

if err := mgr.Add(admissioncontroller.NewProtectedSAAdmissionRunnable(k8sClient, operatorNS)); err != nil {
log.Error(err, "unable to register protected SA admission runnable")
os.Exit(1)
}

if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
log.Error(err, "unable to set up health check")
os.Exit(1)
Expand Down
13 changes: 13 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ metadata:
creationTimestamp: null
name: cluster-logging-operator
rules:
- apiGroups:
- admissionregistration.k8s.io
resources:
- validatingadmissionpolicies
- validatingadmissionpolicybindings
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- apps
resources:
Expand Down
38 changes: 37 additions & 1 deletion docs/administration/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,40 @@ This could suggest that the application generating the log is not correctly term
Does it have a newline character at the end? If not, the application writing the log is not properly terminating its lines.

**Check the source application**: Ensure that the application generating the logs is configured to append a newline character
(\n) to every log entry. This is standard practice for most logging libraries and systems.
(\n) to every log entry. This is standard practice for most logging libraries and systems.

### 3. A Pod or workload is denied: `uses protected ServiceAccount ... which is only allowed for use by authorized ClusterLogForwarders`

The cluster logging operator installs ValidatingAdmissionPolicies that refuse
a Pod or workload when it references a collector ServiceAccount (one referenced by
a `ClusterLogForwarder`) and the creator is not the operator or its built-in
controllers. This stops a user who can create Pods from inheriting the
collector SA's privileges (e.g. `logging-scc` host mounts).

**Common causes**

- A user tried to create a standalone Pod/Deployment/DaemonSet that sets
`serviceAccountName` to a collector ServiceAccount.
- A workload copies the collector's labels/annotations/name — this does not help;
the policy keys on the authenticated creator identity, not on Pod metadata.

**What to do**

1. Confirm the policies are present (operator must be running):

```sh
oc get validatingadmissionpolicy clo-protected-sa-pods clo-protected-sa-workloads
oc get validatingadmissionpolicybinding clo-protected-sa-pods-binding clo-protected-sa-workloads-binding
```

2. Do not reuse a collector ServiceAccount for non-collector workloads. Use a
ServiceAccount that is not referenced by any `ClusterLogForwarder`, and grant
it only the permissions your workload actually needs.

3. The set of protected ServiceAccounts is maintained by the operator in the
`clo-protected-serviceaccounts` ConfigMap in the operator namespace; it is
rebuilt from the current `ClusterLogForwarder` list on every change.

See [`docs/design/validatingadmissionpolicy-guide.md`](../design/validatingadmissionpolicy-guide.md)
for how the policies work and `./hack/test-protected-sa.sh` for a lightweight
verification script.
Loading
Loading