Files
cozystack/cmd/cozystack-controller/main_test.go
Aleksei Sviridkin 37a91f98b8 feat(cozystack-controller): extract application CA into a key-free tenant Secret
Every catalog engine issues a per-release CA, but the object holding
ca.crt usually holds a private key beside it (cert-manager's tls.key,
CloudNativePG's ca.key), so granting a tenant read on it hands over key
material too. Add a controller that publishes the trust anchor as one
canonical, key-free Secret per release, "<release>.tenant-ca", holding
only ca.crt.

A chart declares the anchor by rendering a namespaced TenantProjection
sentinel (internal.cozystack.io/v1alpha1) that names the source Secret
and key. The controller rebuilds ca.crt from the parsed certificate DER
rather than copying the source, refuses any value carrying private key
material, and owns the projection by owner reference so a foreign Secret
at the same name is never overwritten. No tenant RBAC grants any verb on
internal.cozystack.io; a ValidatingAdmissionPolicy pins writes to
helm-controller as defence in depth.

The controller does not grant tenant read access — the lineage webhook
does, from the ApplicationDefinition's spec.secrets. This side stamps the
engine-agnostic internal.cozystack.io/tenant-ca label and forces a
re-admission when those selectors change.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
2026-07-21 23:59:48 +03:00

44 lines
1.6 KiB
Go

/*
Copyright 2026 The Cozystack Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"testing"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
internalv1alpha1 "github.com/cozystack/cozystack/api/internalapi/v1alpha1"
)
// TestSchemeRegistersReconciledKinds pins that the manager scheme init() builds
// resolves the kinds the CA-extraction controller reconciles For(). A kind
// missing here is not a build error — it fails at runtime: SetupWithManager
// cannot resolve the GVK for its field index or its For() source, returns an
// error, and main() calls os.Exit(1), taking the whole binary (and every other
// controller) down with it. The scheme is the package-level var init() populates.
func TestSchemeRegistersReconciledKinds(t *testing.T) {
for name, obj := range map[string]runtime.Object{
"TenantProjection": &internalv1alpha1.TenantProjection{},
"TenantProjectionList": &internalv1alpha1.TenantProjectionList{},
} {
if _, err := apiutil.GVKForObject(obj, scheme); err != nil {
t.Errorf("manager scheme does not register %s, so the CA-extraction controller cannot start: %v", name, err)
}
}
}