Compare commits

...

104 Commits

Author SHA1 Message Date
Kirill Ilin
3b366e28c6 fix(gateway-api): use stable v1 apiVersion for TLSRoute
v1alpha2 is deprecated in Gateway API v1.5.0 with a removal warning.
Update all TLSRoute resources to use gateway.networking.k8s.io/v1.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-13 13:02:18 +05:00
Kirill Ilin
b6195cc8b8 chore(tenant) make generate for gateway
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-13 12:42:21 +05:00
Kirill Ilin
1752f0e121 fix(gateway-api): address review findings
- Add HTTP-to-HTTPS redirect HTTPRoute for all Gateways (central and
  per-tenant) to ensure plain HTTP requests are properly redirected
- Add oidc-enabled check to keycloak HTTPRoute condition to match
  the Gateway listener condition
- Use gateway-name from cluster config instead of hardcoded value
  in central Gateway template
- Remove redundant namespace from TLSRoute metadata where it matches
  the HelmRelease install namespace (kubevirt, kubevirt-cdi)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-13 12:23:20 +05:00
Kirill Ilin
991e0ea3e3 feat(gateway): add Gateway API routes for tenant-level services
Add per-component Gateway + HTTPRoute/TLSRoute for tenant-level
services. Each component creates its own Gateway with specific
hostname HTTPS listener and cert-manager annotation for automatic
certificate provisioning via HTTP01 or DNS01.

All Gateways within a tenant share a single LoadBalancer IP through
infrastructure.labels (cozystack.io/gateway: {tenant-name}), matching
the current ingress-nginx model of one LB per tenant.

HTTPRoute (per-component Gateway with TLS terminate):
- monitoring/grafana: routes to grafana-service:3000
- monitoring/alerta: routes to alerta:80
- bucket: routes to {bucketName}-ui:8080
- apps/harbor: routes to {release}:80
- extra/bootbox: routes to bootbox:8080

TLSRoute (per-component Gateway with TLS passthrough):
- extra/seaweedfs: passthrough to filer-external:18888

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-13 12:09:32 +05:00
Kirill Ilin
00890e0264 feat(gateway): add _namespace.gateway to tenant model
Add gateway field to tenant namespace configuration, following the
same inheritance pattern as ingress:
- tenant-root defaults to gateway: tenant-root
- Sub-tenants with gateway: true get their own LB
- Sub-tenants without gateway inherit from parent

Add infrastructure.labels to central Gateway for shared LB with
tenant-root services (cozystack.io/gateway: tenant-root).

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-13 11:50:39 +05:00
Kirill Ilin
1076719730 feat(gateway): add HTTPRoute/TLSRoute for system services
Add Gateway API route templates alongside existing Ingress templates
for all system-level services. Routes are conditional on
_cluster.gateway-api being enabled.

HTTPRoute (TLS terminate via central Gateway):
- dashboard: routes to incloud-web-gatekeeper:8000
- keycloak: routes to keycloak-http:80

TLSRoute (TLS passthrough via central Gateway):
- cozystack-api: passthrough to kubernetes:443
- kubevirt vm-exportproxy: passthrough to vm-exportproxy:443
- kubevirt-cdi uploadproxy: passthrough to cdi-uploadproxy:443

All routes reference the central Gateway via parentRefs with
sectionName for listener matching. Hostname resolution follows
convention ({service}.{root-host}) with override support via
_cluster.hostnames map.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-13 11:28:24 +05:00
Kirill Ilin
8b58140e0d feat(gateway): add central Gateway resource and platform config
Add cozystack-gateway system package that creates a shared Gateway
resource with per-hostname HTTPS listeners and TLS passthrough
listeners for system services. Listeners are dynamically generated
from expose-services config.

Platform changes:
- Add gateway-api flag to _cluster config for component awareness
- Add gateway.name/namespace to platform values for parentRef config
- Add publishing.hostnames map for per-service hostname overrides
- Wire cozystack-gateway package into system bundle (conditional)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-13 11:26:13 +05:00
Kirill Ilin
b15f2f273c fix(cert-manager): make enableGatewayAPI conditional on gateway.gatewayAPI
Previously enableGatewayAPI was hardcoded to true in cert-manager values,
causing startup failures in isp-hosted variant where Gateway API CRDs
are not installed. Now passed via component override only when
gateway.gatewayAPI is enabled.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-12 09:45:03 +05:00
Kirill Ilin
7247edc280 feat(external-dns): add Gateway API source when gatewayAPI is enabled
When gateway.gatewayAPI is true, pass gateway-httproute source to the
system external-dns package via components values override.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-11 23:27:54 +05:00
Kirill Ilin
2c0a043fa5 feat(gateway-api): add Gateway API support via Cilium
- Upgrade Gateway API CRDs from v1.2.0 to v1.5.0 (experimental channel)
- Add gateway-api-crds as a component in all networking variants,
  with Cilium depending on it to ensure CRDs are available first
- Add gateway.gatewayAPI platform config (enables Cilium
  gatewayAPI.enabled=true), can be used alongside gateway.ingress
