Compare commits

..

2 Commits

Author SHA1 Message Date
Myasnikov Daniil
fd436a7baa Fixed typos in readme
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-03-06 13:08:30 +05:00
Myasnikov Daniil
612b4773bc [docs] Fixed FoundationDB title
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-03-06 10:56:52 +05:00
52 changed files with 125 additions and 3979 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v1.0.3
-->
## Fixes
* **[platform] Fix package name conversion in migration script**: Fixed the `migrate-to-version-1.0.sh` script to correctly prepend the `cozystack.` prefix when converting `BUNDLE_DISABLE` and `BUNDLE_ENABLE` package name lists, ensuring packages are properly identified during the v0.41→v1.0 upgrade ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2144, #2148).
## Documentation
* **[website] Add white labeling guide**: Added a comprehensive guide for configuring white labeling (branding) in Cozystack v1, covering Dashboard fields (`titleText`, `footerText`, `tenantText`, `logoText`, `logoSvg`, `iconSvg`) and Keycloak fields (`brandName`, `brandHtmlName`). Includes SVG preparation workflow with theme-aware template variables, portable base64 encoding, and migration notes from the v0 ConfigMap approach ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#441).
* **[website] Actualize backup and recovery documentation**: Reworked the backup and recovery docs to be user-focused, separating operator and tenant workflows. Added tenant-facing documentation for `BackupJob` and `Plan` resources and status inspection commands, and added a new Velero administration guide for operators covering storage credentials and backup storage configuration ([**@androndo**](https://github.com/androndo) in cozystack/website#434).
---
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.0.2...v1.0.3

View File

@@ -1,126 +0,0 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v1.1.0
-->
# Cozystack v1.1.0
Cozystack v1.1.0 delivers a major expansion of the managed application catalog with **OpenBAO** (open-source HashiCorp Vault fork) for secrets management, comprehensive **tiered object storage** with SeaweedFS storage pools, a new bucket **user model** with per-user credentials and S3 login support, **RabbitMQ version selection**, and **MongoDB Grafana dashboards**. The dashboard gains storageClass dropdowns for all stateful apps. This release also incorporates all fixes from the v1.0.x patch series.
## Feature Highlights
### OpenBAO: Managed Secrets Management Service
Cozystack now ships **OpenBAO** as a fully managed PaaS application — an open-source fork of HashiCorp Vault providing enterprise-grade secrets management. Users can deploy OpenBAO instances in standalone mode (single replica with file storage) or in high-availability Raft mode (multiple replicas with integrated Raft consensus), with the mode switching automatically based on the `replicas` field.
Each OpenBAO instance gets TLS enabled by default via cert-manager self-signed certificates, with DNS SANs covering all service endpoints and pod addresses. The Vault injector and CSI provider are intentionally disabled (they are cluster-scoped components not safe for per-tenant use). OpenBAO requires manual initialization and unsealing by design — no auto-unseal is configured.
A full end-to-end E2E test covers the complete lifecycle: deploy, wait for certificate and API readiness, init, unseal, verify, and cleanup. OpenBAO is available in the application catalog for tenant namespaces.
### SeaweedFS Tiered Storage Pools
SeaweedFS now supports **tiered storage pools** — operators can define separate storage pools per disk type (SSD, HDD, NVMe) in the `volume.pools` field (Simple topology) or `volume.zones[name].pools` (MultiZone topology). Each pool creates an additional Volume StatefulSet alongside the default one, with SeaweedFS distinguishing storage via the `-disk=<type>` flag on volume servers.
Each pool automatically generates its own set of COSI resources: a standard `BucketClass`, a `-lock` BucketClass (COMPLIANCE mode, 365-day retention), a read-write `BucketAccessClass`, and a `-readonly` BucketAccessClass. This allows applications to place data on specific storage tiers and request appropriate access policies per pool.
In MultiZone topology, pools are defined per zone and each zone × pool combination creates a dedicated StatefulSet (e.g., `us-east-ssd`, `us-west-hdd`), with nodes selected via `topology.kubernetes.io/zone` labels. Existing deployments with no pools defined produce output identical to previous versions — no migration is required.
### Bucket User Model with S3 Login
The bucket application introduces a new **user model** for access management. Instead of a single implicit BucketAccess resource, operators now define a `users` map where each entry creates a dedicated `BucketAccess` with its own credentials secret and an optional `readonly` flag. The S3 Manager UI has been updated with a login screen that uses per-session credentials from the user's own secret, replacing the previous basic-auth approach.
Two new bucket parameters are available: `locking` provisions from the `-lock` BucketClass (COMPLIANCE mode, 365-day object lock retention) for write-once-read-many use cases, and `storagePool` selects a specific pool's BucketClass for tiered storage placement. The COSI driver has been updated to v0.3.0 to support the new `diskType` parameter.
**⚠️ Breaking change**: The implicit default BucketAccess resource is no longer created. Existing buckets that relied on the single auto-generated BucketAccess will need to explicitly define users in the `users` map after upgrading.
### RabbitMQ Version Selection
RabbitMQ instances now support a configurable **version selector** (`version` field with values: `v4.2`, `v4.1`, `v4.0`, `v3.13`; default `v4.2`). The chart validates the selection at deploy time and uses it to pin the runtime image, giving operators control over the RabbitMQ release channel per instance. An automatic migration backfills the `version` field on all existing RabbitMQ resources to `v4.2`.
## Major Features and Improvements
* **[apps] Add OpenBAO as a managed secrets management service**: Deployed as a PaaS application with standalone (file storage) and HA Raft modes, TLS enabled by default via cert-manager, injector and CSI provider disabled for tenant safety, and a full E2E lifecycle test ([**@lexfrei**](https://github.com/lexfrei) in #2059).
* **[seaweedfs] Add storage pools support for tiered storage**: Added `volume.pools` (Simple) and `volume.zones[name].pools` (MultiZone) for per-disk-type StatefulSets, zone overrides (`nodeSelector`, `storageClass`, `dataCenter`), per-pool COSI BucketClass and BucketAccessClass resources, and bumped seaweedfs-cosi-driver to v0.3.0 ([**@sircthulhu**](https://github.com/sircthulhu) in #2097).
* **[apps][system] Add bucket user model with locking and storage pool selection**: Replaced implicit BucketAccess with per-user `users` map, added `locking` and `storagePool` parameters, renamed COSI BucketClass suffix from `-worm` to `-lock`, added `-readonly` BucketAccessClass for all topologies, and updated S3 Manager with login screen using per-user credentials ([**@IvanHunters**](https://github.com/IvanHunters) in #2119).
* **[rabbitmq] Add version selection for RabbitMQ instances**: Added `version` field (`v4.2`, `v4.1`, `v4.0`, `v3.13`) with chart-level validation, default `v4.2`, and an automatic migration to backfill the field on existing instances ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2092).
* **[system] Add MongoDB Overview and InMemory Details Grafana dashboards**: Added two comprehensive Grafana dashboards for MongoDB monitoring — Overview (command operations, connections, cursors, query efficiency, write time) and InMemory Details (WiredTiger cache, transactions, concurrency, eviction). Dashboards are registered in `dashboards.list` for automatic GrafanaDashboard CRD generation ([**@IvanHunters**](https://github.com/IvanHunters) in #2158).
* **[dashboard] Add storageClass dropdown for all stateful apps**: Replaced the free-text `storageClass` input with an API-backed dropdown listing available StorageClasses from the cluster. Affects ClickHouse, Harbor, HTTPCache, Kubernetes, MariaDB, MongoDB, NATS, OpenBAO, Postgres, Qdrant, RabbitMQ, Redis, VMDisk (top-level `storageClass`), FoundationDB (`storage.storageClass`), and Kafka (`kafka.storageClass`, `zookeeper.storageClass`) ([**@sircthulhu**](https://github.com/sircthulhu) in #2131).
* **[bucket] Add readonly S3 access credentials**: Added a readonly `BucketAccessClass` to the SeaweedFS COSI chart and updated the bucket application to automatically provision two sets of S3 credentials per bucket: read-write (for UI) and readonly ([**@IvanHunters**](https://github.com/IvanHunters) in #2105).
* **[dashboard] Hide sidebar on cluster-level pages when no tenant selected**: Fixed broken URLs with double `//` on the main cluster page (before tenant selection) by clearing `CUSTOMIZATION_SIDEBAR_FALLBACK_ID` so no sidebar renders when no namespace is selected ([**@sircthulhu**](https://github.com/sircthulhu) in #2106).
* **[cert-manager] Update cert-manager to v1.19.3**: Upgraded cert-manager with new CRDs moved into a dedicated CRD package, added global `nodeSelector` and `hostUsers` (pod user-namespace isolation), and renamed `ServiceMonitor` targetPort default to `http-metrics` ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2070).
* **[dashboard] Add backupClasses dropdown to Plan/BackupJob forms**: Replaced free-text input for `backupClass` field with an API-backed dropdown populated with available BackupClass resources, making it easier to select the correct backup target ([**@androndo**](https://github.com/androndo) in #2104).
## Fixes
* **[platform] Fix package name conversion in migration script**: Fixed the `migrate-to-version-1.0.sh` script to correctly prepend the `cozystack.` prefix when converting `BUNDLE_DISABLE` and `BUNDLE_ENABLE` package name lists, ensuring packages are properly identified during the v0.41→v1.0 upgrade ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2144, #2148).
* **[backups] Fix RBAC for backup controllers**: Updated RBAC permissions for the backup strategy controller to support enhanced backup and restore capabilities, including Velero integration and status management ([**@androndo**](https://github.com/androndo) in #2145).
* **[kubernetes] Set explicit MTU for Cilium in tenant clusters**: Set explicit MTU 1350 for Cilium in KubeVirt-based tenant Kubernetes clusters to prevent packet drops caused by VXLAN encapsulation overhead. Cilium's auto-detection does not account for VXLAN overhead (50 bytes) when the VM interface inherits MTU 1400 from the parent OVN/Geneve overlay, causing intermittent connectivity issues and HTTP 499 errors under load ([**@IvanHunters**](https://github.com/IvanHunters) in #2147).
* **[platform] Prevent cozystack-version ConfigMap from deletion**: Added resource protection annotations to prevent the `cozystack-version` ConfigMap from being accidentally deleted, improving platform stability ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2112, #2114).
* **[installer] Add keep annotation to Namespace and update migration script**: Added `helm.sh/resource-policy: keep` annotation to the `cozy-system` Namespace in the installer Helm chart to prevent Helm from deleting the namespace and all HelmReleases within it when the installer release is removed. The v1.0 migration script is also updated to annotate the namespace and `cozystack-version` ConfigMap before migration ([**@kvaps**](https://github.com/kvaps) in #2122, #2123).
* **[dashboard] Add FlowSchema to exempt BFF from API throttling**: Added a `cozy-dashboard-exempt` FlowSchema to exempt the dashboard Back-End-for-Frontend service account from Kubernetes API Priority and Fairness throttling, preventing 429 errors under load ([**@kvaps**](https://github.com/kvaps) in #2121, #2124).
* **[platform] Suspend cozy-proxy if it conflicts with installer release during migration**: Added a check in the v0.41→v1.0 migration script to detect and suspend the `cozy-proxy` HelmRelease when its `releaseName` is set to `cozystack`, which conflicts with the installer release and would cause `cozystack-operator` deletion during the upgrade ([**@kvaps**](https://github.com/kvaps) in #2128, #2130).
* **[platform] Fix off-by-one error in run-migrations script**: Fixed a bug in the migration runner where the first required migration was always skipped due to an off-by-one error in the migration range calculation ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2126, #2132).
* **[system] Fix Keycloak proxy configuration for v26.x**: Replaced the deprecated `KC_PROXY=edge` environment variable with `KC_PROXY_HEADERS=xforwarded` and `KC_HTTP_ENABLED=true` in the Keycloak StatefulSet. `KC_PROXY` was removed in Keycloak 26.x, previously causing "Non-secure context detected" warnings and broken cookie handling behind a reverse proxy with TLS termination ([**@sircthulhu**](https://github.com/sircthulhu) in #2125, #2134).
* **[dashboard] Allow clearing instanceType field and preserve newlines in secret copy**: Added `allowEmpty: true` to the `instanceType` field in the VMInstance form so users can explicitly clear it to use custom KubeVirt resources without a named instance type. Also fixed newline preservation when copying secrets with CMD+C ([**@sircthulhu**](https://github.com/sircthulhu) in #2135, #2137).
* **[dashboard] Restore stock-instance sidebars for namespace-level pages**: Restored `stock-instance-api-form`, `stock-instance-api-table`, `stock-instance-builtin-form`, and `stock-instance-builtin-table` sidebar resources that were inadvertently removed in #2106. Without these sidebars, namespace-level pages such as Backup Plans rendered as empty pages ([**@sircthulhu**](https://github.com/sircthulhu) in #2136, #2138).
## System Configuration
* **[platform] Disable private key rotation in CA certs**: Set `rotationPolicy: Never` for all CA/root certificates used by system components (ingress-nginx, linstor, linstor-scheduler, seaweedfs, victoria-metrics-operator, kubeovn-webhook, lineage-controller-webhook, cozystack-api, etcd, linstor API/internal) to prevent trust chain problems when CA certificates are reissued ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2113).
## Development, Testing, and CI/CD
* **[ci] Add debug improvements for CI tests**: Added extra debug commands for Kubernetes startup diagnostics and improved error output in CI test runs ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2111).
## Documentation
* **[website] Add object storage guide (pools, buckets, users)**: Added a comprehensive guide covering SeaweedFS object storage configuration including storage pools for tiered storage, bucket creation with access classes, per-user credential management, and credential rotation procedures ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#438).
* **[website] Add Build Your Own Platform (BYOP) guide**: Added a new "Build Your Own Platform" guide and split the installation documentation into platform installation and BYOP sub-pages, with cross-references throughout the documentation ([**@kvaps**](https://github.com/kvaps) in cozystack/website#437).
* **[website] Add white labeling guide**: Added a comprehensive guide for configuring white labeling (branding) in Cozystack v1, covering Dashboard fields (`titleText`, `footerText`, `tenantText`, `logoText`, `logoSvg`, `iconSvg`) and Keycloak fields (`brandName`, `brandHtmlName`). Includes SVG preparation workflow with theme-aware template variables and portable base64 encoding ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#441).
* **[website] Actualize backup and recovery documentation**: Reworked the backup and recovery docs to be user-focused, separating operator and tenant workflows. Added tenant-facing documentation for `BackupJob` and `Plan` resources and a new Velero administration guide for operators ([**@androndo**](https://github.com/androndo) in cozystack/website#434).
* **[website] Add step to protect namespace before upgrading**: Updated the cluster upgrade guide and v0.41→v1.0 migration guide with a required step to annotate the `cozy-system` namespace and `cozystack-version` ConfigMap with `helm.sh/resource-policy=keep` before running `helm upgrade` ([**@kvaps**](https://github.com/kvaps) in cozystack/website#435).
* **[website] Replace bundles documentation with variants**: Renamed the "Bundles" documentation section to "Variants" to match current Cozystack terminology. Removed deprecated variants and added new ones: `default` and `isp-full-generic` ([**@kvaps**](https://github.com/kvaps) in cozystack/website#433).
* **[website] Fix component values override instructions**: Corrected the component values override documentation to reflect current configuration patterns ([**@kvaps**](https://github.com/kvaps) in cozystack/website#436).
## Breaking Changes & Upgrade Notes
* **[bucket] Bucket user model now requires explicit user definitions**: The implicit default `BucketAccess` resource is no longer created automatically. Existing buckets that relied on a single auto-generated credential secret will need to define users explicitly in the `users` map after upgrading. Each user entry creates its own `BucketAccess` resource and credential secret (optionally with `readonly: true`). The COSI BucketClass suffix has also been renamed from `-worm` to `-lock` ([**@IvanHunters**](https://github.com/IvanHunters) in #2119).
## Contributors
We'd like to thank all contributors who made this release possible:
* [**@androndo**](https://github.com/androndo)
* [**@IvanHunters**](https://github.com/IvanHunters)
* [**@kvaps**](https://github.com/kvaps)
* [**@lexfrei**](https://github.com/lexfrei)
* [**@myasnikovdaniil**](https://github.com/myasnikovdaniil)
* [**@sircthulhu**](https://github.com/sircthulhu)
---
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.0.0...v1.1.0

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bats
@test "Create and Verify Seeweedfs Bucket" {
# Create the bucket resource with readwrite and readonly users
# Create the bucket resource
name='test'
kubectl apply -f - <<EOF
apiVersion: apps.cozystack.io/v1alpha1
@@ -9,29 +9,21 @@ kind: Bucket
metadata:
name: ${name}
namespace: tenant-test
spec:
users:
admin: {}
viewer:
readonly: true
spec: {}
EOF
# Wait for the bucket to be ready
kubectl -n tenant-test wait hr bucket-${name} --timeout=100s --for=condition=ready
kubectl -n tenant-test wait bucketclaims.objectstorage.k8s.io bucket-${name} --timeout=300s --for=jsonpath='{.status.bucketReady}'
kubectl -n tenant-test wait bucketaccesses.objectstorage.k8s.io bucket-${name}-admin --timeout=300s --for=jsonpath='{.status.accessGranted}'
kubectl -n tenant-test wait bucketaccesses.objectstorage.k8s.io bucket-${name}-viewer --timeout=300s --for=jsonpath='{.status.accessGranted}'
kubectl -n tenant-test wait bucketaccesses.objectstorage.k8s.io bucket-${name} --timeout=300s --for=jsonpath='{.status.accessGranted}'
# Get admin (readwrite) credentials
kubectl -n tenant-test get secret bucket-${name}-admin -ojsonpath='{.data.BucketInfo}' | base64 -d > bucket-admin-credentials.json
ADMIN_ACCESS_KEY=$(jq -r '.spec.secretS3.accessKeyID' bucket-admin-credentials.json)
ADMIN_SECRET_KEY=$(jq -r '.spec.secretS3.accessSecretKey' bucket-admin-credentials.json)
BUCKET_NAME=$(jq -r '.spec.bucketName' bucket-admin-credentials.json)
# Get and decode credentials
kubectl -n tenant-test get secret bucket-${name} -ojsonpath='{.data.BucketInfo}' | base64 -d > bucket-test-credentials.json
# Get viewer (readonly) credentials
kubectl -n tenant-test get secret bucket-${name}-viewer -ojsonpath='{.data.BucketInfo}' | base64 -d > bucket-viewer-credentials.json
VIEWER_ACCESS_KEY=$(jq -r '.spec.secretS3.accessKeyID' bucket-viewer-credentials.json)
VIEWER_SECRET_KEY=$(jq -r '.spec.secretS3.accessSecretKey' bucket-viewer-credentials.json)
# Get credentials from the secret
ACCESS_KEY=$(jq -r '.spec.secretS3.accessKeyID' bucket-test-credentials.json)
SECRET_KEY=$(jq -r '.spec.secretS3.accessSecretKey' bucket-test-credentials.json)
BUCKET_NAME=$(jq -r '.spec.bucketName' bucket-test-credentials.json)
# Start port-forwarding
bash -c 'timeout 100s kubectl port-forward service/seaweedfs-s3 -n tenant-root 8333:8333 > /dev/null 2>&1 &'
@@ -39,33 +31,17 @@ EOF
# Wait for port-forward to be ready
timeout 30 sh -ec 'until nc -z localhost 8333; do sleep 1; done'
# --- Test readwrite user (admin) ---
mc alias set rw-user https://localhost:8333 $ADMIN_ACCESS_KEY $ADMIN_SECRET_KEY --insecure
# Set up MinIO alias with error handling
mc alias set local https://localhost:8333 $ACCESS_KEY $SECRET_KEY --insecure
# Admin can upload
echo "readwrite test" > /tmp/rw-test.txt
mc cp --insecure /tmp/rw-test.txt rw-user/$BUCKET_NAME/rw-test.txt
# Upload file to bucket
mc cp bucket-test-credentials.json $BUCKET_NAME/bucket-test-credentials.json
# Admin can list
mc ls --insecure rw-user/$BUCKET_NAME/rw-test.txt
# Verify file was uploaded
mc ls $BUCKET_NAME/bucket-test-credentials.json
# Admin can download
mc cp --insecure rw-user/$BUCKET_NAME/rw-test.txt /tmp/rw-test-download.txt
# Clean up uploaded file
mc rm $BUCKET_NAME/bucket-test-credentials.json
# --- Test readonly user (viewer) ---
mc alias set ro-user https://localhost:8333 $VIEWER_ACCESS_KEY $VIEWER_SECRET_KEY --insecure
# Viewer can list
mc ls --insecure ro-user/$BUCKET_NAME/rw-test.txt
# Viewer can download
mc cp --insecure ro-user/$BUCKET_NAME/rw-test.txt /tmp/ro-test-download.txt
# Viewer cannot upload (must fail with Access Denied)
echo "readonly test" > /tmp/ro-test.txt
! mc cp --insecure /tmp/ro-test.txt ro-user/$BUCKET_NAME/ro-test.txt
# --- Cleanup ---
mc rm --insecure rw-user/$BUCKET_NAME/rw-test.txt
kubectl -n tenant-test delete bucket.apps.cozystack.io ${name}
}

View File

@@ -2,4 +2,5 @@ include ../../../hack/package.mk
generate:
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
yq -o json -i '.properties = {}' values.schema.json
../../../hack/update-crd.sh

View File

@@ -1,13 +1,3 @@
# S3 bucket
## Parameters
### Parameters
| Name | Description | Type | Value |
| ---------------------- | -------------------------------------------------------------------------- | ------------------- | ------- |
| `locking` | Provisions bucket from the `-lock` BucketClass (with object lock enabled). | `bool` | `false` |
| `storagePool` | Selects a specific BucketClass by storage pool name. | `string` | `""` |
| `users` | Users configuration map. | `map[string]object` | `{}` |
| `users[name].readonly` | Whether the user has read-only access. | `bool` | `false` |

View File

@@ -1,22 +1,29 @@
{{- $seaweedfs := .Values._namespace.seaweedfs }}
{{- $pool := .Values.storagePool }}
apiVersion: objectstorage.k8s.io/v1alpha1
kind: BucketClaim
metadata:
name: {{ .Release.Name }}
spec:
bucketClassName: {{ $seaweedfs }}{{- if $pool }}-{{ $pool }}{{- end }}{{- if .Values.locking }}-lock{{- end }}
bucketClassName: {{ $seaweedfs }}
protocols:
- s3
{{- range $name, $user := .Values.users }}
---
apiVersion: objectstorage.k8s.io/v1alpha1
kind: BucketAccess
metadata:
name: {{ $.Release.Name }}-{{ $name }}
name: {{ .Release.Name }}
spec:
bucketAccessClassName: {{ $seaweedfs }}{{- if $pool }}-{{ $pool }}{{- end }}{{- if $user.readonly }}-readonly{{- end }}
bucketClaimName: {{ $.Release.Name }}
credentialsSecretName: {{ $.Release.Name }}-{{ $name }}
bucketAccessClassName: {{ $seaweedfs }}
bucketClaimName: {{ .Release.Name }}
credentialsSecretName: {{ .Release.Name }}
protocol: s3
---
apiVersion: objectstorage.k8s.io/v1alpha1
kind: BucketAccess
metadata:
name: {{ .Release.Name }}-readonly
spec:
bucketAccessClassName: {{ $seaweedfs }}-readonly
bucketClaimName: {{ .Release.Name }}
credentialsSecretName: {{ .Release.Name }}-readonly
protocol: s3
{{- end }}

View File

@@ -8,9 +8,9 @@ rules:
resources:
- secrets
resourceNames:
{{- range $name, $user := .Values.users }}
- {{ $.Release.Name }}-{{ $name }}-credentials
{{- end }}
- {{ .Release.Name }}
- {{ .Release.Name }}-credentials
- {{ .Release.Name }}-readonly
verbs: ["get", "list", "watch"]
- apiGroups:
- networking.k8s.io

View File

@@ -23,4 +23,3 @@ spec:
name: cozystack-values
values:
bucketName: {{ .Release.Name }}
users: {{ .Values.users | toJson }}

View File

@@ -1,30 +1,5 @@
{
"title": "Chart Values",
"type": "object",
"properties": {
"locking": {
"description": "Provisions bucket from the `-lock` BucketClass (with object lock enabled).",
"type": "boolean",
"default": false
},
"storagePool": {
"description": "Selects a specific BucketClass by storage pool name.",
"type": "string",
"default": ""
},
"users": {
"description": "Users configuration map.",
"type": "object",
"default": {},
"additionalProperties": {
"type": "object",
"properties": {
"readonly": {
"description": "Whether the user has read-only access.",
"type": "boolean"
}
}
}
}
}
}
"properties": {}
}

View File

@@ -1,11 +1 @@
## @param {bool} locking=false - Provisions bucket from the `-lock` BucketClass (with object lock enabled).
locking: false
## @param {string} [storagePool] - Selects a specific BucketClass by storage pool name.
storagePool: ""
## @typedef {struct} User - Bucket user configuration.
## @field {bool} [readonly] - Whether the user has read-only access.
## @param {map[string]User} users - Users configuration map.
users: {}
{}

View File

@@ -1,4 +1,4 @@
# FoundationDB
# Managed FoundationDB Service
A managed FoundationDB service for Cozystack.

View File

@@ -1,6 +1,6 @@
# Managed Harbor Container Registry
Harbor is an open source trusted cloud native registry project that stores, signs, and scans content.
Harbor is an open-source trusted cloud-native registry project that stores, signs, and scans content.
## Parameters

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:faaa6bcdb68196edb4baafe643679bd7d2ef35f910c639b71e06a4ecc034f232
ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:434aa3b8e2a3cbf6681426b174e1c4fde23bafd12a6cccd046b5cb1749092ec4

View File

@@ -3,7 +3,6 @@ cilium:
k8sServiceHost: {{ .Release.Name }}.{{ .Release.Namespace }}.svc
k8sServicePort: 6443
routingMode: tunnel
MTU: 1350
enableIPv4Masquerade: true
ipv4NativeRoutingCIDR: ""
{{- if $.Values.addons.gatewayAPI.enabled }}

View File

@@ -15,7 +15,7 @@ This managed service is controlled by mariadb-operator, ensuring efficient manag
### How to switch master/slave replica
```bash
kubectl edit mariadb <instnace>
kubectl edit mariadb <instance>
```
update:
@@ -54,11 +54,11 @@ more details:
- **Replication can't be finished with various errors**
- **Replication can't be finished in case if `binlog` purged**
Until `mariadbbackup` is not used to bootstrap a node by mariadb-operator (this feature is not inmplemented yet), follow these manual steps to fix it:
Until `mariadbbackup` is not used to bootstrap a node by mariadb-operator (this feature is not implemented yet), follow these manual steps to fix it:
https://github.com/mariadb-operator/mariadb-operator/issues/141#issuecomment-1804760231
- **Corrupted indicies**
Sometimes some indecies can be corrupted on master replica, you can recover them from slave:
- **Corrupted indices**
Sometimes some indices can be corrupted on master replica, you can recover them from slave:
```bash
mysqldump -h <slave> -P 3306 -u<user> -p<password> --column-statistics=0 <database> <table> ~/tmp/fix-table.sql

View File

@@ -1,9 +1,9 @@
cozystackOperator:
# Deployment variant: talos, generic, hosted
variant: talos
image: ghcr.io/cozystack/cozystack/cozystack-operator:v1.1.0@sha256:9367001a8d1d2dcf08ae74a42ac234eaa6af18f1af64ac28ce8a5946af9c5d3f
image: ghcr.io/cozystack/cozystack/cozystack-operator:v1.0.0@sha256:9e5229764b6077809a1c16566881a524c33e8986e36597e6833f8857a7e6a335
platformSourceUrl: 'oci://ghcr.io/cozystack/cozystack/cozystack-packages'
platformSourceRef: 'digest=sha256:7c6da38e7b99ec80d35ba2cef721ea1579f8a0824989454544fa85318bb7bf15'
platformSourceRef: 'digest=sha256:ef3e4ba7d21572a61794d8be594805f063aa04f4a8c3753351fc89c7804d337e'
# Generic variant configuration (only used when cozystackOperator.variant=generic)
cozystack:
# Kubernetes API server host (IP only, no protocol/port)

View File

@@ -5,7 +5,7 @@ sourceRef:
path: /
migrations:
enabled: false
image: ghcr.io/cozystack/cozystack/platform-migrations:v1.1.0@sha256:d7e8955c1ad8c8fbd4ce42b014c0f849d73d0c3faf0cedaac8e15d647fb2f663
image: ghcr.io/cozystack/cozystack/platform-migrations:v1.0.0@sha256:68dabdebc38ac439228ae07031cc70e0fa184a24bd4e5b3b22c17466b2a55201
targetVersion: 35
# Bundle deployment configuration
bundles:

View File

@@ -1,2 +1,2 @@
e2e:
image: ghcr.io/cozystack/cozystack/e2e-sandbox:v1.1.0@sha256:0eae9f519669667d60b160ebb93c127843c470ad9ca3447fceaa54604503a7ba
image: ghcr.io/cozystack/cozystack/e2e-sandbox:v1.0.0@sha256:0eae9f519669667d60b160ebb93c127843c470ad9ca3447fceaa54604503a7ba

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/matchbox:v1.1.0@sha256:e4c872f6dadc2bbcb9200d04a1d9878f62502f74e979b4eae6c7203abc6d8fa6
ghcr.io/cozystack/cozystack/matchbox:v1.0.0@sha256:c48eb7b23f01a8ff58d409fdb51c88e771f819cb914eee03da89471e62302f33

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/objectstorage-sidecar:v1.1.0@sha256:2a3595cd88b30af55b2000d3ca204899beecef0012b0e0402754c3914aad1f7f
ghcr.io/cozystack/cozystack/objectstorage-sidecar:v1.0.0@sha256:2a3595cd88b30af55b2000d3ca204899beecef0012b0e0402754c3914aad1f7f

View File

@@ -7,32 +7,10 @@ metadata:
driverName: {{ .Release.Namespace }}.seaweedfs.objectstorage.k8s.io
deletionPolicy: Delete
---
kind: BucketClass
apiVersion: objectstorage.k8s.io/v1alpha1
metadata:
name: {{ .Release.Namespace }}-lock
driverName: {{ .Release.Namespace }}.seaweedfs.objectstorage.k8s.io
deletionPolicy: Retain
parameters:
objectLockEnabled: "true"
objectLockRetentionMode: "COMPLIANCE"
objectLockRetentionDays: "365"
---
kind: BucketAccessClass
apiVersion: objectstorage.k8s.io/v1alpha1
metadata:
name: {{ .Release.Namespace }}
driverName: {{ .Release.Namespace }}.seaweedfs.objectstorage.k8s.io
authenticationType: KEY
parameters:
accessPolicy: readwrite
---
kind: BucketAccessClass
apiVersion: objectstorage.k8s.io/v1alpha1
metadata:
name: {{ .Release.Namespace }}-readonly
driverName: {{ .Release.Namespace }}.seaweedfs.objectstorage.k8s.io
authenticationType: KEY
parameters:
accessPolicy: readonly
{{- end }}

View File

@@ -32,8 +32,8 @@
{{- if not (regexMatch "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$" $poolName) }}
{{- fail (printf "volume.pools key '%s' must be a valid DNS label (lowercase alphanumeric and hyphens, no dots)." $poolName) }}
{{- end }}
{{- if or (hasSuffix "-lock" $poolName) (hasSuffix "-readonly" $poolName) }}
{{- fail (printf "volume.pools key '%s' must not end with '-lock' or '-readonly' (reserved suffixes for COSI resources)." $poolName) }}
{{- if or (hasSuffix "-worm" $poolName) (hasSuffix "-readonly" $poolName) }}
{{- fail (printf "volume.pools key '%s' must not end with '-worm' or '-readonly' (reserved suffixes for COSI resources)." $poolName) }}
{{- end }}
{{- if not $pool.diskType }}
{{- fail (printf "volume.pools.%s.diskType is required." $poolName) }}
@@ -52,8 +52,8 @@
{{- if not (regexMatch "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$" $poolName) }}
{{- fail (printf "volume.zones.%s.pools key '%s' must be a valid DNS label." $zoneName $poolName) }}
{{- end }}
{{- if or (hasSuffix "-lock" $poolName) (hasSuffix "-readonly" $poolName) }}
{{- fail (printf "volume.zones.%s.pools key '%s' must not end with '-lock' or '-readonly' (reserved suffixes for COSI resources)." $zoneName $poolName) }}
{{- if or (hasSuffix "-worm" $poolName) (hasSuffix "-readonly" $poolName) }}
{{- fail (printf "volume.zones.%s.pools key '%s' must not end with '-worm' or '-readonly' (reserved suffixes for COSI resources)." $zoneName $poolName) }}
{{- end }}
{{- if not $pool.diskType }}
{{- fail (printf "volume.zones.%s.pools.%s.diskType is required." $zoneName $poolName) }}

View File

@@ -25,14 +25,14 @@ parameters:
kind: BucketClass
apiVersion: objectstorage.k8s.io/v1alpha1
metadata:
name: {{ $.Release.Namespace }}-{{ $poolName }}-lock
name: {{ $.Release.Namespace }}-{{ $poolName }}-worm
driverName: {{ $.Release.Namespace }}.seaweedfs.objectstorage.k8s.io
deletionPolicy: Retain
parameters:
disk: {{ $diskType }}
objectLockEnabled: "true"
objectLockRetentionMode: "COMPLIANCE"
objectLockRetentionDays: "365"
objectLockRetentionMode: COMPLIANCE
objectLockRetentionDays: "36500"
---
kind: BucketAccessClass
apiVersion: objectstorage.k8s.io/v1alpha1

View File

@@ -1,5 +1,5 @@
backupController:
image: "ghcr.io/cozystack/cozystack/backup-controller:v1.1.0@sha256:8e42e29f5d30ecbef1f05cb0601c32703c5f9572b89d2c9032c1dff186e9a526"
image: "ghcr.io/cozystack/cozystack/backup-controller:v1.0.0@sha256:e1a6c8ac7ba64442812464b59c53e782e373a339c18b379c2692921b44c6edb5"
replicas: 2
debug: false
metrics:

View File

@@ -1,5 +1,5 @@
backupStrategyController:
image: "ghcr.io/cozystack/cozystack/backupstrategy-controller:v1.1.0@sha256:508e3bd5a83a316732cfb84fe598064e3092482d941cfc53738ca21237642e6f"
image: "ghcr.io/cozystack/cozystack/backupstrategy-controller:v1.0.0@sha256:29735d945c69c6bbaab21068bf4ea30f6b63f4c71a7a8d95590f370abcb4b328"
replicas: 2
debug: false
metrics:

View File

@@ -8,7 +8,7 @@ spec:
plural: buckets
singular: bucket
openAPISchema: |-
{"title":"Chart Values","type":"object","properties":{"locking":{"description":"Provisions bucket from the `-lock` BucketClass (with object lock enabled).","type":"boolean","default":false},"storagePool":{"description":"Selects a specific BucketClass by storage pool name.","type":"string","default":""},"users":{"description":"Users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"readonly":{"description":"Whether the user has read-only access.","type":"boolean"}}}}}}
{"title":"Chart Values","type":"object","properties":{}}
release:
prefix: bucket-
labels:
@@ -26,14 +26,14 @@ spec:
tags:
- storage
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODNfMzA5MSkiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik03MiAzMC4xNjQxTDExNy45ODMgMzYuNzc4OVY0MC42NzM5QzExNy45ODMgNDYuNDY1MyA5Ny4zODYyIDUxLjEzMzIgNzEuOTgyNyA1MS4xMzMyQzQ2LjU3OTIgNTEuMTMzMiAyNiA0Ni40NjUzIDI2IDQwLjY3MzlWMzYuNDQzMUw3MiAzMC4xNjQxWk03MiA1OC4yNjc4QzkxLjIwODQgNTguMjY3OCAxMDcuNjU4IDU1LjU5ODYgMTE0LjU0NyA1MS44MDQ4TDExNi44MDMgNDguMTExTDExNy43MjMgNDQuNzUzVjQ4LjkxNzFMMTAyLjY3OSAxMTEuMDMzQzEwMi42NzkgMTE0Ljg5NSA4OC45NTMzIDExOCA3Mi4wMTcyIDExOEM1NS4wODEyIDExOCA0MS4zNzQzIDExNC44OTUgNDEuMzc0MyAxMTEuMDMzTDI2LjMzIDQ4LjkxNzFWNDQuODM2OUwyOS44MDA3IDUxLjkzODJDMzYuNzA2NSA1NS42NjUzIDUyLjk5OTcgNTguMjY3OCA3MiA1OC4yNjc4WiIgZmlsbD0iIzhDMzEyMyIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTcyLjAwMDMgMjZDOTcuNDAzOCAyNiAxMTggMzAuNjgzOSAxMTggMzYuNDQyQzExOCA0Mi4yIDk3LjM4NjYgNDYuODUwNyA3Mi4wMDAzIDQ2Ljg1MDdDNDYuNjE0MSA0Ni44NTA3IDI2LjAxNzYgNDIuMjM0NSAyNi4wMTc2IDM2LjQ0MkMyNi4wMTc2IDMwLjY0OTQgNDYuNTk2OCAyNiA3Mi4wMDAzIDI2Wk03Mi4wMDAzIDU0LjEwMzdDOTUuNjg1NyA1NC4xMDM3IDExNS4xNzIgNTAuMDU4IDExNy43MDYgNDQuODE5N0wxMDIuNjYyIDEwNi45MzdDMTAyLjY2MiAxMTAuNzk5IDg4LjkzNjQgMTEzLjkwNSA3Mi4wMDAzIDExMy45MDVDNTUuMDY0MyAxMTMuOTA1IDQxLjMzOSAxMTAuODE2IDQxLjMzOSAxMDYuOTU0TDI2LjI5NTkgNDQuODM3QzI4Ljg0NjYgNTAuMDU4IDQ4LjMzMzMgNTQuMTAzNyA3Mi4wMDAzIDU0LjEwMzdaIiBmaWxsPSIjRTA1MjQzIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNjEuMTcyNSA2MC4wMjkzSDgxLjA5MjhWNzkuMTY3Nkg2MS4xNzI1VjYwLjAyOTNaTTQ1LjMzMDEgOTUuMzY4OEM0NS4zMzAxIDkwLjE0MiA0OS43MTA0IDg1LjkzNDIgNTUuMTUxMSA4NS45MzQyQzYwLjU5MTcgODUuOTM0MiA2NC45NzIxIDkwLjE0MiA2NC45NzIxIDk1LjM2ODhDNjQuOTcyMSAxMDAuNTk2IDYwLjU5MTcgMTA0LjgwMyA1NS4xNTExIDEwNC44MDNDNDkuNzEwNCAxMDQuODAzIDQ1LjMzMDEgMTAwLjU5NiA0NS4zMzAxIDk1LjM2ODhaTTk2LjQ0ODcgMTA0LjM2OEg3Ni43NzIyTDg2LjYxMDUgODYuNzczN0w5Ni40NDg3IDEwNC4zNjhaIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4M18zMDkxIiB4MT0iMCIgeTE9IjAiIHgyPSIxNTEiIHkyPSIxODAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0ZGRjBFRSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNFQzg4N0QiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "locking"], ["spec", "storagePool"], ["spec", "users"]]
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"]]
secrets:
exclude: []
include:
- resourceNames:
- bucket-{{ .name }}
- bucket-{{ .name }}-credentials
- matchLabels:
apps.cozystack.io/user-secret: "true"
- bucket-{{ .name }}-readonly
ingresses:
exclude: []
include:

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:5a7cae722ff6b424bdfbc4aba9d072c11b6930e2ee0f5fa97c3a565bd1c8dc88
ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:279008f87460d709e99ed25ee8a1e4568a290bb9afa0e3dd3a06d524163a132b

View File

@@ -9,7 +9,6 @@ WORKDIR /usr/src/app
RUN wget -O- https://github.com/cloudlena/s3manager/archive/9a7c8e446b422f8973b8c461990f39fdafee9c27.tar.gz | tar -xzf- --strip 1
ADD cozystack.patch /
RUN git apply /cozystack.patch
RUN go mod tidy
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -ldflags="-s -w" -a -installsuffix cgo -o bin/s3manager
FROM docker.io/library/alpine:latest

View File

@@ -1,235 +1,3 @@
diff --git a/go.mod b/go.mod
index b5d8540..6ede8e8 100644
--- a/go.mod
+++ b/go.mod
@@ -1,10 +1,11 @@
module github.com/cloudlena/s3manager
-go 1.22.5
+go 1.23
require (
github.com/cloudlena/adapters v0.0.0-20240708203353-a39be02cc801
github.com/gorilla/mux v1.8.1
+ github.com/gorilla/sessions v1.4.0
github.com/matryer/is v1.4.1
github.com/minio/minio-go/v7 v7.0.74
github.com/spf13/viper v1.19.0
@@ -16,6 +17,7 @@ require (
github.com/go-ini/ini v1.67.0 // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/google/uuid v1.6.0 // indirect
+ github.com/gorilla/securecookie v1.1.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
diff --git a/go.sum b/go.sum
index 1ea1b16..d7866ce 100644
--- a/go.sum
+++ b/go.sum
@@ -16,10 +16,16 @@ github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
+github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
+github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
+github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ=
+github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
diff --git a/main.go b/main.go
index 2ffe8ab..723a1b8 100644
--- a/main.go
+++ b/main.go
@@ -41,10 +41,12 @@ type configuration struct {
Timeout int32
SseType string
SseKey string
+ LoginMode bool
}
func parseConfiguration() configuration {
var accessKeyID, secretAccessKey, iamEndpoint string
+ var loginMode bool
viper.AutomaticEnv()
@@ -57,13 +59,10 @@ func parseConfiguration() configuration {
iamEndpoint = viper.GetString("IAM_ENDPOINT")
} else {
accessKeyID = viper.GetString("ACCESS_KEY_ID")
- if len(accessKeyID) == 0 {
- log.Fatal("please provide ACCESS_KEY_ID")
- }
-
secretAccessKey = viper.GetString("SECRET_ACCESS_KEY")
- if len(secretAccessKey) == 0 {
- log.Fatal("please provide SECRET_ACCESS_KEY")
+ if len(accessKeyID) == 0 || len(secretAccessKey) == 0 {
+ log.Println("ACCESS_KEY_ID or SECRET_ACCESS_KEY not set, starting in login mode")
+ loginMode = true
}
}
@@ -115,6 +114,7 @@ func parseConfiguration() configuration {
Timeout: timeout,
SseType: sseType,
SseKey: sseKey,
+ LoginMode: loginMode,
}
}
@@ -135,57 +135,96 @@ func main() {
log.Fatal(err)
}
- // Set up S3 client
- opts := &minio.Options{
- Secure: configuration.UseSSL,
- }
- if configuration.UseIam {
- opts.Creds = credentials.NewIAM(configuration.IamEndpoint)
- } else {
- var signatureType credentials.SignatureType
-
- switch configuration.SignatureType {
- case "V2":
- signatureType = credentials.SignatureV2
- case "V4":
- signatureType = credentials.SignatureV4
- case "V4Streaming":
- signatureType = credentials.SignatureV4Streaming
- case "Anonymous":
- signatureType = credentials.SignatureAnonymous
- default:
- log.Fatalf("Invalid SIGNATURE_TYPE: %s", configuration.SignatureType)
+ // Set up router
+ r := mux.NewRouter()
+ r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.FS(statics)))).Methods(http.MethodGet)
+
+ if configuration.LoginMode {
+ // Login mode: no pre-configured S3 client, per-session credentials
+ sessionCfg := &s3manager.SessionConfig{
+ Store: s3manager.NewSessionStore(),
+ Endpoint: configuration.Endpoint,
+ UseSSL: configuration.UseSSL,
+ SkipSSLVerify: configuration.SkipSSLVerification,
+ AllowDelete: configuration.AllowDelete,
+ ForceDownload: configuration.ForceDownload,
+ ListRecursive: configuration.ListRecursive,
+ SseInfo: sseType,
+ Templates: templates,
}
- opts.Creds = credentials.NewStatic(configuration.AccessKeyID, configuration.SecretAccessKey, "", signatureType)
- }
+ // Public routes (no auth required)
+ r.Handle("/login", s3manager.HandleLoginView(templates)).Methods(http.MethodGet)
+ r.Handle("/login", s3manager.HandleLogin(sessionCfg)).Methods(http.MethodPost)
+ r.Handle("/logout", s3manager.HandleLogout(sessionCfg)).Methods(http.MethodPost)
+
+ // Protected routes (auth required via middleware)
+ protected := mux.NewRouter()
+ protected.Handle("/", http.RedirectHandler("/buckets", http.StatusPermanentRedirect)).Methods(http.MethodGet)
+ protected.Handle("/buckets", s3manager.HandleBucketsViewDynamic(templates, configuration.AllowDelete)).Methods(http.MethodGet)
+ protected.PathPrefix("/buckets/").Handler(s3manager.HandleBucketViewDynamic(templates, configuration.AllowDelete, configuration.ListRecursive)).Methods(http.MethodGet)
+ protected.Handle("/api/buckets", s3manager.HandleCreateBucketDynamic()).Methods(http.MethodPost)
+ if configuration.AllowDelete {
+ protected.Handle("/api/buckets/{bucketName}", s3manager.HandleDeleteBucketDynamic()).Methods(http.MethodDelete)
+ }
+ protected.Handle("/api/buckets/{bucketName}/objects", s3manager.HandleCreateObjectDynamic(sseType)).Methods(http.MethodPost)
+ protected.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}/url", s3manager.HandleGenerateUrlDynamic()).Methods(http.MethodGet)
+ protected.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}", s3manager.HandleGetObjectDynamic(configuration.ForceDownload)).Methods(http.MethodGet)
+ if configuration.AllowDelete {
+ protected.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}", s3manager.HandleDeleteObjectDynamic()).Methods(http.MethodDelete)
+ }
- if configuration.Region != "" {
- opts.Region = configuration.Region
- }
- if configuration.UseSSL && configuration.SkipSSLVerification {
- opts.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}} //nolint:gosec
- }
- s3, err := minio.New(configuration.Endpoint, opts)
- if err != nil {
- log.Fatalln(fmt.Errorf("error creating s3 client: %w", err))
- }
+ r.PathPrefix("/").Handler(s3manager.RequireAuth(sessionCfg, protected))
+ } else {
+ // Pre-configured mode: existing behavior with static S3 client
+ opts := &minio.Options{
+ Secure: configuration.UseSSL,
+ }
+ if configuration.UseIam {
+ opts.Creds = credentials.NewIAM(configuration.IamEndpoint)
+ } else {
+ var signatureType credentials.SignatureType
+
+ switch configuration.SignatureType {
+ case "V2":
+ signatureType = credentials.SignatureV2
+ case "V4":
+ signatureType = credentials.SignatureV4
+ case "V4Streaming":
+ signatureType = credentials.SignatureV4Streaming
+ case "Anonymous":
+ signatureType = credentials.SignatureAnonymous
+ default:
+ log.Fatalf("Invalid SIGNATURE_TYPE: %s", configuration.SignatureType)
+ }
+
+ opts.Creds = credentials.NewStatic(configuration.AccessKeyID, configuration.SecretAccessKey, "", signatureType)
+ }
- // Set up router
- r := mux.NewRouter()
- r.Handle("/", http.RedirectHandler("/buckets", http.StatusPermanentRedirect)).Methods(http.MethodGet)
- r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.FS(statics)))).Methods(http.MethodGet)
- r.Handle("/buckets", s3manager.HandleBucketsView(s3, templates, configuration.AllowDelete)).Methods(http.MethodGet)
- r.PathPrefix("/buckets/").Handler(s3manager.HandleBucketView(s3, templates, configuration.AllowDelete, configuration.ListRecursive)).Methods(http.MethodGet)
- r.Handle("/api/buckets", s3manager.HandleCreateBucket(s3)).Methods(http.MethodPost)
- if configuration.AllowDelete {
- r.Handle("/api/buckets/{bucketName}", s3manager.HandleDeleteBucket(s3)).Methods(http.MethodDelete)
- }
- r.Handle("/api/buckets/{bucketName}/objects", s3manager.HandleCreateObject(s3, sseType)).Methods(http.MethodPost)
- r.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}/url", s3manager.HandleGenerateUrl(s3)).Methods(http.MethodGet)
- r.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}", s3manager.HandleGetObject(s3, configuration.ForceDownload)).Methods(http.MethodGet)
- if configuration.AllowDelete {
- r.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}", s3manager.HandleDeleteObject(s3)).Methods(http.MethodDelete)
+ if configuration.Region != "" {
+ opts.Region = configuration.Region
+ }
+ if configuration.UseSSL && configuration.SkipSSLVerification {
+ opts.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}} //nolint:gosec
+ }
+ s3, err := minio.New(configuration.Endpoint, opts)
+ if err != nil {
+ log.Fatalln(fmt.Errorf("error creating s3 client: %w", err))
+ }
+
+ r.Handle("/", http.RedirectHandler("/buckets", http.StatusPermanentRedirect)).Methods(http.MethodGet)
+ r.Handle("/buckets", s3manager.HandleBucketsView(s3, templates, configuration.AllowDelete)).Methods(http.MethodGet)
+ r.PathPrefix("/buckets/").Handler(s3manager.HandleBucketView(s3, templates, configuration.AllowDelete, configuration.ListRecursive)).Methods(http.MethodGet)
+ r.Handle("/api/buckets", s3manager.HandleCreateBucket(s3)).Methods(http.MethodPost)
+ if configuration.AllowDelete {
+ r.Handle("/api/buckets/{bucketName}", s3manager.HandleDeleteBucket(s3)).Methods(http.MethodDelete)
+ }
+ r.Handle("/api/buckets/{bucketName}/objects", s3manager.HandleCreateObject(s3, sseType)).Methods(http.MethodPost)
+ r.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}/url", s3manager.HandleGenerateUrl(s3)).Methods(http.MethodGet)
+ r.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}", s3manager.HandleGetObject(s3, configuration.ForceDownload)).Methods(http.MethodGet)
+ if configuration.AllowDelete {
+ r.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}", s3manager.HandleDeleteObject(s3)).Methods(http.MethodDelete)
+ }
}
lr := logging.Handler(os.Stdout)(r)
diff --git a/web/template/bucket.html.tmpl b/web/template/bucket.html.tmpl
index e2f8d28..87add13 100644
--- a/web/template/bucket.html.tmpl
@@ -256,298 +24,3 @@ index c7ea184..fb1dce7 100644
</div>
</nav>
diff --git a/internal/app/s3manager/auth.go b/internal/app/s3manager/auth.go
new file mode 100644
index 0000000..58589e2
--- /dev/null
+++ b/internal/app/s3manager/auth.go
@@ -0,0 +1,237 @@
+package s3manager
+
+import (
+ "context"
+ "crypto/rand"
+ "crypto/tls"
+ "fmt"
+ "html/template"
+ "io/fs"
+ "log"
+ "net/http"
+
+ "github.com/gorilla/sessions"
+ "github.com/minio/minio-go/v7"
+ "github.com/minio/minio-go/v7/pkg/credentials"
+)
+
+type contextKey string
+
+const s3ContextKey contextKey = "s3client"
+
+// SessionConfig holds session store and S3 connection settings for login mode.
+type SessionConfig struct {
+ Store *sessions.CookieStore
+ Endpoint string
+ UseSSL bool
+ SkipSSLVerify bool
+ AllowDelete bool
+ ForceDownload bool
+ ListRecursive bool
+ SseInfo SSEType
+ Templates fs.FS
+}
+
+// NewSessionStore creates a CookieStore with a random encryption key.
+func NewSessionStore() *sessions.CookieStore {
+ key := make([]byte, 32)
+ if _, err := rand.Read(key); err != nil {
+ log.Fatal("failed to generate session key:", err)
+ }
+ store := sessions.NewCookieStore(key)
+ store.Options = &sessions.Options{
+ Path: "/",
+ MaxAge: 86400,
+ HttpOnly: true,
+ Secure: true,
+ SameSite: http.SameSiteLaxMode,
+ }
+ return store
+}
+
+// NewS3Client creates a minio client from user-provided credentials.
+func NewS3Client(endpoint, accessKey, secretKey string, useSSL, skipSSLVerify bool) (*minio.Client, error) {
+ opts := &minio.Options{
+ Creds: credentials.NewStaticV4(accessKey, secretKey, ""),
+ Secure: useSSL,
+ }
+ if useSSL && skipSSLVerify {
+ opts.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}} //nolint:gosec
+ }
+ return minio.New(endpoint, opts)
+}
+
+// S3FromContext retrieves the S3 client stored in request context.
+func S3FromContext(ctx context.Context) S3 {
+ if s3, ok := ctx.Value(s3ContextKey).(S3); ok {
+ return s3
+ }
+ return nil
+}
+
+func contextWithS3(ctx context.Context, s3 S3) context.Context {
+ return context.WithValue(ctx, s3ContextKey, s3)
+}
+
+// RequireAuth is middleware that validates session credentials and injects
+// an S3 client into the request context. Redirects to /login if no session.
+func RequireAuth(cfg *SessionConfig, next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ session, _ := cfg.Store.Get(r, "s3session")
+ accessKey, ok1 := session.Values["accessKey"].(string)
+ secretKey, ok2 := session.Values["secretKey"].(string)
+ if !ok1 || !ok2 || accessKey == "" || secretKey == "" {
+ http.Redirect(w, r, "/login", http.StatusFound)
+ return
+ }
+
+ s3, err := NewS3Client(cfg.Endpoint, accessKey, secretKey, cfg.UseSSL, cfg.SkipSSLVerify)
+ if err != nil {
+ // Session has bad credentials — clear and redirect to login
+ session.Options.MaxAge = -1
+ _ = session.Save(r, w)
+ http.Redirect(w, r, "/login", http.StatusFound)
+ return
+ }
+
+ ctx := contextWithS3(r.Context(), s3)
+ next.ServeHTTP(w, r.WithContext(ctx))
+ })
+}
+
+// HandleLoginView renders the login page.
+func HandleLoginView(templates fs.FS) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ errorMsg := r.URL.Query().Get("error")
+
+ data := struct {
+ Error string
+ }{
+ Error: errorMsg,
+ }
+
+ t, err := template.ParseFS(templates, "layout.html.tmpl", "login.html.tmpl")
+ if err != nil {
+ handleHTTPError(w, fmt.Errorf("error parsing login template: %w", err))
+ return
+ }
+ err = t.ExecuteTemplate(w, "layout", data)
+ if err != nil {
+ handleHTTPError(w, fmt.Errorf("error executing login template: %w", err))
+ return
+ }
+ }
+}
+
+// HandleLogin processes the login form POST.
+func HandleLogin(cfg *SessionConfig) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ accessKey := r.FormValue("accessKey")
+ secretKey := r.FormValue("secretKey")
+
+ if accessKey == "" || secretKey == "" {
+ http.Redirect(w, r, "/login?error=credentials+required", http.StatusFound)
+ return
+ }
+
+ // Validate credentials by attempting ListBuckets
+ s3, err := NewS3Client(cfg.Endpoint, accessKey, secretKey, cfg.UseSSL, cfg.SkipSSLVerify)
+ if err != nil {
+ http.Redirect(w, r, "/login?error=connection+failed", http.StatusFound)
+ return
+ }
+ _, err = s3.ListBuckets(r.Context())
+ if err != nil {
+ http.Redirect(w, r, "/login?error=invalid+credentials", http.StatusFound)
+ return
+ }
+
+ // Save credentials to session
+ session, _ := cfg.Store.Get(r, "s3session")
+ session.Values["accessKey"] = accessKey
+ session.Values["secretKey"] = secretKey
+ err = session.Save(r, w)
+ if err != nil {
+ handleHTTPError(w, fmt.Errorf("error saving session: %w", err))
+ return
+ }
+
+ http.Redirect(w, r, "/buckets", http.StatusFound)
+ }
+}
+
+// HandleLogout destroys the session and redirects to login.
+func HandleLogout(cfg *SessionConfig) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ session, _ := cfg.Store.Get(r, "s3session")
+ session.Options.MaxAge = -1
+ _ = session.Save(r, w)
+ http.Redirect(w, r, "/login", http.StatusFound)
+ }
+}
+
+// Dynamic handler wrappers — extract S3 from context, delegate to original handlers.
+
+// HandleBucketsViewDynamic wraps HandleBucketsView for login mode.
+func HandleBucketsViewDynamic(templates fs.FS, allowDelete bool) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ s3 := S3FromContext(r.Context())
+ HandleBucketsView(s3, templates, allowDelete).ServeHTTP(w, r)
+ }
+}
+
+// HandleBucketViewDynamic wraps HandleBucketView for login mode.
+func HandleBucketViewDynamic(templates fs.FS, allowDelete bool, listRecursive bool) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ s3 := S3FromContext(r.Context())
+ HandleBucketView(s3, templates, allowDelete, listRecursive).ServeHTTP(w, r)
+ }
+}
+
+// HandleCreateBucketDynamic wraps HandleCreateBucket for login mode.
+func HandleCreateBucketDynamic() http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ s3 := S3FromContext(r.Context())
+ HandleCreateBucket(s3).ServeHTTP(w, r)
+ }
+}
+
+// HandleDeleteBucketDynamic wraps HandleDeleteBucket for login mode.
+func HandleDeleteBucketDynamic() http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ s3 := S3FromContext(r.Context())
+ HandleDeleteBucket(s3).ServeHTTP(w, r)
+ }
+}
+
+// HandleCreateObjectDynamic wraps HandleCreateObject for login mode.
+func HandleCreateObjectDynamic(sseInfo SSEType) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ s3 := S3FromContext(r.Context())
+ HandleCreateObject(s3, sseInfo).ServeHTTP(w, r)
+ }
+}
+
+// HandleGenerateUrlDynamic wraps HandleGenerateUrl for login mode.
+func HandleGenerateUrlDynamic() http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ s3 := S3FromContext(r.Context())
+ HandleGenerateUrl(s3).ServeHTTP(w, r)
+ }
+}
+
+// HandleGetObjectDynamic wraps HandleGetObject for login mode.
+func HandleGetObjectDynamic(forceDownload bool) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ s3 := S3FromContext(r.Context())
+ HandleGetObject(s3, forceDownload).ServeHTTP(w, r)
+ }
+}
+
+// HandleDeleteObjectDynamic wraps HandleDeleteObject for login mode.
+func HandleDeleteObjectDynamic() http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ s3 := S3FromContext(r.Context())
+ HandleDeleteObject(s3).ServeHTTP(w, r)
+ }
+}
diff --git a/web/template/login.html.tmpl b/web/template/login.html.tmpl
new file mode 100644
index 0000000..f153018
--- /dev/null
+++ b/web/template/login.html.tmpl
@@ -0,0 +1,46 @@
+{{ define "content" }}
+<nav>
+ <div class="nav-wrapper container">
+ <a href="/" class="brand-logo">Cozystack S3 Manager</a>
+ </div>
+</nav>
+
+<div class="container">
+ <div class="section">
+ <div class="row">
+ <div class="col l6 offset-l3 m8 offset-m2 s12">
+ <div class="card">
+ <div class="card-content">
+ <span class="card-title">Sign In</span>
+ <p>Enter your S3 credentials to access the bucket manager.</p>
+ <br>
+
+ {{ if .Error }}
+ <div class="card-panel red lighten-4 red-text text-darken-4">
+ <i class="material-icons tiny">error</i> {{ .Error }}
+ </div>
+ {{ end }}
+
+ <form method="POST" action="/login">
+ <div class="input-field">
+ <i class="material-icons prefix">vpn_key</i>
+ <input id="accessKey" name="accessKey" type="text" required>
+ <label for="accessKey">Access Key ID</label>
+ </div>
+ <div class="input-field">
+ <i class="material-icons prefix">lock</i>
+ <input id="secretKey" name="secretKey" type="password" required>
+ <label for="secretKey">Secret Access Key</label>
+ </div>
+ <br>
+ <button type="submit" class="btn waves-effect waves-light" style="width:100%;">
+ Sign In <i class="material-icons right">send</i>
+ </button>
+ </form>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+{{ end }}

View File

@@ -17,6 +17,19 @@ spec:
image: "{{ $.Files.Get "images/s3manager.tag" | trim }}"
env:
- name: ENDPOINT
value: "s3.{{ .Values._namespace.host }}"
valueFrom:
secretKeyRef:
name: {{ .Values.bucketName }}-credentials
key: endpoint
- name: SKIP_SSL_VERIFICATION
value: "true"
- name: ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: {{ .Values.bucketName }}-credentials
key: accessKey
- name: SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.bucketName }}-credentials
key: secretKey

View File

@@ -8,6 +8,9 @@ kind: Ingress
metadata:
name: {{ .Values.bucketName }}-ui
annotations:
nginx.ingress.kubernetes.io/auth-type: "basic"
nginx.ingress.kubernetes.io/auth-secret: "{{ .Values.bucketName }}-ui-auth"
nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/proxy-read-timeout: "99999"
nginx.ingress.kubernetes.io/proxy-send-timeout: "99999"

View File

@@ -1,2 +1,24 @@
{{/* Secrets previously used for s3manager credential injection and nginx basic auth */}}
{{/* are no longer needed — s3manager now handles authentication via its own login page */}}
{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace .Values.bucketName }}
{{- $bucketInfo := fromJson (b64dec (index $existingSecret.data "BucketInfo")) }}
{{- $accessKeyID := index $bucketInfo.spec.secretS3 "accessKeyID" }}
{{- $accessSecretKey := index $bucketInfo.spec.secretS3 "accessSecretKey" }}
{{- $endpoint := index $bucketInfo.spec.secretS3 "endpoint" }}
{{- $bucketName := index $bucketInfo.spec "bucketName" }}
apiVersion: v1
kind: Secret
metadata:
name: {{ .Values.bucketName }}-credentials
type: Opaque
stringData:
accessKey: {{ $accessKeyID | quote }}
secretKey: {{ $accessSecretKey | quote }}
endpoint: {{ trimPrefix "https://" $endpoint }}
bucketName: {{ $bucketName | quote }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ .Values.bucketName }}-ui-auth
data:
auth: {{ htpasswd $accessKeyID $accessSecretKey | b64enc | quote }}

View File

@@ -1,20 +0,0 @@
{{- range $name, $user := .Values.users }}
{{- $secretName := printf "%s-%s" $.Values.bucketName $name }}
{{- $existingSecret := lookup "v1" "Secret" $.Release.Namespace $secretName }}
{{- if $existingSecret }}
{{- $bucketInfo := fromJson (b64dec (index $existingSecret.data "BucketInfo")) }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ $secretName }}-credentials
labels:
apps.cozystack.io/user-secret: "true"
type: Opaque
stringData:
accessKey: {{ index $bucketInfo.spec.secretS3 "accessKeyID" | quote }}
secretKey: {{ index $bucketInfo.spec.secretS3 "accessSecretKey" | quote }}
endpoint: {{ trimPrefix "https://" (index $bucketInfo.spec.secretS3 "endpoint") }}
bucketName: {{ index $bucketInfo.spec "bucketName" | quote }}
{{- end }}
{{- end }}

View File

@@ -1,2 +1 @@
bucketName: "cozystack"
users: {}

View File

@@ -1,3 +1,3 @@
cozystackAPI:
image: ghcr.io/cozystack/cozystack/cozystack-api:v1.1.0@sha256:3a8e559b1a71cffb445bab14178d9abeba1b90509f9fec31df5ff5a9a38333d1
image: ghcr.io/cozystack/cozystack/cozystack-api:v1.0.0@sha256:bd70ecb944bde9a0d6b88114aea89bdbbe2d07e33f03175cfd885de013e88294
replicas: 2

View File

@@ -1,4 +1,4 @@
cozystackController:
image: ghcr.io/cozystack/cozystack/cozystack-controller:v1.1.0@sha256:f04fa839924a761571e1035d83f380f39f62d1708ea8d22f7a323f17bb59ff96
image: ghcr.io/cozystack/cozystack/cozystack-controller:v1.0.0@sha256:da01085026a4a01514ae435c7bfb48cca2cf00eb17feb2ed7ae88711f82693e0
debug: false
disableTelemetry: false

View File

@@ -1,6 +1,6 @@
{{- $brandingConfig := .Values._cluster.branding | default dict }}
{{- $tenantText := "v1.1.0" }}
{{- $tenantText := "v1.0.0" }}
{{- $footerText := "Cozystack" }}
{{- $titleText := "Cozystack Dashboard" }}
{{- $logoText := "" }}

View File

@@ -1,6 +1,6 @@
openapiUI:
image: ghcr.io/cozystack/cozystack/openapi-ui:v1.1.0@sha256:bc530ae2e428727eed284d7f80b2eea4fdd98b7618d20cab262eef7199af5fa5
image: ghcr.io/cozystack/cozystack/openapi-ui:v1.0.0@sha256:73a8bd4283a46a99d22536eece9c2059fa2fb1c17b43ddefe6716e8960e4731e
openapiUIK8sBff:
image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v1.1.0@sha256:c938fee904acd948800d4dc5e121c4c5cd64cb4a3160fb8d2f9dbff0e5168740
image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v1.0.0@sha256:c938fee904acd948800d4dc5e121c4c5cd64cb4a3160fb8d2f9dbff0e5168740
tokenProxy:
image: ghcr.io/cozystack/cozystack/token-proxy:v1.1.0@sha256:2e280991e07853ea48f97b0a42946afffa10d03d6a83d41099ed83e6ffc94fdc
image: ghcr.io/cozystack/cozystack/token-proxy:v1.0.0@sha256:2e280991e07853ea48f97b0a42946afffa10d03d6a83d41099ed83e6ffc94fdc

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/grafana-dashboards:v1.1.0@sha256:2c9aa0b48e2bf6167db198f4d15882bfe51700108edf2e9f6d0942940a2c1204
ghcr.io/cozystack/cozystack/grafana-dashboards:v1.0.0@sha256:7a3c9af59f8d74d5a23750bbc845c7de64610dbd4d4f84011e10be037b3ce2a0

View File

@@ -3,7 +3,7 @@ kamaji:
deploy: false
image:
pullPolicy: IfNotPresent
tag: v1.1.0@sha256:914d04f7442f0faecf18f8282c192dee9fe244a711494a8c892e2f9e2ad415f7
tag: v1.0.0@sha256:50db517ebe7698083dd32223a96c987b6ed0c88d3a093969beb571e4a96d18e4
repository: ghcr.io/cozystack/cozystack/kamaji
resources:
limits:
@@ -13,4 +13,4 @@ kamaji:
cpu: 100m
memory: 100Mi
extraArgs:
- --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v1.1.0@sha256:914d04f7442f0faecf18f8282c192dee9fe244a711494a8c892e2f9e2ad415f7
- --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v1.0.0@sha256:50db517ebe7698083dd32223a96c987b6ed0c88d3a093969beb571e4a96d18e4

View File

@@ -1,4 +1,4 @@
portSecurity: true
routes: ""
image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v1.1.0@sha256:b91bf0964a3204e50f703092f190b7d96c078a6ccee430215042ae1275ed5127
image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v1.0.0@sha256:b6045fdb4f324b9b1cb44a218c40422aafbbc600b085c819ff58809bb6e97220
ovnCentralName: ovn-central

View File

@@ -1,3 +1,3 @@
portSecurity: true
routes: ""
image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v1.1.0@sha256:e18f9fd679e38f65362a8d0042f25468272f6d081136ad47027168d8e7e07a4a
image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v1.0.0@sha256:e18f9fd679e38f65362a8d0042f25468272f6d081136ad47027168d8e7e07a4a

View File

@@ -1,3 +1,3 @@
storageClass: replicated
csiDriver:
image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:faaa6bcdb68196edb4baafe643679bd7d2ef35f910c639b71e06a4ecc034f232
image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:434aa3b8e2a3cbf6681426b174e1c4fde23bafd12a6cccd046b5cb1749092ec4

View File

@@ -1,5 +1,5 @@
lineageControllerWebhook:
image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v1.1.0@sha256:4d6a2bb76cae84e24cd48c7377b03ed6bdfefe611221d2c0a7f77a5457db8849
image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v1.0.0@sha256:af765c2829db4f513084522a384710acc321bd4a332eaf7fe814fecacea1022f
debug: false
localK8sAPIEndpoint:
enabled: true

View File

@@ -13,4 +13,4 @@ linstor:
linstorCSI:
image:
repository: ghcr.io/cozystack/cozystack/linstor-csi
tag: v1.10.5@sha256:50ab1ab0210d4e7ebfca311f445bb764516db5ddb63fc6d28536b28622eee753
tag: v1.10.5@sha256:c87b6f6dadaa6e3a3643d3279e81742830147f6c38f99e9232d9780abbcac897

View File

@@ -45,5 +45,3 @@ hubble/l7-http-metrics
hubble/network-overview
nats/nats-jetstream
nats/nats-server
mongodb/mongodb-overview
mongodb/mongodb-inmemory

View File

@@ -1,3 +1,3 @@
objectstorage:
controller:
image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v1.1.0@sha256:e40e94f3014cfd04cce4230597315a1acfcca2daa8051b987614d0c05da6d928"
image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v1.0.0@sha256:e40e94f3014cfd04cce4230597315a1acfcca2daa8051b987614d0c05da6d928"

View File

@@ -7,25 +7,12 @@ metadata:
driverName: {{ .Values.cosi.driverName }}
deletionPolicy: Delete
---
kind: BucketClass
apiVersion: objectstorage.k8s.io/v1alpha1
metadata:
name: {{ .Values.cosi.bucketClassName }}-lock
driverName: {{ .Values.cosi.driverName }}
deletionPolicy: Retain
parameters:
objectLockEnabled: "true"
objectLockRetentionMode: "COMPLIANCE"
objectLockRetentionDays: "365"
---
kind: BucketAccessClass
apiVersion: objectstorage.k8s.io/v1alpha1
metadata:
name: {{ .Values.cosi.bucketClassName }}
driverName: {{ .Values.cosi.driverName }}
authenticationType: KEY
parameters:
accessPolicy: readwrite
---
kind: BucketAccessClass
apiVersion: objectstorage.k8s.io/v1alpha1
@@ -34,5 +21,5 @@ metadata:
driverName: {{ .Values.cosi.driverName }}
authenticationType: KEY
parameters:
accessPolicy: readonly
accessPolicy: "readonly"
{{- end }}

View File

@@ -1546,7 +1546,7 @@ allInOne:
# For more information, visit: https://container-object-storage-interface.github.io/docs/deployment-guide
cosi:
enabled: false
image: "ghcr.io/seaweedfs/seaweedfs-cosi-driver:v0.3.0"
image: "ghcr.io/seaweedfs/seaweedfs-cosi-driver:v0.1.2"
driverName: "seaweedfs.objectstorage.k8s.io"
bucketClassName: "seaweedfs"
endpoint: ""

View File

@@ -177,7 +177,7 @@ seaweedfs:
bucketClassName: "seaweedfs"
region: ""
sidecar:
image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v1.1.0@sha256:2a3595cd88b30af55b2000d3ca204899beecef0012b0e0402754c3914aad1f7f"
image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v1.0.0@sha256:2a3595cd88b30af55b2000d3ca204899beecef0012b0e0402754c3914aad1f7f"
certificates:
commonName: "SeaweedFS CA"
ipAddresses: []