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
2 changes: 1 addition & 1 deletion .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,4 @@ runs:
components: rustfmt, clippy

- name: Install cargo-nextest
uses: taiki-e/install-action@cargo-nextest
uses: taiki-e/install-action@cargo-nextest
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ jobs:
with:
version: 3.21.3

- name: Check release metadata
run: make release-metadata-check

- name: Run tests
run: |
cargo nextest run --all --no-tests pass
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/helm-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ jobs:
set -eux
helm package ./deploy/rustfs-operator \
--destination deploy/rustfs-operator/ \
--version "${{ steps.version.outputs.chart_version }}"
--version "${{ steps.version.outputs.chart_version }}" \
--app-version "${{ steps.version.outputs.chart_version }}"

- name: Upload helm package as artifact
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
Expand Down
120 changes: 120 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<!--
Copyright 2026 RustFS Team

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

# Changelog

All notable changes to RustFS Operator are documented in this file. The format is based on
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and releases follow
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.0.6] - 2026-08-22

### Added

- Restricted Pod Security defaults for generated RustFS workloads.
- Configurable Kubernetes cluster DNS domains and generated TLS SAN coverage.
- Kubernetes STS support with PolicyBinding authorization and managed or external TLS.
- OpenShift installation support that delegates UID and FSGroup selection to SCC admission.
- Tenant credential, RPC authentication, KMS, certificate, and provisioning lifecycle validation.

### Changed

- Removed legacy Tenant workload Roles and RoleBindings and disabled automatic ServiceAccount token
mounting for generated RustFS workloads.
- Changed `sts.tls.auto` from `true` to `false`; installations must now provide the STS TLS Secret
unless Operator-managed certificate generation is explicitly enabled.
- Restricted Console to one replica with a `Recreate` deployment strategy because sessions are
process-local. Console restarts and session Secret rotation invalidate active sessions.
- Tightened validation for credentials, security contexts, public TLS SANs, pool volume counts, and
immutable PVC template fields.
- Required an explicit runtime-image acknowledgement when a Tenant overrides the default RustFS
image.
- Defaulted chart-managed Operator and Console images to the immutable chart `appVersion` instead
of the mutable `latest` tag.

### Fixed

- Made repeated blocked status updates idempotent and hardened leader-election loss handling.
- Tolerated transient node lookup failures while preserving Pod cleanup safety.
- Protected existing RustFS users during provisioning reconciliation.
- Corrected monitoring responses wrapped by the RustFS API.
- Corrected STS SigV4 query encoding, bounded session duration, and rotated managed TLS certificates.
- Revoked Console sessions on logout and prevented pool volume-count overflow.
- Added finalizer RBAC required by Kubernetes and OpenShift admission.

### Security

- Applied authentication to an explicit protected Console API router instead of relying on a
fail-open path allowlist.
- Added admission limits for unauthenticated Console login and STS requests.
- Required cryptographically strong Console session keys and rejected empty credential Secrets.
- Bounded generated TLS SAN work and HTTP metrics label cardinality.

### Upgrade notes

#### Apply CRDs before upgrading the controller

Helm does not upgrade CRDs already installed from a chart's `crds/` directory. Apply both packaged
CRDs before the Helm upgrade:

```bash
kubectl apply --server-side --force-conflicts \
--field-manager=rustfs-operator-crd-upgrade \
-f deploy/rustfs-operator/crds/tenant-crd.yaml
kubectl apply --server-side --force-conflicts \
--field-manager=rustfs-operator-crd-upgrade \
-f deploy/rustfs-operator/crds/policybinding-crd.yaml
```

#### Review Tenant Kubernetes API access

The Operator removes legacy Tenant workload RBAC and renders
`automountServiceAccountToken: false`. Standard RustFS workloads do not need Kubernetes API access.
Custom sidecars or scripts that do need it must use a user-owned ServiceAccount, least-privilege
RBAC, and an explicit projected token. This migration changes the StatefulSet Pod template and
causes a rolling restart.

