mirror of
https://github.com/rustfs/rustfs.git
synced 2026-10-12 23:52:45 +00:00
feat(tls): reload and publish external certificate generations (#8467)
* feat(tls): reload external certificate snapshots coherently Pin projected certificate generations, validate complete TLS material, coordinate server consumers, and invalidate outbound RPC caches coherently. Add externally managed TLS Secret support and rotation guidance. Co-Authored-By: heihutu <heihutu@gmail.com> Co-Authored-By: zhi22915 <qiuzgang@gmail.com> * feat(tls): publish server certificates through a fenced admin API Add opt-in server-leaf publication with dedicated IAM actions, actual TLS transport checks, immutable generations, durable captured-token CAS and idempotent receipts. Preserve independent trust and client identity sources and distinguish visible publication state from the full serving chain. Validate 64 TLS tests, 41 TLS-runtime tests, the focused IAM policy test, and eight live local API scenarios including least privilege and restart. Co-Authored-By: heihutu <heihutu@gmail.com> Co-Authored-By: zhi22915 <qiuzgang@gmail.com> * fix(admin): route certificate handler types through S3 facade Use the existing admin S3 facade to keep direct s3s imports within the footprint ratchet. Co-Authored-By: heihutu <heihutu@gmail.com> Co-Authored-By: zhi22915 <qiuzgang@gmail.com> * test(admin): include TLS certificate routes in route matrix Account for the registered certificate-state GET and certificate publication POST without changing route behavior or weakening matrix assertions. Co-Authored-By: heihutu <heihutu@gmail.com> Co-Authored-By: zhi22915 <qiuzgang@gmail.com> * fix(tls): reconcile startup trust before skipping reloads Compare the initialized listener bundle with coherently published outbound material, retain startup trust and client identity when sources disappear, and cover independent startup rotations through real reload passes. Co-Authored-By: heihutu <heihutu@gmail.com> Co-Authored-By: zhi22915 <qiuzgang@gmail.com> * refactor(tls): reuse pinned generations and prepared listener state Co-Authored-By: heihutu <heihutu@gmail.com> Co-Authored-By: zhi22915 <qiuzgang@gmail.com> * fix(tls): preserve startup trust source requirements --------- Co-authored-by: heihutu <heihutu@gmail.com> Co-authored-by: zhi22915 <qiuzgang@gmail.com> Co-authored-by: overtrue <anzhengchao@gmail.com>
This commit is contained in:
@@ -568,7 +568,7 @@ nondefault_statefulset=$(awk '
|
||||
nondefault_local_host=$(statefulset_env_value RUSTFS_LOCAL_ENDPOINT_HOST <<<"$nondefault_statefulset")
|
||||
nondefault_namespace=$(yq eval '.metadata.namespace' - <<<"$nondefault_statefulset")
|
||||
nondefault_endpoint_port=$(yq eval '.spec.template.spec.containers[0].ports[] | select(.name == "endpoint") | .containerPort' - <<<"$nondefault_statefulset")
|
||||
mtls_liveness_command=$(yq eval '.spec.template.spec.containers[0].livenessProbe.exec.command[-1]' - <<<"$nondefault_statefulset")
|
||||
mtls_liveness_port=$(yq eval '.spec.template.spec.containers[0].livenessProbe.tcpSocket.port' - <<<"$nondefault_statefulset")
|
||||
mtls_readiness_command=$(yq eval '.spec.template.spec.containers[0].readinessProbe.exec.command[-1]' - <<<"$nondefault_statefulset")
|
||||
if [[ "$nondefault_local_host" != '$(RUSTFS_CHART_POD_NAME).tenant-rustfs-headless.object-storage.svc.cluster.corp' ]]; then
|
||||
echo "Combined generated topology produced an unexpected local endpoint host: $nondefault_local_host" >&2
|
||||
@@ -578,9 +578,8 @@ if [[ "$nondefault_namespace" != "object-storage" || "$nondefault_endpoint_port"
|
||||
echo "Combined generated topology must retain its namespace and custom endpoint port" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! grep -Fq 'https://127.0.0.1:9443/health' <<<"$mtls_liveness_command" ||
|
||||
grep -Fq '/health/ready' <<<"$mtls_liveness_command"; then
|
||||
echo "mTLS liveness must use the process health endpoint, not readiness" >&2
|
||||
if [[ "$mtls_liveness_port" != 9443 ]]; then
|
||||
echo "mTLS liveness must check the listener independently of certificate validity" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! grep -Fq 'https://127.0.0.1:9443/health/ready' <<<"$mtls_readiness_command"; then
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
|
||||
CHART_DIR="$ROOT_DIR/helm/rustfs"
|
||||
|
||||
for distributed in false true; do
|
||||
rendered=$(helm template tls-reload "$CHART_DIR" \
|
||||
--set secret.allowInsecureDefaults=true \
|
||||
--set mode.distributed.enabled="$distributed" \
|
||||
--set mode.standalone.enabled="$([[ "$distributed" == false ]] && echo true || echo false)" \
|
||||
--set tls.enabled=true --set tls.existingSecret=issued-tls)
|
||||
workload=$(yq eval 'select(.kind == "Deployment" or .kind == "StatefulSet")' - <<<"$rendered")
|
||||
mount=$(yq eval '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "tls-material")' - <<<"$workload")
|
||||
[[ $(yq eval '.mountPath' - <<<"$mount") == /opt/tls ]]
|
||||
[[ $(yq eval '.readOnly' - <<<"$mount") == true ]]
|
||||
[[ $(yq eval 'has("subPath")' - <<<"$mount") == false ]]
|
||||
keys=$(yq eval '.spec.template.spec.volumes[] | select(.name == "tls-material") | .projected.sources[].secret.items[].key' - <<<"$workload")
|
||||
[[ "$keys" == $'tls.crt\ntls.key' ]]
|
||||
[[ $(yq eval '.spec.template.spec.containers[0].readinessProbe.httpGet.scheme' - <<<"$workload") == HTTPS ]]
|
||||
[[ $(yq eval '.spec.template.spec.containers[0].livenessProbe.tcpSocket.port' - <<<"$workload") == 9000 ]]
|
||||
config=$(yq eval 'select(.kind == "ConfigMap") | .data' - <<<"$rendered")
|
||||
[[ $(yq eval '.RUSTFS_TLS_RELOAD_ENABLE' - <<<"$config") == 1 ]]
|
||||
[[ $(yq eval '.RUSTFS_TLS_KEYLOG' - <<<"$config") == 0 ]]
|
||||
if [[ "$distributed" == true ]]; then
|
||||
[[ $(yq eval '.RUSTFS_VOLUMES' - <<<"$config") == https://* ]]
|
||||
fi
|
||||
|
||||
mtls=$(helm template tls-reload "$CHART_DIR" --set secret.allowInsecureDefaults=true \
|
||||
--set mode.distributed.enabled="$distributed" \
|
||||
--set mode.standalone.enabled="$([[ "$distributed" == false ]] && echo true || echo false)" \
|
||||
--set mtls.enabled=true)
|
||||
workload=$(yq eval 'select(.kind == "Deployment" or .kind == "StatefulSet")' - <<<"$mtls")
|
||||
[[ $(yq eval '.spec.template.spec.volumes[] | select(.name == "tls-material") | .projected.sources | length' - <<<"$workload") == 2 ]]
|
||||
[[ $(yq eval '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "tls-material") | has("subPath")' - <<<"$workload") == false ]]
|
||||
[[ $(yq eval '.spec.template.spec.containers[0].livenessProbe.tcpSocket.port' - <<<"$workload") == 9000 ]]
|
||||
done
|
||||
|
||||
if helm template tls-reload "$CHART_DIR" --set secret.allowInsecureDefaults=true \
|
||||
--set tls.enabled=true --set tls.existingSecret=issued-tls --set mtls.enabled=true >/dev/null 2>&1; then
|
||||
echo "Public TLS must not silently enable global client authentication" >&2
|
||||
exit 1
|
||||
fi
|
||||
if helm template tls-reload "$CHART_DIR" --set secret.allowInsecureDefaults=true \
|
||||
--set tls.enabled=true >/dev/null 2>&1; then
|
||||
echo "Native TLS requires an explicitly configured serving Secret" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "TLS Secret projection, rotation settings, topology and probes passed"
|
||||
Reference in New Issue
Block a user