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
3 changes: 3 additions & 0 deletions charts/function-mesh-operator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ function mesh operator Helm chart for Kubernetes
| controllerManager.addDefaultAffinity | bool | `true` | |
| controllerManager.affinity | object | `{}` | |
| controllerManager.autoFailover | bool | `true` | |
| controllerManager.automountServiceAccountToken | string | `nil` | Optional setting on the chart-managed ServiceAccount. Null preserves the Kubernetes default. The controller requires Kubernetes API credentials; do not disable token mounting without an alternative. |
| controllerManager.configFile | string | `"/etc/config/config.yaml"` | |
| controllerManager.create | bool | `true` | |
| controllerManager.enableInitContainers | bool | `false` | |
Expand All @@ -42,11 +43,13 @@ function mesh operator Helm chart for Kubernetes
| controllerManager.namespacedBackendConfig | string | `"backend-config"` | |
| controllerManager.nodeSelector | object | `{}` | |
| controllerManager.pauseRollout | bool | `false` | |
| controllerManager.podSecurityContext | object | `{}` | Optional controller Pod security context. Empty preserves existing behavior. |
| controllerManager.pprof.enable | bool | `false` | |
| controllerManager.pprof.port | int | `8090` | |
| controllerManager.replicas | int | `1` | |
| controllerManager.resources.requests.cpu | string | `"80m"` | |
| controllerManager.resources.requests.memory | string | `"50Mi"` | |
| controllerManager.securityContext | object | `{}` | Optional controller container security context. Empty preserves existing behavior. |
| controllerManager.selector | list | `[]` | |
| controllerManager.serviceAccount | string | `"function-mesh-controller-manager"` | |
| controllerManager.tolerations | list | `[]` | |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ spec:
{{- if .Values.controllerManager.serviceAccount }}
serviceAccount: {{ .Values.controllerManager.serviceAccount }}
{{- end }}
{{- with .Values.controllerManager.podSecurityContext }}
securityContext:
{{ toYaml . | indent 8 }}
{{- end }}
{{- if .Values.imagePullSecrets }}
imagePullSecrets:
{{ toYaml .Values.imagePullSecrets | indent 6 }}
Expand All @@ -40,6 +44,10 @@ spec:
- name: function-mesh-operator
image: {{ .Values.operatorImage }}
imagePullPolicy: {{ .Values.imagePullPolicy | default "IfNotPresent" }}
{{- with .Values.controllerManager.securityContext }}
securityContext:
{{ toYaml . | indent 10 }}
{{- end }}
{{- if .Values.controllerManager.resources }}
resources:
{{ toYaml .Values.controllerManager.resources | indent 12 }}
Expand Down Expand Up @@ -105,4 +113,4 @@ spec:
priorityClassName: {{ .Values.controllerManager.priorityClassName }}
{{- end }}
volumes:
{{- include "function-mesh-operator.volumes" . | nindent 6 -}}
{{- include "function-mesh-operator.volumes" . | nindent 6 -}}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ metadata:
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: controller-manager
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
{{- if kindIs "bool" .Values.controllerManager.automountServiceAccountToken }}
automountServiceAccountToken: {{ .Values.controllerManager.automountServiceAccountToken }}
{{- end }}
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
Expand All @@ -22,6 +25,19 @@ metadata:
app.kubernetes.io/component: controller-manager
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
rules:
# Required by the controller metrics authentication and authorization filter.
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create
- apiGroups:
- apps
resources:
Expand Down
6 changes: 6 additions & 0 deletions charts/function-mesh-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ controllerManager:
# With rbac.create=true, this service account will be created
# Also see rbac.create and clusterScoped
serviceAccount: function-mesh-controller-manager
# -- Optional setting on the chart-managed ServiceAccount. Null preserves the Kubernetes default. The controller requires Kubernetes API credentials; do not disable token mounting without an alternative.
automountServiceAccountToken: null
# -- Optional controller Pod security context. Empty preserves existing behavior.
podSecurityContext: {}
# -- Optional controller container security context. Empty preserves existing behavior.
securityContext: {}
replicas: 1
resources:
requests:
Expand Down
116 changes: 116 additions & 0 deletions docs/security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Security configuration