#### Choose the STS TLS owner

The new default is `sts.tls.auto=false`. Pre-create the configured STS TLS Secret with `tls.crt`,
`tls.key`, and `ca.crt`, or explicitly preserve the previous behavior with:

```yaml
sts:
tls:
auto: true
```

#### Plan Console session interruption

The Console now uses one replica and a `Recreate` rollout. Plan for a brief Console interruption;
users must authenticate again after a restart or session Secret rotation. Tenant data-plane traffic
is unaffected.

#### Rollback considerations

- Back up Tenant resources, Helm values, and the installed CRDs before upgrading.
- Do not downgrade CRDs automatically; keep the newer schema unless compatibility with the older
controller has been verified.
- An older Operator may recreate legacy Tenant RBAC and revert the ServiceAccount token setting,
causing another Tenant rollout and restoring broader Kubernetes API access.
- Pin Operator and RustFS images independently, then verify Tenant readiness and S3 read/write data
before and after any rollback.

[Unreleased]: https://github.com/rustfs/operator/compare/0.0.6...HEAD
[0.0.6]: https://github.com/rustfs/operator/compare/0.0.5...0.0.6
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "operator"
version = "0.1.0"
version = "0.0.6"
edition = "2024"
repository = "https://github.com/rustfs/operator"
license = "Apache-2.0"
Expand Down
7 changes: 6 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# Base image for final stage (override with: docker build --build-arg BASE_IMAGE=...)
ARG BASE_IMAGE=debian:bookworm-slim

# Use rust:bookworm so the binary is linked against glibc 2.36, matching final image.
# Use the latest stable Rust on bookworm so release binaries match CI and glibc 2.36.
ARG RUST_BUILD_IMAGE=rust:bookworm

# Operator version embedded in release binaries. Local builds fall back to Cargo.toml.
ARG VERSION

# Build image for the static Console frontend.
ARG NODE_BUILD_IMAGE=node:24-alpine

Expand Down Expand Up @@ -49,6 +52,8 @@ RUN cargo chef cook --release --recipe-path recipe.json

# Stage 3: Build the binary
FROM rust-base AS builder
ARG VERSION
ENV RUSTFS_OPERATOR_VERSION=${VERSION}
WORKDIR /app
COPY . .
COPY --from=cacher /app/target target
Expand Down
9 changes: 7 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

.PHONY: pre-commit fmt fmt-check clippy test build help
.PHONY: pre-commit release-metadata-check fmt fmt-check clippy test build help
.PHONY: docker-build-operator docker-build-console-web docker-build-all
.PHONY: console-lint console-build console-fmt console-fmt-check
.PHONY: e2e-check e2e-live-create .e2e-live-install-cert-manager e2e-live-run e2e-live-update e2e-live-delete
Expand All @@ -28,6 +28,7 @@ help:
@echo ""
@echo "Usage:"
@echo " make pre-commit - Run the full local gate (Rust + frontend), matching CI"
@echo " make release-metadata-check - Verify release and Rust versions stay aligned"
@echo " make fmt - Format Rust code"
@echo " make fmt-check - Check Rust formatting without modifying files"
@echo " make clippy - Run clippy checks"
Expand All @@ -47,9 +48,13 @@ help:
@echo " make e2e-live-delete - Delete live Kind environment and clean dedicated storage"

# pre-commit checks: Rust main crate + e2e harness + frontend (lint + build + format checks)
pre-commit: fmt-check clippy test e2e-check console-lint console-build console-fmt-check
pre-commit: release-metadata-check fmt-check clippy test e2e-check console-lint console-build console-fmt-check
@echo "pre-commit: all checks passed"

# Keep source, chart, CI, and container release metadata aligned.
release-metadata-check:
bash scripts/check-release-metadata.sh

# Format Rust code.
fmt:
cargo fmt --all
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