- Enable Gateway API support in cert-manager

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-11 23:27:30 +05:00
Andrei Kvapil
bf472fb941 [keycloak-operator] Update to v1.32.0 (#2206)
## What this PR does

Updates the Keycloak Operator Helm chart to v1.32.0 and builds a custom
operator image from upstream master
(https://github.com/epam/edp-keycloak-operator/commit/facbc36)
with the group rename detection patch from PR
https://github.com/epam/edp-keycloak-operator/pull/309 applied on top.

Bumps Keycloak server from 26.0.4 to 26.5.2, which is required by the
new operator client (sends `description` field rejected by older
versions).

Adds SSO session settings (idleTimeout: 86400, maxLifespan: 604800) to
the ClusterKeycloakRealm to match the dashboard client's session
attributes,
as Keycloak 26 enforces realm-level session limits strictly.

Removes `authorizationServicesEnabled` from the dashboard
KeycloakClient,
which is incompatible with Keycloak 26's stricter validation.

### Release note

```release-note
[keycloak-operator] Update the operator to v1.32.0 with group rename fix
(https://github.com/epam/edp-keycloak-operator/pull/309). Bump Keycloak to 26.5.2.
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Optional webhook support with cert-manager integration and webhook
service; feature toggles for webhooks and owner refs
* New realm login and session settings, organizations resource/CRD, and
expanded client/user schemas (including ClientRolesV2)

* **Documentation**
* Chart bumped to 1.32.0; README documents new values (clusterDomain,
podLabels, image.registry, securityContext, containerSecurityContext)

* **Security / RBAC**
* RBAC updated to cover organization resources and webhook bindings;
consolidated operator permissions

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-11 18:14:38 +01:00
Kirill Ilin
5e773486e5 feat(extra): add external-dns as standalone extra package (#1988)
## Summary

Add external-dns as a standalone self-managed application in
`packages/extra/external-dns/`, allowing tenants to deploy and configure
their own DNS management directly from the dashboard.

## Motivation

Tenants need the ability to manage their own DNS domains with their own
provider. Following the [developers
guide](https://github.com/cozystack/website/pull/413), this is
implemented as an extra package (like `ingress` and `seaweedfs`) using
the HelmRelease-based pattern, rather than embedding it in the tenant
chart.

This enables multi-tenant scenarios where:
- Tenant A uses Cloudflare for `domain-a.com`
- Tenant B uses AWS Route53 for `domain-b.com`
- Each tenant deploys and manages external-dns independently from the
dashboard

## Changes

- **New package**: `packages/extra/external-dns/` — standalone
HelmRelease-based application
- **New PackageSource**:
`packages/core/platform/sources/external-dns-application.yaml` —
references `system/external-dns` and `extra/external-dns` components
- **Cleaned tenant chart**: removed the previously embedded
`externalDns` block from `packages/apps/tenant/`

## Features

- Support for 9 DNS providers: cloudflare, aws, azure, google,
digitalocean, linode, ovh, exoscale, godaddy
- Per-provider credential configuration with full JSON schema validation
- Domain filtering via `domainFilters`
- Configurable sync policy (`sync` or `upsert-only`)
- Namespaced operation (`namespaced: true`) for tenant isolation
- Unique `txtOwnerId` per namespace to prevent DNS record conflicts
- Resource sizing via presets or explicit CPU/memory

## Usage Example

Deploy from the dashboard, or via values:

```yaml
# Cloudflare
provider: cloudflare
domainFilters:
  - example.com
cloudflare:
  apiToken: "your-cloudflare-api-token"
```

```yaml
# AWS Route53
provider: aws
domainFilters:
  - example.org
aws:
  accessKeyId: "AKIAXXXXXXXX"
  secretAccessKey: "your-secret-key"
  region: "us-east-1"
```

## Test plan

- [ ] `helm template external-dns packages/extra/external-dns/ --set
provider=cloudflare --set cloudflare.apiToken=test` renders correctly
- [ ] `helm template external-dns packages/extra/external-dns/` fails
(provider required)
- [ ] `helm template wrong-name packages/extra/external-dns/ --set
provider=cloudflare` fails (release name check)
- [ ] Deploy external-dns from tenant dashboard
- [ ] Verify HelmRelease is created in tenant namespace with namespaced
RBAC
- [ ] Create an Ingress and verify DNS record is created
- [ ] Verify no conflict with global external-dns instance

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
  * Added an External DNS package for automatic DNS record management.
* Support for 9 DNS providers: Cloudflare, AWS, Azure, Google,
DigitalOcean, Linode, OVH, Exoscale, GoDaddy.
* Helm-based deployment with namespaced/system variants and release
configuration options.
* Configurable synchronization policies, domain filtering, provider
credentials, extra args, and resource presets.

* **Documentation**
* New README and schema-driven values documentation for installation and
configuration.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-11 21:58:55 +05:00
Timofei Larkin
cfd57f8c1e [keycloak-operator] Update to v1.32.0
## What this PR does

Updates the Keycloak Operator Helm chart to v1.32.0 and builds a custom
operator image from upstream master (epam/edp-keycloak-operator@facbc36)
with the group rename detection patch from PR
epam/edp-keycloak-operator#309 applied on top.

Bumps Keycloak server from 26.0.4 to 26.5.2, which is required by the
new operator client (sends `description` field rejected by older versions).

Adds SSO session settings (idleTimeout: 86400, maxLifespan: 604800) to
the ClusterKeycloakRealm to match the dashboard client's session attributes,
as Keycloak 26 enforces realm-level session limits strictly.

Removes `authorizationServicesEnabled` from the dashboard KeycloakClient,
which is incompatible with Keycloak 26's stricter validation.

### Release note

```release-note
[keycloak-operator] Update the operator to v1.32.0 with group rename fix
(epam/edp-keycloak-operator#309). Bump Keycloak to 26.5.2.
```

Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
2026-03-11 15:15:09 +03:00
Andrei Kvapil
7e2c035179 feat(monitoring): migrate VictoriaLogs from VLogs to VLCluster (#2153)
## What this PR does

Migrates VictoriaLogs from the deprecated single-node `VLogs` CR to
`VLCluster` (cluster mode) with vlinsert/vlselect/vlstorage components
for reliability and horizontal scalability.

**Operator upgrade:**
- Upgrades victoria-metrics-operator from v0.55.0 to v0.68.1 to add
VLCluster CRD support

**VLCluster deployment:**
- Replaces `VLogs` (v1beta1) with `VLCluster` (v1) — 2 replicas per
component, consistent with VMCluster
- Adds VPA for all VLCluster components (vlinsert, vlselect, vlstorage)
- Updates WorkloadMonitors for the three-component architecture

**Endpoint updates:**
- Fluent-bit outputs: `vlogs-generic:9428` → `vlinsert-generic:9481`
- Grafana datasource: `vlogs-{name}:9428` → `vlselect-{name}:9471`
- ExternalName service: `vlogs-generic` → `vlinsert-generic`

**Migration (35 → 36):**
- Adds `helm.sh/resource-policy: keep` annotation to existing VLogs
resources so they are preserved during upgrade
- Users need to verify the new VLCluster is working, then optionally
migrate historical data and manually delete old VLogs resources

### Release note

```release-note
[monitoring] Migrate VictoriaLogs from single-node VLogs to VLCluster (cluster mode). Old VLogs resources are preserved with `helm.sh/resource-policy: keep` annotation. After upgrade, verify the new cluster is working, then optionally migrate historical data and delete old VLogs resources manually.
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* CRD upgrade workflow with configurable hooks, Job, and ServiceAccount
support
* Monitoring storage split into vlinsert / vlselect / vlstorage with
corresponding VPAs
* Service traffic distribution option and optional shareProcessNamespace
toggle

* **Updates**
  * VictoriaMetrics Operator bumped to v0.68.1
* Fluent Bit and Grafana endpoints/ports updated to new monitoring
targets
  * Global extra-labels support for resources
  * Migration target advanced to version 36
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-11 08:58:19 +01:00
Kirill Ilin
9e166300a7 fix(e2e): update VMCluster status field after operator upgrade
The victoria-metrics-operator v0.68.1 renamed VMCluster status field
from .status.clusterStatus to .status.updateStatus.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-11 09:30:41 +05:00
Andrei Kvapil
bf31b7c408 docs: add changelog for v1.1.1 (#2187)
This PR adds the changelog for release `v1.1.1`.

 Changelog has been automatically generated in
`docs/changelogs/v1.1.1.md`.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Fixed MarketplacePanel visibility and disabled state management in
dashboard sidebar
  * Fixed External IP address display in dashboard resource tables
  * Fixed MAC address preservation during virtual machine migrations
  * Resolved deprecated component image issue
  * Improved migration handling for missing component dependencies
  * Fixed Keycloak health monitoring and application stability

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-11 00:13:09 +01:00
Andrei Kvapil
fb5820e858 docs: add changelog for v1.0.4 (#2189)
This PR adds the changelog for release `v1.0.4`.

 Changelog has been automatically generated in
`docs/changelogs/v1.0.4.md`.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Updated v1.0.4 changelog with system, platform, and dashboard
improvements
  * Added OIDC self-signed certificates configuration guide
* Documented fixes for health probes, virtual machine migration, and
dashboard features

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-10 22:59:20 +01:00
cozystack-bot
7b0a5d216f docs: add changelog for v1.0.4
Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com>
2026-03-10 20:44:49 +00:00
cozystack-bot
12b34c737a docs: add changelog for v1.1.1
Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com>
2026-03-10 20:39:12 +00:00
Andrei Kvapil
a240ff4b27 [monitoring] Scope infrastructure dashboards to tenant-root only (#2197)
## Summary

- Splits `dashboards.list` into tenant-facing dashboards and
infrastructure dashboards (`dashboards-infra.list`)
- Infrastructure dashboards (VictoriaMetrics, Flux, Hubble, LINSTOR,
control-plane, etc.) are only rendered for `tenant-root`
- Tenant-facing dashboards (ingress, db, kafka, nats, clickhouse, vm)
remain available to all tenants

## Problem

All tenants currently receive infrastructure dashboards
(VictoriaMetrics, Hubble, LINSTOR, Flux, control-plane, etc.) that are
only relevant to platform operators.

Relates to #2194

## Test plan

- [ ] `helm template` monitoring in `tenant-root` namespace — both lists
rendered
- [ ] `helm template` monitoring in a child tenant namespace — only
`dashboards.list` rendered
- [ ] Verify no dashboard names collide between the two lists

```release-note
Scope infrastructure dashboards to tenant-root only
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Infrastructure dashboards exposed via the monitoring system for
tenant-root deployments.
* Added new ingress dashboards including vhosts and vhost-detail views.

* **Chores**
* Removed a large set of legacy dashboards to streamline the monitoring
surface.
* Reorganized dashboard generation to separate infra-specific dashboards
from standard sets.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-10 18:19:28 +01:00
Andrei Kvapil
539b5c3d44 [tenant] Allow egress to virt-handler for VM metrics scraping (#2199)
## Summary

- Adds a `CiliumClusterwideNetworkPolicy` allowing egress from tenant
pods to `virt-handler` in `cozy-kubevirt` namespace on port 8443/TCP
- Conditional on `.Values.monitoring` being enabled

## Problem

Tenant vmagent cannot scrape KubeVirt VM metrics from `virt-handler`
because no network policy allows the traffic.

Relates to #2194

## Test plan

- [ ] `helm template` tenant with `monitoring: true` — virt-handler
policy present
- [ ] `helm template` tenant with `monitoring: false` — virt-handler
policy absent
- [ ] Deploy and verify vmagent can scrape kubevirt_vmi_* metrics

```release-note
Allow tenant egress to virt-handler for VM metrics scraping
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Added a network egress policy that, when monitoring is enabled, allows
tenant namespaces to reach the virt-handler service on TCP port 8443,
improving connectivity for monitoring-related traffic.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-10 18:16:01 +01:00
Kirill Ilin
b772475ad5 fix(e2e): update VLogs to VLCluster resource in tenant monitoring test
After migrating VictoriaLogs from VLogs to VLCluster, the e2e test
still waited for the old vlogs/generic resource which no longer exists.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-10 22:06:50 +05:00
Andrei Kvapil
27c5b0b1e2 fix(dashboard): exclude hidden MarketplacePanel resources from sidebar menu (#2177)
## Summary

- Sidebar menu was showing all resources regardless of their
MarketplacePanel `hidden` state
- Fetch MarketplacePanels during sidebar reconciliation and skip
resources where `hidden=true`
- Hiding a resource from the marketplace now also removes it from the
sidebar navigation

## Test plan

- [ ] Set `hidden: true` on a MarketplacePanel (e.g. qdrant)
- [ ] Trigger controller reconciliation
- [ ] Verify the resource is removed from the sidebar menu
- [ ] Set `hidden: false` and verify the resource reappears in the
sidebar

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Sidebar can now hide resources based on MarketplacePanel configuration
parsed from panel definitions.
* Hidden resources are filtered early when assembling sidebar
categories, preventing them from contributing to menu items.
* Listing failures are non-fatal: if configuration fetch fails, no
hiding is applied and the dashboard remains functional.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-10 17:49:21 +01:00
Andrei Kvapil
6535ec9f38 [ci] Fix E2E check blocking docs-only PRs (#2170)
## What this PR does

The `pull-requests.yaml` workflow used `paths-ignore` at the trigger
level to skip runs for docs-only changes. This prevented the entire
workflow from triggering, so the required "E2E Tests" check was never
created — blocking merge for non-admin users.

This PR replaces trigger-level `paths-ignore` with a `detect-changes`
job using `dorny/paths-filter@v3`. The workflow now always triggers (so
all checks are reported to GitHub), but `build` and downstream jobs are
skipped when only `docs/` files change.

| PR type | build | resolve_assets | e2e |
| --- | --- | --- | --- |
| Code PR | runs | skipped | runs |
| Release PR | skipped (label) | runs | runs |
| Docs-only PR | skipped | skipped | skipped |

### Release note

```release-note
[ci] Fix required E2E check blocking merge of docs-only pull requests
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* CI pipeline optimized to skip builds when only documentation changes
occur.
* Added a checks step that detects whether code changed and gates the
build accordingly.
* Build now runs only if code changes are present and the PR is not
marked as a release, reducing unnecessary build runs.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-10 17:48:47 +01:00
Andrei Kvapil
8ac57811eb [cilium] Update cilium to 1.19.1 (#2173)
## What this PR does
This PR updates the cilium system package to the version 1.19.1

### Release note

```release-note
[cilium] Update cilium system package to the version 1.19.1
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
* Upgraded to version 1.19.1 with enhanced security and observability
capabilities
  * Added standalone DNS proxy support for improved DNS handling
* Enhanced multi-cluster service mesh support with automatic CoreDNS
configuration
* Expanded cloud provider integrations with improved node resource
management
  * Added ztunnel encryption support

* **Improvements**
  * Enhanced TLS certificate management and auto-generation
  * Extended observability and profiling options
* Improved endpoint and service handling with updated resource
management

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-10 17:48:36 +01:00
Andrei Kvapil
4b9c64c459 fix(dashboard): preserve disabled/hidden state on MarketplacePanel reconciliation (#2176)
## Summary

- Fix "Disabling features from menu and marketplace is not working" by
preserving user-set `disabled` and `hidden` values during controller
reconciliation
- The controller was hardcoding `disabled=false` and `hidden=false` on
every reconcile loop, overwriting any changes made through the dashboard
UI

## Test plan

- [ ] Disable a service from the dashboard marketplace panel
- [ ] Verify the service stays disabled after controller reconciliation
- [ ] Hide a service from the dashboard menu
- [ ] Verify the service stays hidden after controller reconciliation
- [ ] Create a new ApplicationDefinition and verify its MarketplacePanel
defaults to disabled=false, hidden=false

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Fixed an issue where user-configured "disabled" and "hidden" settings
in the marketplace panel could be reset during updates. These
preferences are now preserved when the panel is created or updated, and
the system avoids applying unnecessary configuration changes when values
haven't actually changed.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-10 17:48:17 +01:00
Mattia Eleuteri
e08c895a09 [monitoring] Scope infrastructure dashboards to tenant-root only
Signed-off-by: Mattia Eleuteri <mattia@hidora.io>
Signed-off-by: mattia-eleuteri <mattia@hidora.io>
2026-03-10 16:57:24 +01:00
Mattia Eleuteri
630dfc767a [tenant] Allow egress to virt-handler for VM metrics scraping
- Add CiliumClusterwideNetworkPolicy for vmagent egress to virt-handler
- Restrict endpointSelector to vmagent pods only via app.kubernetes.io/name label

Signed-off-by: Mattia Eleuteri <mattia.eleuteri@hidora.io>
Signed-off-by: mattia-eleuteri <mattia@hidora.io>
2026-03-10 16:56:50 +01:00
Andrei Kvapil
a13481bfea fix(dashboard): fix External IPs factory EnrichedTable rendering (#2175)
## Summary

- Fix External IPs page showing empty rows in the dashboard by
correcting EnrichedTable properties in the `external-ips` factory
- Replace `clusterNamePartOfUrl` with `cluster` and change `pathToItems`
from array format to dot-path string to match convention used by all
other EnrichedTable instances

## Test plan

- [ ] Open Administration → External IPs in dashboard for a tenant with
LoadBalancer services
- [ ] Verify table columns (Name, ClusterIP, LoadbalancerIP, Created)
are rendered
- [ ] Verify service data is displayed correctly in the rows

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Fixed configuration handling for the external-ips dashboard tab to
ensure cluster names display correctly and service items are
consistently listed, improving stability and data presentation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-10 15:18:56 +01:00
Andrei Kvapil
3606b51a3f [platform] Fix VM MAC address not preserved during migration (#2169)
## What this PR does

During the virtual-machine → vm-instance migration (script 29), VM MAC
addresses
are not preserved. Kube-OVN reads MAC exclusively from the pod
annotation
`ovn.kubernetes.io/mac_address`, not from the IP resource
`spec.macAddress`.
Without the annotation, migrated VMs get a new random MAC, breaking
OS-level
network config that matches by MAC (e.g. netplan).

This adds a Helm `lookup` for the Kube-OVN IP resource in the
vm-instance chart
template. When the resource exists, its `macAddress` and `ipAddress` are
automatically injected as pod annotations. This approach is reliable
across
HelmRelease reconciliations — unlike postRenderers, the annotations
cannot be
accidentally lost.

Fixes #2166

### Release note

```release-note
[platform] Fix VM MAC address not preserved during virtual-machine → vm-instance migration, causing network loss on VMs with MAC-based netplan config
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* VM templates now automatically populate network annotations (MAC and
IP) from kubeovn IP records when available. This streamlines VM network
setup on deployment, reduces manual annotation steps, and lowers risk of
misconfiguration by ensuring VMs receive the correct address and MAC
information from associated network records.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-10 15:18:17 +01:00
mattia-eleuteri
f201fe4dac feat(extra): add external-dns as standalone extra package
Signed-off-by: mattia-eleuteri <mattia@hidora.io>
2026-03-10 12:48:01 +01:00
Artem Bortnikov
748f814523 chore: update cilium to 1.19.1
Signed-off-by: Artem Bortnikov <brongineer747@gmail.com>
2026-03-10 12:41:51 +01:00
Kirill Ilin
9a4f49238c fix(migration): preserve VM MAC address during virtual-machine to vm-instance migration
Kube-OVN reads MAC address exclusively from the pod annotation
ovn.kubernetes.io/mac_address, not from the IP resource spec.macAddress.
Without pod-level annotations, migrated VMs receive a new random MAC,
breaking OS-level network config that matches by MAC (e.g. netplan).

Add a Helm lookup for the Kube-OVN IP resource in the vm-instance chart
template. When the IP resource exists, its macAddress and ipAddress are
automatically injected as pod annotations. This removes the need for
fragile Flux postRenderers on the HelmRelease — the chart itself handles
MAC/IP preservation based on actual cluster state.

Remove the postRenderers approach from migration 29 since the chart now
handles this natively.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-10 12:41:50 +01:00
IvanHunters
4b166e788a fix(ci): unblock docs-only PRs by moving path filtering to job level
The pull-requests workflow used paths-ignore at the trigger level, which
prevented the entire workflow from running on docs-only PRs. This meant
the required "E2E Tests" check was never created, blocking merge for
non-admin users.

Replace trigger-level paths-ignore with a detect-changes job using
dorny/paths-filter. The workflow now always triggers (so checks are
always reported), but build and downstream jobs are skipped when only
docs files change.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-10 12:41:48 +01:00
IvanHunters
49601b166d fix(dashboard): fix External IPs factory EnrichedTable rendering
The external-ips factory used incorrect EnrichedTable properties causing
empty rows in the dashboard. Replace `clusterNamePartOfUrl` with
`cluster` and change `pathToItems` from array to dot-path string format
to match the convention used by all other working EnrichedTable instances.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-10 12:41:45 +01:00
IvanHunters
e69efd80c4 fix(dashboard): preserve disabled/hidden state on MarketplacePanel reconciliation
The controller was hardcoding disabled=false and hidden=false on every
reconciliation, overwriting any user changes made through the dashboard
UI. Move spec building inside the CreateOrUpdate mutate function to read
and preserve current disabled/hidden values from the existing resource.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-10 12:41:43 +01:00
IvanHunters
318079bf66 fix(dashboard): exclude hidden MarketplacePanel resources from sidebar menu
The sidebar was generated independently from MarketplacePanels, always
showing all resources regardless of their hidden state. Fetch
MarketplacePanels during sidebar reconciliation and skip resources
where hidden=true, so hiding a resource from the marketplace also
removes it from the sidebar navigation.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-10 12:41:42 +01:00
Andrei Kvapil
9bb6625c28 fix(etcd-operator): replace deprecated kube-rbac-proxy image (#2181)
## Summary
- Replace deprecated `gcr.io/kubebuilder/kube-rbac-proxy:v0.16.0` with
`quay.io/brancz/kube-rbac-proxy:v0.18.1` in the vendored etcd-operator
chart
- The GCR-hosted image became unavailable after March 18, 2025

Fixes #2172 #488

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated proxy component to v0.18.1 with configuration changes for
improved stability and compatibility.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-10 12:36:51 +01:00
Andrei Kvapil
4946383cf1 fix(etcd-operator): replace deprecated kube-rbac-proxy image
The gcr.io/kubebuilder/kube-rbac-proxy image is no longer available
since GCR was deprecated. Replace it with quay.io/brancz/kube-rbac-proxy
from the original upstream author.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2026-03-10 08:30:43 +01:00
Andrei Kvapil
25f0b91e6f fix(migrations): handle missing rabbitmq CRD in migration 34 (#2168)
## Summary

- Migration 34 fails with `error: the server doesn't have a resource
type "rabbitmqs"` when `rabbitmqs.apps.cozystack.io` CRD does not exist
on the cluster
- This happens when RabbitMQ was never installed — the CRD is not
present, `kubectl get` fails, and `set -euo pipefail` terminates the
migration job
- Added a CRD existence check before listing resources; if CRD is
absent, the migration stamps the version and exits cleanly

## Test plan

- [ ] Deploy a cluster without RabbitMQ installed and run migration 34 —
should skip gracefully
- [ ] Deploy a cluster with RabbitMQ instances without `spec.version`
set — should patch them to `v3.13`
- [ ] Deploy a cluster with RabbitMQ instances already having
`spec.version` — should skip patching
2026-03-10 08:18:47 +01:00
Andrei Kvapil
5c7311dc7a fix(keycloak): use management port health endpoints for probes (#2162)
## Summary

- Fix Keycloak crashloop caused by misconfigured liveness/readiness
probes
- Add `KC_HEALTH_ENABLED=true` to activate health endpoints on
management port
- Switch probes from application port 8080 (`/`, `/realms/master`) to
management port 9000 (`/health/live`, `/health/ready`)

## Problem

Keycloak 26.x redirects all HTTP requests on port 8080 to the configured
`KC_HOSTNAME` (HTTPS). Since kubelet does not follow redirects, probes
fail with:

```
Probe terminated redirects, Response body:
```

After consecutive failures, kubelet kills the container → restart →
crashloop.

Additionally, `KC_HEALTH_ENABLED` was not set, so the dedicated health
endpoints on the management port (9000) returned 404 even though the
management interface was active (via `KC_METRICS_ENABLED=true`).

## Changes

- `packages/system/keycloak/templates/sts.yaml`:
- Add `KC_HEALTH_ENABLED=true` env var to activate `/health/live` and
`/health/ready`
  - Expose management port 9000 in container ports
- Liveness probe: `GET /health/live` on port 9000 (was `GET /` on 8080)
- Readiness probe: `GET /health/ready` on port 9000 (was `GET
/realms/master` on 8080)
  - Increase failure thresholds for better startup tolerance

## Test plan

- [x] Verified `/health/live` returns `{"status":"UP"}` (HTTP 200) on
port 9000
- [x] Verified `/health/ready` returns
`{"status":"UP","checks":[{"name":"Keycloak database connections async
health check","status":"UP"}]}` (HTTP 200)
- [x] Confirmed 0 restarts after 10+ minutes
- [x] Confirmed no more `ProbeWarning` or `Killing` events

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-10 08:15:18 +01:00
Andrei Kvapil
d619d96531 [docs] Fixed docs for managed apps (#2161)
<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- If it's a work in progress, consider creating this PR as a draft.
- Don't hesistate to ask for opinion and review in the community chats,
even if it's still a draft.
- Add the label `backport` if it's a bugfix that needs to be backported
to a previous version.
-->

## What this PR does


### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
[docs] Fixed docs for managed apps
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Documentation

* Updated FoundationDB README title to "Managed FoundationDB Service"
* Improved Harbor README text formatting for consistency
* Corrected spelling and terminology errors in MariaDB README
* Enhanced MariaDB recovery documentation with additional command
example

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-10 08:14:36 +01:00
Kirill Ilin
62d36ec4ee feat(monitoring): migrate VictoriaLogs from VLogs to VLCluster
Replace deprecated single-node VLogs CR with VLCluster (cluster mode)
for reliability and horizontal scalability.

Changes:
- Replace VLogs (v1beta1) with VLCluster (v1) using vlinsert/vlselect/vlstorage
- Update fluent-bit outputs to vlinsert-generic:9481
- Update Grafana datasource to vlselect:9471
- Update ExternalName service from vlogs-generic to vlinsert-generic
- Add VPA for all VLCluster components
- Update WorkloadMonitors for three-component architecture
- Add migration 35 to preserve old VLogs resources with keep annotation

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-10 12:04:12 +05:00
Kirill Ilin
a3825314e6 feat(monitoring): upgrade victoria-metrics-operator to v0.68.1
Upgrade from v0.55.0 to v0.68.1 to add VLCluster CRD support,
which is required for migrating VictoriaLogs from single-node
to cluster mode.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-10 12:03:51 +05:00
IvanHunters
21f293ace5 fix(migrations): handle missing rabbitmq CRD in migration 34
Migration 34 fails when rabbitmqs.apps.cozystack.io CRD does not exist,
which happens when RabbitMQ was never installed on the cluster. Add a
check for CRD presence before attempting to list resources.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-06 19:22:21 +03:00
Timofei Larkin
adacd44a29 docs: add changelog for v1.1.0 (#2164)
This PR adds the changelog for release `v1.1.0`.

 Changelog has been automatically generated in
`docs/changelogs/v1.1.0.md`.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Published v1.1.0 changelog documenting major features: managed secrets
service, tiered storage pools, per-user bucket credentials with S3 UI
updates, RabbitMQ version selection, and monitoring dashboards
  * Included breaking changes and upgrade notes for v1.1.0

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-06 17:27:30 +04:00
IvanHunters
3736dd4285 Release v1.1.0 (#2163)
This PR prepares the release `v1.1.0`.
2026-03-06 16:21:32 +03:00
cozystack-bot
20d1343bd6 docs: add changelog for v1.1.0
Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com>
2026-03-06 12:13:09 +00:00
cozystack-bot
3c971d0e1b Prepare release v1.1.0
Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com>
2026-03-06 12:03:56 +00:00
IvanHunters
8166df23de [system] Add MongoDB Grafana dashboards (#2158)
## What this PR does

Adds two Grafana dashboards for MongoDB monitoring, adapted to cozystack
conventions:

- **MongoDB Overview** — command operations, connections, cursors,
document operations, queued operations, query efficiency, scanned
objects, write time/operations, asserts, page faults
- **MongoDB InMemory Details** — WiredTiger cache size/capacity, dirty
pages, transactions, sessions, pages, concurrency tickets, cache
eviction, document changes, scanned objects, page faults

Key adaptations from the original PMM dashboards:
- Replaced hardcoded datasource UIDs with `${ds_prometheus}` variable
- Replaced PMM-specific variables with standard `job`-based service
filtering
- Removed Node Summary section (covered by existing node dashboards)
- Registered both dashboards in `dashboards.list` for automatic
GrafanaDashboard CRD generation

### Release note

```release-note
[system] Add MongoDB Overview and MongoDB InMemory Details Grafana dashboards to the monitoring stack
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added MongoDB InMemory dashboard providing detailed visibility into
in-memory metrics, cache performance, and data management.
* Added MongoDB Overview dashboard for monitoring operations,
connections, cursors, document activity, and query efficiency.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-06 14:53:40 +03:00
Timofei Larkin
c30a3cff13 docs: add changelog for v1.0.3 (#2160)
This PR adds the changelog for release `v1.0.3`.

 Changelog has been automatically generated in
`docs/changelogs/v1.0.3.md`.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Fixed migration script to correctly apply configuration prefixes
during v0.41 to v1.0 upgrade.

* **Documentation**
* Added white labeling guide covering branding customization and SVG
handling.
* Updated backup and recovery documentation with improved operator and
tenant workflow guidance and administration resources.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-06 15:45:12 +04:00
mattia-eleuteri
d18ed79382 fix(keycloak): add startupProbe, remove initialDelaySeconds
Use a startupProbe to defer liveness/readiness checks until Keycloak
has fully started, instead of relying on initialDelaySeconds. This is
more robust for applications with variable startup times.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: mattia-eleuteri <mattia@hidora.io>
2026-03-06 11:26:52 +01:00
mattia-eleuteri
0873691913 fix(keycloak): use management port health endpoints for probes
Keycloak 26.x exposes dedicated health endpoints on the management
port (9000) via /health/live and /health/ready. The previous probes
used GET / on port 8080 which redirects to the configured KC_HOSTNAME
(HTTPS), causing kubelet to fail the probe with "Probe terminated
redirects" and eventually kill the pod in a crashloop.

Changes:
- Add KC_HEALTH_ENABLED=true to activate health endpoints
- Expose management port 9000 in container ports
- Switch liveness probe to /health/live on port 9000
- Switch readiness probe to /health/ready on port 9000
- Increase failure thresholds for more tolerance during startup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: mattia-eleuteri <mattia@hidora.io>
2026-03-06 10:30:38 +01:00
Andrei Kvapil
d8c96ecf50 [apps][system] Add -lock BucketClass, -readonly BucketAccessClass, and bucket user model (#2119)
## What this PR does

Combines and unifies COSI enhancements across seaweedfs and bucket
charts:

**SeaweedFS (extra + system charts):**
- Rename storage pool BucketClass suffix from `-worm` to `-lock`
- Rename parameter `disk` to `diskType` for consistency with COSI driver
- Reduce default object lock retention from 36500 to 365 days
- Add `-lock` BucketClass (COMPLIANCE mode, 365 days) for client and
system topologies
- Add `-readonly` BucketAccessClass with explicit `accessPolicy` for all
topologies
- Add explicit `accessPolicy: readwrite` on default BucketAccessClass
- Update pool name validation to reject `-lock` suffix (was `-worm`)

**Bucket app:**
- Add `locking` parameter: provisions from `-lock` BucketClass
- Add `storagePool` parameter: selects pool-specific BucketClass
- Replace hardcoded BucketAccess with `users` map — each entry creates a
BucketAccess with optional `readonly` flag
- Update dashboard RBAC to dynamically list user credential secrets
- Update ApplicationDefinition schema with new properties

**Breaking change:** empty `users: {}` (default) produces zero
BucketAccess resources. Existing buckets that relied on the implicit
default BucketAccess will need to define users explicitly.

### Release note

```release-note
[apps] Add locking, storagePool, and users configuration to bucket app; rename COSI BucketClass suffix from -worm to -lock
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Bucket locking with a shorter retention option, storage-pool
selectable bucket classes, and per-user access (per-user BucketAccess
and readonly controls)
* S3 Manager login mode: user login/logout, per-session credentials, and
new login UI

* **Behavior Changes**
* Credential handling changed to per-user secrets/label selection;
previously generated secrets removed; Ingress basic auth annotations
removed

* **Documentation**
* Added parameters: locking, storagePool, users (including per-user
readonly)

* **Updates**
  * Updated COSI driver and S3 manager images
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-06 09:17:53 +01:00
Andrei Kvapil
2731972129 fix(kubernetes): set explicit MTU for Cilium in tenant clusters (#2147)
## Summary

- Set explicit MTU 1350 for Cilium in KubeVirt-based tenant Kubernetes
clusters to prevent packet drops caused by VXLAN encapsulation overhead

## Problem

Cilium's MTU auto-detection does not account for VXLAN overhead when
running inside KubeVirt VMs. The VM network interface inherits MTU 1400
from the parent cluster's OVN/Geneve overlay (1500 - 100 Geneve
overhead). Cilium detects this MTU and applies it to all tunnel
interfaces without subtracting the 50-byte VXLAN encapsulation overhead.

This results in:
- Large packets (> 1350 bytes) being silently dropped when crossing
VXLAN tunnels between nodes
- Intermittent connectivity issues for services in tenant clusters (TLS
handshakes, HTTP responses with data)
- HTTP 499 errors and timeouts observed under load

## Fix

Explicitly set `MTU: 1350` (1400 - 50 VXLAN overhead) in the default
Cilium values for tenant clusters. This value can still be overridden
via `addons.cilium.valuesOverride` if needed.

## Test plan

- [ ] Deploy a tenant Kubernetes cluster and verify Cilium interfaces
use MTU 1350
- [ ] Verify large packet connectivity from pods inside the tenant
cluster
2026-03-06 09:10:37 +01:00
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
cozystack-bot
133a071d6b docs: add changelog for v1.0.3
Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com>
2026-03-06 01:42:51 +00:00
IvanHunters
c838358c26 feat(monitoring): register MongoDB dashboards in dashboards.list
Add mongodb/mongodb-overview and mongodb/mongodb-inmemory entries
to the monitoring dashboards list so GrafanaDashboard CRDs are
generated and dashboards are served by the grafana-dashboards
HTTP service.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-05 22:48:05 +03:00
IvanHunters
6408988115 feat(monitoring): add MongoDB Grafana dashboards
Add two MongoDB dashboards adapted for cozystack monitoring:
- mongodb-overview: command operations, connections, cursors,
  document operations, queued operations, query efficiency,
  scanned objects, write time, asserts, page faults
- mongodb-inmemory: WiredTiger InMemory cache details including
  data size, capacity, transactions, sessions, pages, concurrency
  tickets, cache eviction, document changes

Dashboards use ds_prometheus variable for datasource selection and
job-based service filtering compatible with Percona MongoDB exporter
metrics.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-05 22:47:53 +03:00
IvanHunters
e1b169d6a7 fix(test): replace bats-specific run command with shell negation
cozytest.sh executes .bats files as plain shell functions where bats
builtins like `run` are not available. Use `!` negation to assert that
readonly user upload fails.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-05 08:45:57 +03:00
IvanHunters
4e8733091d fix(test): add --insecure flag to all mc commands in bucket E2E test
The mc client requires --insecure on each command when connecting to
SeaweedFS S3 with self-signed certificates via port-forward.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-04 22:37:37 +03:00
IvanHunters
15ed534c25 test(bucket): update E2E test for user model and readonly access
Update bucket E2E test to match the new per-user access model:
- Create bucket with admin (readwrite) and viewer (readonly) users
- Test that readwrite user can upload, list, and download objects
- Test that readonly user can list and download but cannot upload
- Use per-user BucketAccess and credential secret names

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-04 21:13:46 +03:00
IvanHunters
72a91c7780 fix(seaweedfs): update COSI driver to v0.3.0
v0.1.2 ignores accessPolicy parameter from BucketAccessClass,
granting readwrite access to all users regardless of the
readonly flag. v0.3.0 includes support for readonly bucket
access, Object Lock, and improved error handling.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-04 20:15:03 +03:00
IvanHunters
fdb015458c build(bucket): rebuild s3manager image with login mode
Rebuild s3manager with auth.go login page support and push
to 999669/s3manager registry for testing.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-04 19:01:27 +03:00
IvanHunters
84da47a2ce refactor(bucket): replace basic auth with s3manager login page
Remove nginx basic auth and credential secret injection from the
bucket Helm chart. s3manager now always starts in login mode and
handles authentication via its own login page with encrypted
session cookies. This eliminates the dependency on the -credentials
and -ui-auth secrets for the UI layer.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-04 18:47:51 +03:00
IvanHunters
175b3badd2 feat(bucket): make credentials and basic auth conditional on users
deployment.yaml: use s3._namespace.host for ENDPOINT instead of
secret ref, inject ACCESS_KEY_ID/SECRET_ACCESS_KEY only when users
exist. Without users, s3manager starts in login mode.

ingress.yaml: nginx basic auth annotations only when users exist.
Without users, s3manager handles authentication via its login form.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-04 18:30:49 +03:00
IvanHunters
f777f659d5 feat(bucket): add login screen to s3manager for credentialless mode
When a bucket has no users configured, s3manager previously crashed
due to missing ACCESS_KEY_ID/SECRET_ACCESS_KEY env vars. This adds
a login mode where users enter their S3 credentials via a web form.

New Go code (via cozystack.patch):
- auth.go: session-based auth middleware, login/logout handlers,
  per-request S3 client from encrypted cookie session
- login.html.tmpl: Materialize CSS login form
- main.go: LoginMode toggle, conditional route setup
- Dependency: gorilla/sessions for AES-256 encrypted cookies

Dockerfile: add go mod tidy step for new dependency resolution.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-04 18:30:40 +03:00
IvanHunters
69e0320e3a fix(bucket): remove duplicate credentials from dashboard
Show only per-user credential secrets in the dashboard instead of
both the internal UI secret and per-user secrets.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-04 17:02:36 +03:00
Andrei Kvapil
f5b29e1182 Fixed packages name conversion in migration script (#2144)
<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- If it's a work in progress, consider creating this PR as a draft.
- Don't hesistate to ask for opinion and review in the community chats,
even if it's still a draft.
- Add the label `backport` if it's a bugfix that needs to be backported
to a previous version.
-->

## What this PR does


### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
Fixed migrate-to-version-1.0.sh script to properly convert packages names.
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated migration tooling to improve package configuration handling
during version upgrades.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-04 00:22:42 +01:00
IvanHunters
9e6c240d6e fix(bucket): use per-user COSI secret for UI credentials
The default BucketAccess was removed in favor of per-user access.
Update secret.yaml to look up the first user's COSI secret instead
of the non-existent default one, with nil-check for race conditions.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-04 00:34:33 +03:00
IvanHunters
79b2546e67 fix(kubernetes): set explicit MTU for Cilium in tenant clusters
Cilium's MTU auto-detection does not account for VXLAN overhead when
running inside KubeVirt VMs. The VM interface inherits MTU 1400 from
the parent OVN/Geneve overlay, and Cilium sets all interfaces
(cilium_vxlan, lxc*, cilium_host/net) to 1400 without subtracting
the 50-byte VXLAN encapsulation overhead.

This causes intermittent packet drops for large packets (TLS
handshakes, HTTP responses with data), resulting in timeouts and
499 errors for services running in tenant clusters.

Set MTU to 1350 (1400 - 50 VXLAN overhead) explicitly in the default
Cilium values for tenant Kubernetes clusters.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-03 21:35:39 +03:00
IvanHunters
1d41e270b9 fix(bucket): regenerate schema and docs from values.yaml annotations
Remove the yq strip of properties from Makefile that was clearing
the schema, and run make generate to sync all generated files.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-03 19:32:32 +03:00
IvanHunters
b4f1e96b98 feat(bucket): include COSI user credential secrets in dashboard
Create labeled secrets in the -system chart using lookup to copy
credentials from COSI-created secrets. The ApplicationDefinition
matchLabels selector exposes them in the dashboard.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-03 19:32:32 +03:00
IvanHunters
757f8b5699 Revert "fix(bucket): include COSI user credential secrets in dashboard"
This reverts commit 87b89d90e6.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-03 19:32:32 +03:00
IvanHunters
70c6dfd704 fix(bucket): include COSI user credential secrets in dashboard
Add a catch-all include selector so that COSI-created user credential
secrets (dynamically named per user) are visible in the dashboard.

The lineage webhook already verifies ownership via the graph walk
(Secret -> BucketAccess -> HelmRelease -> Bucket), so an empty selector
safely matches only secrets belonging to this application.

This is needed because COSI sidecar creates secrets without custom
labels, making the matchLabels pattern (used by rabbitmq) inapplicable.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-03 19:32:32 +03:00
IvanHunters
d4043bd71c fix(seaweedfs): use correct COSI driver parameter name 'disk'
The seaweedfs-cosi-driver v0.3.0 expects the parameter key 'disk',
not 'diskType'. Restore the correct key to match the driver's
paramDisk constant.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-03 19:32:32 +03:00
IvanHunters
2dbc27075a feat(bucket): add locking, storagePool, and users configuration
Replace hardcoded BucketAccess with user-driven model:
- locking: provisions from -lock BucketClass (object lock enabled)
- storagePool: selects pool-specific BucketClass
- users: map of named users, each creating a BucketAccess with
  optional readonly flag

Empty users map produces zero BucketAccess resources (breaking change).
Update ApplicationDefinition schema and dashboard RBAC accordingly.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-03 19:32:32 +03:00
IvanHunters
96e27cbcab feat(seaweedfs): add -lock BucketClass and -readonly BucketAccessClass
Add COSI resources for object locking and read-only access to both
client topology and system chart:
- BucketClass with -lock suffix (COMPLIANCE mode, 365 days retention)
- BucketAccessClass with -readonly suffix
- Explicit accessPolicy: readwrite on default BucketAccessClass

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-03 19:32:32 +03:00
IvanHunters
e822768fcf feat(seaweedfs): rename -worm to -lock BucketClass and update pool COSI parameters
Rename storage pool COSI resources to use consistent naming:
- BucketClass suffix: -worm -> -lock
- Parameter name: disk -> diskType
- Retention days: 36500 -> 365
- Validation suffix check updated accordingly

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-03-03 19:32:31 +03:00
Andrey Kolkov
1429b94f5d fix(backups): rbac actualized (#2145)
<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- If it's a work in progress, consider creating this PR as a draft.
- Don't hesistate to ask for opinion and review in the community chats,
even if it's still a draft.
- Add the label `backport` if it's a bugfix that needs to be backported
to a previous version.
-->

## What this PR does


### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
- fixed rbac for backup controllers 
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated backup controller permissions to focus on core backup
operations.
* Expanded backup strategy controller permissions to support enhanced
backup and restore capabilities, including Velero integration and status
management.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-03 19:36:06 +04:00
Andrey Kolkov
9ac8b2d291 fix(backups): rbac actualized
Signed-off-by: Andrey Kolkov <androndo@gmail.com>
2026-03-03 18:23:40 +04:00
Myasnikov Daniil
780af33ee1 Fixed packages name conversion in migration script
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-03-03 19:10:39 +05:00
Andrei Kvapil
772fb4363a docs: add changelog for v1.0.2 (#2141)
This PR adds the changelog for release `v1.0.2`.

 Changelog has been automatically generated in
`docs/changelogs/v1.0.2.md`.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
  * Published v1.0.2 release notes.

* **Bug Fixes**
  * Fixed migration script to ensure all upgrade steps execute.
* Improved dashboard functionality for field clearing and secret
copying.
  * Restored sidebar navigation on namespace-level pages.
  * Updated proxy configurations for enhanced TLS handling.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-02 21:50:58 +01:00
Kirill Ilin
cb919f4c85 [dashboard] Add storageClass dropdown for stateful apps (#2131)
## What this PR does

Replaces the plain text input for `storageClass` fields with an
API-backed dropdown listing available StorageClasses from the cluster.
Follows the same pattern as the `instanceType` dropdown for VMInstance.

Affected applications:
- **Top-level `spec.storageClass`**: ClickHouse, Harbor, HTTPCache,
  Kubernetes, MariaDB, MongoDB, NATS, OpenBAO, Postgres, Qdrant,
  RabbitMQ, Redis, VMDisk
- **Nested `spec.storage.storageClass`**: FoundationDB
- **Nested `spec.kafka.storageClass` / `spec.zookeeper.storageClass`**:
Kafka

### Release note

```release-note
[dashboard] storageClass fields in stateful app forms now render as a
dropdown populated with available StorageClasses from the cluster,
instead of a free-text input.
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
* Storage class selection dropdowns now available in configuration forms
for multiple database, messaging, and storage services.

* **Tests**
* Added comprehensive test coverage for storage class configuration
handling.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-02 23:55:12 +05:00
cozystack-bot
aed46a8819 docs: add changelog for v1.0.2
Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com>
2026-03-02 18:45:19 +00:00
Andrei Kvapil
35e3eddeff [dashboard] fix: restore stock-instance sidebars for namespace-level pages (#2136)
## What this PR does

Restores `stock-instance-api-form`, `stock-instance-api-table`,
`stock-instance-builtin-form`, and `stock-instance-builtin-table`
sidebar
resources that were removed in #2106, and adds them back to the orphan
cleanup allowlist.

PR #2106 removed these sidebars to fix broken URLs on the main page
before
namespace selection (`default//api-table/...`). However,
`stock-instance-*`
sidebars are required by the frontend for namespace-level
api-table/api-form
pages. Without them and with `CUSTOMIZATION_SIDEBAR_FALLBACK_ID=""`, the
frontend cannot find a sidebar for pages like Backup Plans and renders
an
empty page where no interaction is possible.

The broken-URL bug is already fully fixed by
`CUSTOMIZATION_SIDEBAR_FALLBACK_ID=""`
in `web.yaml`. Re-adding `stock-instance-*` does not reintroduce it,
since
these sidebars are only shown when the user is on a namespace-level page
where the `{namespace}` placeholder is filled.

### Release note

```release-note
[dashboard] fix empty page on Backup Plans and other namespace-level api-table pages
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added four new dashboard sidebar resources for stock instances: API
form, API table, built-in form, and built-in table views. These enable
expanded dashboard customization options for managing stock instance
configurations and data.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-02 19:28:18 +01:00
Andrei Kvapil
8d566a27ed [dashboard] fix: allow clearing instanceType and preserve secret copy newlines (#2135)
## What this PR does

Updates the openapi-k8s-toolkit integration in the dashboard to fix two
UX issues:

**1. Allow clearing the instanceType field in VMInstance form**

When `instanceType` has a default value, clearing the field in the form
UI would
silently revert to the default, making it impossible to explicitly send
an empty
value. This blocked use of custom KubeVirt resources without a named
instance type.

Adds `allowEmpty: true` to the instanceType listInput field so the BFF
preserves
an explicit empty value. Also introduces a generic `persistType` prop
(`'str' | 'number' | 'arr' | 'obj'`) to the listInput component, so the
allow-empty behaviour works correctly for any field type, not just
strings.

Updates openapi-k8s-toolkit to release/1.4.0 (d6b9e4ad), which already
includes
the FormListInput layout refactor — the previous
formlistinput-value-binding.diff
patch is no longer needed.

Upstream PR:
https://github.com/PRO-Robotech/openapi-k8s-toolkit/pull/340

**2. Preserve newlines when copying secrets with CMD+C**

Native `input[type=text]` strips newlines on copy. Adds an `onCopy`
handler to
the SecretBase64Plain component that intercepts the copy event and
writes the full
decoded value (including newlines) to the clipboard.

Upstream PR:
https://github.com/PRO-Robotech/openapi-k8s-toolkit/pull/339

### Release note

```release-note
[dashboard] Fix clearing instanceType in VMInstance form: explicit empty value
is now correctly sent to the API instead of falling back to the schema default.
Fix CMD+C copying of secrets stripping newlines.
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
  * Dropdown fields now support configuration to allow empty selections
* Enhanced empty value handling for form fields across multiple data
types (string, number, array, object)

* **Bug Fixes**
* Fixed secret field copy functionality to preserve plain-text format
when visible

* **Chores**
  * Updated base image dependencies for dashboard build

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-02 19:27:35 +01:00
Kirill Ilin
45b61f812d fix(dashboard): restore stock-instance sidebars for namespace-level pages
PR #2106 removed stock-instance-* sidebar resources to fix broken URLs
on the main page before namespace selection. However, these sidebars are
required for rendering namespace-level pages (api-table, api-form, etc.)
such as the Backup Plans page.

Without stock-instance-api-table, the frontend cannot find the sidebar
for namespace-scoped api-table pages and renders an empty page instead.

The original bug (broken URLs with empty namespace placeholder) is already
fixed by CUSTOMIZATION_SIDEBAR_FALLBACK_ID="" in web.yaml, so re-adding
stock-instance-* sidebars does not reintroduce it.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-02 23:13:48 +05:00
Kirill Ilin
99ee0e34bf fix(dashboard): preserve newlines when copying secrets with CMD+C
Add onCopy handler to SecretBase64Plain inputs to intercept native browser
copy events and explicitly write the full decoded text (including newlines)
to the clipboard. Without this, input[type=text] strips newlines on copy.

Upstream PR: https://github.com/PRO-Robotech/openapi-k8s-toolkit/pull/339

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-02 22:36:01 +05:00
Andrei Kvapil
0a461958ca [system] Fix Keycloak proxy configuration for v26.x (#2125)
## What this PR does

Replace deprecated `KC_PROXY=edge` with `KC_PROXY_HEADERS=xforwarded`
and `KC_HTTP_ENABLED=true` in the Keycloak StatefulSet template.

`KC_PROXY` was removed in Keycloak 26.x, causing "Non-secure context
detected" warnings and broken cookie handling when running behind a
reverse proxy with TLS termination.

### Release note

```release-note
[system] Fix Keycloak proxy headers configuration for compatibility with Keycloak 26.x
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **Chores**
* Updated system configuration to improve proxy header handling and
enable direct HTTP support for enhanced compatibility with reverse proxy
environments.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-02 18:29:35 +01:00
Kirill Ilin
6e8ce65e49 feat(dashboard): set allowEmpty on instanceType and update openapi-ui toolkit
Update openapi-k8s-toolkit commit to d6b9e4ad (release/1.4.0) which
includes the FormListInput layout refactor, making formlistinput-value-binding.diff
obsolete.

Set allowEmpty: true on the VMInstance instanceType field so users can
explicitly clear the selection and override the default instance type.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-02 22:19:54 +05:00
Kirill Ilin
a3ccb4f87d feat(dashboard): allow clearing instanceType field in VMInstance form
Update openapi-k8s-toolkit to release/1.4.0 (d6b9e4ad). The previous
value-binding layout refactor is already included upstream, so drop the
formlistinput-value-binding.diff patch.

Add formlistinput-allow-empty.diff patch which introduces two props to
the listInput component:
- allowEmpty: when set, auto-persists the field so BFF sends an empty
  value instead of falling back to the schema default
- persistType: controls the type of empty value ('str' | 'number' | 'arr'
  | 'obj'), allowing the feature to work correctly for any field type

Set allowEmpty: true on the VMInstance instanceType field so users can
explicitly clear the selection and override the default instance type.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-02 22:18:53 +05:00
Andrei Kvapil
20c91f25da [platform] Fixed run-migrations script (#2126)
<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- If it's a work in progress, consider creating this PR as a draft.
- Don't hesistate to ask for opinion and review in the community chats,
even if it's still a draft.
- Add the label `backport` if it's a bugfix that needs to be backported
to a previous version.
-->

## What this PR does


### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
[platform] Fixed off-by-one error where the first required migration was always skipped.
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Corrected migration range handling so upgrade steps run for the
intended version window, preventing skipped or duplicated migrations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-02 17:53:41 +01:00
Andrei Kvapil
ee36c50d69 Disable private key rotation in CA certs (#2113)
<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- If it's a work in progress, consider creating this PR as a draft.
- Don't hesistate to ask for opinion and review in the community chats,
even if it's still a draft.
- Add the label `backport` if it's a bugfix that needs to be backported
to a previous version.
-->

## What this PR does


### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
Disabled private key rotation in every CA cert in cozystack system packages to prevent trustchain problems when CA cert reissued
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Disabled private-key rotation (set rotationPolicy: Never) for CA/root
certificates used by multiple system components (ingress-nginx, linstor,
linstor-scheduler, seaweedfs, victoria-metrics-operator,
kubeovn-webhook, lineage-controller-webhook, cozystack-api, etcd,
linstor API/internal, seaweedfs).
* Added patch application steps to relevant update workflows to ensure
the certificate template changes are applied during chart/update
operations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-02 17:48:21 +01:00
Andrei Kvapil
1de4bb39a8 [rabbitmq] update version selection (#2092)
<!-- Thank you for making a contribution! Here are some tips for you:
- Start the PR title with the [label] of Cozystack component:
- For system components: [platform], [system], [linstor], [cilium],
[kube-ovn], [dashboard], [cluster-api], etc.
- For managed apps: [apps], [tenant], [kubernetes], [postgres],
[virtual-machine] etc.
- For development and maintenance: [tests], [ci], [docs], [maintenance].
- If it's a work in progress, consider creating this PR as a draft.
- Don't hesistate to ask for opinion and review in the community chats,
even if it's still a draft.
- Add the label `backport` if it's a bugfix that needs to be backported
to a previous version.
-->

## What this PR does


### Release note

<!--  Write a release note:
- Explain what has changed internally and for users.
- Start with the same [label] as in the PR title
- Follow the guidelines at
https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md.
-->

```release-note
[rabbitmq] Added version selection to newly created RabbitMQ instances.
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Configurable RabbitMQ major.minor version selector (v4.2, v4.1, v4.0,
v3.13), default v4.2; chart validates selection and uses it to pick the
runtime image.

* **Chores**
  * Default RabbitMQ image updated to 4.2.4.
* Added an automated version-update helper and a Makefile target to
refresh available versions and regenerate manifests.

* **Migration**
* Migration added to backfill the version field on existing RabbitMQ
resources.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-02 17:46:22 +01:00
Kirill Ilin
c2bf8cf56f feat(dashboard): add storageClass dropdown for all stateful apps
Replace plain text input with an API-backed listInput dropdown for
storageClass fields across all applications that expose them.

The dropdown fetches available StorageClasses from the cluster via
/api/clusters/{cluster}/k8s/apis/storage.k8s.io/v1/storageclasses,
following the same pattern as the instanceType dropdown for VMInstance.

Top-level spec.storageClass: ClickHouse, Harbor, HTTPCache, Kubernetes,
MariaDB, MongoDB, NATS, OpenBAO, Postgres, Qdrant, RabbitMQ, Redis, VMDisk.

Nested paths: FoundationDB (spec.storage.storageClass),
Kafka (spec.kafka.storageClass and spec.zookeeper.storageClass).

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-02 21:26:51 +05:00
Andrei Kvapil
b455405402 fix(migration): suspend cozy-proxy if it conflicts with installer release (#2128)
## What this PR does

Adds a check in the migration script to detect and suspend the
`cozy-proxy`
HelmRelease if it has `releaseName: cozystack`, which conflicts with the
installer
release and causes cozystack-operator deletion during upgrade from v0.41
to v1.0.

### Release note

```release-note
[platform] Fix migration script to handle cozy-proxy releaseName conflict during v0.41→v1.0 upgrade.
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Enhanced the version 1.0 migration process with automatic conflict
detection and interactive guidance, prompting users to resolve issues
during the upgrade for a smoother migration experience.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-02 16:31:03 +01:00
Andrei Kvapil
14a9017932 fix(migration): suspend cozy-proxy if it conflicts with installer release
In v0.41.x, cozy-proxy HelmRelease was configured with
releaseName: cozystack, which collides with the installer helm release.
If not suspended before upgrade, the cozy-proxy HR reconciles and
overwrites the installer release, deleting cozystack-operator.

Add a check in the migration script that detects this conflict and
suspends the cozy-proxy HelmRelease before proceeding.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2026-03-02 12:59:36 +01:00
Myasnikov Daniil
dc5c3dc9bc [rabbitmq] Added app version selection
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-03-02 15:36:20 +05:00
Myasnikov Daniil
79c57874bb [platform] Fixed run-migrations script
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-03-02 15:34:13 +05:00
Kirill Ilin
14228aa0d7 fix(keycloak): replace deprecated KC_PROXY with KC_PROXY_HEADERS
KC_PROXY=edge was deprecated and removed in Keycloak 26.x, causing
"Non-secure context detected" warnings and broken cookie handling
behind reverse proxy. Replace with KC_PROXY_HEADERS=xforwarded and
KC_HTTP_ENABLED=true.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Kirill Ilin <stitch14@yandex.ru>
2026-03-02 14:35:04 +05:00
Myasnikov Daniil
013b5b0873 Replaced direct chart edits with patch files
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-03-02 12:35:14 +05:00
Myasnikov Daniil
47d81f70d7 Disabled private key rotation in CA certs
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-02-27 19:09:10 +05:00
315 changed files with 44220 additions and 48631 deletions

View File

@@ -6,8 +6,6 @@ env:
on:
pull_request:
types: [opened, synchronize, reopened]
paths-ignore:
- 'docs/**/*'
# Cancel inflight runs for the same PR when a new push arrives.
concurrency:
@@ -15,6 +13,19 @@ concurrency:
cancel-in-progress: true
jobs:
detect-changes:
name: Detect changes
runs-on: ubuntu-latest
outputs:
code: ${{ steps.filter.outputs.code }}
steps:
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
code:
- '!docs/**'
build:
name: Build
runs-on: [self-hosted]
@@ -22,9 +33,11 @@ jobs:
contents: read
packages: write
# Never run when the PR carries the "release" label.
needs: ["detect-changes"]
# Never run when the PR carries the "release" label or only docs changed.
if: |
!contains(github.event.pull_request.labels.*.name, 'release')
needs.detect-changes.outputs.code == 'true'
&& !contains(github.event.pull_request.labels.*.name, 'release')
steps:
- name: Checkout code

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

19
docs/changelogs/v1.0.2.md Normal file
View File

@@ -0,0 +1,19 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v1.0.2
-->
## Fixes
* **[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 automatically 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, ensuring all upgrade steps execute correctly ([**@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 template. `KC_PROXY` was removed in Keycloak 26.x, previously causing "Non-secure context detected" warnings and broken cookie handling when running 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 with no interactive content ([**@sircthulhu**](https://github.com/sircthulhu) in #2136, #2138).
---
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.0.1...v1.0.2

17
docs/changelogs/v1.0.3.md Normal file
View File

@@ -0,0 +1,17 @@
<!--
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

25
docs/changelogs/v1.0.4.md Normal file
View File

@@ -0,0 +1,25 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v1.0.4
-->
## Fixes
* **[system] Fix Keycloak probe crashloop with management port health endpoints**: Fixed a crashloop where Keycloak 26.x was endlessly restarting because liveness and readiness probes were sending HTTP requests to port 8080. Keycloak 26.x redirects all requests on port 8080 to `KC_HOSTNAME` (HTTPS), and since kubelet does not follow redirects, probes failed, eventually triggering container restarts. The fix switches probes to the dedicated management port 9000 (`/health/live`, `/health/ready`) enabled via `KC_HEALTH_ENABLED=true`, exposes management port 9000, and adds a `startupProbe` with appropriate failure thresholds for better startup tolerance ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2162, #2178).
* **[system] Fix etcd-operator deprecated kube-rbac-proxy image**: Replaced the deprecated `gcr.io/kubebuilder/kube-rbac-proxy:v0.16.0` image with `quay.io/brancz/kube-rbac-proxy:v0.18.1` in the vendored etcd-operator chart. The GCR-hosted image became unavailable after March 18, 2025, causing etcd-operator pods to fail on image pull ([**@kvaps**](https://github.com/kvaps) in #2181, #2183).
* **[platform] Fix VM MAC address not preserved during virtual-machine to vm-instance migration**: During the `virtual-machine``vm-instance` migration (script 29), VM MAC addresses were not preserved. Kube-OVN reads MAC addresses exclusively from the pod annotation `ovn.kubernetes.io/mac_address`, not from `spec.macAddress` of the IP resource. Without this annotation, migrated VMs received a new random MAC address, breaking OS-level network configuration that matches by MAC (e.g., netplan). The fix adds a Helm `lookup` in the vm-instance chart template to read the Kube-OVN IP resource and automatically inject the MAC and IP addresses as pod annotations ([**@sircthulhu**](https://github.com/sircthulhu) in #2169, #2191).
* **[dashboard] Fix External IPs page showing empty rows**: Fixed the External IPs administration page displaying empty rows instead of service data. The `EnrichedTable` configuration in the `external-ips` factory was using incorrect property names — replaced `clusterNamePartOfUrl` with `cluster` and changed `pathToItems` from array format to dot-path string format, matching the convention used by all other `EnrichedTable` instances ([**@IvanHunters**](https://github.com/IvanHunters) in #2175, #2192).
* **[dashboard] Fix disabled/hidden state reset on MarketplacePanel reconciliation**: Fixed a bug where the dashboard controller was hardcoding `disabled=false` and `hidden=false` on every reconcile loop, overwriting changes made through the dashboard UI. Services disabled or hidden via the marketplace panel now correctly retain their state after controller reconciliation ([**@IvanHunters**](https://github.com/IvanHunters) in #2176, #2202).
* **[dashboard] Fix hidden MarketplacePanel resources appearing in sidebar menu**: Fixed the sidebar navigation showing all resources regardless of their MarketplacePanel `hidden` state. The controller now fetches MarketplacePanels during sidebar reconciliation and filters out resources where `hidden=true`, ensuring that hiding a resource from the marketplace also removes it from the sidebar navigation. Listing failures are non-fatal — if the configuration fetch fails, no hiding is applied and the dashboard remains functional ([**@IvanHunters**](https://github.com/IvanHunters) in #2177, #2204).
## Documentation
* **[website] Add OIDC self-signed certificates configuration guide**: Added a comprehensive guide for configuring OIDC authentication with Keycloak when using self-signed certificates (the default in Cozystack). Covers Talos machine configuration with certificate mounting and host entries, kubelogin setup instructions, and a troubleshooting section. The guide is available for both v0 and v1 versioned documentation paths ([**@IvanHunters**](https://github.com/IvanHunters) in cozystack/website#443).
---
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.0.3...v1.0.4

126
docs/changelogs/v1.1.0.md Normal file
View File

@@ -0,0 +1,126 @@
<!--
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

23
docs/changelogs/v1.1.1.md Normal file
View File

@@ -0,0 +1,23 @@
<!--
https://github.com/cozystack/cozystack/releases/tag/v1.1.1
-->
## Fixes
* **[dashboard] Fix hidden MarketplacePanel resources appearing in sidebar menu**: The sidebar was generated independently from MarketplacePanels, always showing all resources regardless of their `hidden` state. Fixed by fetching MarketplacePanels during sidebar reconciliation and skipping resources where `hidden=true`, so hiding a resource from the marketplace also removes it from the sidebar navigation ([**@IvanHunters**](https://github.com/IvanHunters) in #2177, #2203).
* **[dashboard] Fix disabled/hidden state overwritten on every MarketplacePanel reconciliation**: The controller was hardcoding `disabled=false` and `hidden=false` on every reconciliation, silently overwriting any user changes made through the dashboard UI. Fixed by reading and preserving the current `disabled`/`hidden` values from the existing resource before updating ([**@IvanHunters**](https://github.com/IvanHunters) in #2176, #2201).
* **[dashboard] Fix External IPs factory EnrichedTable rendering**: The external-IPs table displayed empty rows because the factory used incorrect `EnrichedTable` properties. Replaced `clusterNamePartOfUrl` with `cluster` and changed `pathToItems` from array to dot-path string format, consistent with all other working `EnrichedTable` instances ([**@IvanHunters**](https://github.com/IvanHunters) in #2175, #2193).
* **[platform] Fix VM MAC address not preserved during virtual-machine to vm-instance migration**: Kube-OVN reads MAC address exclusively from the pod annotation `ovn.kubernetes.io/mac_address`, not from the IP resource `spec.macAddress`. Without the annotation, migrated VMs received a new random MAC, breaking OS-level network configurations that match by MAC (e.g. netplan). Added a Helm `lookup` for the Kube-OVN IP resource in the vm-instance chart so that MAC and IP addresses are automatically injected as pod annotations when the resource exists ([**@sircthulhu**](https://github.com/sircthulhu) in #2169, #2190).
* **[etcd-operator] Replace deprecated kube-rbac-proxy image**: The `gcr.io/kubebuilder/kube-rbac-proxy` image became unavailable after Google Container Registry was deprecated. Replaced it with `quay.io/brancz/kube-rbac-proxy` from the original upstream author, restoring etcd-operator functionality ([**@kvaps**](https://github.com/kvaps) in #2181, #2182).
* **[migrations] Handle missing RabbitMQ CRD in migration 34**: Migration 34 failed with an error when the `rabbitmqs.apps.cozystack.io` CRD did not exist — which occurs on clusters where RabbitMQ was never installed. Added a CRD presence check before attempting to list resources so that migration 34 completes cleanly on such clusters ([**@IvanHunters**](https://github.com/IvanHunters) in #2168, #2180).
* **[keycloak] Fix Keycloak crashloop due to misconfigured health probes**: Keycloak 26.x redirects all HTTP requests on port 8080 to the configured HTTPS hostname; since kubelet does not follow redirects, liveness and readiness probes failed causing a crashloop. Fixed by enabling `KC_HEALTH_ENABLED=true`, exposing management port 9000, and switching all probes to `/health/live` and `/health/ready` on port 9000. Also added a `startupProbe` for improved startup tolerance ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2162, #2179).
---
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.1.0...v1.1.1

View File

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

@@ -0,0 +1,50 @@
#!/usr/bin/env bats
teardown() {
kubectl -n tenant-test delete externaldns.apps.cozystack.io --all --ignore-not-found 2>/dev/null || true
}
@test "Create and Verify ExternalDNS with inmemory provider" {
name='test'
kubectl apply -f - <<EOF
apiVersion: apps.cozystack.io/v1alpha1
kind: ExternalDNS
metadata:
name: ${name}
namespace: tenant-test
spec:
provider: inmemory
domainFilters:
- example.com
EOF
sleep 5
kubectl -n tenant-test wait hr ${name} --timeout=120s --for=condition=ready
kubectl -n tenant-test wait hr ${name}-system --timeout=120s --for=condition=ready
timeout 60 sh -ec "until kubectl -n tenant-test get deploy -l app.kubernetes.io/instance=${name}-system -o jsonpath='{.items[0].status.readyReplicas}' | grep -q '1'; do sleep 5; done"
kubectl -n tenant-test delete externaldns.apps.cozystack.io ${name}
}
@test "Create and Verify ExternalDNS with custom annotationPrefix" {
name='test-prefix'
kubectl apply -f - <<EOF
apiVersion: apps.cozystack.io/v1alpha1
kind: ExternalDNS
metadata:
name: ${name}
namespace: tenant-test
spec:
provider: inmemory
annotationPrefix: custom-dns/
domainFilters:
- example.org
EOF
sleep 5
kubectl -n tenant-test wait hr ${name} --timeout=120s --for=condition=ready
kubectl -n tenant-test wait hr ${name}-system --timeout=120s --for=condition=ready
timeout 60 sh -ec "until kubectl -n tenant-test get deploy -l app.kubernetes.io/instance=${name}-system -o jsonpath='{.items[0].status.readyReplicas}' | grep -q '1'; do sleep 5; done"
kubectl -n tenant-test delete externaldns.apps.cozystack.io ${name}
}

View File

@@ -46,6 +46,9 @@ spec:
publishing:
host: "example.org"
apiServerEndpoint: "https://192.168.123.10:6443"
bundles:
enabledPackages:
- cozystack.external-dns-application
EOF
# Wait until HelmReleases appear & reconcile them
@@ -175,8 +178,8 @@ EOF
# VictoriaMetrics components
kubectl wait vmalert/vmalert-shortterm vmalertmanager/alertmanager -n tenant-root --for=jsonpath='{.status.updateStatus}'=operational --timeout=15m
kubectl wait vlogs/generic -n tenant-root --for=jsonpath='{.status.updateStatus}'=operational --timeout=5m
kubectl wait vmcluster/shortterm vmcluster/longterm -n tenant-root --for=jsonpath='{.status.clusterStatus}'=operational --timeout=5m
kubectl wait vlclusters/generic -n tenant-root --for=jsonpath='{.status.updateStatus}'=operational --timeout=5m
kubectl wait vmcluster/shortterm vmcluster/longterm -n tenant-root --for=jsonpath='{.status.updateStatus}'=operational --timeout=5m
# Grafana
kubectl wait clusters.postgresql.cnpg.io/grafana-db -n tenant-root --for=condition=ready --timeout=5m

View File

@@ -56,6 +56,30 @@ else
fi
echo ""
# Step 1: Check for cozy-proxy HelmRelease with conflicting releaseName
# In v0.41.x, cozy-proxy was incorrectly configured with releaseName "cozystack",
# which conflicts with the installer helm release name. If not suspended, cozy-proxy
# HelmRelease will overwrite the installer release and delete cozystack-operator.
COZY_PROXY_RELEASE_NAME=$(kubectl get hr -n "$NAMESPACE" cozy-proxy -o jsonpath='{.spec.releaseName}' 2>/dev/null || true)
if [ "$COZY_PROXY_RELEASE_NAME" = "cozystack" ]; then
echo "WARNING: HelmRelease cozy-proxy has releaseName 'cozystack', which conflicts"
echo "with the installer release. It must be suspended before proceeding, otherwise"
echo "it will overwrite the installer and delete cozystack-operator."
echo ""
read -p "Suspend HelmRelease cozy-proxy? (y/N) " -n 1 -r
echo ""
if [[ $REPLY =~ ^[Yy]$ ]]; then
kubectl -n "$NAMESPACE" patch hr cozy-proxy --type=merge --field-manager=flux-client-side-apply -p '{"spec":{"suspend":true}}'
echo "HelmRelease cozy-proxy suspended."
else
echo "ERROR: Cannot proceed with conflicting cozy-proxy HelmRelease active."
echo "Please suspend it manually:"
echo " kubectl -n $NAMESPACE patch hr cozy-proxy --type=merge -p '{\"spec\":{\"suspend\":true}}'"
exit 1
fi
echo ""
fi
# Read ConfigMap cozystack
echo "Reading ConfigMap cozystack..."
COZYSTACK_CM=$(kubectl get configmap -n "$NAMESPACE" cozystack -o json 2>/dev/null || echo "{}")
@@ -131,13 +155,13 @@ fi
if [ -z "$BUNDLE_DISABLE" ]; then
DISABLED_PACKAGES="[]"
else
DISABLED_PACKAGES=$(echo "$BUNDLE_DISABLE" | sed 's/,/\n/g' | awk 'BEGIN{print}{print " - "$0}')
DISABLED_PACKAGES=$(echo "$BUNDLE_DISABLE" | sed 's/,/\n/g' | awk 'BEGIN{print}{print " - cozystack."$0}')
fi
if [ -z "$BUNDLE_ENABLE" ]; then
ENABLED_PACKAGES="[]"
else
ENABLED_PACKAGES=$(echo "$BUNDLE_ENABLE" | sed 's/,/\n/g' | awk 'BEGIN{print}{print " - "$0}')
ENABLED_PACKAGES=$(echo "$BUNDLE_ENABLE" | sed 's/,/\n/g' | awk 'BEGIN{print}{print " - cozystack."$0}')
fi
if [ -z "$EXPOSE_SERVICES" ]; then
@@ -151,7 +175,7 @@ BUNDLE_NAME=$(echo "$BUNDLE_NAME" | sed 's/paas/isp/')
# Extract branding if available
BRANDING=$(echo "$BRANDING_CM" | jq -r '.data // {} | to_entries[] | "\(.key): \"\(.value)\""')
if [ -z "$BRANDING" ]; then
if [ -z "$BRANDING" ]; then
BRANDING="{}"
else
BRANDING=$(echo "$BRANDING" | awk 'BEGIN{print}{print " " $0}')

View File

@@ -195,6 +195,7 @@ func applyListInputOverrides(schema map[string]any, kind string, openAPIProps ma
"valueUri": "/api/clusters/{cluster}/k8s/apis/instancetype.kubevirt.io/v1beta1/virtualmachineclusterinstancetypes",
"keysToValue": []any{"metadata", "name"},
"keysToLabel": []any{"metadata", "name"},
"allowEmpty": true,
},
}
if prop, _ := openAPIProps["instanceType"].(map[string]any); prop != nil {
@@ -214,6 +215,34 @@ func applyListInputOverrides(schema map[string]any, kind string, openAPIProps ma
"keysToLabel": []any{"metadata", "name"},
},
}
case "ClickHouse", "Harbor", "HTTPCache", "Kubernetes", "MariaDB", "MongoDB",
"NATS", "OpenBAO", "Postgres", "Qdrant", "RabbitMQ", "Redis", "VMDisk":
specProps := ensureSchemaPath(schema, "spec")
specProps["storageClass"] = storageClassListInput()
case "FoundationDB":
storageProps := ensureSchemaPath(schema, "spec", "storage")
storageProps["storageClass"] = storageClassListInput()
case "Kafka":
kafkaProps := ensureSchemaPath(schema, "spec", "kafka")
kafkaProps["storageClass"] = storageClassListInput()
zkProps := ensureSchemaPath(schema, "spec", "zookeeper")
zkProps["storageClass"] = storageClassListInput()
}
}
// storageClassListInput returns a listInput field config for a storageClass dropdown
// backed by the cluster's available StorageClasses.
func storageClassListInput() map[string]any {
return map[string]any{
"type": "listInput",
"customProps": map[string]any{
"valueUri": "/api/clusters/{cluster}/k8s/apis/storage.k8s.io/v1/storageclasses",
"keysToValue": []any{"metadata", "name"},
"keysToLabel": []any{"metadata", "name"},
},
}
}

View File

@@ -202,6 +202,10 @@ func TestApplyListInputOverrides_VMInstance(t *testing.T) {
t.Errorf("expected valueUri %s, got %v", expectedURI, customProps["valueUri"])
}
if customProps["allowEmpty"] != true {
t.Errorf("expected allowEmpty true, got %v", customProps["allowEmpty"])
}
// Check disks[].name is a listInput
disks, ok := specProps["disks"].(map[string]any)
if !ok {
@@ -232,6 +236,72 @@ func TestApplyListInputOverrides_VMInstance(t *testing.T) {
}
}
func TestApplyListInputOverrides_StorageClassSimple(t *testing.T) {
for _, kind := range []string{
"ClickHouse", "Harbor", "HTTPCache", "Kubernetes", "MariaDB", "MongoDB",
"NATS", "OpenBAO", "Postgres", "Qdrant", "RabbitMQ", "Redis", "VMDisk",
} {
t.Run(kind, func(t *testing.T) {
schema := map[string]any{}
applyListInputOverrides(schema, kind, map[string]any{})
specProps := schema["properties"].(map[string]any)["spec"].(map[string]any)["properties"].(map[string]any)
sc, ok := specProps["storageClass"].(map[string]any)
if !ok {
t.Fatalf("storageClass not found in spec.properties for kind %s", kind)
}
assertStorageClassListInput(t, sc)
})
}
}
func TestApplyListInputOverrides_StorageClassFoundationDB(t *testing.T) {
schema := map[string]any{}
applyListInputOverrides(schema, "FoundationDB", map[string]any{})
storageProps := schema["properties"].(map[string]any)["spec"].(map[string]any)["properties"].(map[string]any)["storage"].(map[string]any)["properties"].(map[string]any)
sc, ok := storageProps["storageClass"].(map[string]any)
if !ok {
t.Fatal("storageClass not found in spec.storage.properties")
}
assertStorageClassListInput(t, sc)
}
func TestApplyListInputOverrides_StorageClassKafka(t *testing.T) {
schema := map[string]any{}
applyListInputOverrides(schema, "Kafka", map[string]any{})
specProps := schema["properties"].(map[string]any)["spec"].(map[string]any)["properties"].(map[string]any)
kafkaSC, ok := specProps["kafka"].(map[string]any)["properties"].(map[string]any)["storageClass"].(map[string]any)
if !ok {
t.Fatal("storageClass not found in spec.kafka.properties")
}
assertStorageClassListInput(t, kafkaSC)
zkSC, ok := specProps["zookeeper"].(map[string]any)["properties"].(map[string]any)["storageClass"].(map[string]any)
if !ok {
t.Fatal("storageClass not found in spec.zookeeper.properties")
}
assertStorageClassListInput(t, zkSC)
}
// assertStorageClassListInput verifies that a field is a correctly configured storageClass listInput.
func assertStorageClassListInput(t *testing.T, field map[string]any) {
t.Helper()
if field["type"] != "listInput" {
t.Errorf("expected type listInput, got %v", field["type"])
}
customProps, ok := field["customProps"].(map[string]any)
if !ok {
t.Fatal("customProps not found")
}
expectedURI := "/api/clusters/{cluster}/k8s/apis/storage.k8s.io/v1/storageclasses"
if customProps["valueUri"] != expectedURI {
t.Errorf("expected valueUri %s, got %v", expectedURI, customProps["valueUri"])
}
}
func TestApplyListInputOverrides_UnknownKind(t *testing.T) {
schema := map[string]any{}
applyListInputOverrides(schema, "SomeOtherKind", map[string]any{})

View File

@@ -307,6 +307,10 @@ func (m *Manager) buildExpectedResourceSet(crds []cozyv1alpha1.ApplicationDefini
"stock-project-builtin-table",
"stock-project-crd-form",
"stock-project-crd-table",
"stock-instance-api-form",
"stock-instance-api-table",
"stock-instance-builtin-form",
"stock-instance-builtin-table",
}
for _, sidebarID := range stockSidebars {
expected["Sidebar"][sidebarID] = true

View File

@@ -68,31 +68,46 @@ func (m *Manager) ensureMarketplacePanel(ctx context.Context, crd *cozyv1alpha1.
tags[i] = t
}
specMap := map[string]any{
"description": d.Description,
"name": displayName,
"type": "nonCrd",
"apiGroup": "apps.cozystack.io",
"apiVersion": "v1alpha1",
"plural": app.Plural, // e.g., "buckets"
"disabled": false,
"hidden": false,
"tags": tags,
"icon": d.Icon,
}
specBytes, err := json.Marshal(specMap)
if err != nil {
return reconcile.Result{}, err
}
_, err = controllerutil.CreateOrUpdate(ctx, m.Client, mp, func() error {
_, err := controllerutil.CreateOrUpdate(ctx, m.Client, mp, func() error {
if err := controllerutil.SetOwnerReference(crd, mp, m.Scheme); err != nil {
return err
}
// Add dashboard labels to dynamic resources
m.addDashboardLabels(mp, crd, ResourceTypeDynamic)
// Preserve user-set disabled/hidden values from existing resource
disabled := false
hidden := false
if mp.Spec.Raw != nil {
var existing map[string]any
if err := json.Unmarshal(mp.Spec.Raw, &existing); err == nil {
if v, ok := existing["disabled"].(bool); ok {
disabled = v
}
if v, ok := existing["hidden"].(bool); ok {
hidden = v
}
}
}
specMap := map[string]any{
"description": d.Description,
"name": displayName,
"type": "nonCrd",
"apiGroup": "apps.cozystack.io",
"apiVersion": "v1alpha1",
"plural": app.Plural, // e.g., "buckets"
"disabled": disabled,
"hidden": hidden,
"tags": tags,
"icon": d.Icon,
}
specBytes, err := json.Marshal(specMap)
if err != nil {
return err
}
// Only update spec if it's different to avoid unnecessary updates
newSpec := dashv1alpha1.ArbitrarySpec{
JSON: apiextv1.JSON{Raw: specBytes},

View File

@@ -38,6 +38,23 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Applicati
}
all = crdList.Items
// 1b) Fetch all MarketplacePanels to determine which resources are hidden
hiddenResources := map[string]bool{}
var mpList dashv1alpha1.MarketplacePanelList
if err := m.List(ctx, &mpList, &client.ListOptions{}); err == nil {
for i := range mpList.Items {
mp := &mpList.Items[i]
if mp.Spec.Raw != nil {
var spec map[string]any
if err := json.Unmarshal(mp.Spec.Raw, &spec); err == nil {
if hidden, ok := spec["hidden"].(bool); ok && hidden {
hiddenResources[mp.Name] = true
}
}
}
}
}
// 2) Build category -> []item map (only for CRDs with spec.dashboard != nil)
type item struct {
Key string
@@ -63,6 +80,11 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Applicati
plural := pickPlural(kind, def)
lowerKind := strings.ToLower(kind)
// Skip resources hidden via MarketplacePanel
if hiddenResources[def.Name] {
continue
}
// Check if this resource is a module
if def.Spec.Dashboard.Module {
// Special case: info should have its own keysAndTags, not be in modules
@@ -243,6 +265,11 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Applicati
"stock-project-builtin-table",
"stock-project-crd-form",
"stock-project-crd-table",
// stock-instance sidebars (namespace-level pages after namespace is selected)
"stock-instance-api-form",
"stock-instance-api-table",
"stock-instance-builtin-form",
"stock-instance-builtin-table",
}
// Add details sidebars for all CRDs with dashboard config

View File

@@ -1924,12 +1924,12 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory {
map[string]any{
"type": "EnrichedTable",
"data": map[string]any{
"id": "external-ips-table",
"fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/services",
"clusterNamePartOfUrl": "{2}",
"baseprefix": "/openapi-ui",
"customizationId": "factory-details-v1.services",
"pathToItems": []any{"items"},
"id": "external-ips-table",
"fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/services",
"cluster": "{2}",
"baseprefix": "/openapi-ui",
"customizationId": "factory-details-v1.services",
"pathToItems": ".items",
"fieldSelector": map[string]any{
"spec.type": "LoadBalancer",
},

View File

@@ -2,5 +2,4 @@ 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,3 +1,13 @@
# 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,29 +1,22 @@
{{- $seaweedfs := .Values._namespace.seaweedfs }}
{{- $pool := .Values.storagePool }}
apiVersion: objectstorage.k8s.io/v1alpha1
kind: BucketClaim
metadata:
name: {{ .Release.Name }}
spec:
bucketClassName: {{ $seaweedfs }}
bucketClassName: {{ $seaweedfs }}{{- if $pool }}-{{ $pool }}{{- end }}{{- if .Values.locking }}-lock{{- end }}
protocols:
- s3
{{- range $name, $user := .Values.users }}
---
apiVersion: objectstorage.k8s.io/v1alpha1
kind: BucketAccess
metadata:
name: {{ .Release.Name }}
name: {{ $.Release.Name }}-{{ $name }}
spec:
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
bucketAccessClassName: {{ $seaweedfs }}{{- if $pool }}-{{ $pool }}{{- end }}{{- if $user.readonly }}-readonly{{- end }}
bucketClaimName: {{ $.Release.Name }}
credentialsSecretName: {{ $.Release.Name }}-{{ $name }}
protocol: s3
{{- end }}

View File

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

View File

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

View File

@@ -1,5 +1,30 @@
{
"title": "Chart Values",
"type": "object",
"properties": {}
}
"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"
}
}
}
}
}
}

View File

@@ -1 +1,11 @@
{}
## @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

@@ -0,0 +1,75 @@
{{- $gatewayAPI := (index .Values._cluster "gateway-api") | default "false" }}
{{- $clusterIssuer := (index .Values._cluster "issuer-name") | default "letsencrypt-prod" }}
{{- $gateway := .Values._namespace.gateway | default "" }}
{{- $host := .Values._namespace.host }}
{{- $harborHost := .Values.host | default (printf "%s.%s" .Release.Name $host) }}
{{- if and (eq $gatewayAPI "true") (ne $gateway "") }}
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: {{ .Release.Name }}-harbor
annotations:
cert-manager.io/cluster-issuer: {{ $clusterIssuer }}
spec:
gatewayClassName: cilium
infrastructure:
labels:
cozystack.io/gateway: {{ $gateway }}
listeners:
- name: http
protocol: HTTP
port: 80
hostname: {{ $harborHost | quote }}
allowedRoutes:
namespaces:
from: Same
- name: https
protocol: HTTPS
port: 443
hostname: {{ $harborHost | quote }}
tls:
mode: Terminate
certificateRefs:
- name: {{ .Release.Name }}-harbor-gateway-tls
allowedRoutes:
namespaces:
from: Same
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: {{ .Release.Name }}-harbor-redirect-to-https
spec:
parentRefs:
- name: {{ .Release.Name }}-harbor
sectionName: http
hostnames:
- {{ $harborHost | quote }}
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: {{ .Release.Name }}-harbor
spec:
parentRefs:
- name: {{ .Release.Name }}-harbor
sectionName: https
hostnames:
- {{ $harborHost | quote }}
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: {{ .Release.Name }}
port: 80
{{- end }}

View File

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

View File

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

View File

@@ -73,8 +73,8 @@ spec:
[OUTPUT]
Name http
Match kube.*
Host vlogs-generic.{{ $targetTenant }}.svc.{{ $clusterDomain }}
port 9428
Host vlinsert-generic.{{ $targetTenant }}.svc.{{ $clusterDomain }}
port 9481
compress gzip
uri /insert/jsonline?_stream_fields=stream,kubernetes_pod_name,kubernetes_container_name,kubernetes_namespace_name&_msg_field=log&_time_field=date
format json_lines

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

@@ -4,4 +4,4 @@ description: Managed RabbitMQ service
icon: /logos/rabbitmq.svg
type: application
version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process
appVersion: "3.13.2"
appVersion: "4.2.4"

View File

@@ -3,3 +3,7 @@ include ../../../hack/package.mk
generate:
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
../../../hack/update-crd.sh
update:
hack/update-versions.sh
make generate

View File

@@ -23,6 +23,7 @@ The service utilizes official RabbitMQ operator. This ensures the reliability an
| `size` | Persistent Volume Claim size available for application data. | `quantity` | `10Gi` |
| `storageClass` | StorageClass used to store the data. | `string` | `""` |
| `external` | Enable external access from outside the cluster. | `bool` | `false` |
| `version` | RabbitMQ major.minor version to deploy | `string` | `v4.2` |
### Application-specific parameters

View File

@@ -0,0 +1,4 @@
"v4.2": "4.2.4"
"v4.1": "4.1.8"
"v4.0": "4.0.9"
"v3.13": "3.13.7"

View File

@@ -0,0 +1,129 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
RABBITMQ_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
VALUES_FILE="${RABBITMQ_DIR}/values.yaml"
VERSIONS_FILE="${RABBITMQ_DIR}/files/versions.yaml"
GITHUB_API_URL="https://api.github.com/repos/rabbitmq/rabbitmq-server/releases"
# Check if jq is installed
if ! command -v jq &> /dev/null; then
echo "Error: jq is not installed. Please install jq and try again." >&2
exit 1
fi
# Fetch releases from GitHub API
echo "Fetching releases from GitHub API..."
RELEASES_JSON=$(curl -sSL "${GITHUB_API_URL}?per_page=100")
if [ -z "$RELEASES_JSON" ]; then
echo "Error: Could not fetch releases from GitHub API" >&2
exit 1
fi
# Extract stable release tags (format: v3.13.7, v4.0.3, etc.)
# Filter out pre-releases and draft releases
RELEASE_TAGS=$(echo "$RELEASES_JSON" | jq -r '.[] | select(.prerelease == false) | select(.draft == false) | .tag_name' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V)
if [ -z "$RELEASE_TAGS" ]; then
echo "Error: Could not find any stable release tags" >&2
exit 1
fi
echo "Found release tags: $(echo "$RELEASE_TAGS" | tr '\n' ' ')"
# Supported major.minor versions (newest first)
# We support the last few minor releases of each active major
SUPPORTED_MAJORS=("4.2" "4.1" "4.0" "3.13")
# Build versions map: major.minor -> latest patch version
declare -A VERSION_MAP
MAJOR_VERSIONS=()
for major_minor in "${SUPPORTED_MAJORS[@]}"; do
# Find the latest patch version for this major.minor
MATCHING=$(echo "$RELEASE_TAGS" | grep -E "^v${major_minor//./\\.}\.[0-9]+$" | tail -n1)
if [ -n "$MATCHING" ]; then
# Strip the 'v' prefix for the value (Docker tag format is e.g. 3.13.7)
TAG_VERSION="${MATCHING#v}"
VERSION_MAP["v${major_minor}"]="${TAG_VERSION}"
MAJOR_VERSIONS+=("v${major_minor}")
echo "Found version: v${major_minor} -> ${TAG_VERSION}"
else
echo "Warning: No stable releases found for ${major_minor}, skipping..." >&2
fi
done
if [ ${#MAJOR_VERSIONS[@]} -eq 0 ]; then
echo "Error: No matching versions found" >&2
exit 1
fi
echo "Major versions to add: ${MAJOR_VERSIONS[*]}"
# Create/update versions.yaml file
echo "Updating $VERSIONS_FILE..."
{
for major_ver in "${MAJOR_VERSIONS[@]}"; do
echo "\"${major_ver}\": \"${VERSION_MAP[$major_ver]}\""
done
} > "$VERSIONS_FILE"
echo "Successfully updated $VERSIONS_FILE"
# Update values.yaml - enum with major.minor versions only
TEMP_FILE=$(mktemp)
trap "rm -f $TEMP_FILE" EXIT
# Build new version section
NEW_VERSION_SECTION="## @enum {string} Version"
for major_ver in "${MAJOR_VERSIONS[@]}"; do
NEW_VERSION_SECTION="${NEW_VERSION_SECTION}
## @value $major_ver"
done
NEW_VERSION_SECTION="${NEW_VERSION_SECTION}
## @param {Version} version - RabbitMQ major.minor version to deploy
version: ${MAJOR_VERSIONS[0]}"
# Check if version section already exists
if grep -q "^## @enum {string} Version" "$VALUES_FILE"; then
# Version section exists, update it using awk
echo "Updating existing version section in $VALUES_FILE..."
awk -v new_section="$NEW_VERSION_SECTION" '
/^## @enum {string} Version/ {
in_section = 1
print new_section
next
}
in_section && /^version: / {
in_section = 0
next
}
in_section {
next
}
{ print }
' "$VALUES_FILE" > "$TEMP_FILE.tmp"
mv "$TEMP_FILE.tmp" "$VALUES_FILE"
else
# Version section doesn't exist, insert it before Application-specific parameters section
echo "Inserting new version section in $VALUES_FILE..."
awk -v new_section="$NEW_VERSION_SECTION" '
/^## @section Application-specific parameters/ {
print new_section
print ""
}
{ print }
' "$VALUES_FILE" > "$TEMP_FILE.tmp"
mv "$TEMP_FILE.tmp" "$VALUES_FILE"
fi
echo "Successfully updated $VALUES_FILE with major.minor versions: ${MAJOR_VERSIONS[*]}"

View File

@@ -0,0 +1,8 @@
{{- define "rabbitmq.versionMap" }}
{{- $versionMap := .Files.Get "files/versions.yaml" | fromYaml }}
{{- if not (hasKey $versionMap .Values.version) }}
{{- printf `RabbitMQ version %s is not supported, allowed versions are %s` $.Values.version (keys $versionMap) | fail }}
{{- end }}
{{- index $versionMap .Values.version }}
{{- end }}

View File

@@ -7,6 +7,7 @@ metadata:
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicas }}
image: 'rabbitmq:{{ include "rabbitmq.versionMap" $ }}-management'
{{- if .Values.external }}
service:
type: LoadBalancer

View File

@@ -92,6 +92,17 @@
}
}
},
"version": {
"description": "RabbitMQ major.minor version to deploy",
"type": "string",
"default": "v4.2",
"enum": [
"v4.2",
"v4.1",
"v4.0",
"v3.13"
]
},
"vhosts": {
"description": "Virtual hosts configuration map.",
"type": "object",

View File

@@ -34,6 +34,15 @@ storageClass: ""
external: false
##
## @enum {string} Version
## @value v4.2
## @value v4.1
## @value v4.0
## @value v3.13
## @param {Version} version - RabbitMQ major.minor version to deploy
version: v4.2
## @section Application-specific parameters
##

View File

@@ -80,6 +80,7 @@ tenant-u1
| `etcd` | Deploy own Etcd cluster. | `bool` | `false` |
| `monitoring` | Deploy own Monitoring Stack. | `bool` | `false` |
| `ingress` | Deploy own Ingress Controller. | `bool` | `false` |
| `gateway` | Deploy own Gateway API gateway (separate LB for this tenant). | `bool` | `false` |
| `seaweedfs` | Deploy own SeaweedFS. | `bool` | `false` |
| `resourceQuotas` | Define resource quotas for the tenant. | `map[string]quantity` | `{}` |

View File

@@ -29,6 +29,11 @@
{{- $ingress = $tenantName }}
{{- end }}
{{- $gateway := $parentNamespace.gateway | default "" }}
{{- if .Values.gateway }}
{{- $gateway = $tenantName }}
{{- end }}
{{- $monitoring := $parentNamespace.monitoring | default "" }}
{{- if .Values.monitoring }}
{{- $monitoring = $tenantName }}
@@ -55,6 +60,7 @@ metadata:
{{/* Labels for network policies */}}
namespace.cozystack.io/etcd: {{ $etcd | quote }}
namespace.cozystack.io/ingress: {{ $ingress | quote }}
namespace.cozystack.io/gateway: {{ $gateway | quote }}
namespace.cozystack.io/monitoring: {{ $monitoring | quote }}
namespace.cozystack.io/seaweedfs: {{ $seaweedfs | quote }}
namespace.cozystack.io/host: {{ $computedHost | quote }}
@@ -83,6 +89,7 @@ stringData:
_namespace:
etcd: {{ $etcd | quote }}
ingress: {{ $ingress | quote }}
gateway: {{ $gateway | quote }}
monitoring: {{ $monitoring | quote }}
seaweedfs: {{ $seaweedfs | quote }}
host: {{ $computedHost | quote }}

View File

@@ -207,6 +207,27 @@ spec:
- toEndpoints:
- matchLabels:
"k8s:io.kubernetes.pod.namespace": cozy-kubevirt-cdi
{{- if .Values.monitoring }}
---
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: {{ include "tenant.name" . }}-egress-virt-handler
spec:
endpointSelector:
matchLabels:
"k8s:io.kubernetes.pod.namespace": "{{ include "tenant.name" . }}"
"k8s:app.kubernetes.io/name": "vmagent"
egress:
- toEndpoints:
- matchLabels:
"k8s:kubevirt.io": "virt-handler"
"k8s:io.kubernetes.pod.namespace": "cozy-kubevirt"
toPorts:
- ports:
- port: "8443"
protocol: TCP
{{- end }}
---
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy

View File

@@ -7,6 +7,11 @@
"type": "boolean",
"default": false
},
"gateway": {
"description": "Deploy own Gateway API gateway (separate LB for this tenant).",
"type": "boolean",
"default": false
},
"host": {
"description": "The hostname used to access tenant services (defaults to using the tenant name as a subdomain for its parent tenant host).",
"type": "string",

View File

@@ -14,6 +14,9 @@ monitoring: false
## @param {bool} ingress - Deploy own Ingress Controller.
ingress: false
## @param {bool} gateway - Deploy own Gateway API gateway (separate LB for this tenant).
gateway: false
## @param {bool} seaweedfs - Deploy own SeaweedFS.
seaweedfs: false

View File

@@ -34,6 +34,12 @@ spec:
metadata:
annotations:
kubevirt.io/allow-pod-bridge-network-live-migration: "true"
{{- $ovnIPName := printf "%s.%s" (include "virtual-machine.fullname" .) .Release.Namespace }}
{{- $ovnIP := lookup "kubeovn.io/v1" "IP" "" $ovnIPName }}
{{- if $ovnIP }}
ovn.kubernetes.io/mac_address: {{ $ovnIP.spec.macAddress | quote }}
ovn.kubernetes.io/ip_address: {{ $ovnIP.spec.ipAddress | quote }}
{{- end }}
labels:
{{- include "virtual-machine.labels" . | nindent 8 }}
spec:

View File

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

View File

@@ -0,0 +1,46 @@
#!/bin/sh
# Migration 34 --> 35
# Backfill spec.version on rabbitmq.apps.cozystack.io resources.
#
# Before this migration RabbitMQ had no user-selectable version; the
# operator always used its built-in default image (v3.x). A version field
# was added in this release. Without this migration every existing cluster
# would be upgraded to the new default (v4.2) on the next reconcile.
#
# Set spec.version to "v3.13" for any rabbitmq app resource that does not
# already have it set.
set -euo pipefail
DEFAULT_VERSION="v3.13"
# Skip if the CRD does not exist (rabbitmq was never installed)
if ! kubectl api-resources --api-group=apps.cozystack.io -o name 2>/dev/null | grep -q '^rabbitmqs\.'; then
echo "CRD rabbitmqs.apps.cozystack.io not found, skipping migration"
kubectl create configmap -n cozy-system cozystack-version \
--from-literal=version=35 --dry-run=client -o yaml | kubectl apply -f-
exit 0
fi
RABBITMQS=$(kubectl get rabbitmqs.apps.cozystack.io -A -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}')
for resource in $RABBITMQS; do
NS="${resource%%/*}"
APP_NAME="${resource##*/}"
# Skip if spec.version is already set
CURRENT_VER=$(kubectl get rabbitmqs.apps.cozystack.io -n "$NS" "$APP_NAME" \
-o jsonpath='{.spec.version}')
if [ -n "$CURRENT_VER" ]; then
echo "SKIP $NS/$APP_NAME: spec.version already set to '$CURRENT_VER'"
continue
fi
echo "Patching rabbitmq/$APP_NAME in $NS: setting version=$DEFAULT_VERSION"
kubectl patch rabbitmqs.apps.cozystack.io -n "$NS" "$APP_NAME" --type=merge \
--patch "{\"spec\":{\"version\":\"${DEFAULT_VERSION}\"}}"
done
# Stamp version
kubectl create configmap -n cozy-system cozystack-version \
--from-literal=version=35 --dry-run=client -o yaml | kubectl apply -f-

View File

@@ -0,0 +1,21 @@
#!/bin/sh
# Migration 35 --> 36
# Add helm.sh/resource-policy=keep annotation to existing VLogs resources
# so they are preserved when the monitoring helm release upgrades to VLCluster.
# Users will need to manually verify the new cluster is working, then optionally
# migrate historical data and delete old VLogs resources.
set -euo pipefail
VLOGS=$(kubectl get vlogs.operator.victoriametrics.com --all-namespaces --output jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}' 2>/dev/null || true)
for resource in $VLOGS; do
NS="${resource%%/*}"
NAME="${resource##*/}"
echo "Adding keep annotation to VLogs/$NAME in $NS"
kubectl annotate vlogs.operator.victoriametrics.com --namespace "$NS" "$NAME" \
helm.sh/resource-policy=keep \
--overwrite
done
kubectl create configmap --namespace cozy-system cozystack-version \
--from-literal=version=36 --dry-run=client --output yaml | kubectl apply --filename -

View File

@@ -24,7 +24,7 @@ if [ "$CURRENT_VERSION" -ge "$TARGET_VERSION" ]; then
fi
# Run migrations sequentially from current version to target version
for i in $(seq $((CURRENT_VERSION + 1)) $TARGET_VERSION); do
for i in $(seq $CURRENT_VERSION $((TARGET_VERSION - 1))); do
if [ -f "/migrations/$i" ]; then
echo "Running migration $i"
chmod +x /migrations/$i

View File

@@ -0,0 +1,22 @@
---
apiVersion: cozystack.io/v1alpha1
kind: PackageSource
metadata:
name: cozystack.cozystack-gateway
spec:
sourceRef:
kind: OCIRepository
name: cozystack-packages
namespace: cozy-system
path: /
variants:
- name: default
dependsOn:
- cozystack.networking
- cozystack.cert-manager
components:
- name: cozystack-gateway
path: system/cozystack-gateway
install:
namespace: cozy-gateway
releaseName: cozystack-gateway

View File

@@ -0,0 +1,29 @@
---
apiVersion: cozystack.io/v1alpha1
kind: PackageSource
metadata:
name: cozystack.external-dns-application
spec:
sourceRef:
kind: OCIRepository
name: cozystack-packages
namespace: cozy-system
path: /
variants:
- name: default
dependsOn:
- cozystack.networking
libraries:
- name: cozy-lib
path: library/cozy-lib
components:
- name: external-dns-system
path: system/external-dns
- name: external-dns
path: extra/external-dns
libraries: ["cozy-lib"]
- name: external-dns-rd
path: system/external-dns-rd
install:
namespace: cozy-system
releaseName: external-dns-rd

View File

@@ -15,6 +15,12 @@ spec:
- name: cilium
dependsOn: []
components:
- name: gateway-api-crds
path: system/gateway-api-crds
install:
namespace: cozy-gateway-api-crds
releaseName: gateway-api-crds
dependsOn: []
- name: cilium
path: system/cilium
valuesFiles:
@@ -24,7 +30,8 @@ spec:
privileged: true
namespace: cozy-cilium
releaseName: cilium
dependsOn: []
dependsOn:
- gateway-api-crds
- name: cilium-networkpolicy
path: system/cilium-networkpolicy
install:
@@ -36,6 +43,12 @@ spec:
- name: cilium-kilo
dependsOn: []
components:
- name: gateway-api-crds
path: system/gateway-api-crds
install:
namespace: cozy-gateway-api-crds
releaseName: gateway-api-crds
dependsOn: []
- name: cilium
path: system/cilium
valuesFiles:
@@ -46,7 +59,8 @@ spec:
privileged: true
namespace: cozy-cilium
releaseName: cilium
dependsOn: []
dependsOn:
- gateway-api-crds
- name: kilo
path: system/kilo
valuesFiles:
@@ -62,6 +76,12 @@ spec:
- name: cilium-generic
dependsOn: []
components:
- name: gateway-api-crds
path: system/gateway-api-crds
install:
namespace: cozy-gateway-api-crds
releaseName: gateway-api-crds
dependsOn: []
- name: cilium
path: system/cilium
valuesFiles:
@@ -70,7 +90,8 @@ spec:
privileged: true
namespace: cozy-cilium
releaseName: cilium
dependsOn: []
dependsOn:
- gateway-api-crds
- name: cilium-networkpolicy
path: system/cilium-networkpolicy
install:
@@ -82,6 +103,12 @@ spec:
- name: kubeovn-cilium
dependsOn: []
components:
- name: gateway-api-crds
path: system/gateway-api-crds
install:
namespace: cozy-gateway-api-crds
releaseName: gateway-api-crds
dependsOn: []
- name: cilium
path: system/cilium
valuesFiles:
@@ -92,7 +119,8 @@ spec:
privileged: true
namespace: cozy-cilium
releaseName: cilium
dependsOn: []
dependsOn:
- gateway-api-crds
- name: cilium-networkpolicy
path: system/cilium-networkpolicy
install:
@@ -113,6 +141,12 @@ spec:
- name: kubeovn-cilium-generic
dependsOn: []
components:
- name: gateway-api-crds
path: system/gateway-api-crds
install:
namespace: cozy-gateway-api-crds
releaseName: gateway-api-crds
dependsOn: []
- name: cilium
path: system/cilium
valuesFiles:
@@ -122,7 +156,8 @@ spec:
privileged: true
namespace: cozy-cilium
releaseName: cilium
dependsOn: []
dependsOn:
- gateway-api-crds
- name: cilium-networkpolicy
path: system/cilium-networkpolicy
install:

View File

@@ -39,6 +39,13 @@ stringData:
scheduling:
{{- . | toYaml | nindent 8 }}
{{- end }}
gateway-api: {{ .Values.gateway.gatewayAPI | quote }}
gateway-name: {{ .Values.gateway.name | quote }}
gateway-namespace: {{ .Values.gateway.namespace | quote }}
{{- with .Values.publishing.hostnames }}
hostnames:
{{- . | toYaml | nindent 8 }}
{{- end }}
{{- with $kubeRootCa.data }}
kube-root-ca: {{ index . "ca.crt" | b64enc | quote }}
{{- end }}

View File

@@ -16,10 +16,14 @@
{{- $kubeovnValues := dict "kube-ovn" $kubeovnDict -}}
{{- $_ := set $networkingComponents "kubeovn" (dict "values" $kubeovnValues) -}}
{{- /* For Talos (isp-full): use KubePrism endpoint and disable cgroup autoMount */ -}}
{{- $ciliumValues := dict "cilium" (dict
{{- $ciliumDict := dict
"k8sServiceHost" "localhost"
"k8sServicePort" "7445"
"cgroup" (dict "autoMount" (dict "enabled" false))) -}}
"cgroup" (dict "autoMount" (dict "enabled" false)) -}}
{{- if .Values.gateway.gatewayAPI -}}
{{- $_ := set $ciliumDict "gatewayAPI" (dict "enabled" true) -}}
{{- end -}}
{{- $ciliumValues := dict "cilium" $ciliumDict -}}
{{- $_ := set $networkingComponents "cilium" (dict "values" $ciliumValues) -}}
{{- end -}}
{{include "cozystack.platform.package" (list "cozystack.networking" "kubeovn-cilium" $ $networkingComponents) }}
@@ -83,10 +87,14 @@
{{- $kubeovnValues := dict "kube-ovn" $kubeovnDict -}}
{{- $_ := set $networkingComponents "kubeovn" (dict "values" $kubeovnValues) -}}
{{- /* Cilium configuration - for generic k8s, always enable cgroup autoMount */ -}}
{{- $ciliumValues := dict "cilium" (dict
{{- $ciliumDict := dict
"k8sServiceHost" $apiHost
"k8sServicePort" $apiPort
"cgroup" (dict "autoMount" (dict "enabled" true))) -}}
"cgroup" (dict "autoMount" (dict "enabled" true)) -}}
{{- if .Values.gateway.gatewayAPI -}}
{{- $_ := set $ciliumDict "gatewayAPI" (dict "enabled" true) -}}
{{- end -}}
{{- $ciliumValues := dict "cilium" $ciliumDict -}}
{{- $_ := set $networkingComponents "cilium" (dict "values" $ciliumValues) -}}
{{- end -}}
{{- /* Use kubeovn-cilium-generic variant (no values-talos.yaml) */ -}}
@@ -118,7 +126,15 @@
{{- end }}
# Common Packages
{{include "cozystack.platform.package.default" (list "cozystack.cert-manager" $) }}
{{- $certManagerComponents := dict -}}
{{- if .Values.gateway.gatewayAPI -}}
{{- $certManagerValues := dict "cert-manager" (dict "config" (dict "enableGatewayAPI" true)) -}}
{{- $_ := set $certManagerComponents "cert-manager" (dict "values" $certManagerValues) -}}
{{- end -}}
{{include "cozystack.platform.package" (list "cozystack.cert-manager" "default" $ $certManagerComponents) }}
{{- if .Values.gateway.gatewayAPI }}
{{include "cozystack.platform.package.default" (list "cozystack.cozystack-gateway" $) }}
{{- end }}
{{include "cozystack.platform.package.default" (list "cozystack.flux-plunger" $) }}
{{include "cozystack.platform.package.default" (list "cozystack.victoria-metrics-operator" $) }}
{{- $tenantComponents := dict -}}
@@ -148,7 +164,17 @@
# Optional System Packages (controlled via bundles.enabledPackages)
{{include "cozystack.platform.package.optional.default" (list "cozystack.nfs-driver" $) }}
{{include "cozystack.platform.package.optional.default" (list "cozystack.telepresence" $) }}
{{include "cozystack.platform.package.optional.default" (list "cozystack.external-dns" $) }}
{{- $externalDnsComponents := dict -}}
{{- if .Values.gateway.gatewayAPI -}}
{{- $externalDnsValues := dict "external-dns" (dict "sources" (list "service" "ingress" "gateway-httproute")) -}}
{{- $_ := set $externalDnsComponents "external-dns" (dict "values" $externalDnsValues) -}}
{{- end -}}
{{- $disabled := default (list) .Values.bundles.disabledPackages -}}
{{- $enabled := default (list) .Values.bundles.enabledPackages -}}
{{- if and (has "cozystack.external-dns" $enabled) (not (has "cozystack.external-dns" $disabled)) -}}
{{include "cozystack.platform.package" (list "cozystack.external-dns" "default" $ $externalDnsComponents) }}
{{- end }}
{{include "cozystack.platform.package.optional.default" (list "cozystack.external-dns-application" $) }}
{{include "cozystack.platform.package.optional.default" (list "cozystack.external-secrets-operator" $) }}
{{- if has "cozystack.bootbox" (default (list) .Values.bundles.enabledPackages) }}
{{include "cozystack.platform.package.default" (list "cozystack.bootbox-application" $) }}

View File

@@ -5,8 +5,8 @@ sourceRef:
path: /
migrations:
enabled: false
image: ghcr.io/cozystack/cozystack/platform-migrations:v1.0.0@sha256:68dabdebc38ac439228ae07031cc70e0fa184a24bd4e5b3b22c17466b2a55201
targetVersion: 34
image: ghcr.io/cozystack/cozystack/platform-migrations:v1.1.0@sha256:d7e8955c1ad8c8fbd4ce42b014c0f849d73d0c3faf0cedaac8e15d647fb2f663
targetVersion: 36
# Bundle deployment configuration
bundles:
system:
@@ -34,6 +34,16 @@ networking:
# Set this to comma-separated list of master node IPs to override.
kubeovn:
MASTER_NODES: ""
# Gateway configuration
# ingress and gatewayAPI can be enabled independently;
# future work will wire gateway.ingress into ingress controller selection
gateway:
ingress: true
gatewayAPI: false
# Gateway name and namespace for system-level Gateway resource
# Components reference this Gateway via parentRefs
name: cozystack
namespace: cozy-gateway
# Service publishing and ingress configuration
publishing:
host: "example.org"
@@ -43,6 +53,15 @@ publishing:
- dashboard
- vm-exportproxy
- cdi-uploadproxy
# Hostname overrides for system services
# By default, hostname = {service-name}.{host}
# Override individual hostnames when the convention doesn't fit
#
# Example:
# hostnames:
# keycloak: "auth.example.org"
# dashboard: "panel.example.org"
hostnames: {}
apiServerEndpoint: "" # example: "https://api.example.org"
externalIPs: []
certificates:

View File

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

View File

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

View File

@@ -0,0 +1,75 @@
{{- $gatewayAPI := (index .Values._cluster "gateway-api") | default "false" }}
{{- $clusterIssuer := (index .Values._cluster "issuer-name") | default "letsencrypt-prod" }}
{{- $gateway := .Values._namespace.gateway | default "" }}
{{- $host := .Values._namespace.host }}
{{- $bootboxHost := printf "bootbox.%s" (.Values.host | default $host) }}
{{- if and (eq $gatewayAPI "true") (ne $gateway "") }}
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: bootbox
annotations:
cert-manager.io/cluster-issuer: {{ $clusterIssuer }}
spec:
gatewayClassName: cilium
infrastructure:
labels:
cozystack.io/gateway: {{ $gateway }}
listeners:
- name: http
protocol: HTTP
port: 80
hostname: {{ $bootboxHost | quote }}
allowedRoutes:
namespaces:
from: Same
- name: https
protocol: HTTPS
port: 443
hostname: {{ $bootboxHost | quote }}
tls:
mode: Terminate
certificateRefs:
- name: bootbox-gateway-tls
allowedRoutes:
namespaces:
from: Same
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: bootbox-redirect-to-https
spec:
parentRefs:
- name: bootbox
sectionName: http
hostnames:
- {{ $bootboxHost | quote }}
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: bootbox
spec:
parentRefs:
- name: bootbox
sectionName: https
hostnames:
- {{ $bootboxHost | quote }}
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: bootbox
port: 8080
{{- end }}

View File

@@ -104,6 +104,7 @@ spec:
- {{ .Release.Name }}
secretName: etcd-peer-ca-tls
privateKey:
rotationPolicy: Never
algorithm: RSA
size: 4096
issuerRef:
@@ -130,6 +131,7 @@ spec:
- {{ .Release.Name }}
secretName: etcd-ca-tls
privateKey:
rotationPolicy: Never
algorithm: RSA
size: 4096
issuerRef:

View File

@@ -0,0 +1,6 @@
apiVersion: v2
name: external-dns
description: External DNS for automatic DNS record management
icon: /logos/external-dns.svg
type: application
version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process

View File

@@ -0,0 +1,7 @@
NAME=external-dns
include ../../../hack/package.mk
generate:
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
../../../hack/update-crd.sh

View File

@@ -0,0 +1,88 @@
# External DNS
## Parameters
### Common parameters
| Name | Description | Type | Value |
| ------------------ | ---------------------------------------------------------------------------------- | ---------- | ------------- |
| `provider` | DNS provider name. | `string` | `{}` |
| `domainFilters` | List of domains this external-dns instance can manage. | `[]string` | `[]` |
| `policy` | How DNS records are synchronized. | `string` | `upsert-only` |
| `extraArgs` | Extra arguments for external-dns. | `[]string` | `[]` |
| `gatewayAPI` | Enable Gateway API HTTPRoute as a source for DNS records. | `bool` | `false` |
| `annotationPrefix` | Custom annotation prefix for external-dns (useful for running multiple instances). | `string` | `""` |
### Cloudflare
| Name | Description | Type | Value |
| ------------ | -------------------------------- | -------- | ----------------------------------------------------------- |
| `cloudflare` | Cloudflare provider credentials. | `object` | `{"apiEmail":"","apiKey":"","apiToken":"","proxied":false}` |
### AWS
| Name | Description | Type | Value |
| ----- | --------------------------------- | -------- | ------------------------------------------------------------------- |
| `aws` | AWS Route53 provider credentials. | `object` | `{"accessKeyId":"","region":"","secretAccessKey":"","zoneType":""}` |
### Azure
| Name | Description | Type | Value |
| ------- | ------------------------------- | -------- | ---------------------------------------------------------------------------------------------- |
| `azure` | Azure DNS provider credentials. | `object` | `{"aadClientId":"","aadClientSecret":"","resourceGroup":"","subscriptionId":"","tenantId":""}` |
### Google
| Name | Description | Type | Value |
| -------- | -------------------------------------- | -------- | --------------------------------------- |
| `google` | Google Cloud DNS provider credentials. | `object` | `{"project":"","serviceAccountKey":""}` |
### DigitalOcean
| Name | Description | Type | Value |
| -------------- | -------------------------------------- | -------- | -------------- |
| `digitalocean` | DigitalOcean DNS provider credentials. | `object` | `{"token":""}` |
### Linode
| Name | Description | Type | Value |
| -------- | -------------------------------- | -------- | -------------- |
| `linode` | Linode DNS provider credentials. | `object` | `{"token":""}` |
### OVH
| Name | Description | Type | Value |
| ----- | ----------------------------- | -------- | ----------------------------------------------------------------------------- |
| `ovh` | OVH DNS provider credentials. | `object` | `{"applicationKey":"","applicationSecret":"","consumerKey":"","endpoint":""}` |
### Exoscale
| Name | Description | Type | Value |
| ---------- | ---------------------------------- | -------- | ------------------------------ |
| `exoscale` | Exoscale DNS provider credentials. | `object` | `{"apiKey":"","apiSecret":""}` |
### GoDaddy
| Name | Description | Type | Value |
| --------- | --------------------------------- | -------- | ------------------------------ |
| `godaddy` | GoDaddy DNS provider credentials. | `object` | `{"apiKey":"","apiSecret":""}` |
### Resources
| Name | Description | Type | Value |
| ------------------ | -------------------------------------------------------------------------------------------------------- | ---------- | ------ |
| `resources` | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
| `resources.cpu` | CPU available to each replica. | `quantity` | `""` |
| `resources.memory` | Memory (RAM) available to each replica. | `quantity` | `""` |
| `resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `nano` |

View File

@@ -0,0 +1 @@
../../../library/cozy-lib

View File

@@ -0,0 +1,23 @@
{
"comments": {
"format": "##"
},
"tags": {
"param": "@param",
"section": "@section",
"descriptionStart": "@descriptionStart",
"descriptionEnd": "@descriptionEnd",
"skip": "@skip",
"extra": "@extra"
},
"modifiers": {
"array": "array",
"object": "object",
"string": "string",
"nullable": "nullable",
"default": "default"
},
"regexp": {
"paramsSectionTitle": "Parameters"
}
}

View File

@@ -0,0 +1,20 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 144 144" width="144" height="144">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#3B82F6"/>
<stop offset="100%" style="stop-color:#1D4ED8"/>
</linearGradient>
</defs>
<rect width="144" height="144" rx="28" fill="url(#bg)"/>
<g transform="translate(72,72)" fill="none" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round">
<!-- Globe -->
<circle cx="0" cy="-4" r="32"/>
<ellipse cx="0" cy="-4" rx="14" ry="32"/>
<line x1="-32" y1="-4" x2="32" y2="-4"/>
<path d="M-28,12 Q0,18 28,12"/>
<path d="M-28,-20 Q0,-14 28,-20"/>
<!-- Arrow pointing out -->
<line x1="18" y1="18" x2="36" y2="36"/>
<polyline points="28,36 36,36 36,28"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 840 B

View File

@@ -0,0 +1,23 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ .Release.Name }}-dashboard-resources
rules:
- apiGroups:
- helm.toolkit.fluxcd.io
resources:
- helmreleases
resourceNames:
- {{ .Release.Name }}
verbs: ["get", "list", "watch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: {{ .Release.Name }}-dashboard-resources
subjects:
{{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "admin" .Release.Namespace) }}
roleRef:
kind: Role
name: {{ .Release.Name }}-dashboard-resources
apiGroup: rbac.authorization.k8s.io

View File

@@ -0,0 +1,169 @@
{{- if not .Values.provider }}
{{- fail "provider is required: set it to one of cloudflare, aws, azure, google, digitalocean, linode, ovh, exoscale, godaddy, inmemory" }}
{{- end }}
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: {{ .Release.Name }}-system
labels:
app.kubernetes.io/instance: {{ .Release.Name }}-system
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
chartRef:
kind: ExternalArtifact
name: cozystack-external-dns-application-default-external-dns-system
namespace: cozy-system
interval: 5m
timeout: 10m
install:
remediation:
retries: -1
upgrade:
force: true
remediation:
retries: -1
values:
external-dns:
namespaced: true
txtOwnerId: {{ .Release.Namespace | quote }}
policy: {{ .Values.policy | quote }}
{{- if .Values.annotationPrefix }}
annotationPrefix: {{ .Values.annotationPrefix | quote }}
{{- end }}
provider:
name: {{ .Values.provider | quote }}
sources:
- ingress
- service
{{- if .Values.gatewayAPI }}
- gateway-httproute
{{- end }}
{{- with .Values.domainFilters }}
domainFilters:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- /* Provider-specific credentials and config */}}
{{- if eq .Values.provider "cloudflare" }}
{{- if or .Values.cloudflare.apiToken (and .Values.cloudflare.apiKey .Values.cloudflare.apiEmail) }}
env:
{{- if .Values.cloudflare.apiToken }}
- name: CF_API_TOKEN
value: {{ .Values.cloudflare.apiToken | quote }}
{{- else }}
- name: CF_API_KEY
value: {{ .Values.cloudflare.apiKey | quote }}
- name: CF_API_EMAIL
value: {{ .Values.cloudflare.apiEmail | quote }}
{{- end }}
{{- end }}
{{- if .Values.cloudflare.proxied }}
cloudflare:
proxied: true
{{- end }}
{{- end }}
{{- if eq .Values.provider "aws" }}
{{- if or .Values.aws.accessKeyId .Values.aws.secretAccessKey .Values.aws.region }}
env:
{{- if .Values.aws.accessKeyId }}
- name: AWS_ACCESS_KEY_ID
value: {{ .Values.aws.accessKeyId | quote }}
{{- end }}
{{- if .Values.aws.secretAccessKey }}
- name: AWS_SECRET_ACCESS_KEY
value: {{ .Values.aws.secretAccessKey | quote }}
{{- end }}
{{- if .Values.aws.region }}
- name: AWS_DEFAULT_REGION
value: {{ .Values.aws.region | quote }}
{{- end }}
{{- end }}
{{- if .Values.aws.zoneType }}
aws:
zoneType: {{ .Values.aws.zoneType | quote }}
{{- end }}
{{- end }}
{{- if eq .Values.provider "azure" }}
{{- if or .Values.azure.tenantId .Values.azure.subscriptionId .Values.azure.resourceGroup .Values.azure.aadClientId .Values.azure.aadClientSecret }}
azure:
tenantId: {{ .Values.azure.tenantId | quote }}
subscriptionId: {{ .Values.azure.subscriptionId | quote }}
resourceGroup: {{ .Values.azure.resourceGroup | quote }}
aadClientId: {{ .Values.azure.aadClientId | quote }}
aadClientSecret: {{ .Values.azure.aadClientSecret | quote }}
{{- end }}
{{- end }}
{{- if eq .Values.provider "digitalocean" }}
{{- if .Values.digitalocean.token }}
env:
- name: DO_TOKEN
value: {{ .Values.digitalocean.token | quote }}
{{- end }}
{{- end }}
{{- if eq .Values.provider "google" }}
{{- if or .Values.google.project .Values.google.serviceAccountKey }}
google:
project: {{ .Values.google.project | quote }}
{{- if .Values.google.serviceAccountKey }}
serviceAccountKey: {{ .Values.google.serviceAccountKey | quote }}
{{- end }}
{{- end }}
{{- end }}
{{- if eq .Values.provider "linode" }}
{{- if .Values.linode.token }}
env:
- name: LINODE_TOKEN
value: {{ .Values.linode.token | quote }}
{{- end }}
{{- end }}
{{- if eq .Values.provider "ovh" }}
{{- if or .Values.ovh.endpoint .Values.ovh.applicationKey .Values.ovh.applicationSecret .Values.ovh.consumerKey }}
env:
- name: OVH_ENDPOINT
value: {{ .Values.ovh.endpoint | quote }}
- name: OVH_APPLICATION_KEY
value: {{ .Values.ovh.applicationKey | quote }}
- name: OVH_APPLICATION_SECRET
value: {{ .Values.ovh.applicationSecret | quote }}
- name: OVH_CONSUMER_KEY
value: {{ .Values.ovh.consumerKey | quote }}
{{- end }}
{{- end }}
{{- if eq .Values.provider "exoscale" }}
{{- if or .Values.exoscale.apiKey .Values.exoscale.apiSecret }}
env:
- name: EXOSCALE_API_KEY
value: {{ .Values.exoscale.apiKey | quote }}
- name: EXOSCALE_API_SECRET
value: {{ .Values.exoscale.apiSecret | quote }}
{{- end }}
{{- end }}
{{- /* extraArgs: merge user-supplied args with provider-specific args (godaddy) */}}
{{- $godaddyArgs := list }}
{{- if eq .Values.provider "godaddy" }}
{{- if .Values.godaddy.apiKey }}
{{- $godaddyArgs = append $godaddyArgs (printf "--godaddy-api-key=%s" .Values.godaddy.apiKey) }}
{{- end }}
{{- if .Values.godaddy.apiSecret }}
{{- $godaddyArgs = append $godaddyArgs (printf "--godaddy-api-secret=%s" .Values.godaddy.apiSecret) }}
{{- end }}
{{- end }}
{{- $allArgs := concat (.Values.extraArgs | default list) $godaddyArgs }}
{{- with $allArgs }}
extraArgs:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with (include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $)) }}
resources:
{{- . | nindent 8 }}
{{- end }}

View File

@@ -0,0 +1,193 @@
{
"title": "Chart Values",
"type": "object",
"properties": {
"annotationPrefix": {
"description": "Custom annotation prefix for external-dns (useful for running multiple instances).",
"type": "string",
"default": ""
},
"aws": {
"description": "AWS Route53 provider credentials.",
"type": "object",
"default": {
"accessKeyId": "",
"region": "",
"secretAccessKey": "",
"zoneType": ""
},
"x-kubernetes-preserve-unknown-fields": true
},
"azure": {
"description": "Azure DNS provider credentials.",
"type": "object",
"default": {
"aadClientId": "",
"aadClientSecret": "",
"resourceGroup": "",
"subscriptionId": "",
"tenantId": ""
},
"x-kubernetes-preserve-unknown-fields": true
},
"cloudflare": {
"description": "Cloudflare provider credentials.",
"type": "object",
"default": {
"apiEmail": "",
"apiKey": "",
"apiToken": "",
"proxied": false
},
"x-kubernetes-preserve-unknown-fields": true
},
"digitalocean": {
"description": "DigitalOcean DNS provider credentials.",
"type": "object",
"default": {
"token": ""
},
"x-kubernetes-preserve-unknown-fields": true
},
"domainFilters": {
"description": "List of domains this external-dns instance can manage.",
"type": "array",
"default": [],
"items": {
"type": "string"
}
},
"exoscale": {
"description": "Exoscale DNS provider credentials.",
"type": "object",
"default": {
"apiKey": "",
"apiSecret": ""
},
"x-kubernetes-preserve-unknown-fields": true
},
"extraArgs": {
"description": "Extra arguments for external-dns.",
"type": "array",
"default": [],
"items": {
"type": "string"
}
},
"gatewayAPI": {
"description": "Enable Gateway API HTTPRoute as a source for DNS records.",
"type": "boolean",
"default": false
},
"godaddy": {
"description": "GoDaddy DNS provider credentials.",
"type": "object",
"default": {
"apiKey": "",
"apiSecret": ""
},
"x-kubernetes-preserve-unknown-fields": true
},
"google": {
"description": "Google Cloud DNS provider credentials.",
"type": "object",
"default": {
"project": "",
"serviceAccountKey": ""
},
"x-kubernetes-preserve-unknown-fields": true
},
"linode": {
"description": "Linode DNS provider credentials.",
"type": "object",
"default": {
"token": ""
},
"x-kubernetes-preserve-unknown-fields": true
},
"ovh": {
"description": "OVH DNS provider credentials.",
"type": "object",
"default": {
"applicationKey": "",
"applicationSecret": "",
"consumerKey": "",
"endpoint": ""
},
"x-kubernetes-preserve-unknown-fields": true
},
"policy": {
"description": "How DNS records are synchronized.",
"type": "string",
"default": "upsert-only",
"enum": [
"create-only",
"sync",
"upsert-only"
]
},
"provider": {
"description": "DNS provider name.",
"type": "string",
"enum": [
"cloudflare",
"aws",
"azure",
"google",
"digitalocean",
"linode",
"ovh",
"exoscale",
"godaddy",
"inmemory"
]
},
"resources": {
"description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.",
"type": "object",
"default": {},
"properties": {
"cpu": {
"description": "CPU available to each replica.",
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
],
"x-kubernetes-int-or-string": true
},
"memory": {
"description": "Memory (RAM) available to each replica.",
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
],
"x-kubernetes-int-or-string": true
}
}
},
"resourcesPreset": {
"description": "Default sizing preset used when `resources` is omitted.",
"type": "string",
"default": "nano",
"enum": [
"nano",
"micro",
"small",
"medium",
"large",
"xlarge",
"2xlarge"
]
}
}
}

View File

@@ -0,0 +1,149 @@
##
## @section Common parameters
##
## @enum {string} Provider - DNS provider.
## @value cloudflare
## @value aws
## @value azure
## @value google
## @value digitalocean
## @value linode
## @value ovh
## @value exoscale
## @value godaddy
## @value inmemory
## @param {Provider} provider - DNS provider name.
# provider:
## @param {[]string} domainFilters - List of domains this external-dns instance can manage.
domainFilters: []
## @enum {string} Policy - How DNS records are synchronized.
## @value create-only
## @value sync
## @value upsert-only
## @param {Policy} policy="upsert-only" - How DNS records are synchronized.
policy: "upsert-only"
## @param {[]string} extraArgs - Extra arguments for external-dns.
extraArgs: []
## @param {bool} gatewayAPI=false - Enable Gateway API HTTPRoute as a source for DNS records.
gatewayAPI: false
## @param {string} [annotationPrefix] - Custom annotation prefix for external-dns (useful for running multiple instances).
annotationPrefix: ""
##
## @section Cloudflare
##
## @param {object} cloudflare - Cloudflare provider credentials.
cloudflare:
apiToken: ""
apiKey: ""
apiEmail: ""
proxied: false
##
## @section AWS
##
## @param {object} aws - AWS Route53 provider credentials.
aws:
accessKeyId: ""
secretAccessKey: ""
region: ""
zoneType: ""
##
## @section Azure
##
## @param {object} azure - Azure DNS provider credentials.
azure:
tenantId: ""
subscriptionId: ""
resourceGroup: ""
aadClientId: ""
aadClientSecret: ""
##
## @section Google
##
## @param {object} google - Google Cloud DNS provider credentials.
google:
project: ""
serviceAccountKey: ""
##
## @section DigitalOcean
##
## @param {object} digitalocean - DigitalOcean DNS provider credentials.
digitalocean:
token: ""
##
## @section Linode
##
## @param {object} linode - Linode DNS provider credentials.
linode:
token: ""
##
## @section OVH
##
## @param {object} ovh - OVH DNS provider credentials.
ovh:
endpoint: ""
applicationKey: ""
applicationSecret: ""
consumerKey: ""
##
## @section Exoscale
##
## @param {object} exoscale - Exoscale DNS provider credentials.
exoscale:
apiKey: ""
apiSecret: ""
##
## @section GoDaddy
##
## @param {object} godaddy - GoDaddy DNS provider credentials.
godaddy:
apiKey: ""
apiSecret: ""
##
## @section Resources
##
## @typedef {struct} Resources - Explicit CPU and memory configuration.
## @field {quantity} [cpu] - CPU available to each replica.
## @field {quantity} [memory] - Memory (RAM) available to each replica.
## @enum {string} ResourcesPreset - Default sizing preset.
## @value nano
## @value micro
## @value small
## @value medium
## @value large
## @value xlarge
## @value 2xlarge
## @param {Resources} [resources] - Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.
resources: {}
## @param {ResourcesPreset} resourcesPreset="nano" - Default sizing preset used when `resources` is omitted.
resourcesPreset: "nano"

View File

@@ -42,7 +42,9 @@ rules:
- {{ .name }}-vminsert
{{- end }}
{{- range .Values.logsStorages }}
- {{ $.Release.Name }}-vlogs-{{ .name }}
- {{ .name }}-vlstorage
- {{ .name }}-vlselect
- {{ .name }}-vlinsert
{{- end }}
{{- range .Values.metricsStorages }}
- vmalert-{{ .name }}

View File

@@ -67,16 +67,46 @@ spec:
apiVersion: cozystack.io/v1alpha1
kind: WorkloadMonitor
metadata:
name: vlogs-{{ .name }}
name: {{ .name }}-vlstorage
spec:
replicas: 1
replicas: 2
minReplicas: 1
kind: monitoring
type: vlogs
type: vlstorage
selector:
app.kubernetes.io/component: monitoring
app.kubernetes.io/instance: {{ .name }}
app.kubernetes.io/name: vlogs
app.kubernetes.io/name: vlstorage
version: {{ $.Chart.Version }}
---
apiVersion: cozystack.io/v1alpha1
kind: WorkloadMonitor
metadata:
name: {{ .name }}-vlselect
spec:
replicas: 2
minReplicas: 1
kind: monitoring
type: vlselect
selector:
app.kubernetes.io/component: monitoring
app.kubernetes.io/instance: {{ .name }}
app.kubernetes.io/name: vlselect
version: {{ $.Chart.Version }}
---
apiVersion: cozystack.io/v1alpha1
kind: WorkloadMonitor
metadata:
name: {{ .name }}-vlinsert
spec:
replicas: 2
minReplicas: 1
kind: monitoring
type: vlinsert
selector:
app.kubernetes.io/component: monitoring
app.kubernetes.io/instance: {{ .name }}
app.kubernetes.io/name: vlinsert
version: {{ $.Chart.Version }}
{{- end }}
---

View File

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

View File

@@ -7,10 +7,32 @@ 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 "-worm" $poolName) (hasSuffix "-readonly" $poolName) }}
{{- fail (printf "volume.pools key '%s' must not end with '-worm' or '-readonly' (reserved suffixes for COSI resources)." $poolName) }}
{{- 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) }}
{{- 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 "-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) }}
{{- 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) }}
{{- 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 }}-worm
name: {{ $.Release.Namespace }}-{{ $poolName }}-lock
driverName: {{ $.Release.Namespace }}.seaweedfs.objectstorage.k8s.io
deletionPolicy: Retain
parameters:
disk: {{ $diskType }}
objectLockEnabled: "true"
objectLockRetentionMode: COMPLIANCE
objectLockRetentionDays: "36500"
objectLockRetentionMode: "COMPLIANCE"
objectLockRetentionDays: "365"
---
kind: BucketAccessClass
apiVersion: objectstorage.k8s.io/v1alpha1

View File

@@ -0,0 +1,41 @@
{{- $gatewayAPI := (index .Values._cluster "gateway-api") | default "false" }}
{{- $gateway := .Values._namespace.gateway | default "" }}
{{- $host := .Values._namespace.host }}
{{- if and (eq $gatewayAPI "true") (ne $gateway "") (not (eq .Values.topology "Client")) (.Values.filer.grpcHost) }}
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: seaweedfs-filer
spec:
gatewayClassName: cilium
infrastructure:
labels:
cozystack.io/gateway: {{ $gateway }}
listeners:
- name: tls-passthrough
protocol: TLS
port: 443
hostname: {{ .Values.filer.grpcHost | default (printf "filer.%s" $host) | quote }}
tls:
mode: Passthrough
allowedRoutes:
namespaces:
from: Same
---
apiVersion: gateway.networking.k8s.io/v1
kind: TLSRoute
metadata:
name: seaweedfs-filer
spec:
parentRefs:
- name: seaweedfs-filer
sectionName: tls-passthrough
hostnames:
- {{ .Values.filer.grpcHost | default (printf "filer.%s" $host) | quote }}
rules:
- backendRefs:
- name: {{ $.Release.Name }}-filer-external
port: 18888
{{- end }}

View File

@@ -3,30 +3,14 @@ apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: backups.cozystack.io:core-controller
rules:
# Plan: reconcile schedule and update status
- apiGroups: ["backups.cozystack.io"]
resources: ["plans"]
verbs: ["get", "list", "watch"]
- apiGroups: ["backups.cozystack.io"]
resources: ["backupjobs"]
verbs: ["create", "get", "list", "watch", "update", "patch"]
- apiGroups: ["backups.cozystack.io"]
resources: ["backupjobs/status"]
resources: ["plans/status"]
verbs: ["get", "update", "patch"]
# BackupJob: create when schedule fires (status is updated by backupstrategy-controller)
- apiGroups: ["backups.cozystack.io"]
resources: ["backups"]
resources: ["backupjobs"]
verbs: ["create", "get", "list", "watch"]
- apiGroups: ["apps.cozystack.io"]
resources: ["buckets", "bucketaccesses", "virtualmachines"]
verbs: ["get", "list", "watch"]
- apiGroups: ["objectstorage.k8s.io"]
resources: ["buckets", "bucketaccesses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["create", "get", "list", "watch", "update", "patch"]
- apiGroups: ["kubevirt.io"]
resources: ["virtualmachines"]
verbs: ["get", "list", "watch"]
- apiGroups: ["velero.io"]
resources: ["backups", "backupstoragelocations", "volumesnapshotlocations", "restores"]
verbs: ["create", "get", "list", "watch", "update", "patch"]

View File

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

View File

@@ -3,9 +3,34 @@ apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: backups.cozystack.io:strategy-controller
rules:
# Strategy types (Velero, Job)
- apiGroups: ["strategy.backups.cozystack.io"]
resources: ["*"]
verbs: ["get", "list", "watch"]
# BackupClass: resolve strategy per application
- apiGroups: ["backups.cozystack.io"]
resources: ["backupclasses"]
verbs: ["get", "list", "watch"]
# BackupJob / RestoreJob: reconcile and update status
- apiGroups: ["backups.cozystack.io"]
resources: ["backupjobs", "restorejobs"]
verbs: ["get", "list", "watch"]
- apiGroups: ["backups.cozystack.io"]
resources: ["backupjobs/status", "restorejobs/status"]
verbs: ["get", "update", "patch"]
# Backup: create after Velero backup completes
- apiGroups: ["backups.cozystack.io"]
resources: ["backups"]
verbs: ["create", "get", "list", "watch"]
# Application refs (e.g. VMInstance, VirtualMachine) for backup/restore scope
- apiGroups: ["apps.cozystack.io"]
resources: ["*"]
verbs: ["get", "list", "watch"]
# Velero Backup/Restore in cozy-velero namespace
- apiGroups: ["velero.io"]
resources: ["backups", "restores"]
verbs: ["create", "get", "list", "watch", "update", "patch"]
# Leader election (--leader-elect)
- apiGroups: ["coordination.k8s.io"]
resources: ["leases"]
verbs: ["get", "list", "watch", "create", "update", "patch"]

View File

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

View File

@@ -8,7 +8,7 @@ spec:
plural: buckets
singular: bucket
openAPISchema: |-
{"title":"Chart Values","type":"object","properties":{}}
{"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"}}}}}}
release:
prefix: bucket-
labels:
@@ -26,14 +26,14 @@ spec:
tags:
- storage
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODNfMzA5MSkiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik03MiAzMC4xNjQxTDExNy45ODMgMzYuNzc4OVY0MC42NzM5QzExNy45ODMgNDYuNDY1MyA5Ny4zODYyIDUxLjEzMzIgNzEuOTgyNyA1MS4xMzMyQzQ2LjU3OTIgNTEuMTMzMiAyNiA0Ni40NjUzIDI2IDQwLjY3MzlWMzYuNDQzMUw3MiAzMC4xNjQxWk03MiA1OC4yNjc4QzkxLjIwODQgNTguMjY3OCAxMDcuNjU4IDU1LjU5ODYgMTE0LjU0NyA1MS44MDQ4TDExNi44MDMgNDguMTExTDExNy43MjMgNDQuNzUzVjQ4LjkxNzFMMTAyLjY3OSAxMTEuMDMzQzEwMi42NzkgMTE0Ljg5NSA4OC45NTMzIDExOCA3Mi4wMTcyIDExOEM1NS4wODEyIDExOCA0MS4zNzQzIDExNC44OTUgNDEuMzc0MyAxMTEuMDMzTDI2LjMzIDQ4LjkxNzFWNDQuODM2OUwyOS44MDA3IDUxLjkzODJDMzYuNzA2NSA1NS42NjUzIDUyLjk5OTcgNTguMjY3OCA3MiA1OC4yNjc4WiIgZmlsbD0iIzhDMzEyMyIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTcyLjAwMDMgMjZDOTcuNDAzOCAyNiAxMTggMzAuNjgzOSAxMTggMzYuNDQyQzExOCA0Mi4yIDk3LjM4NjYgNDYuODUwNyA3Mi4wMDAzIDQ2Ljg1MDdDNDYuNjE0MSA0Ni44NTA3IDI2LjAxNzYgNDIuMjM0NSAyNi4wMTc2IDM2LjQ0MkMyNi4wMTc2IDMwLjY0OTQgNDYuNTk2OCAyNiA3Mi4wMDAzIDI2Wk03Mi4wMDAzIDU0LjEwMzdDOTUuNjg1NyA1NC4xMDM3IDExNS4xNzIgNTAuMDU4IDExNy43MDYgNDQuODE5N0wxMDIuNjYyIDEwNi45MzdDMTAyLjY2MiAxMTAuNzk5IDg4LjkzNjQgMTEzLjkwNSA3Mi4wMDAzIDExMy45MDVDNTUuMDY0MyAxMTMuOTA1IDQxLjMzOSAxMTAuODE2IDQxLjMzOSAxMDYuOTU0TDI2LjI5NTkgNDQuODM3QzI4Ljg0NjYgNTAuMDU4IDQ4LjMzMzMgNTQuMTAzNyA3Mi4wMDAzIDU0LjEwMzdaIiBmaWxsPSIjRTA1MjQzIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNjEuMTcyNSA2MC4wMjkzSDgxLjA5MjhWNzkuMTY3Nkg2MS4xNzI1VjYwLjAyOTNaTTQ1LjMzMDEgOTUuMzY4OEM0NS4zMzAxIDkwLjE0MiA0OS43MTA0IDg1LjkzNDIgNTUuMTUxMSA4NS45MzQyQzYwLjU5MTcgODUuOTM0MiA2NC45NzIxIDkwLjE0MiA2NC45NzIxIDk1LjM2ODhDNjQuOTcyMSAxMDAuNTk2IDYwLjU5MTcgMTA0LjgwMyA1NS4xNTExIDEwNC44MDNDNDkuNzEwNCAxMDQuODAzIDQ1LjMzMDEgMTAwLjU5NiA0NS4zMzAxIDk1LjM2ODhaTTk2LjQ0ODcgMTA0LjM2OEg3Ni43NzIyTDg2LjYxMDUgODYuNzczN0w5Ni40NDg3IDEwNC4zNjhaIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4M18zMDkxIiB4MT0iMCIgeTE9IjAiIHgyPSIxNTEiIHkyPSIxODAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0ZGRjBFRSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNFQzg4N0QiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"]]
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "locking"], ["spec", "storagePool"], ["spec", "users"]]
secrets:
exclude: []
include:
- resourceNames:
- bucket-{{ .name }}
- bucket-{{ .name }}-credentials
- bucket-{{ .name }}-readonly
- matchLabels:
apps.cozystack.io/user-secret: "true"
ingresses:
exclude: []
include:

View File

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

View File

@@ -9,6 +9,7 @@ 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,3 +1,235 @@
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
@@ -24,3 +256,298 @@ 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,19 +17,6 @@ spec:
image: "{{ $.Files.Get "images/s3manager.tag" | trim }}"
env:
- name: ENDPOINT
valueFrom:
secretKeyRef:
name: {{ .Values.bucketName }}-credentials
key: endpoint
value: "s3.{{ .Values._namespace.host }}"
- 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

@@ -0,0 +1,75 @@
{{- $gatewayAPI := (index .Values._cluster "gateway-api") | default "false" }}
{{- $clusterIssuer := (index .Values._cluster "issuer-name") | default "letsencrypt-prod" }}
{{- $gateway := .Values._namespace.gateway | default "" }}
{{- $host := .Values._namespace.host }}
{{- $bucketHost := printf "%s.%s" .Values.bucketName $host }}
{{- if and (eq $gatewayAPI "true") (ne $gateway "") }}
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: {{ .Values.bucketName }}-ui
annotations:
cert-manager.io/cluster-issuer: {{ $clusterIssuer }}
spec:
gatewayClassName: cilium
infrastructure:
labels:
cozystack.io/gateway: {{ $gateway }}
listeners:
- name: http
protocol: HTTP
port: 80
hostname: {{ $bucketHost | quote }}
allowedRoutes:
namespaces:
from: Same
- name: https
protocol: HTTPS
port: 443
hostname: {{ $bucketHost | quote }}
tls:
mode: Terminate
certificateRefs:
- name: {{ .Values.bucketName }}-ui-gateway-tls
allowedRoutes:
namespaces:
from: Same
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: {{ .Values.bucketName }}-ui-redirect-to-https
spec:
parentRefs:
- name: {{ .Values.bucketName }}-ui
sectionName: http
hostnames:
- {{ $bucketHost | quote }}
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: {{ .Values.bucketName }}-ui
spec:
parentRefs:
- name: {{ .Values.bucketName }}-ui
sectionName: https
hostnames:
- {{ $bucketHost | quote }}
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: {{ .Values.bucketName }}-ui
port: 8080
{{- end }}

View File

@@ -8,9 +8,6 @@ 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,24 +1,2 @@
{{- $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 }}
{{/* Secrets previously used for s3manager credential injection and nginx basic auth */}}
{{/* are no longer needed — s3manager now handles authentication via its own login page */}}

View File

@@ -0,0 +1,20 @@
{{- 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 +1,2 @@
bucketName: "cozystack"
users: {}

View File

@@ -0,0 +1 @@
cert-manager: {}

View File

@@ -10,7 +10,7 @@ update:
rm -rf charts
helm repo add cilium https://helm.cilium.io/
helm repo update cilium
helm pull cilium/cilium --untar --untardir charts --version 1.18
helm pull cilium/cilium --untar --untardir charts --version 1.19
$(SED_INPLACE) -e '/Used in iptables/d' -e '/SYS_MODULE/d' charts/cilium/values.yaml
version=$$(awk '$$1 == "version:" {print $$2}' charts/cilium/Chart.yaml) && \
$(SED_INPLACE) "s/ARG VERSION=.*/ARG VERSION=v$${version}/" images/cilium/Dockerfile

View File

@@ -41,11 +41,8 @@ annotations:
namespace context.\n- kind: CiliumNodeConfig\n version: v2\n name: ciliumnodeconfigs.cilium.io\n
\ displayName: Cilium Node Configuration\n description: |\n CiliumNodeConfig
is a list of configuration key-value pairs. It is applied to\n nodes indicated
by a label selector.\n- kind: CiliumBGPPeeringPolicy\n version: v2alpha1\n name:
ciliumbgppeeringpolicies.cilium.io\n displayName: Cilium BGP Peering Policy\n
\ description: |\n Cilium BGP Peering Policy instructs Cilium to create specific
BGP peering\n configurations.\n- kind: CiliumBGPClusterConfig\n version: v2alpha1\n
\ name: ciliumbgpclusterconfigs.cilium.io\n displayName: Cilium BGP Cluster Config\n
by a label selector.\n- kind: CiliumBGPClusterConfig\n version: v2alpha1\n name:
ciliumbgpclusterconfigs.cilium.io\n displayName: Cilium BGP Cluster Config\n
\ description: |\n Cilium BGP Cluster Config instructs Cilium operator to create
specific BGP cluster\n configurations.\n- kind: CiliumBGPPeerConfig\n version:
v2alpha1\n name: ciliumbgppeerconfigs.cilium.io\n displayName: Cilium BGP Peer
@@ -79,7 +76,7 @@ annotations:
Cilium Gateway Class Config\n description: |\n CiliumGatewayClassConfig defines
a configuration for Gateway API GatewayClass.\n"
apiVersion: v2
appVersion: 1.18.6
appVersion: 1.19.1
description: eBPF-based Networking, Security, and Observability
home: https://cilium.io/
icon: https://cdn.jsdelivr.net/gh/cilium/cilium@main/Documentation/images/logo-solo.svg
@@ -95,4 +92,4 @@ kubeVersion: '>= 1.21.0-0'
name: cilium
sources:
- https://github.com/cilium/cilium
version: 1.18.6
version: 1.19.1

View File

@@ -1,6 +1,6 @@
# cilium
![Version: 1.18.6](https://img.shields.io/badge/Version-1.18.6-informational?style=flat-square) ![AppVersion: 1.18.6](https://img.shields.io/badge/AppVersion-1.18.6-informational?style=flat-square)
![Version: 1.19.1](https://img.shields.io/badge/Version-1.19.1-informational?style=flat-square) ![AppVersion: 1.19.1](https://img.shields.io/badge/AppVersion-1.19.1-informational?style=flat-square)
Cilium is open source software for providing and transparently securing
network connectivity and loadbalancing between application workloads such as
@@ -59,10 +59,14 @@ contributors across the globe, there is almost always someone available to help.
| agentNotReadyTaintKey | string | `"node.cilium.io/agent-not-ready"` | Configure the key of the taint indicating that Cilium is not ready on the node. When set to a value starting with `ignore-taint.cluster-autoscaler.kubernetes.io/`, the Cluster Autoscaler will ignore the taint on its decisions, allowing the cluster to scale up. |
| aksbyocni.enabled | bool | `false` | Enable AKS BYOCNI integration. Note that this is incompatible with AKS clusters not created in BYOCNI mode: use Azure integration (`azure.enabled`) instead. |
| alibabacloud.enabled | bool | `false` | Enable AlibabaCloud ENI integration |
| alibabacloud.nodeSpec.securityGroupTags | list | `[]` | |
| alibabacloud.nodeSpec.securityGroups | list | `[]` | |
| alibabacloud.nodeSpec.vSwitchTags | list | `[]` | |
| alibabacloud.nodeSpec.vSwitches | list | `[]` | |
| annotateK8sNode | bool | `false` | Annotate k8s node upon initialization with Cilium's metadata. |
| annotations | object | `{}` | Annotations to be added to all top-level cilium-agent objects (resources under templates/cilium-agent) |
| apiRateLimit | string | `nil` | The api-rate-limit option can be used to overwrite individual settings of the default configuration for rate limiting calls to the Cilium Agent API |
| authentication.enabled | bool | `true` | Enable authentication processing and garbage collection. Note that if disabled, policy enforcement will still block requests that require authentication. But the resulting authentication requests for these requests will not be processed, therefore the requests not be allowed. |
| authentication.enabled | bool | `false` | Enable authentication processing and garbage collection. Note that if disabled, policy enforcement will still block requests that require authentication. But the resulting authentication requests for these requests will not be processed, therefore the requests not be allowed. |
| authentication.gcInterval | string | `"5m0s"` | Interval for garbage collection of auth map entries. |
| authentication.mutual.connectTimeout | string | `"5s"` | Timeout for connecting to the remote node TCP socket |
| authentication.mutual.port | int | `4250` | Port on the agent where mutual authentication handshakes between agents will be performed |
@@ -73,7 +77,7 @@ contributors across the globe, there is almost always someone available to help.
| authentication.mutual.spire.enabled | bool | `false` | Enable SPIRE integration (beta) |
| authentication.mutual.spire.install.agent.affinity | object | `{}` | SPIRE agent affinity configuration |
| authentication.mutual.spire.install.agent.annotations | object | `{}` | SPIRE agent annotations |
| authentication.mutual.spire.install.agent.image | object | `{"digest":"sha256:163970884fba18860cac93655dc32b6af85a5dcf2ebb7e3e119a10888eff8fcd","override":null,"pullPolicy":"IfNotPresent","repository":"ghcr.io/spiffe/spire-agent","tag":"1.12.4","useDigest":true}` | SPIRE agent image |
| authentication.mutual.spire.install.agent.image | object | `{"digest":"sha256:5106ac601272a88684db14daf7f54b9a45f31f77bb16a906bd5e87756ee7b97c","override":null,"pullPolicy":"IfNotPresent","repository":"ghcr.io/spiffe/spire-agent","tag":"1.9.6","useDigest":true}` | SPIRE agent image |
| authentication.mutual.spire.install.agent.labels | object | `{}` | SPIRE agent labels |
| authentication.mutual.spire.install.agent.nodeSelector | object | `{}` | SPIRE agent nodeSelector configuration ref: ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector |
| authentication.mutual.spire.install.agent.podSecurityContext | object | `{}` | Security context to be added to spire agent pods. SecurityContext holds pod-level security attributes and common container settings. ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod |
@@ -85,7 +89,7 @@ contributors across the globe, there is almost always someone available to help.
| authentication.mutual.spire.install.agent.tolerations | list | `[{"effect":"NoSchedule","key":"node.kubernetes.io/not-ready"},{"effect":"NoSchedule","key":"node-role.kubernetes.io/master"},{"effect":"NoSchedule","key":"node-role.kubernetes.io/control-plane"},{"effect":"NoSchedule","key":"node.cloudprovider.kubernetes.io/uninitialized","value":"true"},{"key":"CriticalAddonsOnly","operator":"Exists"}]` | SPIRE agent tolerations configuration By default it follows the same tolerations as the agent itself to allow the Cilium agent on this node to connect to SPIRE. ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ |
| authentication.mutual.spire.install.enabled | bool | `true` | Enable SPIRE installation. This will only take effect only if authentication.mutual.spire.enabled is true |
| authentication.mutual.spire.install.existingNamespace | bool | `false` | SPIRE namespace already exists. Set to true if Helm should not create, manage, and import the SPIRE namespace. |
| authentication.mutual.spire.install.initImage | object | `{"digest":"sha256:2383baad1860bbe9d8a7a843775048fd07d8afe292b94bd876df64a69aae7cb1","override":null,"pullPolicy":"IfNotPresent","repository":"docker.io/library/busybox","tag":"1.37.0","useDigest":true}` | init container image of SPIRE agent and server |
| authentication.mutual.spire.install.initImage | object | `{"digest":"sha256:b3255e7dfbcd10cb367af0d409747d511aeb66dfac98cf30e97e87e4207dd76f","override":null,"pullPolicy":"IfNotPresent","repository":"docker.io/library/busybox","tag":"1.37.0","useDigest":true}` | init container image of SPIRE agent and server |
| authentication.mutual.spire.install.namespace | string | `"cilium-spire"` | SPIRE namespace to install into |
| authentication.mutual.spire.install.server.affinity | object | `{}` | SPIRE server affinity configuration |
| authentication.mutual.spire.install.server.annotations | object | `{}` | SPIRE server annotations |
@@ -95,7 +99,7 @@ contributors across the globe, there is almost always someone available to help.
| authentication.mutual.spire.install.server.dataStorage.enabled | bool | `true` | Enable SPIRE server data storage |
| authentication.mutual.spire.install.server.dataStorage.size | string | `"1Gi"` | Size of the SPIRE server data storage |
| authentication.mutual.spire.install.server.dataStorage.storageClass | string | `nil` | StorageClass of the SPIRE server data storage |
| authentication.mutual.spire.install.server.image | object | `{"digest":"sha256:34147f27066ab2be5cc10ca1d4bfd361144196467155d46c45f3519f41596e49","override":null,"pullPolicy":"IfNotPresent","repository":"ghcr.io/spiffe/spire-server","tag":"1.12.4","useDigest":true}` | SPIRE server image |
| authentication.mutual.spire.install.server.image | object | `{"digest":"sha256:59a0b92b39773515e25e68a46c40d3b931b9c1860bc445a79ceb45a805cab8b4","override":null,"pullPolicy":"IfNotPresent","repository":"ghcr.io/spiffe/spire-server","tag":"1.9.6","useDigest":true}` | SPIRE server image |
| authentication.mutual.spire.install.server.initContainers | list | `[]` | SPIRE server init containers |
| authentication.mutual.spire.install.server.labels | object | `{}` | SPIRE server labels |
| authentication.mutual.spire.install.server.nodeSelector | object | `{}` | SPIRE server nodeSelector configuration ref: ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector |
@@ -114,13 +118,14 @@ contributors across the globe, there is almost always someone available to help.
| authentication.rotatedIdentitiesQueueSize | int | `1024` | Buffer size of the channel Cilium uses to receive certificate expiration events from auth handlers. |
| autoDirectNodeRoutes | bool | `false` | Enable installation of PodCIDR routes between worker nodes if worker nodes share a common L2 network segment. |
| azure.enabled | bool | `false` | Enable Azure integration. Note that this is incompatible with AKS clusters created in BYOCNI mode: use AKS BYOCNI integration (`aksbyocni.enabled`) instead. |
| azure.nodeSpec.azureInterfaceName | string | `""` | |
| bandwidthManager | object | `{"bbr":false,"bbrHostNamespaceOnly":false,"enabled":false}` | Enable bandwidth manager to optimize TCP and UDP workloads and allow for rate-limiting traffic from individual Pods with EDT (Earliest Departure Time) through the "kubernetes.io/egress-bandwidth" Pod annotation. |
| bandwidthManager.bbr | bool | `false` | Activate BBR TCP congestion control for Pods |
| bandwidthManager.bbrHostNamespaceOnly | bool | `false` | Activate BBR TCP congestion control for Pods in the host namespace only. |
| bandwidthManager.enabled | bool | `false` | Enable bandwidth manager infrastructure (also prerequirement for BBR) |
| bgpControlPlane | object | `{"enabled":false,"legacyOriginAttribute":{"enabled":false},"routerIDAllocation":{"ipPool":"","mode":"default"},"secretsNamespace":{"create":false,"name":"kube-system"},"statusReport":{"enabled":true}}` | This feature set enables virtual BGP routers to be created via CiliumBGPPeeringPolicy CRDs. |
| bgpControlPlane | object | `{"enabled":false,"legacyOriginAttribute":{"enabled":false},"routerIDAllocation":{"ipPool":"","mode":"default"},"secretsNamespace":{"create":false,"name":"kube-system"},"statusReport":{"enabled":true}}` | This feature set enables virtual BGP routers to be created via BGP CRDs. |
| bgpControlPlane.enabled | bool | `false` | Enables the BGP control plane. |
| bgpControlPlane.legacyOriginAttribute | object | `{"enabled":false}` | Legacy BGP ORIGIN attribute settings (BGPv2 only) |
| bgpControlPlane.legacyOriginAttribute | object | `{"enabled":false}` | Legacy BGP ORIGIN attribute settings |
| bgpControlPlane.legacyOriginAttribute.enabled | bool | `false` | Enable/Disable advertising LoadBalancerIP routes with the legacy BGP ORIGIN attribute value INCOMPLETE (2) instead of the default IGP (0). Enable for compatibility with the legacy behavior of MetalLB integration. |
| bgpControlPlane.routerIDAllocation | object | `{"ipPool":"","mode":"default"}` | BGP router-id allocation mode |
| bgpControlPlane.routerIDAllocation.ipPool | string | `""` | IP pool to allocate the BGP router-id from when the mode is ip-pool. |
@@ -128,20 +133,20 @@ contributors across the globe, there is almost always someone available to help.
| bgpControlPlane.secretsNamespace | object | `{"create":false,"name":"kube-system"}` | SecretsNamespace is the namespace which BGP support will retrieve secrets from. |
| bgpControlPlane.secretsNamespace.create | bool | `false` | Create secrets namespace for BGP secrets. |
| bgpControlPlane.secretsNamespace.name | string | `"kube-system"` | The name of the secret namespace to which Cilium agents are given read access |
| bgpControlPlane.statusReport | object | `{"enabled":true}` | Status reporting settings (BGPv2 only) |
| bgpControlPlane.statusReport.enabled | bool | `true` | Enable/Disable BGPv2 status reporting It is recommended to enable status reporting in general, but if you have any issue such as high API server load, you can disable it by setting this to false. |
| bgpControlPlane.statusReport | object | `{"enabled":true}` | Status reporting settings |
| bgpControlPlane.statusReport.enabled | bool | `true` | Enable/Disable BGP status reporting It is recommended to enable status reporting in general, but if you have any issue such as high API server load, you can disable it by setting this to false. |
| bpf.authMapMax | int | `524288` | Configure the maximum number of entries in auth map. |
| bpf.autoMount.enabled | bool | `true` | Enable automatic mount of BPF filesystem When `autoMount` is enabled, the BPF filesystem is mounted at `bpf.root` path on the underlying host and inside the cilium agent pod. If users disable `autoMount`, it's expected that users have mounted bpffs filesystem at the specified `bpf.root` volume, and then the volume will be mounted inside the cilium agent pod at the same path. |
| bpf.ctAccounting | bool | `false` | Enable CT accounting for packets and bytes |
| bpf.ctAnyMax | int | `262144` | Configure the maximum number of entries for the non-TCP connection tracking table. |
| bpf.ctTcpMax | int | `524288` | Configure the maximum number of entries in the TCP connection tracking table. |
| bpf.datapathMode | string | `veth` | Mode for Pod devices for the core datapath (veth, netkit, netkit-l2) |
| bpf.datapathMode | string | `veth` | Mode for Pod devices for the core datapath (veth, netkit, netkit-l2). Note netkit is incompatible with TPROXY (`bpf.tproxy`). |
| bpf.disableExternalIPMitigation | bool | `false` | Disable ExternalIP mitigation (CVE-2020-8554) |
| bpf.distributedLRU | object | `{"enabled":false}` | Control to use a distributed per-CPU backend memory for the core BPF LRU maps which Cilium uses. This improves performance significantly, but it is also recommended to increase BPF map sizing along with that. |
| bpf.distributedLRU.enabled | bool | `false` | Enable distributed LRU backend memory. For compatibility with existing installations it is off by default. |
| bpf.enableTCX | bool | `true` | Attach endpoint programs using tcx instead of legacy tc hooks on supported kernels. |
| bpf.events | object | `{"default":{"burstLimit":null,"rateLimit":null},"drop":{"enabled":true},"policyVerdict":{"enabled":true},"trace":{"enabled":true}}` | Control events generated by the Cilium datapath exposed to Cilium monitor and Hubble. Helm configuration for BPF events map rate limiting is experimental and might change in upcoming releases. |
| bpf.events.default | object | `{"burstLimit":null,"rateLimit":null}` | Default settings for all types of events except dbg and pcap. |
| bpf.events.default | object | `{"burstLimit":null,"rateLimit":null}` | Default settings for all types of events except dbg. |
| bpf.events.default.burstLimit | int | `0` | Configure the maximum number of messages that can be written to BPF events map in 1 second. If burstLimit is greater than 0, non-zero value for rateLimit must also be provided lest the configuration is considered invalid. Setting both burstLimit and rateLimit to 0 disables BPF events rate limiting. |
| bpf.events.default.rateLimit | int | `0` | Configure the limit of messages per second that can be written to BPF events map. The number of messages is averaged, meaning that if no messages were written to the map over 5 seconds, it's possible to write more events in the 6th second. If rateLimit is greater than 0, non-zero value for burstLimit must also be provided lest the configuration is considered invalid. Setting both burstLimit and rateLimit to 0 disables BPF events rate limiting. |
| bpf.events.drop.enabled | bool | `true` | Enable drop events. |
@@ -158,19 +163,23 @@ contributors across the globe, there is almost always someone available to help.
| bpf.monitorAggregation | string | `"medium"` | Configure the level of aggregation for monitor notifications. Valid options are none, low, medium, maximum. |
| bpf.monitorFlags | string | `"all"` | Configure which TCP flags trigger notifications when seen for the first time in a connection. |
| bpf.monitorInterval | string | `"5s"` | Configure the typical time between monitor notifications for active connections. |
| bpf.monitorTraceIPOption | int | `0` | Configure the IP tracing option type. This option is used to specify the IP option type to use for tracing. The value must be an integer between 0 and 255. @schema type: [null, integer] minimum: 0 maximum: 255 @schema |
| bpf.natMax | int | `524288` | Configure the maximum number of entries for the NAT table. |
| bpf.neighMax | int | `524288` | Configure the maximum number of entries for the neighbor table. |
| bpf.nodeMapMax | int | `nil` | Configures the maximum number of entries for the node table. |
| bpf.policyMapMax | int | `16384` | Configure the maximum number of entries in endpoint policy map (per endpoint). @schema type: [null, integer] @schema |
| bpf.policyMapPressureMetricsThreshold | float64 | `0.1` | Configure threshold for emitting pressure metrics of policy maps. @schema type: [null, number] @schema |
| bpf.policyStatsMapMax | int | `65536` | Configure the maximum number of entries in global policy stats map. @schema type: [null, integer] @schema |
| bpf.preallocateMaps | bool | `false` | Enables pre-allocation of eBPF map values. This increases memory usage but can reduce latency. |
| bpf.root | string | `"/sys/fs/bpf"` | Configure the mount point for the BPF filesystem |
| bpf.tproxy | bool | `false` | Configure the eBPF-based TPROXY (beta) to reduce reliance on iptables rules for implementing Layer 7 policy. |
| bpf.tproxy | bool | `false` | Configure the eBPF-based TPROXY (beta) to reduce reliance on iptables rules for implementing Layer 7 policy. Note this is incompatible with netkit (`bpf.datapathMode=netkit`, `bpf.datapathMode=netkit-l2`). |
| bpf.vlanBypass | list | `[]` | Configure explicitly allowed VLAN id's for bpf logic bypass. [0] will allow all VLAN id's without any filtering. |
| bpfClockProbe | bool | `false` | Enable BPF clock source probing for more efficient tick retrieval. |
| certgen | object | `{"affinity":{},"annotations":{"cronJob":{},"job":{}},"extraVolumeMounts":[],"extraVolumes":[],"generateCA":true,"image":{"digest":"sha256:2825dbfa6f89cbed882fd1d81e46a56c087e35885825139923aa29eb8aec47a9","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/certgen","tag":"v0.3.1","useDigest":true},"nodeSelector":{},"podLabels":{},"priorityClassName":"","resources":{},"tolerations":[],"ttlSecondsAfterFinished":1800}` | Configure certificate generation for Hubble integration. If hubble.tls.auto.method=cronJob, these values are used for the Kubernetes CronJob which will be scheduled regularly to (re)generate any certificates not provided manually. |
| certgen | object | `{"affinity":{},"annotations":{"cronJob":{},"job":{}},"cronJob":{"failedJobsHistoryLimit":1,"successfulJobsHistoryLimit":3},"extraVolumeMounts":[],"extraVolumes":[],"generateCA":true,"image":{"digest":"sha256:19921f48ee7e2295ea4dca955878a6cd8d70e6d4219d08f688e866ece9d95d4d","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/certgen","tag":"v0.3.2","useDigest":true},"nodeSelector":{},"podLabels":{},"priorityClassName":"","resources":{},"tolerations":[],"ttlSecondsAfterFinished":null}` | Configure certificate generation for Hubble integration. If hubble.tls.auto.method=cronJob, these values are used for the Kubernetes CronJob which will be scheduled regularly to (re)generate any certificates not provided manually. |
| certgen.affinity | object | `{}` | Affinity for certgen |
| certgen.annotations | object | `{"cronJob":{},"job":{}}` | Annotations to be added to the hubble-certgen initial Job and CronJob |
| certgen.cronJob.failedJobsHistoryLimit | int | `1` | The number of failed finished jobs to keep |
| certgen.cronJob.successfulJobsHistoryLimit | int | `3` | The number of successful finished jobs to keep |
| certgen.extraVolumeMounts | list | `[]` | Additional certgen volumeMounts. |
| certgen.extraVolumes | list | `[]` | Additional certgen volumes. |
| certgen.generateCA | bool | `true` | When set to true the certificate authority secret is created. |
@@ -179,7 +188,7 @@ contributors across the globe, there is almost always someone available to help.
| certgen.priorityClassName | string | `""` | Priority class for certgen ref: https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#priorityclass |
| certgen.resources | object | `{}` | Resource limits for certgen ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers |
| certgen.tolerations | list | `[]` | Node tolerations for pod assignment on nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ |
| certgen.ttlSecondsAfterFinished | int | `1800` | Seconds after which the completed job pod will be deleted |
| certgen.ttlSecondsAfterFinished | string | `nil` | Seconds after which the completed job pod will be deleted |
| cgroup | object | `{"autoMount":{"enabled":true,"resources":{}},"hostRoot":"/run/cilium/cgroupv2"}` | Configure cgroup related configuration |
| cgroup.autoMount.enabled | bool | `true` | Enable auto mount of cgroup2 filesystem. When `autoMount` is enabled, cgroup2 filesystem is mounted at `cgroup.hostRoot` path on the underlying host and inside the cilium agent pod. If users disable `autoMount`, it's expected that users have mounted cgroup2 filesystem at the specified `cgroup.hostRoot` volume, and then the volume will be mounted inside the cilium agent pod at the same path. |
| cgroup.autoMount.resources | object | `{}` | Init Container Cgroup Automount resource limits & requests |
@@ -205,7 +214,7 @@ contributors across the globe, there is almost always someone available to help.
| clustermesh.apiserver.extraVolumeMounts | list | `[]` | Additional clustermesh-apiserver volumeMounts. |
| clustermesh.apiserver.extraVolumes | list | `[]` | Additional clustermesh-apiserver volumes. |
| clustermesh.apiserver.healthPort | int | `9880` | TCP port for the clustermesh-apiserver health API. |
| clustermesh.apiserver.image | object | `{"digest":"sha256:8ee142912a0e261850c0802d9256ddbe3729e1cd35c6bea2d93077f334c3cf3b","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/clustermesh-apiserver","tag":"v1.18.6","useDigest":true}` | Clustermesh API server image. |
| clustermesh.apiserver.image | object | `{"digest":"sha256:56d6c3dc13b50126b80ecb571707a0ea97f6db694182b9d61efd386d04e5bb28","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/clustermesh-apiserver","tag":"v1.19.1","useDigest":true}` | Clustermesh API server image. |
| clustermesh.apiserver.kvstoremesh.enabled | bool | `true` | Enable KVStoreMesh. KVStoreMesh caches the information retrieved from the remote clusters in the local etcd instance (deprecated - KVStoreMesh will always be enabled once the option is removed). |
| clustermesh.apiserver.kvstoremesh.extraArgs | list | `[]` | Additional KVStoreMesh arguments. |
| clustermesh.apiserver.kvstoremesh.extraEnv | list | `[]` | Additional KVStoreMesh environment variables. |
@@ -255,38 +264,65 @@ contributors across the globe, there is almost always someone available to help.
| clustermesh.apiserver.service.annotations | object | `{}` | Annotations for the clustermesh-apiserver service. Example annotations to configure an internal load balancer on different cloud providers: * AKS: service.beta.kubernetes.io/azure-load-balancer-internal: "true" * EKS: service.beta.kubernetes.io/aws-load-balancer-scheme: "internal" * GKE: networking.gke.io/load-balancer-type: "Internal" |
| clustermesh.apiserver.service.enableSessionAffinity | string | `"HAOnly"` | Defines when to enable session affinity. Each replica in a clustermesh-apiserver deployment runs its own discrete etcd cluster. Remote clients connect to one of the replicas through a shared Kubernetes Service. A client reconnecting to a different backend will require a full resync to ensure data integrity. Session affinity can reduce the likelihood of this happening, but may not be supported by all cloud providers. Possible values: - "HAOnly" (default) Only enable session affinity for deployments with more than 1 replica. - "Always" Always enable session affinity. - "Never" Never enable session affinity. Useful in environments where session affinity is not supported, but may lead to slightly degraded performance due to more frequent reconnections. |
| clustermesh.apiserver.service.externalTrafficPolicy | string | `"Cluster"` | The externalTrafficPolicy of service used for apiserver access. |
| clustermesh.apiserver.service.externallyCreated | bool | `false` | Set externallyCreated to true to create the clustermesh-apiserver service outside this helm chart. For example after external load balancer controllers are created. |
| clustermesh.apiserver.service.internalTrafficPolicy | string | `"Cluster"` | The internalTrafficPolicy of service used for apiserver access. |
| clustermesh.apiserver.service.labels | object | `{}` | Labels for the clustermesh-apiserver service. |
| clustermesh.apiserver.service.loadBalancerClass | string | `nil` | Configure a loadBalancerClass. Allows to configure the loadBalancerClass on the clustermesh-apiserver LB service in case the Service type is set to LoadBalancer (requires Kubernetes 1.24+). |
| clustermesh.apiserver.service.loadBalancerIP | string | `nil` | Configure a specific loadBalancerIP. Allows to configure a specific loadBalancerIP on the clustermesh-apiserver LB service in case the Service type is set to LoadBalancer. |
| clustermesh.apiserver.service.loadBalancerSourceRanges | list | `[]` | Configure loadBalancerSourceRanges. Allows to configure the source IP ranges allowed to access the clustermesh-apiserver LB service in case the Service type is set to LoadBalancer. |
| clustermesh.apiserver.service.nodePort | int | `32379` | Optional port to use as the node port for apiserver access. WARNING: make sure to configure a different NodePort in each cluster if kube-proxy replacement is enabled, as Cilium is currently affected by a known bug (#24692) when NodePorts are handled by the KPR implementation. If a service with the same NodePort exists both in the local and the remote cluster, all traffic originating from inside the cluster and targeting the corresponding NodePort will be redirected to a local backend, regardless of whether the destination node belongs to the local or the remote cluster. |
| clustermesh.apiserver.service.nodePort | int | `32379` | Optional port to use as the node port for apiserver access. |
| clustermesh.apiserver.service.type | string | `"NodePort"` | The type of service used for apiserver access. |
| clustermesh.apiserver.terminationGracePeriodSeconds | int | `30` | terminationGracePeriodSeconds for the clustermesh-apiserver deployment |
| clustermesh.apiserver.tls.admin | object | `{"cert":"","key":""}` | base64 encoded PEM values for the clustermesh-apiserver admin certificate and private key. Used if 'auto' is not enabled. |
| clustermesh.apiserver.tls.authMode | string | `"legacy"` | Configure the clustermesh authentication mode. Supported values: - legacy: All clusters access remote clustermesh instances with the same username (i.e., remote). The "remote" certificate must be generated with CN=remote if provided manually. - migration: Intermediate mode required to upgrade from legacy to cluster (and vice versa) with no disruption. Specifically, it enables the creation of the per-cluster usernames, while still using the common one for authentication. The "remote" certificate must be generated with CN=remote if provided manually (same as legacy). - cluster: Each cluster accesses remote etcd instances with a username depending on the local cluster name (i.e., remote-<cluster-name>). The "remote" certificate must be generated with CN=remote-<cluster-name> if provided manually. Cluster mode is meaningful only when the same CA is shared across all clusters part of the mesh. |
| clustermesh.apiserver.tls.admin.cert | string | `""` | Deprecated, as secrets will always need to be created externally if `auto` is disabled. |
| clustermesh.apiserver.tls.admin.key | string | `""` | Deprecated, as secrets will always need to be created externally if `auto` is disabled. |
| clustermesh.apiserver.tls.authMode | string | `"migration"` | Configure the clustermesh authentication mode. Supported values: - legacy: All clusters access remote clustermesh instances with the same username (i.e., remote). The "remote" certificate must be generated with CN=remote if provided manually. - migration: Intermediate mode required to upgrade from legacy to cluster (and vice versa) with no disruption. Specifically, it enables the creation of the per-cluster usernames, while still using the common one for authentication. The "remote" certificate must be generated with CN=remote if provided manually (same as legacy). - cluster: Each cluster accesses remote etcd instances with a username depending on the local cluster name (i.e., remote-<cluster-name>). The "remote" certificate must be generated with CN=remote-<cluster-name> if provided manually. Cluster mode is meaningful only when the same CA is shared across all clusters part of the mesh. |
| clustermesh.apiserver.tls.auto | object | `{"certManagerIssuerRef":{},"certValidityDuration":1095,"enabled":true,"method":"helm"}` | Configure automatic TLS certificates generation. A Kubernetes CronJob is used the generate any certificates not provided by the user at installation time. |
| clustermesh.apiserver.tls.auto.certManagerIssuerRef | object | `{}` | certmanager issuer used when clustermesh.apiserver.tls.auto.method=certmanager. |
| clustermesh.apiserver.tls.auto.certValidityDuration | int | `1095` | Generated certificates validity duration in days. |
| clustermesh.apiserver.tls.auto.enabled | bool | `true` | When set to true, automatically generate a CA and certificates to enable mTLS between clustermesh-apiserver and external workload instances. If set to false, the certs to be provided by setting appropriate values below. |
| clustermesh.apiserver.tls.client | object | `{"cert":"","key":""}` | base64 encoded PEM values for the clustermesh-apiserver client certificate and private key. Used if 'auto' is not enabled. |
| clustermesh.apiserver.tls.enableSecrets | bool | `true` | Allow users to provide their own certificates Users may need to provide their certificates using a mechanism that requires they provide their own secrets. This setting does not apply to any of the auto-generated mechanisms below, it only restricts the creation of secrets via the `tls-provided` templates. |
| clustermesh.apiserver.tls.auto.enabled | bool | `true` | When set to true, automatically generate a CA and certificates to enable mTLS between clustermesh-apiserver and external workload instances. When set to false you need to pre-create the following secrets: - clustermesh-apiserver-server-cert - clustermesh-apiserver-admin-cert - clustermesh-apiserver-remote-cert - clustermesh-apiserver-local-cert The above secret should at least contains the keys `tls.crt` and `tls.key` and optionally `ca.crt` if a CA bundle is not configured. |
| clustermesh.apiserver.tls.enableSecrets | deprecated | `true` | Allow users to provide their own certificates Users may need to provide their certificates using a mechanism that requires they provide their own secrets. This setting does not apply to any of the auto-generated mechanisms below, it only restricts the creation of secrets via the `tls-provided` templates. This option is deprecated as secrets are expected to be created externally when 'auto' is not enabled. |
| clustermesh.apiserver.tls.remote | object | `{"cert":"","key":""}` | base64 encoded PEM values for the clustermesh-apiserver remote cluster certificate and private key. Used if 'auto' is not enabled. |
| clustermesh.apiserver.tls.remote.cert | string | `""` | Deprecated, as secrets will always need to be created externally if `auto` is disabled. |
| clustermesh.apiserver.tls.remote.key | string | `""` | Deprecated, as secrets will always need to be created externally if `auto` is disabled. |
| clustermesh.apiserver.tls.server | object | `{"cert":"","extraDnsNames":[],"extraIpAddresses":[],"key":""}` | base64 encoded PEM values for the clustermesh-apiserver server certificate and private key. Used if 'auto' is not enabled. |
| clustermesh.apiserver.tls.server.cert | string | `""` | Deprecated, as secrets will always need to be created externally if `auto` is disabled. |
| clustermesh.apiserver.tls.server.extraDnsNames | list | `[]` | Extra DNS names added to certificate when it's auto generated |
| clustermesh.apiserver.tls.server.extraIpAddresses | list | `[]` | Extra IP addresses added to certificate when it's auto generated |
| clustermesh.apiserver.tls.server.key | string | `""` | Deprecated, as secrets will always need to be created externally if `auto` is disabled. |
| clustermesh.apiserver.tolerations | list | `[]` | Node tolerations for pod assignment on nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ |
| clustermesh.apiserver.topologySpreadConstraints | list | `[]` | Pod topology spread constraints for clustermesh-apiserver |
| clustermesh.apiserver.updateStrategy | object | `{"rollingUpdate":{"maxSurge":1,"maxUnavailable":0},"type":"RollingUpdate"}` | clustermesh-apiserver update strategy |
| clustermesh.cacheTTL | string | `"0s"` | The time to live for the cache of a remote cluster after connectivity is lost. If the connection is not re-established within this duration, the cached data is revoked to prevent stale state. If not specified or set to 0s, the cache is never revoked (default). |
| clustermesh.config | object | `{"clusters":[],"domain":"mesh.cilium.io","enabled":false}` | Clustermesh explicit configuration. |
| clustermesh.config.clusters | list | `[]` | List of clusters to be peered in the mesh. |
| clustermesh.config.clusters | list | `[]` | Clusters to be peered in the mesh. @schema type: [object, array] @schema |
| clustermesh.config.domain | string | `"mesh.cilium.io"` | Default dns domain for the Clustermesh API servers This is used in the case cluster addresses are not provided and IPs are used. |
| clustermesh.config.enabled | bool | `false` | Enable the Clustermesh explicit configuration. |
| clustermesh.config.enabled | bool | `false` | Enable the Clustermesh explicit configuration. If set to false, you need to provide the following resources yourself: - (Secret) cilium-clustermesh (used by cilium-agent/cilium-operator to connect to the local etcd instance if KVStoreMesh is enabled or the remote clusters if KVStoreMesh is disabled) - (Secret) cilium-kvstoremesh (used by KVStoreMesh to connect to the remote clusters) - (ConfigMap) clustermesh-remote-users (used to create one etcd user per remote cluster if clustermesh-apiserver is used and `clustermesh.apiserver.tls.authMode` is not set to `legacy`) |
| clustermesh.enableEndpointSliceSynchronization | bool | `false` | Enable the synchronization of Kubernetes EndpointSlices corresponding to the remote endpoints of appropriately-annotated global services through ClusterMesh |
| clustermesh.enableMCSAPISupport | bool | `false` | Enable Multi-Cluster Services API support |
| clustermesh.enableMCSAPISupport | bool | `false` | Enable Multi-Cluster Services API support (deprecated; use clustermesh.mcsapi.enabled) |
| clustermesh.maxConnectedClusters | int | `255` | The maximum number of clusters to support in a ClusterMesh. This value cannot be changed on running clusters, and all clusters in a ClusterMesh must be configured with the same value. Values > 255 will decrease the maximum allocatable cluster-local identities. Supported values are 255 and 511. |
| clustermesh.policyDefaultLocalCluster | bool | `false` | Control whether policy rules assume by default the local cluster if not explicitly selected |
| clustermesh.useAPIServer | bool | `false` | Deploy clustermesh-apiserver for clustermesh |
| clustermesh.mcsapi.corednsAutoConfigure.affinity | object | `{}` | Affinity for coredns-mcsapi-autoconfig |
| clustermesh.mcsapi.corednsAutoConfigure.annotations | object | `{}` | Annotations to be added to the coredns-mcsapi-autoconfig Job |
| clustermesh.mcsapi.corednsAutoConfigure.coredns.clusterDomain | string | `"cluster.local"` | The cluster domain for the cluster CoreDNS service |
| clustermesh.mcsapi.corednsAutoConfigure.coredns.clustersetDomain | string | `"clusterset.local"` | The clusterset domain for the cluster CoreDNS service |
| clustermesh.mcsapi.corednsAutoConfigure.coredns.configMapName | string | `"coredns"` | The ConfigMap name for the cluster CoreDNS service |
| clustermesh.mcsapi.corednsAutoConfigure.coredns.deploymentName | string | `"coredns"` | The Deployment for the cluster CoreDNS service |
| clustermesh.mcsapi.corednsAutoConfigure.coredns.namespace | string | `"kube-system"` | The namespace for the cluster CoreDNS service |
| clustermesh.mcsapi.corednsAutoConfigure.coredns.serviceAccountName | string | `"coredns"` | The Service Account name for the cluster CoreDNS service |
| clustermesh.mcsapi.corednsAutoConfigure.enabled | bool | `false` | Enable auto-configuration of CoreDNS for Multi-Cluster Services API. CoreDNS MUST be at least in version v1.12.2 to run this. |
| clustermesh.mcsapi.corednsAutoConfigure.extraArgs | list | `[]` | Additional arguments to `clustermesh-apiserver coredns-mcsapi-auto-configure`. |
| clustermesh.mcsapi.corednsAutoConfigure.extraVolumeMounts | list | `[]` | Additional coredns-mcsapi-autoconfig volumeMounts. |
| clustermesh.mcsapi.corednsAutoConfigure.extraVolumes | list | `[]` | Additional coredns-mcsapi-autoconfig volumes. |
| clustermesh.mcsapi.corednsAutoConfigure.nodeSelector | object | `{}` | Node selector for coredns-mcsapi-autoconfig ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector |
| clustermesh.mcsapi.corednsAutoConfigure.podLabels | object | `{}` | Labels to be added to coredns-mcsapi-autoconfig pods |
| clustermesh.mcsapi.corednsAutoConfigure.priorityClassName | string | `""` | Priority class for coredns-mcsapi-autoconfig ref: https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#priorityclass |
| clustermesh.mcsapi.corednsAutoConfigure.resources | object | `{}` | Resource limits for coredns-mcsapi-autoconfig ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers |
| clustermesh.mcsapi.corednsAutoConfigure.tolerations | list | `[]` | Node tolerations for pod assignment on nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ |
| clustermesh.mcsapi.corednsAutoConfigure.ttlSecondsAfterFinished | int | `1800` | Seconds after which the completed job pod will be deleted |
| clustermesh.mcsapi.enabled | bool | `false` | Enable Multi-Cluster Services API support |
| clustermesh.mcsapi.installCRDs | bool | `true` | Enabled MCS-API CRDs auto-installation |
| clustermesh.policyDefaultLocalCluster | bool | `true` | Control whether policy rules assume by default the local cluster if not explicitly selected |
| clustermesh.useAPIServer | bool | `false` | Deploy clustermesh-apiserver for clustermesh. This option is typically used with ``clustermesh.config.enabled=true``. Refer to the ``clustermesh.config.enabled=true``documentation for more information. |
| cni.binPath | string | `"/opt/cni/bin"` | Configure the path to the CNI binary directory on the host. |
| cni.chainingMode | string | `nil` | Configure chaining on top of other CNI plugins. Possible values: - none - aws-cni - flannel - generic-veth - portmap |
| cni.chainingTarget | string | `nil` | A CNI network name in to which the Cilium plugin should be added as a chained plugin. This will cause the agent to watch for a CNI network with this network name. When it is found, this will be used as the basis for Cilium's CNI configuration file. If this is set, it assumes a chaining mode of generic-veth. As a special case, a chaining mode of aws-cni implies a chainingTarget of aws-cni. |
@@ -301,15 +337,13 @@ contributors across the globe, there is almost always someone available to help.
| cni.install | bool | `true` | Install the CNI configuration and binary files into the filesystem. |
| cni.iptablesRemoveAWSRules | bool | `true` | Enable the removal of iptables rules created by the AWS CNI VPC plugin. |
| cni.logFile | string | `"/var/run/cilium/cilium-cni.log"` | Configure the log file for CNI logging with retention policy of 7 days. Disable CNI file logging by setting this field to empty explicitly. |
| cni.resources | object | `{"requests":{"cpu":"100m","memory":"10Mi"}}` | Specifies the resources for the cni initContainer |
| cni.resources | object | `{"limits":{"cpu":1,"memory":"1Gi"},"requests":{"cpu":"100m","memory":"10Mi"}}` | Specifies the resources for the cni initContainer |
| cni.uninstall | bool | `false` | Remove the CNI configuration and binary files on agent shutdown. Enable this if you're removing Cilium from the cluster. Disable this to prevent the CNI configuration file from being removed during agent upgrade, which can cause nodes to go unmanageable. |
| commonLabels | object | `{}` | commonLabels allows users to add common labels for all Cilium resources. |
| connectivityProbeFrequencyRatio | float64 | `0.5` | Ratio of the connectivity probe frequency vs resource usage, a float in [0, 1]. 0 will give more frequent probing, 1 will give less frequent probing. Probing frequency is dynamically adjusted based on the cluster size. |
| conntrackGCInterval | string | `"0s"` | Configure how frequently garbage collection should occur for the datapath connection tracking table. |
| conntrackGCMaxInterval | string | `""` | Configure the maximum frequency for the garbage collection of the connection tracking table. Only affects the automatic computation for the frequency and has no effect when 'conntrackGCInterval' is set. This can be set to more frequently clean up unused identities created from ToFQDN policies. |
| crdWaitTimeout | string | `"5m"` | Configure timeout in which Cilium will exit if CRDs are not available |
| customCalls | object | `{"enabled":false}` | Tail call hooks for custom eBPF programs. |
| customCalls.enabled | bool | `false` | Enable tail call hooks for custom eBPF programs. |
| daemon.allowedConfigOverrides | string | `nil` | allowedConfigOverrides is a list of config-map keys that can be overridden. That is to say, if this value is set, config sources (excepting the first one) can only override keys in this list. This takes precedence over blockedConfigOverrides. By default, all keys may be overridden. To disable overrides, set this to "none" or change the configSources variable. |
| daemon.blockedConfigOverrides | string | `nil` | blockedConfigOverrides is a list of config-map keys that may not be overridden. In other words, if any of these keys appear in a configuration source excepting the first one, they will be ignored This is ignored if allowedConfigOverrides is set. By default, all keys may be overridden. |
| daemon.configSources | string | `nil` | Configure a custom list of possible configuration override sources The default is "config-map:cilium-config,cilium-node-config". For supported values, see the help text for the build-config subcommand. Note that this value should be a comma-separated string. |
@@ -318,8 +352,8 @@ contributors across the globe, there is almost always someone available to help.
| dashboards | object | `{"annotations":{},"enabled":false,"label":"grafana_dashboard","labelValue":"1","namespace":null}` | Grafana dashboards for cilium-agent grafana can import dashboards based on the label and value ref: https://github.com/grafana/helm-charts/tree/main/charts/grafana#sidecar-for-dashboards |
| debug.enabled | bool | `false` | Enable debug logging |
| debug.metricsSamplingInterval | string | `"5m"` | Set the agent-internal metrics sampling frequency. This sets the frequency of the internal sampling of the agent metrics. These are available via the "cilium-dbg shell -- metrics -s" command and are part of the metrics HTML page included in the sysdump. @schema type: [null, string] @schema |
| debug.verbose | string | `nil` | Configure verbosity levels for debug logging This option is used to enable debug messages for operations related to such sub-system such as (e.g. kvstore, envoy, datapath or policy), and flow is for enabling debug messages emitted per request, message and connection. Multiple values can be set via a space-separated string (e.g. "datapath envoy"). Applicable values: - flow - kvstore - envoy - datapath - policy |
| defaultLBServiceIPAM | string | `"lbipam"` | defaultLBServiceIPAM indicates the default LoadBalancer Service IPAM when no LoadBalancer class is set. Applicable values: lbipam, nodeipam, none @schema type: [string] @schema |
| debug.verbose | string | `nil` | Configure verbosity levels for debug logging This option is used to enable debug messages for operations related to such sub-system such as (e.g. kvstore, envoy, datapath, policy, or tagged), and flow is for enabling debug messages emitted per request, message and connection. Multiple values can be set via a space-separated string (e.g. "datapath envoy"). Applicable values: - flow - kvstore - envoy - datapath - policy - tagged |
| defaultLBServiceIPAM | string | `"lbipam"` | defaultLBServiceIPAM indicates the default LoadBalancer Service IPAM when no LoadBalancer class is set. Applicable values: lbipam, nodeipam, none |
| directRoutingSkipUnreachable | bool | `false` | Enable skipping of PodCIDR routes between worker nodes if the worker nodes are in a different L2 network segment. |
| disableEndpointCRD | bool | `false` | Disable the usage of CiliumEndpoint CRD. |
| dnsPolicy | string | `""` | DNS policy for Cilium agent pods. Ref: https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy |
@@ -338,13 +372,15 @@ contributors across the globe, there is almost always someone available to help.
| egressGateway.reconciliationTriggerInterval | string | `"1s"` | Time between triggers of egress gateway state reconciliations |
| enableCriticalPriorityClass | bool | `true` | Explicitly enable or disable priority class. .Capabilities.KubeVersion is unsettable in `helm template` calls, it depends on k8s libraries version that Helm was compiled against. This option allows to explicitly disable setting the priority class, which is useful for rendering charts for gke clusters in advance. |
| enableIPv4BIGTCP | bool | `false` | Enables IPv4 BIG TCP support which increases maximum IPv4 GSO/GRO limits for nodes and pods |
| enableIPv4Masquerade | bool | `true` unless ipam eni mode is active | Enables masquerading of IPv4 traffic leaving the node from endpoints. |
| enableIPv4Masquerade | bool | `true` unless ipam eni mode is active | Enables masquerading of IPv4 traffic leaving the node from endpoints. |
| enableIPv6BIGTCP | bool | `false` | Enables IPv6 BIG TCP support which increases maximum IPv6 GSO/GRO limits for nodes and pods |
| enableIPv6Masquerade | bool | `true` | Enables masquerading of IPv6 traffic leaving the node from endpoints. |
| enableInternalTrafficPolicy | bool | `true` | Enable Internal Traffic Policy |
| enableLBIPAM | bool | `true` | Enable LoadBalancer IP Address Management |
| enableMasqueradeRouteSource | bool | `false` | Enables masquerading to the source of the route for traffic leaving the node from endpoints. |
| enableNoServiceEndpointsRoutable | bool | `true` | Enable routing to a service that has zero endpoints |
| enableNonDefaultDenyPolicies | bool | `true` | Enable Non-Default-Deny policies |
| enableTunnelBIGTCP | bool | `false` | Enable BIG TCP in tunneling mode and increase maximum GRO/GSO limits for VXLAN/GENEVE tunnels |
| enableXTSocketFallback | bool | `true` | Enables the fallback compatibility solution for when the xt_socket kernel module is missing and it is needed for the datapath L7 redirection to work properly. See documentation for details on when this can be disabled: https://docs.cilium.io/en/stable/operations/system_requirements/#linux-kernel. |
| encryption.enabled | bool | `false` | Enable transparent network encryption. |
| encryption.ipsec.encryptedOverlay | bool | `false` | Enable IPsec encrypted overlay |
@@ -355,11 +391,15 @@ contributors across the globe, there is almost always someone available to help.
| encryption.ipsec.mountPath | string | `"/etc/ipsec"` | Path to mount the secret inside the Cilium pod. |
| encryption.ipsec.secretName | string | `"cilium-ipsec-keys"` | Name of the Kubernetes secret containing the encryption keys. |
| encryption.nodeEncryption | bool | `false` | Enable encryption for pure node to node traffic. This option is only effective when encryption.type is set to "wireguard". |
| encryption.strictMode | object | `{"allowRemoteNodeIdentities":false,"cidr":"","enabled":false}` | Configure the WireGuard Pod2Pod strict mode. |
| encryption.strictMode.allowRemoteNodeIdentities | bool | `false` | Allow dynamic lookup of remote node identities. This is required when tunneling is used or direct routing is used and the node CIDR and pod CIDR overlap. |
| encryption.strictMode.cidr | string | `""` | CIDR for the WireGuard Pod2Pod strict mode. |
| encryption.strictMode.enabled | bool | `false` | Enable WireGuard Pod2Pod strict mode. |
| encryption.type | string | `"ipsec"` | Encryption method. Can be either ipsec or wireguard. |
| encryption.strictMode | object | `{"allowRemoteNodeIdentities":false,"cidr":"","egress":{"allowRemoteNodeIdentities":false,"cidr":"","enabled":false},"enabled":false,"ingress":{"enabled":false}}` | Configure the Encryption Pod2Pod strict mode. |
| encryption.strictMode.allowRemoteNodeIdentities | bool | `false` | Allow dynamic lookup of remote node identities. (deprecated: please use encryption.strictMode.egress.allowRemoteNodeIdentities) This is required when tunneling is used or direct routing is used and the node CIDR and pod CIDR overlap. |
| encryption.strictMode.cidr | string | `""` | CIDR for the Encryption Pod2Pod strict mode. (deprecated: please use encryption.strictMode.egress.cidr) |
| encryption.strictMode.egress.allowRemoteNodeIdentities | bool | `false` | Allow dynamic lookup of remote node identities. This is required when tunneling is used or direct routing is used and the node CIDR and pod CIDR overlap. |
| encryption.strictMode.egress.cidr | string | `""` | CIDR for the Encryption Pod2Pod strict egress mode. |
| encryption.strictMode.egress.enabled | bool | `false` | Enable strict egress encryption. |
| encryption.strictMode.enabled | bool | `false` | Enable Encryption Pod2Pod strict mode. (deprecated: please use encryption.strictMode.egress.enabled) |
| encryption.strictMode.ingress.enabled | bool | `false` | Enable strict ingress encryption. When enabled, all unencrypted overlay ingress traffic will be dropped. This option is only applicable when WireGuard and tunneling are enabled. |
| encryption.type | string | `"ipsec"` | Encryption method. Can be one of ipsec, wireguard or ztunnel. |
| encryption.wireguard.persistentKeepalive | string | `"0s"` | Controls WireGuard PersistentKeepalive option. Set 0s to disable. |
| endpointHealthChecking.enabled | bool | `true` | Enable connectivity health checking between virtual endpoints. |
| endpointLockdownOnMapOverflow | bool | `false` | Enable endpoint lockdown on policy map overflow. |
@@ -373,12 +413,24 @@ contributors across the globe, there is almost always someone available to help.
| eni.gcTags | object | `{"io.cilium/cilium-managed":"true,"io.cilium/cluster-name":"<auto-detected>"}` | Additional tags attached to ENIs created by Cilium. Dangling ENIs with this tag will be garbage collected |
| eni.iamRole | string | `""` | If using IAM role for Service Accounts will not try to inject identity values from cilium-aws kubernetes secret. Adds annotation to service account if managed by Helm. See https://github.com/aws/amazon-eks-pod-identity-webhook |
| eni.instanceTagsFilter | list | `[]` | Filter via AWS EC2 Instance tags (k=v) which will dictate which AWS EC2 Instances are going to be used to create new ENIs |
| eni.nodeSpec | object | `{"deleteOnTermination":null,"disablePrefixDelegation":false,"excludeInterfaceTags":[],"firstInterfaceIndex":null,"securityGroupTags":[],"securityGroups":[],"subnetIDs":[],"subnetTags":[],"usePrimaryAddress":false}` | NodeSpec configuration for the ENI |
| eni.nodeSpec.deleteOnTermination | string | `nil` | Delete ENI on termination @schema type: [null, boolean] @schema |
| eni.nodeSpec.disablePrefixDelegation | bool | `false` | Disable prefix delegation for IP allocation |
| eni.nodeSpec.excludeInterfaceTags | list | `[]` | Exclude interface tags to use for IP allocation |
| eni.nodeSpec.firstInterfaceIndex | string | `nil` | First interface index to use for IP allocation @schema type: [null, integer] @schema |
| eni.nodeSpec.securityGroupTags | list | `[]` | Security group tags to use for IP allocation |
| eni.nodeSpec.securityGroups | list | `[]` | Security groups to use for IP allocation |
| eni.nodeSpec.subnetIDs | list | `[]` | Subnet IDs to use for IP allocation |
| eni.nodeSpec.subnetTags | list | `[]` | Subnet tags to use for IP allocation |
| eni.nodeSpec.usePrimaryAddress | bool | `false` | Use primary address for IP allocation |
| eni.subnetIDsFilter | list | `[]` | Filter via subnet IDs which will dictate which subnets are going to be used to create new ENIs Important note: This requires that each instance has an ENI with a matching subnet attached when Cilium is deployed. If you only want to control subnets for ENIs attached by Cilium, use the CNI configuration file settings (cni.customConf) instead. |
| eni.subnetTagsFilter | list | `[]` | Filter via tags (k=v) which will dictate which subnets are going to be used to create new ENIs Important note: This requires that each instance has an ENI with a matching subnet attached when Cilium is deployed. If you only want to control subnets for ENIs attached by Cilium, use the CNI configuration file settings (cni.customConf) instead. |
| envoy.affinity | object | `{"nodeAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"cilium.io/no-schedule","operator":"NotIn","values":["true"]}]}]}},"podAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":[{"labelSelector":{"matchLabels":{"k8s-app":"cilium"}},"topologyKey":"kubernetes.io/hostname"}]},"podAntiAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":[{"labelSelector":{"matchLabels":{"k8s-app":"cilium-envoy"}},"topologyKey":"kubernetes.io/hostname"}]}}` | Affinity for cilium-envoy. |
| envoy.annotations | object | `{}` | Annotations to be added to all top-level cilium-envoy objects (resources under templates/cilium-envoy) |
| envoy.baseID | int | `0` | Set Envoy'--base-id' to use when allocating shared memory regions. Only needs to be changed if multiple Envoy instances will run on the same node and may have conflicts. Supported values: 0 - 4294967295. Defaults to '0' |
| envoy.bootstrapConfigMap | string | `nil` | ADVANCED OPTION: Bring your own custom Envoy bootstrap ConfigMap. Provide the name of a ConfigMap with a `bootstrap-config.json` key. When specified, Envoy will use this ConfigMap instead of the default provided by the chart. WARNING: Use of this setting has the potential to prevent cilium-envoy from starting up, and can cause unexpected behavior (e.g. due to syntax error or semantically incorrect configuration). Before submitting an issue, please ensure you have disabled this feature, as support cannot be provided for custom Envoy bootstrap configs. @schema type: [null, string] @schema |
| envoy.clusterMaxConnections | int | `1024` | Maximum number of connections on Envoy clusters |
| envoy.clusterMaxRequests | int | `1024` | Maximum number of requests on Envoy clusters |
| envoy.connectTimeoutSeconds | int | `2` | Time in seconds after which a TCP connection attempt times out |
| envoy.debug.admin.enabled | bool | `false` | Enable admin interface for cilium-envoy. This is useful for debugging and should not be enabled in production. |
| envoy.debug.admin.port | int | `9901` | Port number (bound to loopback interface). kubectl port-forward can be used to access the admin interface. |
@@ -394,7 +446,8 @@ contributors across the globe, there is almost always someone available to help.
| envoy.httpRetryCount | int | `3` | Maximum number of retries for each HTTP request |
| envoy.httpUpstreamLingerTimeout | string | `nil` | Time in seconds to block Envoy worker thread while an upstream HTTP connection is closing. If set to 0, the connection is closed immediately (with TCP RST). If set to -1, the connection is closed asynchronously in the background. |
| envoy.idleTimeoutDurationSeconds | int | `60` | Set Envoy upstream HTTP idle connection timeout seconds. Does not apply to connections with pending requests. Default 60s |
| envoy.image | object | `{"digest":"sha256:81398e449f2d3d0a6a70527e4f641aaa685d3156bea0bb30712fae3fd8822b86","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium-envoy","tag":"v1.35.9-1767794330-db497dd19e346b39d81d7b5c0dedf6c812bcc5c9","useDigest":true}` | Envoy container image. |
| envoy.image | object | `{"digest":"sha256:8188114a2768b5f49d6ce58e168b20d765e0fbc64eee0d83241aa2b150ccd788","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium-envoy","tag":"v1.35.9-1770979049-232ed4a26881e4ab4f766f251f258ed424fff663","useDigest":true}` | Envoy container image. |
| envoy.initContainers | list | `[]` | Init containers added to the cilium Envoy DaemonSet. |
| envoy.initialFetchTimeoutSeconds | int | `30` | Time in seconds after which the initial fetch on an xDS stream is considered timed out |
| envoy.livenessProbe.enabled | bool | `true` | Enable liveness probe for cilium-envoy |
| envoy.livenessProbe.failureThreshold | int | `10` | failure threshold of liveness probe |
@@ -406,6 +459,7 @@ contributors across the globe, there is almost always someone available to help.
| envoy.log.path | string | `""` | Path to a separate Envoy log file, if any. Defaults to /dev/stdout. |
| envoy.maxConcurrentRetries | int | `128` | Maximum number of concurrent retries on Envoy clusters |
| envoy.maxConnectionDurationSeconds | int | `0` | Set Envoy HTTP option max_connection_duration seconds. Default 0 (disable) |
| envoy.maxGlobalDownstreamConnections | int | `50000` | Maximum number of global downstream connections |
| envoy.maxRequestsPerConnection | int | `0` | ProxyMaxRequestsPerConnection specifies the max_requests_per_connection setting for Envoy |
| envoy.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node selector for cilium-envoy. |
| envoy.podAnnotations | object | `{}` | Annotations to be added to envoy pods |
@@ -439,6 +493,7 @@ contributors across the globe, there is almost always someone available to help.
| envoy.terminationGracePeriodSeconds | int | `1` | Configure termination grace period for cilium-envoy DaemonSet. |
| envoy.tolerations | list | `[{"operator":"Exists"}]` | Node tolerations for envoy scheduling to nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ |
| envoy.updateStrategy | object | `{"rollingUpdate":{"maxUnavailable":2},"type":"RollingUpdate"}` | cilium-envoy update strategy ref: https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/#updating-a-daemonset |
| envoy.useOriginalSourceAddress | bool | `true` | For cases when CiliumEnvoyConfig is not used directly (Ingress, Gateway), configures Cilium BPF Metadata listener filter to use the original source address when extracting the metadata for a request. |
| envoy.xffNumTrustedHopsL7PolicyEgress | int | `0` | Number of trusted hops regarding the x-forwarded-for and related HTTP headers for the egress L7 policy enforcement Envoy listeners. |
| envoy.xffNumTrustedHopsL7PolicyIngress | int | `0` | Number of trusted hops regarding the x-forwarded-for and related HTTP headers for the ingress L7 policy enforcement Envoy listeners. |
| envoyConfig.enabled | bool | `false` | Enable CiliumEnvoyConfig CRD CiliumEnvoyConfig CRD can also be implicitly enabled by other options. |
@@ -482,12 +537,13 @@ contributors across the globe, there is almost always someone available to help.
| hubble.dropEventEmitter.interval | string | `"2m"` | - Minimum time between emitting same events. |
| hubble.dropEventEmitter.reasons | list | `["auth_required","policy_denied"]` | - Drop reasons to emit events for. ref: https://docs.cilium.io/en/stable/_api/v1/flow/README/#dropreason |
| hubble.enabled | bool | `true` | Enable Hubble (true by default). |
| hubble.export | object | `{"dynamic":{"config":{"configMapName":"cilium-flowlog-config","content":[{"excludeFilters":[],"fieldMask":[],"fileCompress":false,"fileMaxBackups":5,"fileMaxSizeMb":10,"filePath":"/var/run/cilium/hubble/events.log","includeFilters":[],"name":"all"}],"createConfigMap":true},"enabled":false},"static":{"allowList":[],"denyList":[],"enabled":false,"fieldMask":[],"fileCompress":false,"fileMaxBackups":5,"fileMaxSizeMb":10,"filePath":"/var/run/cilium/hubble/events.log"}}` | Hubble flows export. |
| hubble.export.dynamic | object | `{"config":{"configMapName":"cilium-flowlog-config","content":[{"excludeFilters":[],"fieldMask":[],"fileCompress":false,"fileMaxBackups":5,"fileMaxSizeMb":10,"filePath":"/var/run/cilium/hubble/events.log","includeFilters":[],"name":"all"}],"createConfigMap":true},"enabled":false}` | - Dynamic exporters configuration. Dynamic exporters may be reconfigured without a need of agent restarts. |
| hubble.export | object | `{"dynamic":{"config":{"configMapName":"cilium-flowlog-config","content":[{"aggregationInterval":"0s","excludeFilters":[],"fieldAggregate":[],"fieldMask":[],"fileCompress":false,"fileMaxBackups":5,"fileMaxSizeMb":10,"filePath":"/var/run/cilium/hubble/events.log","includeFilters":[],"name":"all"}],"createConfigMap":true},"enabled":false},"static":{"aggregationInterval":"0s","allowList":[],"denyList":[],"enabled":false,"fieldAggregate":[],"fieldMask":[],"fileCompress":false,"fileMaxBackups":5,"fileMaxSizeMb":10,"filePath":"/var/run/cilium/hubble/events.log"}}` | Hubble flows export. |
| hubble.export.dynamic | object | `{"config":{"configMapName":"cilium-flowlog-config","content":[{"aggregationInterval":"0s","excludeFilters":[],"fieldAggregate":[],"fieldMask":[],"fileCompress":false,"fileMaxBackups":5,"fileMaxSizeMb":10,"filePath":"/var/run/cilium/hubble/events.log","includeFilters":[],"name":"all"}],"createConfigMap":true},"enabled":false}` | - Dynamic exporters configuration. Dynamic exporters may be reconfigured without a need of agent restarts. |
| hubble.export.dynamic.config.configMapName | string | `"cilium-flowlog-config"` | -- Name of configmap with configuration that may be altered to reconfigure exporters within a running agents. |
| hubble.export.dynamic.config.content | list | `[{"excludeFilters":[],"fieldMask":[],"fileCompress":false,"fileMaxBackups":5,"fileMaxSizeMb":10,"filePath":"/var/run/cilium/hubble/events.log","includeFilters":[],"name":"all"}]` | -- Exporters configuration in YAML format. |
| hubble.export.dynamic.config.content | list | `[{"aggregationInterval":"0s","excludeFilters":[],"fieldAggregate":[],"fieldMask":[],"fileCompress":false,"fileMaxBackups":5,"fileMaxSizeMb":10,"filePath":"/var/run/cilium/hubble/events.log","includeFilters":[],"name":"all"}]` | -- Exporters configuration in YAML format. |
| hubble.export.dynamic.config.createConfigMap | bool | `true` | -- True if helm installer should create config map. Switch to false if you want to self maintain the file content. |
| hubble.export.static | object | `{"allowList":[],"denyList":[],"enabled":false,"fieldMask":[],"fileCompress":false,"fileMaxBackups":5,"fileMaxSizeMb":10,"filePath":"/var/run/cilium/hubble/events.log"}` | - Static exporter configuration. Static exporter is bound to agent lifecycle. |
| hubble.export.static | object | `{"aggregationInterval":"0s","allowList":[],"denyList":[],"enabled":false,"fieldAggregate":[],"fieldMask":[],"fileCompress":false,"fileMaxBackups":5,"fileMaxSizeMb":10,"filePath":"/var/run/cilium/hubble/events.log"}` | - Static exporter configuration. Static exporter is bound to agent lifecycle. |
| hubble.export.static.aggregationInterval | string | `"0s"` | - Defines the interval at which to aggregate before exporting Hubble flows. Aggregation feature is only enabled when fieldAggregate is specified and aggregationInterval > 0s. |
| hubble.export.static.fileCompress | bool | `false` | - Enable compression of rotated files. |
| hubble.export.static.fileMaxBackups | int | `5` | - Defines max number of backup/rotated files. |
| hubble.export.static.fileMaxSizeMb | int | `10` | - Defines max file size of output file before it gets rotated. |
@@ -535,9 +591,12 @@ contributors across the globe, there is almost always someone available to help.
| hubble.relay.extraVolumes | list | `[]` | Additional hubble-relay volumes. |
| hubble.relay.gops.enabled | bool | `true` | Enable gops for hubble-relay |
| hubble.relay.gops.port | int | `9893` | Configure gops listen port for hubble-relay |
| hubble.relay.image | object | `{"digest":"sha256:fb6135e34c31e5f175cb5e75f86cea52ef2ff12b49bcefb7088ed93f5009eb8e","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/hubble-relay","tag":"v1.18.6","useDigest":true}` | Hubble-relay container image. |
| hubble.relay.image | object | `{"digest":"sha256:d8c4e13bc36a56179292bb52bc6255379cb94cb873700d316ea3139b1bdb8165","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/hubble-relay","tag":"v1.19.1","useDigest":true}` | Hubble-relay container image. |
| hubble.relay.listenHost | string | `""` | Host to listen to. Specify an empty string to bind to all the interfaces. |
| hubble.relay.listenPort | string | `"4245"` | Port to listen to. |
| hubble.relay.logOptions | object | `{"format":null,"level":null}` | Logging configuration for hubble-relay. |
| hubble.relay.logOptions.format | string | text-ts | Log format for hubble-relay. Valid values are: text, text-ts, json, json-ts. |
| hubble.relay.logOptions.level | string | info | Log level for hubble-relay. Valid values are: debug, info, warn, error. |
| hubble.relay.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for pod assignment ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector |
| hubble.relay.podAnnotations | object | `{}` | Annotations to be added to hubble-relay pods |
| hubble.relay.podDisruptionBudget.enabled | bool | `false` | enable PodDisruptionBudget ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ |
@@ -547,7 +606,9 @@ contributors across the globe, there is almost always someone available to help.
| hubble.relay.podLabels | object | `{}` | Labels to be added to hubble-relay pods |
| hubble.relay.podSecurityContext | object | `{"fsGroup":65532,"seccompProfile":{"type":"RuntimeDefault"}}` | hubble-relay pod security context |
| hubble.relay.pprof.address | string | `"localhost"` | Configure pprof listen address for hubble-relay |
| hubble.relay.pprof.blockProfileRate | int | `0` | Enable goroutine blocking profiling for hubble-relay and set the rate of sampled events in nanoseconds (set to 1 to sample all events [warning: performance overhead]) |
| hubble.relay.pprof.enabled | bool | `false` | Enable pprof for hubble-relay |
| hubble.relay.pprof.mutexProfileFraction | int | `0` | Enable mutex contention profiling for hubble-relay and set the fraction of sampled events (set to 1 to sample all events) |
| hubble.relay.pprof.port | int | `6062` | Configure pprof listen port for hubble-relay |
| hubble.relay.priorityClassName | string | `""` | The priority class to use for hubble-relay |
| hubble.relay.prometheus | object | `{"enabled":false,"port":9966,"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","labels":{},"metricRelabelings":null,"relabelings":null,"scrapeTimeout":null}}` | Enable prometheus metrics for hubble-relay on the configured port at /metrics |
@@ -641,13 +702,14 @@ contributors across the globe, there is almost always someone available to help.
| hubble.ui.tls.client.cert | string | `""` | base64 encoded PEM values for the Hubble UI client certificate (deprecated). Use existingSecret instead. |
| hubble.ui.tls.client.existingSecret | string | `""` | Name of the Secret containing the client certificate and key for Hubble UI If specified, cert and key are ignored. |
| hubble.ui.tls.client.key | string | `""` | base64 encoded PEM values for the Hubble UI client key (deprecated). Use existingSecret instead. |
| hubble.ui.tmpVolume | object | `{}` | Configure temporary volume for hubble-ui |
| hubble.ui.tolerations | list | `[]` | Node tolerations for pod assignment on nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ |
| hubble.ui.topologySpreadConstraints | list | `[]` | Pod topology spread constraints for hubble-ui |
| hubble.ui.updateStrategy | object | `{"rollingUpdate":{"maxUnavailable":1},"type":"RollingUpdate"}` | hubble-ui update strategy. |
| identityAllocationMode | string | `"crd"` | Method to use for identity allocation (`crd`, `kvstore` or `doublewrite-readkvstore` / `doublewrite-readcrd` for migrating between identity backends). |
| identityChangeGracePeriod | string | `"5s"` | Time to wait before using new identity on endpoint identity change. |
| identityManagementMode | string | `"agent"` | Control whether CiliumIdentities are created by the agent ("agent"), the operator ("operator") or both ("both"). "Both" should be used only to migrate between "agent" and "operator". Operator-managed identities is a beta feature. |
| image | object | `{"digest":"sha256:42ec562a5ff6c8a860c0639f5a7611685e253fd9eb2d2fcdade693724c9166a4","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium","tag":"v1.18.6","useDigest":true}` | Agent container image. |
| image | object | `{"digest":"sha256:41f1f74a0000de8656f1de4088ea00c8f2d49d6edea579034c73c5fd5fe01792","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium","tag":"v1.19.1","useDigest":true}` | Agent container image. |
| imagePullSecrets | list | `[]` | Configure image pull secrets for pulling container images |
| ingressController.default | bool | `false` | Set cilium ingress controller to be the default ingress controller This will let cilium ingress controller route entries without ingress class set |
| ingressController.defaultSecretName | string | `nil` | Default secret name for ingresses without .spec.tls[].secretName set. |
@@ -682,6 +744,11 @@ contributors across the globe, there is almost always someone available to help.
| ipam.installUplinkRoutesForDelegatedIPAM | bool | `false` | Install ingress/egress routes through uplink on host for Pods when working with delegated IPAM plugin. |
| ipam.mode | string | `"cluster-pool"` | Configure IP Address Management mode. ref: https://docs.cilium.io/en/stable/network/concepts/ipam/ |
| ipam.multiPoolPreAllocation | string | `""` | Pre-allocation settings for IPAM in Multi-Pool mode |
| ipam.nodeSpec | object | `{"ipamMaxAllocate":null,"ipamMinAllocate":null,"ipamPreAllocate":null,"ipamStaticIPTags":[]}` | NodeSpec configuration for the IPAM |
| ipam.nodeSpec.ipamMaxAllocate | string | `nil` | IPAM max allocate @schema type: [null, integer] @schema |
| ipam.nodeSpec.ipamMinAllocate | string | `nil` | IPAM min allocate @schema type: [null, integer] @schema |
| ipam.nodeSpec.ipamPreAllocate | string | `nil` | IPAM pre allocate @schema type: [null, integer] @schema |
| ipam.nodeSpec.ipamStaticIPTags | list | `[]` | IPAM static IP tags (currently only works with AWS and Azure) |
| ipam.operator.autoCreateCiliumPodIPPools | object | `{}` | IP pools to auto-create in multi-pool IPAM mode. |
| ipam.operator.clusterPoolIPv4MaskSize | int | `24` | IPv4 CIDR mask size to delegate to individual nodes for IPAM. |
| ipam.operator.clusterPoolIPv4PodCIDRList | list | `["10.0.0.0/8"]` | IPv4 CIDR list range to delegate to individual nodes for IPAM. |
@@ -744,19 +811,18 @@ contributors across the globe, there is almost always someone available to help.
| monitor | object | `{"enabled":false}` | cilium-monitor sidecar. |
| monitor.enabled | bool | `false` | Enable the cilium-monitor sidecar. |
| name | string | `"cilium"` | Agent daemonset name. |
| namespaceOverride | string | `""` | namespaceOverride allows to override the destination namespace for Cilium resources. This property allows to use Cilium as part of an Umbrella Chart with different targets. |
| namespaceOverride | string | `""` | namespaceOverride allows to override the destination namespace for Cilium resources. |
| nat.mapStatsEntries | int | `32` | Number of the top-k SNAT map connections to track in Cilium statedb. |
| nat.mapStatsInterval | string | `"30s"` | Interval between how often SNAT map is counted for stats. |
| nat46x64Gateway | object | `{"enabled":false}` | Configure standalone NAT46/NAT64 gateway |
| nat46x64Gateway.enabled | bool | `false` | Enable RFC6052-prefixed translation |
| nodeIPAM.enabled | bool | `false` | Configure Node IPAM ref: https://docs.cilium.io/en/stable/network/node-ipam/ |
| nodePort | object | `{"addresses":null,"autoProtectPortRange":true,"bindProtection":true,"enableHealthCheck":true,"enableHealthCheckLoadBalancerIP":false,"enabled":false}` | Configure N-S k8s service loadbalancing |
| nodePort | object | `{"addresses":null,"autoProtectPortRange":true,"bindProtection":true,"enableHealthCheck":true,"enableHealthCheckLoadBalancerIP":false}` | Configure N-S k8s service loadbalancing |
| nodePort.addresses | string | `nil` | List of CIDRs for choosing which IP addresses assigned to native devices are used for NodePort load-balancing. By default this is empty and the first suitable, preferably private, IPv4 and IPv6 address assigned to each device is used. Example: addresses: ["192.168.1.0/24", "2001::/64"] |
| nodePort.autoProtectPortRange | bool | `true` | Append NodePort range to ip_local_reserved_ports if clash with ephemeral ports is detected. |
| nodePort.bindProtection | bool | `true` | Set to true to prevent applications binding to service ports. |
| nodePort.enableHealthCheck | bool | `true` | Enable healthcheck nodePort server for NodePort services |
| nodePort.enableHealthCheckLoadBalancerIP | bool | `false` | Enable access of the healthcheck nodePort on the LoadBalancerIP. Needs EnableHealthCheck to be enabled |
| nodePort.enabled | bool | `false` | Enable the Cilium NodePort service implementation. |
| nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node selector for cilium-agent. |
| nodeSelectorLabels | bool | `false` | Enable/Disable use of node label based identity |
| nodeinit.affinity | object | `{}` | Affinity for cilium-nodeinit |
@@ -766,7 +832,7 @@ contributors across the globe, there is almost always someone available to help.
| nodeinit.extraEnv | list | `[]` | Additional nodeinit environment variables. |
| nodeinit.extraVolumeMounts | list | `[]` | Additional nodeinit volumeMounts. |
| nodeinit.extraVolumes | list | `[]` | Additional nodeinit volumes. |
| nodeinit.image | object | `{"digest":"sha256:5bdca3c2dec2c79f58d45a7a560bf1098c2126350c901379fe850b7f78d3d757","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/startup-script","tag":"1755531540-60ee83e","useDigest":true}` | node-init image. |
| nodeinit.image | object | `{"digest":"sha256:50b9cf9c280096b59b80d2fc8ee6638facef79ac18998a22f0cbc40d5d28c16f","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/startup-script","tag":"1763560095-8f36c34","useDigest":true}` | node-init image. |
| nodeinit.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for nodeinit pod assignment ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector |
| nodeinit.podAnnotations | object | `{}` | Annotations to be added to node-init pods. |
| nodeinit.podLabels | object | `{}` | Labels to be added to node-init pods. |
@@ -779,6 +845,7 @@ contributors across the globe, there is almost always someone available to help.
| nodeinit.startup | object | `{"postScript":"","preScript":""}` | startup offers way to customize startup nodeinit script (pre and post position) |
| nodeinit.tolerations | list | `[{"operator":"Exists"}]` | Node tolerations for nodeinit scheduling to nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ |
| nodeinit.updateStrategy | object | `{"type":"RollingUpdate"}` | node-init update strategy |
| nodeinit.waitForCloudInit | bool | `false` | wait for Cloud init to finish on the host and assume the node has cloud init installed |
| operator.affinity | object | `{"podAntiAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":[{"labelSelector":{"matchLabels":{"io.cilium/app":"operator"}},"topologyKey":"kubernetes.io/hostname"}]}}` | Affinity for cilium-operator |
| operator.annotations | object | `{}` | Annotations to be added to all top-level cilium-operator objects (resources under templates/cilium-operator) |
| operator.dashboards | object | `{"annotations":{},"enabled":false,"label":"grafana_dashboard","labelValue":"1","namespace":null}` | Grafana dashboards for cilium-operator grafana can import dashboards based on the label and value ref: https://github.com/grafana/helm-charts/tree/main/charts/grafana#sidecar-for-dashboards |
@@ -793,7 +860,7 @@ contributors across the globe, there is almost always someone available to help.
| operator.hostNetwork | bool | `true` | HostNetwork setting |
| operator.identityGCInterval | string | `"15m0s"` | Interval for identity garbage collection. |
| operator.identityHeartbeatTimeout | string | `"30m0s"` | Timeout for identity heartbeats. |
| operator.image | object | `{"alibabacloudDigest":"sha256:212c4cbe27da3772bcb952b8f8cbaa0b0eef72488b52edf90ad2b32072a3ca4c","awsDigest":"sha256:47dbc1a5bd483fec170dab7fb0bf2cca3585a4893675b0324d41d97bac8be5eb","azureDigest":"sha256:a57aff47aeb32eccfedaa2a49d1af984d996d6d6de79609c232e0c4cf9ce97a1","genericDigest":"sha256:34a827ce9ed021c8adf8f0feca131f53b3c54a3ef529053d871d0347ec4d69af","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/operator","suffix":"","tag":"v1.18.6","useDigest":true}` | cilium-operator image. |
| operator.image | object | `{"alibabacloudDigest":"sha256:837b12f4239e88ea5b4b5708ab982c319a94ee05edaecaafe5fd0e5b1962f554","awsDigest":"sha256:18913d05a6c4d205f0b7126c4723bb9ccbd4dc24403da46ed0f9f4bf2a142804","azureDigest":"sha256:82bce78603056e709d4c4e9f9ebb25c222c36d8a07f8c05381c2372d9078eca8","genericDigest":"sha256:e7278d763e448bf6c184b0682cf98cdca078d58a27e1b2f3c906792670aa211a","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/operator","suffix":"","tag":"v1.19.1","useDigest":true}` | cilium-operator image. |
| operator.nodeGCInterval | string | `"5m0s"` | Interval for cilium node garbage collection. |
| operator.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for cilium-operator pod assignment ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector |
| operator.podAnnotations | object | `{}` | Annotations to be added to cilium-operator pods |
@@ -804,10 +871,12 @@ contributors across the globe, there is almost always someone available to help.
| operator.podLabels | object | `{}` | Labels to be added to cilium-operator pods |
| operator.podSecurityContext | object | `{"seccompProfile":{"type":"RuntimeDefault"}}` | Security context to be added to cilium-operator pods |
| operator.pprof.address | string | `"localhost"` | Configure pprof listen address for cilium-operator |
| operator.pprof.blockProfileRate | int | `0` | Enable goroutine blocking profiling for cilium-operator and set the rate of sampled events in nanoseconds (set to 1 to sample all events [warning: performance overhead]) |
| operator.pprof.enabled | bool | `false` | Enable pprof for cilium-operator |
| operator.pprof.mutexProfileFraction | int | `0` | Enable mutex contention profiling for cilium-operator and set the fraction of sampled events (set to 1 to sample all events) |
| operator.pprof.port | int | `6061` | Configure pprof listen port for cilium-operator |
| operator.priorityClassName | string | `""` | The priority class to use for cilium-operator |
| operator.prometheus | object | `{"enabled":true,"metricsService":false,"port":9963,"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","jobLabel":"","labels":{},"metricRelabelings":null,"relabelings":null,"scrapeTimeout":null}}` | Enable prometheus metrics for cilium-operator on the configured port at /metrics |
| operator.prometheus | object | `{"enabled":true,"metricsService":false,"port":9963,"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","jobLabel":"","labels":{},"metricRelabelings":null,"relabelings":null,"scrapeTimeout":null},"tls":{"enabled":false,"server":{"existingSecret":"","mtls":{"enabled":false}}}}` | Enable prometheus metrics for cilium-operator on the configured port at /metrics |
| operator.prometheus.serviceMonitor.annotations | object | `{}` | Annotations to add to ServiceMonitor cilium-operator |
| operator.prometheus.serviceMonitor.enabled | bool | `false` | Enable service monitors. This requires the prometheus CRDs to be available (see https://github.com/prometheus-operator/prometheus-operator/blob/main/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml) |
| operator.prometheus.serviceMonitor.interval | string | `"10s"` | Interval for scrape metrics. |
@@ -816,6 +885,8 @@ contributors across the globe, there is almost always someone available to help.
| operator.prometheus.serviceMonitor.metricRelabelings | string | `nil` | Metrics relabeling configs for the ServiceMonitor cilium-operator |
| operator.prometheus.serviceMonitor.relabelings | string | `nil` | Relabeling configs for the ServiceMonitor cilium-operator |
| operator.prometheus.serviceMonitor.scrapeTimeout | string | `nil` | Timeout after which scrape is considered to be failed. |
| operator.prometheus.tls | object | `{"enabled":false,"server":{"existingSecret":"","mtls":{"enabled":false}}}` | TLS configuration for Prometheus |
| operator.prometheus.tls.server.existingSecret | string | `""` | Name of the Secret containing the certificate, key and CA files for the Prometheus server. |
| operator.removeNodeTaints | bool | `true` | Remove Cilium node taint from Kubernetes nodes that have a healthy Cilium pod running. |
| operator.replicas | int | `2` | Number of replicas to run for the cilium-operator deployment |
| operator.resources | object | `{}` | cilium-operator resource limits & requests ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ |
@@ -828,25 +899,30 @@ contributors across the globe, there is almost always someone available to help.
| operator.topologySpreadConstraints | list | `[]` | Pod topology spread constraints for cilium-operator |
| operator.unmanagedPodWatcher.intervalSeconds | int | `15` | Interval, in seconds, to check if there are any pods that are not managed by Cilium. |
| operator.unmanagedPodWatcher.restart | bool | `true` | Restart any pod that are not managed by Cilium. |
| operator.unmanagedPodWatcher.selector | string | `nil` | Selector for pods that should be restarted when not managed by Cilium. If not set, defaults to built-in selector "k8s-app=kube-dns". Set to empty string to select all pods. @schema type: [null, string] @schema |
| operator.updateStrategy | object | `{"rollingUpdate":{"maxSurge":"25%","maxUnavailable":"50%"},"type":"RollingUpdate"}` | cilium-operator update strategy |
| pmtuDiscovery.enabled | bool | `false` | Enable path MTU discovery to send ICMP fragmentation-needed replies to the client. |
| pmtuDiscovery.packetizationLayerPMTUDMode | string | `"blackhole"` | Enable kernel probing path MTU discovery for Pods which uses different message sizes to search for correct MTU value. Valid values are: always, blackhole, disabled and unset (or empty). If value is 'unset' or left empty then will not try to override setting. |
| podAnnotations | object | `{}` | Annotations to be added to agent pods |
| podLabels | object | `{}` | Labels to be added to agent pods |
| podSecurityContext | object | `{"appArmorProfile":{"type":"Unconfined"},"seccompProfile":{"type":"Unconfined"}}` | Security Context for cilium-agent pods. |
| podSecurityContext.appArmorProfile | object | `{"type":"Unconfined"}` | AppArmorProfile options for the `cilium-agent` and init containers |
| policyCIDRMatchMode | string | `nil` | policyCIDRMatchMode is a list of entities that may be selected by CIDR selector. The possible value is "nodes". |
| policyDenyResponse | string | `"none"` | Configure what the response should be to pod egress traffic denied by network policy. Possible values: - none (default) - icmp |
| policyEnforcementMode | string | `"default"` | The agent can be put into one of the three policy enforcement modes: default, always and never. ref: https://docs.cilium.io/en/stable/security/policy/intro/#policy-enforcement-modes |
| pprof.address | string | `"localhost"` | Configure pprof listen address for cilium-agent |
| pprof.blockProfileRate | int | `0` | Enable goroutine blocking profiling for cilium-agent and set the rate of sampled events in nanoseconds (set to 1 to sample all events [warning: performance overhead]) |
| pprof.enabled | bool | `false` | Enable pprof for cilium-agent |
| pprof.mutexProfileFraction | int | `0` | Enable mutex contention profiling for cilium-agent and set the fraction of sampled events (set to 1 to sample all events) |
| pprof.port | int | `6060` | Configure pprof listen port for cilium-agent |
| preflight.affinity | object | `{"podAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":[{"labelSelector":{"matchLabels":{"k8s-app":"cilium"}},"topologyKey":"kubernetes.io/hostname"}]}}` | Affinity for cilium-preflight |
| preflight.annotations | object | `{}` | Annotations to be added to all top-level preflight objects (resources under templates/cilium-preflight) |
| preflight.enabled | bool | `false` | Enable Cilium pre-flight resources (required for upgrade) |
| preflight.envoy.image | object | `{"digest":"sha256:81398e449f2d3d0a6a70527e4f641aaa685d3156bea0bb30712fae3fd8822b86","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium-envoy","tag":"v1.35.9-1767794330-db497dd19e346b39d81d7b5c0dedf6c812bcc5c9","useDigest":true}` | Envoy pre-flight image. |
| preflight.envoy.image | object | `{"digest":"sha256:8188114a2768b5f49d6ce58e168b20d765e0fbc64eee0d83241aa2b150ccd788","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium-envoy","tag":"v1.35.9-1770979049-232ed4a26881e4ab4f766f251f258ed424fff663","useDigest":true}` | Envoy pre-flight image. |
| preflight.extraEnv | list | `[]` | Additional preflight environment variables. |
| preflight.extraVolumeMounts | list | `[]` | Additional preflight volumeMounts. |
| preflight.extraVolumes | list | `[]` | Additional preflight volumes. |
| preflight.image | object | `{"digest":"sha256:42ec562a5ff6c8a860c0639f5a7611685e253fd9eb2d2fcdade693724c9166a4","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium","tag":"v1.18.6","useDigest":true}` | Cilium pre-flight image. |
| preflight.image | object | `{"digest":"sha256:41f1f74a0000de8656f1de4088ea00c8f2d49d6edea579034c73c5fd5fe01792","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium","tag":"v1.19.1","useDigest":true}` | Cilium pre-flight image. |
| preflight.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for preflight pod assignment ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector |
| preflight.podAnnotations | object | `{}` | Annotations to be added to preflight pods |
| preflight.podDisruptionBudget.enabled | bool | `false` | enable PodDisruptionBudget ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ |
@@ -890,24 +966,36 @@ contributors across the globe, there is almost always someone available to help.
| sctp | object | `{"enabled":false}` | SCTP Configuration Values |
| sctp.enabled | bool | `false` | Enable SCTP support. NOTE: Currently, SCTP support does not support rewriting ports or multihoming. |
| secretsNamespaceAnnotations | object | `{}` | Annotations to be added to all cilium-secret namespaces (resources under templates/cilium-secrets-namespace) |
| secretsNamespaceLabels | object | `{}` | Labels to be added to all cilium-secret namespaces (resources under templates/cilium-secrets-namespace) |
| securityContext.allowPrivilegeEscalation | bool | `false` | disable privilege escalation |
| securityContext.capabilities.applySysctlOverwrites | list | `["SYS_ADMIN","SYS_CHROOT","SYS_PTRACE"]` | capabilities for the `apply-sysctl-overwrites` init container |
| securityContext.capabilities.ciliumAgent | list | `["CHOWN","KILL","NET_ADMIN","NET_RAW","IPC_LOCK","SYS_MODULE","SYS_ADMIN","SYS_RESOURCE","DAC_OVERRIDE","FOWNER","SETGID","SETUID"]` | Capabilities for the `cilium-agent` container |
| securityContext.capabilities.ciliumAgent | list | `["CHOWN","KILL","NET_ADMIN","NET_RAW","IPC_LOCK","SYS_MODULE","SYS_ADMIN","SYS_RESOURCE","DAC_OVERRIDE","FOWNER","SETGID","SETUID","SYSLOG"]` | Capabilities for the `cilium-agent` container |
| securityContext.capabilities.cleanCiliumState | list | `["NET_ADMIN","SYS_MODULE","SYS_ADMIN","SYS_RESOURCE"]` | Capabilities for the `clean-cilium-state` init container |
| securityContext.capabilities.mountCgroup | list | `["SYS_ADMIN","SYS_CHROOT","SYS_PTRACE"]` | Capabilities for the `mount-cgroup` init container |
| securityContext.privileged | bool | `false` | Run the pod with elevated privileges |
| securityContext.seLinuxOptions | object | `{"level":"s0","type":"spc_t"}` | SELinux options for the `cilium-agent` and init containers |
| serviceAccounts | object | Component's fully qualified name. | Define serviceAccount names for components. |
| serviceAccounts.clustermeshcertgen | object | `{"annotations":{},"automount":true,"create":true,"name":"clustermesh-apiserver-generate-certs"}` | Clustermeshcertgen is used if clustermesh.apiserver.tls.auto.method=cronJob |
| serviceAccounts.corednsMCSAPI | object | `{"annotations":{},"automount":true,"create":true,"name":"cilium-coredns-mcsapi-autoconfig"}` | CorednsMCSAPI is used if clustermesh.mcsapi.corednsAutoConfigure.enabled=true |
| serviceAccounts.hubblecertgen | object | `{"annotations":{},"automount":true,"create":true,"name":"hubble-generate-certs"}` | Hubblecertgen is used if hubble.tls.auto.method=cronJob |
| serviceAccounts.nodeinit.enabled | bool | `false` | Enabled is temporary until https://github.com/cilium/cilium-cli/issues/1396 is implemented. Cilium CLI doesn't create the SAs for node-init, thus the workaround. Helm is not affected by this issue. Name and automount can be configured, if enabled is set to true. Otherwise, they are ignored. Enabled can be removed once the issue is fixed. Cilium-nodeinit DS must also be fixed. |
| serviceNoBackendResponse | string | `"reject"` | Configure what the response should be to traffic for a service without backends. Possible values: - reject (default) - drop |
| sleepAfterInit | bool | `false` | Do not run Cilium agent when running with clean mode. Useful to completely uninstall Cilium as it will stop Cilium from starting and create artifacts in the node. |
| socketLB | object | `{"enabled":false}` | Configure socket LB |
| socketLB.enabled | bool | `false` | Enable socket LB |
| standaloneDnsProxy | object | `{"annotations":{},"automountServiceAccountToken":false,"debug":false,"enabled":false,"image":{"digest":"","override":null,"pullPolicy":"IfNotPresent","repository":"","tag":"","useDigest":true},"nodeSelector":{"kubernetes.io/os":"linux"},"rollOutPods":false,"serverPort":10095,"tolerations":[],"updateStrategy":{"rollingUpdate":{"maxSurge":2,"maxUnavailable":0},"type":"RollingUpdate"}}` | Standalone DNS Proxy Configuration Note: The standalone DNS proxy uses the agent's dnsProxy.* configuration for DNS settings (proxyPort, enableDnsCompression) to ensure consistency. |
| standaloneDnsProxy.annotations | object | `{}` | Standalone DNS proxy annotations |
| standaloneDnsProxy.automountServiceAccountToken | bool | `false` | Standalone DNS proxy auto mount service account token |
| standaloneDnsProxy.debug | bool | `false` | Standalone DNS proxy debug mode |
| standaloneDnsProxy.enabled | bool | `false` | Enable standalone DNS proxy (alpha feature) |
| standaloneDnsProxy.image | object | `{"digest":"","override":null,"pullPolicy":"IfNotPresent","repository":"","tag":"","useDigest":true}` | Standalone DNS proxy image |
| standaloneDnsProxy.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Standalone DNS proxy Node Selector |
| standaloneDnsProxy.rollOutPods | bool | `false` | Roll out Standalone DNS proxy automatically when configmap is updated. |
| standaloneDnsProxy.serverPort | int | `10095` | Standalone DNS proxy server port |
| standaloneDnsProxy.tolerations | list | `[]` | Standalone DNS proxy tolerations |
| standaloneDnsProxy.updateStrategy | object | `{"rollingUpdate":{"maxSurge":2,"maxUnavailable":0},"type":"RollingUpdate"}` | Standalone DNS proxy update strategy |
| startupProbe.failureThreshold | int | `300` | failure threshold of startup probe. Allow Cilium to take up to 600s to start up (300 attempts with 2s between attempts). |
| startupProbe.periodSeconds | int | `2` | interval between checks of the startup probe |
| svcSourceRangeCheck | bool | `true` | Enable check of service source ranges (currently, only for LoadBalancer). |
| synchronizeK8sNodes | bool | `true` | Synchronize Kubernetes nodes to kvstore and perform CNP GC. |
| sysctlfix | object | `{"enabled":true}` | Configure sysctl override described in #20072. |
| sysctlfix.enabled | bool | `true` | Enable the sysctl override. When enabled, the init container will mount the /proc of the host so that the `sysctlfix` utility can execute. |
@@ -929,11 +1017,12 @@ contributors across the globe, there is almost always someone available to help.
| tls.secretsNamespace | object | `{"create":true,"name":"cilium-secrets"}` | Configures where secrets used in CiliumNetworkPolicies will be looked for |
| tls.secretsNamespace.create | bool | `true` | Create secrets namespace for TLS Interception secrets. |
| tls.secretsNamespace.name | string | `"cilium-secrets"` | Name of TLS Interception secret namespace. |
| tmpVolume | object | `{}` | Configure temporary volume for cilium-agent |
| tolerations | list | `[{"operator":"Exists"}]` | Node tolerations for agent scheduling to nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ |
| tunnelPort | int | Port 8472 for VXLAN, Port 6081 for Geneve | Configure VXLAN and Geneve tunnel port. |
| tunnelProtocol | string | `"vxlan"` | Tunneling protocol to use in tunneling mode and for ad-hoc tunnels. Possible values: - "" - vxlan - geneve |
| tunnelSourcePortRange | string | 0-0 to let the kernel driver decide the range | Configure VXLAN and Geneve tunnel source port range hint. |
| underlayProtocol | string | `"ipv4"` | IP family for the underlay. |
| underlayProtocol | string | `"ipv4"` | IP family for the underlay. Possible values: - "ipv4" - "ipv6" |
| updateStrategy | object | `{"rollingUpdate":{"maxUnavailable":2},"type":"RollingUpdate"}` | Cilium agent update strategy |
| upgradeCompatibility | string | `nil` | upgradeCompatibility helps users upgrading to ensure that the configMap for Cilium will not change critical values to ensure continued operation This flag is not required for new installations. For example: '1.7', '1.8', '1.9' |
| vtep.cidr | string | `""` | A space separated list of VTEP device CIDRs, for example "1.1.1.0/24 1.1.2.0/24" |

View File

@@ -292,7 +292,7 @@ overloadManager:
- name: "envoy.resource_monitors.global_downstream_max_connections"
typedConfig:
"@type": "type.googleapis.com/envoy.extensions.resource_monitors.downstream_connections.v3.DownstreamConnectionsConfig"
max_active_downstream_connections: "50000"
max_active_downstream_connections: "{{ .Values.envoy.maxGlobalDownstreamConnections }}"
applicationLogConfig:
logFormat:
{{- if .Values.envoy.log.format_json }}

View File

@@ -156,6 +156,14 @@ fi
iptables -w -t nat -D POSTROUTING -m comment --comment "ip-masq: ensure nat POSTROUTING directs all non-LOCAL destination traffic to our custom IP-MASQ chain" -m addrtype ! --dst-type LOCAL -j IP-MASQ || true
{{- end }}
{{- if .Values.nodeinit.waitForCloudInit }}
echo "Waiting for cloud-init..."
if command -v cloud-init >/dev/null 2>&1; then
cloud-init status --wait
echo "cloud-init completed!"
fi
{{- end }}
{{- if not (eq .Values.nodeinit.bootstrapFile "") }}
mkdir -p {{ .Values.nodeinit.bootstrapFile | dir | quote }}
date > {{ .Values.nodeinit.bootstrapFile | quote }}

View File

@@ -21,6 +21,24 @@ dnsPolicy: {{ .Values.dnsPolicy }}
{{- end }}
{{- end }}
{{/*
Allow packagers to add extra volumes to cilium-operator.
*/}}
{{- define "cilium-operator.volumes.extra" }}
{{- end }}
{{- define "cilium-operator.volumeMounts.extra" }}
{{- end }}
{{/*
Allow packagers to set securityContext for cilium-operator.
*/}}
{{- define "cilium.operator.securityContext" }}
{{- with .Values.operator.securityContext }}
{{ toYaml . }}
{{- end }}
{{- end }}
{{/*
Intentionally empty to allow downstream chart packagers to add extra
containers to hubble-relay without having to modify the deployment manifest
@@ -72,3 +90,87 @@ Allow packagers to add extra configuration to certgen.
*/}}
{{- define "certgen.config.extra" -}}
{{- end }}
{{/*
Allow packagers to add extra arguments to the clustermesh-apiserver apiserver container.
*/}}
{{- define "clustermesh.apiserver.args.extra" -}}
{{- end }}
{{/*
Allow packagers to add extra arguments to the clustermesh-apiserver kvstoremesh container.
*/}}
{{- define "clustermesh.kvstoremesh.args.extra" -}}
{{- end }}
{{/*
Allow packagers to add init containers to the cilium-envoy pods.
*/}}
{{- define "envoy.initContainers" -}}
{{- end }}
{{/*
Allow packagers to add extra args to the cilium-envoy container.
*/}}
{{- define "envoy.args.extra" -}}
{{- end }}
{{/*
Allow packagers to add extra env vars to the cilium-envoy container.
*/}}
{{- define "envoy.env.extra" -}}
{{- end }}
{{/*
Allow packagers to add extra volume mounts to the cilium-envoy container.
*/}}
{{- define "envoy.volumeMounts.extra" -}}
{{- end }}
{{/*
Allow packagers to add extra host path mounts to the cilium-envoy container.
*/}}
{{- define "envoy.hostPathMounts.extra" -}}
{{- end }}
{{/*
Allow packagers to define set of ports for cilium-envoy container.
The template needs to allow overriding ports spec not just adding.
*/}}
{{- define "envoy.ports" -}}
{{- if .Values.envoy.prometheus.enabled }}
ports:
- name: envoy-metrics
containerPort: {{ .Values.envoy.prometheus.port }}
hostPort: {{ .Values.envoy.prometheus.port }}
protocol: TCP
{{- if and .Values.envoy.debug.admin.enabled .Values.envoy.debug.admin.port }}
- name: envoy-admin
containerPort: {{ .Values.envoy.debug.admin.port }}
hostPort: {{ .Values.envoy.debug.admin.port }}
protocol: TCP
{{- end }}
{{- end }}
{{- end }}
{{/*
Allow packagers to define update strategy for cilium-envoy pods.
*/}}
{{- define "envoy.updateStrategy" -}}
{{- with .Values.envoy.updateStrategy }}
updateStrategy:
{{- toYaml . | trim | nindent 2 }}
{{- end }}
{{- end }}
{{/*
Allow packagers to define affinity for cilium-envoy pods.
*/}}
{{- define "envoy.affinity" -}}
{{- with .Values.envoy.affinity }}
affinity:
{{- toYaml . | nindent 2 }}
{{- end }}
{{- end }}

View File

@@ -131,12 +131,16 @@ To override the namespace and configMap when using `auto`:
{{- define "k8sServiceHost" }}
{{- $configmapName := default "cluster-info" .Values.k8sServiceLookupConfigMapName }}
{{- $configmapNamespace := default "kube-public" .Values.k8sServiceLookupNamespace }}
{{- if and (eq .Values.k8sServiceHost "auto") (lookup "v1" "ConfigMap" $configmapNamespace $configmapName) }}
{{- if eq .Values.k8sServiceHost "auto" }}
{{- $configmap := (lookup "v1" "ConfigMap" $configmapNamespace $configmapName) }}
{{- $kubeconfig := get $configmap.data "kubeconfig" }}
{{- $k8sServer := get ($kubeconfig | fromYaml) "clusters" | mustFirst | dig "cluster" "server" "" }}
{{- $uri := (split "https://" $k8sServer)._1 | trim }}
{{- (split ":" $uri)._0 | quote }}
{{- if $configmap }}
{{- $kubeconfig := get $configmap.data "kubeconfig" }}
{{- $k8sServer := get ($kubeconfig | fromYaml) "clusters" | mustFirst | dig "cluster" "server" "" }}
{{- $uri := (split "https://" $k8sServer)._1 | trim }}
{{- (split ":" $uri)._0 | quote }}
{{- else }}
{{- fail (printf "ConfigMap %s/%s not found, please create it or set k8sServiceHost to a valid value" $configmapNamespace $configmapName) }}
{{- end }}
{{- else }}
{{- .Values.k8sServiceHost | quote }}
{{- end }}

Some files were not shown because too many files have changed in this diff Show More