## Operator

The Helm chart preserves existing security settings by default. To opt in to
container hardening, use the following values and verify them against your
operator image and admission policies:

```yaml
controllerManager:
podSecurityContext:
runAsNonRoot: true
# UID/GID for the chart default image streamnative/function-mesh:v0.29.0.
# Verify these IDs before using a different image.
runAsUser: 10000
runAsGroup: 10001
seccompProfile:
type: RuntimeDefault
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: [ALL]
```

These settings affect only the controller manager, not Function, Source or Sink
pods. The chart default image declares `USER pulsar`. With only
`runAsNonRoot: true`, kubelet cannot verify that this non-numeric image user is
non-root and refuses to start the container. Set an image-appropriate numeric
`runAsUser`, as shown above. Do not assume every operator image uses the same
UID/GID; these values are opt-in, not new chart defaults.

`controllerManager.automountServiceAccountToken` optionally sets the field on
the chart-managed ServiceAccount; its default `null` omits the field. It has no
effect on externally managed ServiceAccounts when `rbac.create: false`. The
controller needs Kubernetes API credentials for reconciliation and leader
election. Setting this value to `false` alone breaks the default in-cluster
authentication for new pods. Prefer a narrowly scoped policy exception when
token access is required; this setting does not provision alternative credentials.

## Metrics authentication and authorization

The operator serves HTTPS metrics with Kubernetes authentication and authorization.
The chart grants its ServiceAccount `create` on
`tokenreviews.authentication.k8s.io` and
`subjectaccessreviews.authorization.k8s.io` so it can validate scrape requests.
When `rbac.create: false`, include these permissions in the externally managed
ClusterRole and bind it to the operator ServiceAccount. Missing permissions cause
authenticated scrapes to return HTTP 500.

The scraping client (for example, Prometheus) separately needs a ClusterRole with:

```yaml
rules:
- nonResourceURLs: ["/metrics"]
verbs: ["get"]
```

Bind that role to the actual scraping ServiceAccount using a ClusterRoleBinding
and configure the client to send its bearer token over HTTPS with the appropriate
TLS trust configuration. The chart does not grant metrics access to arbitrary
clients. Requests without a bearer token return HTTP 401; authenticated clients
without permission return HTTP 403; authorized requests return HTTP 200. The
current controller-runtime filter reports authentication errors, including
invalid bearer token errors, as HTTP 500; check the operator logs to distinguish
these from missing RBAC permissions.

## Explicit ServiceAccount token mounting for sinks

Function Mesh does not create runtime ServiceAccounts. A user-managed account
with `automountServiceAccountToken: false` disables automatic mounting but still
allows explicit projected tokens. No additional CRD field is required.

For a ServiceAccount named `pulsar-sink-job-sac` in the Sink namespace, merge
the following fields into the existing Sink spec. Preserve any existing volumes
and volume mounts. This example supplies the standard Kubernetes in-cluster
client paths:

```yaml
spec:
pod:
serviceAccountName: pulsar-sink-job-sac
volumes:
- name: explicit-kube-api-access
projected:
sources:
- serviceAccountToken:
path: token
expirationSeconds: 3600
- configMap:
name: kube-root-ca.crt
items:
- key: ca.crt
path: ca.crt
- downwardAPI:
items:
- path: namespace
fieldRef:
fieldPath: metadata.namespace
volumeMounts:
- name: explicit-kube-api-access
mountPath: /var/run/secrets/kubernetes.io/serviceaccount
readOnly: true
```

The token identifies the Pod ServiceAccount; its Kubernetes API permissions
still depend on RBAC. Omitting `audience` uses the API server default. For another
service, set its expected audience and adjust the mount path as needed.

Kubelet rotates projected tokens. Do not use `subPath` for the token mount, and
ensure the client reloads the token. Custom `spec.volumeMounts` also propagate
to built-in downloader, filebeat and cleanup containers when enabled; the mount
is not necessarily exclusive to the sink main container. Verify that the
admission policy permits explicit token projection. This does not satisfy a
policy that separately requires an explicit Pod-level
`automountServiceAccountToken: false` field.
Loading