A Kubernetes operator for [RustFS](https://rustfs.com/) object storage, written in Rust with [kube-rs](https://github.com/kube-rs/kube). It reconciles a **`Tenant` custom resource** (`rustfs.com/v1alpha1`), validates referenced credential and KMS Secrets, and applies ServiceAccounts, Services, and StatefulSets so RustFS runs inside your cluster, from single-node single-disk development tenants to erasure-coded distributed clusters.

**Status:** v0.1.0 pre-release — under active development.
**Status:** v0.0.6 — under active development.

## Features

Expand Down
4 changes: 2 additions & 2 deletions deploy/rustfs-operator/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ apiVersion: v2
name: rustfs-operator
description: Kubernetes operator for managing RustFS storage clusters
type: application
version: 0.1.0
appVersion: "1.0.0-beta.9"
version: 0.0.6
appVersion: "0.0.6"
home: https://rustfs.com
sources:
- https://github.com/rustfs/operator
Expand Down
4 changes: 2 additions & 2 deletions deploy/rustfs-operator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ The following table lists the configurable parameters of the RustFS Operator cha
|-----------|-------------|---------|
| `operator.replicas` | Number of operator replicas | `1` |
| `operator.image.repository` | Operator image repository | `rustfs/operator` |
| `operator.image.tag` | Operator image tag | `latest` |
| `operator.image.tag` | Operator image tag; empty uses `Chart.appVersion` | `""` |
| `operator.image.pullPolicy` | Image pull policy | `IfNotPresent` |
| `operator.imagePullSecrets` | Image pull secrets | `[]` |
| `operator.leaderElect` | Enable leader election override (`null`/unset for auto by replicas) | `null` |
Expand Down Expand Up @@ -248,7 +248,7 @@ The generated ClusterRole grants only `get`, `list`, and `watch` for Secrets and
```bash
helm install rustfs-operator deploy/rustfs-operator/ \
--set operator.image.repository=myregistry/operator \
--set operator.image.tag=v0.2.0
--set operator.image.tag=0.0.6
```

### Increased Resources
Expand Down
2 changes: 1 addition & 1 deletion deploy/rustfs-operator/templates/console-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ spec:
{{- end }}
containers:
- name: console
image: "{{ .Values.console.image.repository }}:{{ .Values.console.image.tag | default .Values.operator.image.tag }}"
image: "{{ .Values.console.image.repository }}:{{ .Values.console.image.tag | default .Values.operator.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.console.image.pullPolicy }}
command: ["./operator", "console", "--port", "{{ .Values.console.port }}"]
env:
Expand Down
2 changes: 1 addition & 1 deletion deploy/rustfs-operator/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ spec:
{{- end }}
containers:
- name: operator
image: "{{ .Values.operator.image.repository }}:{{ .Values.operator.image.tag }}"
image: "{{ .Values.operator.image.repository }}:{{ .Values.operator.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.operator.image.pullPolicy }}
command: ["./operator", "server"]
{{- $leaderElect := gt (int .Values.operator.replicas) 1 }}
Expand Down
3 changes: 2 additions & 1 deletion deploy/rustfs-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ operator:

image:
repository: rustfs/operator
tag: latest
# Defaults to Chart.appVersion so a released chart never selects a mutable image tag.
tag: ""
pullPolicy: IfNotPresent

# Image pull secrets for private registries
Expand Down
2 changes: 1 addition & 1 deletion docs/operator-user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ operator:
replicas: 2
image:
repository: registry.example.com/rustfs/operator
tag: v0.1.0
tag: 0.0.6
resources:
requests:
cpu: 200m
Expand Down
2 changes: 1 addition & 1 deletion docs/operator-user-guide.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ operator:
replicas: 2
image:
repository: registry.example.com/rustfs/operator
tag: v0.1.0
tag: 0.0.6
resources:
requests:
cpu: 200m
Expand Down
2 changes: 1 addition & 1 deletion e2e/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -562,5 +562,5 @@ spec:

---

**Version**: v0.1.0
**Last Updated**: 2025-11-05
**Version**: v0.0.6
**Last Updated**: 2026-08-22
Loading
Loading