Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
14bd268
feat: add separate reconciler to initialize account workspaces of typ…
simontesar Jan 28, 2026
03cac88
fix: correct accounttype predicate
simontesar Jan 28, 2026
0e1bd75
feat: use openfga SDK
simontesar Jan 28, 2026
572a88b
Merge remote-tracking branch 'origin/main' into feat/migrate-fga-to-seco
simontesar Feb 2, 2026
97f1bbf
Merge remote-tracking branch 'origin/main' into feat/migrate-fga-to-seco
simontesar Feb 3, 2026
f5b771c
fix: org predicate checks owner not path
simontesar Feb 3, 2026
1d23cd7
fix: have account initializer also use remove-initializer subroutine
simontesar Feb 3, 2026
f00315a
refactor: consistent file naming
simontesar Feb 3, 2026
464faf8
feat: implement account initializer using Store resource
simontesar Feb 4, 2026
56ae52c
feat: add note about not checking condition
simontesar Feb 4, 2026
85a5534
fix: rework org account type predicate
simontesar Feb 5, 2026
341aeb4
fix: invite: clearer and non-duplicate error messages
simontesar Feb 5, 2026
1b4bb23
feat: introduce client package
simontesar Feb 9, 2026
f18194a
feat: account-initializer: check tuples in status
simontesar Feb 9, 2026
ac4d5ed
chore: account-initializer: reordering and comments
simontesar Feb 9, 2026
642d28a
refactor: rename org initalization controller
simontesar Feb 9, 2026
4ca56ae
feat: add internal fga package
simontesar Feb 10, 2026
d3a5350
fix: logicalclusterclient: remove bogus print
simontesar Feb 10, 2026
4fe4960
feat: account-tuples: check for change
simontesar Feb 10, 2026
ae12f7b
feat: org-initializer: create tuples
simontesar Feb 10, 2026
e650fb1
refactor: make fga package importable
simontesar Feb 10, 2026
f4cc794
fix: remove bogus print
simontesar Feb 10, 2026
4c13c3a
refactor: remove constant dependencies on account operator
simontesar Feb 10, 2026
519c56c
chore: some comments
simontesar Feb 10, 2026
6fadcce
chore: go mod tidy
simontesar Feb 10, 2026
b42e6a2
chore: comment about requeueing and updating
simontesar Feb 10, 2026
63fd1df
Merge remote-tracking branch 'origin/main' into feat/migrate-fga-to-seco
simontesar Feb 10, 2026
046b7e8
fga: dont check for k8s SA but always replace colons with dots
simontesar Feb 10, 2026
23bf1b1
chore: formatting for linter
simontesar Feb 10, 2026
ec189a4
fix: config: correct FGA mapstructure paths
simontesar Feb 10, 2026
cbfe46a
feat: org-initalization: check store readiness on tuple change
simontesar Feb 10, 2026
8a35ddf
fix: account-initializer: get AccountInfo from parent Account's
simontesar Feb 11, 2026
a16a400
Merge remote-tracking branch 'origin/main' into feat/migrate-fga-to-seco
simontesar Feb 11, 2026
4beb6b2
chore: clarifying comments
simontesar Feb 11, 2026
72e72a4
Merge remote-tracking branch 'origin/main' into feat/migrate-fga-to-seco
simontesar Feb 11, 2026
1eaee22
fix: fga: check tuple building input for errors
simontesar Feb 11, 2026
45f4b9c
fix: remove now unused parentRelation from org initalizer
simontesar Feb 11, 2026
7a2d408
fix: client: check APIExportEndpointSlice length
simontesar Feb 11, 2026
13af20e
fix: predicates: check slice length
simontesar Feb 11, 2026
f52e0ba
fix: remove now unused parentRelation from org initalizer
simontesar Feb 11, 2026
9195391
fix: account-tuples: remove unused finalizer and check context cluster
simontesar Feb 11, 2026
a47af51
chore: fix typo in comment
simontesar Feb 11, 2026
ad0fc3d
fix: typo in error message
simontesar Feb 11, 2026
e405a78
fix: org-initalizer: remove pointless logger
simontesar Feb 11, 2026
37709cd
fix: initializer: use correct config
simontesar Feb 11, 2026
3c4ceaa
Merge remote-tracking branch 'origin/main' into feat/migrate-fga-to-seco
simontesar Feb 12, 2026
3483a52
feat: add tuple manager
simontesar Feb 12, 2026
189ca8a
feat: tuple manager: add latest store constant
simontesar Feb 12, 2026
d9c17f7
feat: account-initializer: directly speak to openfga
simontesar Feb 12, 2026
ec8e6e4
feat: add terminatingworkspaces provider
simontesar Feb 13, 2026
5270bff
fix: pin k8s dependencies to 0.34.0
simontesar Feb 17, 2026
0e9fc65
fix: correct bogus command
simontesar Feb 17, 2026
28c234d
feat: add terminator command
simontesar Feb 17, 2026
8eb7faf
feat: add terminator controller and subroutine skaffolding
simontesar Feb 17, 2026
fa9493a
Merge remote-tracking branch 'origin/main' into feat/migrate-fga-to-seco
simontesar Feb 17, 2026
7882db0
chore: regenerate mocks
simontesar Feb 17, 2026
62030d3
feat: delete tuples in terminator
simontesar Feb 18, 2026
ca1f5e0
Merge remote-tracking branch 'origin/main' into feat/migrate-fga-to-seco
simontesar Feb 18, 2026
8307219
feat: implement terminator interface
simontesar Feb 18, 2026
1f00145
feat: split docker kind tasks
simontesar Feb 18, 2026
466cb2f
feat: tuples: implement initializer and terminator interfaces in a si…
simontesar Feb 18, 2026
47f8d56
refactor: unify account init and term controllers/subroutines
simontesar Feb 18, 2026
a618566
initializer: implement initalizer interface in all subroutines
simontesar Feb 18, 2026
385605e
refactor: break comment
simontesar Feb 18, 2026
ed43936
fix: remove now unused removeInitializer subroutine
simontesar Feb 18, 2026
600a72f
fix: change error wrt not found
simontesar Feb 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ tasks:
cmds:
- go run ./cmd/main.go operator

docker:kind:
desc: "Build container image with current tag from kind cluster and load it"
docker:kind:load:
desc: "Build container image with current tag from kind cluster and load it into kind"
vars:
CONTAINER_RUNTIME: '{{.CONTAINER_RUNTIME | default "docker"}}'
KIND_CLUSTER: '{{.KIND_CLUSTER | default "platform-mesh"}}'
Expand All @@ -143,8 +143,30 @@ tasks:
else
kind load docker-image {{.IMAGE_NAME}} --name {{.KIND_CLUSTER}}
fi
- echo "Image loaded into kind cluster {{.KIND_CLUSTER}}"
docker:kind:restart:
desc: "Restart security-operator deployments to pick up new image"
vars:
DEPLOYMENT_NAMESPACE: '{{.DEPLOYMENT_NAMESPACE | default "platform-mesh-system"}}'
cmds:
- kubectl rollout restart deployment/security-operator -n {{.DEPLOYMENT_NAMESPACE}}
- kubectl rollout restart deployment/security-operator-generator -n {{.DEPLOYMENT_NAMESPACE}}
- kubectl rollout restart deployment/security-operator-initializer -n {{.DEPLOYMENT_NAMESPACE}}
- echo "Image loaded and all deployments restarted"
- kubectl rollout restart deployment/security-operator-terminator -n {{.DEPLOYMENT_NAMESPACE}}
- echo "All deployments restarted"
docker:kind:
desc: "Build container image, load it into kind cluster, and restart deployments"
vars:
DEPLOYMENT_NAMESPACE: '{{.DEPLOYMENT_NAMESPACE | default "platform-mesh-system"}}'
CONTAINER_RUNTIME: '{{.CONTAINER_RUNTIME | default "docker"}}'
KIND_CLUSTER: '{{.KIND_CLUSTER | default "platform-mesh"}}'
cmds:
- task: docker:kind:load
vars:
DEPLOYMENT_NAMESPACE: '{{.DEPLOYMENT_NAMESPACE}}'
CONTAINER_RUNTIME: '{{.CONTAINER_RUNTIME}}'
KIND_CLUSTER: '{{.KIND_CLUSTER}}'
- task: docker:kind:restart
vars:
DEPLOYMENT_NAMESPACE: '{{.DEPLOYMENT_NAMESPACE}}'

34 changes: 32 additions & 2 deletions cmd/initializer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,25 @@ import (

helmv2 "github.com/fluxcd/helm-controller/api/v2"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
openfgav1 "github.com/openfga/api/proto/openfga/v1"
"github.com/platform-mesh/security-operator/internal/controller"
"github.com/platform-mesh/security-operator/internal/predicates"
"github.com/spf13/cobra"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/metrics/server"
"sigs.k8s.io/controller-runtime/pkg/predicate"
mcmanager "sigs.k8s.io/multicluster-runtime/pkg/manager"

"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/rest"

"github.com/kcp-dev/logicalcluster/v3"
mcclient "github.com/kcp-dev/multicluster-provider/client"
"github.com/kcp-dev/multicluster-provider/initializingworkspaces"
)

Expand Down Expand Up @@ -94,12 +100,36 @@ var initializerCmd = &cobra.Command{
initializerCfg.IDP.AdditionalRedirectURLs = []string{}
}

if err := controller.NewLogicalClusterReconciler(log, orgClient, initializerCfg, runtimeClient, mgr).
SetupWithManager(mgr, defaultCfg); err != nil {
if err := controller.NewOrgLogicalClusterReconciler(log, orgClient, initializerCfg, runtimeClient, mgr).
SetupWithManager(mgr, defaultCfg, predicates.LogicalClusterIsAccountTypeOrg()); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "LogicalCluster")
os.Exit(1)
}

kcpCfg, err := getKubeconfigFromPath(initializerCfg.KCP.Kubeconfig)
if err != nil {
log.Error().Err(err).Msg("unable to get KCP kubeconfig")
return err
}

conn, err := grpc.NewClient(initializerCfg.FGA.Target, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Error().Err(err).Msg("unable to create grpc client")
return err
}
fga := openfgav1.NewOpenFGAServiceClient(conn)

mcc, err := mcclient.New(kcpCfg, client.Options{Scheme: scheme})
if err != nil {
log.Error().Err(err).Msg("Failed to create multicluster client")
os.Exit(1)
}
if err := controller.NewAccountLogicalClusterReconciler(log, initializerCfg, fga, mcc, mgr).
SetupWithManager(mgr, defaultCfg, predicate.Not(predicates.LogicalClusterIsAccountTypeOrg())); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "AccountLogicalCluster")
os.Exit(1)
}

if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
setupLog.Error(err, "unable to set up health check")
os.Exit(1)
Expand Down
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ var rootCmd = &cobra.Command{

func init() {
rootCmd.AddCommand(initializerCmd)
rootCmd.AddCommand(terminatorCmd)
rootCmd.AddCommand(operatorCmd)
rootCmd.AddCommand(modelGeneratorCmd)
rootCmd.AddCommand(initContainerCmd)
Expand Down
147 changes: 147 additions & 0 deletions cmd/terminator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package cmd

import (
"crypto/tls"
"os"
"strings"

openfgav1 "github.com/openfga/api/proto/openfga/v1"
platformeshconfig "github.com/platform-mesh/golang-commons/config"
iclient "github.com/platform-mesh/security-operator/internal/client"
"github.com/platform-mesh/security-operator/internal/terminatingworkspaces"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"

"github.com/platform-mesh/security-operator/internal/config"
"github.com/platform-mesh/security-operator/internal/controller"
"github.com/platform-mesh/security-operator/internal/predicates"
"github.com/spf13/cobra"
"github.com/spf13/viper"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/metrics/server"
"sigs.k8s.io/controller-runtime/pkg/predicate"
mcmanager "sigs.k8s.io/multicluster-runtime/pkg/manager"

"k8s.io/client-go/rest"

"github.com/kcp-dev/logicalcluster/v3"
kcptenancyv1alphav1 "github.com/kcp-dev/sdk/apis/tenancy/v1alpha1"

mcclient "github.com/kcp-dev/multicluster-provider/client"
)

var terminatorCfg config.Config

var terminatorCmd = &cobra.Command{
Use: "terminator",
Short: "FGA terminator for account workspaces",
RunE: func(cmd *cobra.Command, args []string) error {
kcpCfg, err := getKubeconfigFromPath(terminatorCfg.KCP.Kubeconfig)
if err != nil {
log.Error().Err(err).Msg("unable to get KCP kubeconfig")
os.Exit(1)
}

mgrOpts := ctrl.Options{
Scheme: scheme,
LeaderElection: defaultCfg.LeaderElection.Enabled,
LeaderElectionID: "security-operator-terminator.platform-mesh.io",
HealthProbeBindAddress: defaultCfg.HealthProbeBindAddress,
Metrics: server.Options{
BindAddress: defaultCfg.Metrics.BindAddress,
TLSOpts: []func(*tls.Config){
func(c *tls.Config) {
log.Info().Msg("disabling http/2")
c.NextProtos = []string{"http/1.1"}
},
},
},
}
if defaultCfg.LeaderElection.Enabled {
inClusterCfg, err := rest.InClusterConfig()
if err != nil {
log.Error().Err(err).Msg("unable to create in-cluster config")
return err
}
mgrOpts.LeaderElectionConfig = inClusterCfg
}

mcc, err := mcclient.New(kcpCfg, client.Options{Scheme: scheme})
if err != nil {
log.Error().Err(err).Msg("Failed to create multicluster client")
os.Exit(1)
}
rootClient, err := iclient.NewForLogicalCluster(kcpCfg, scheme, logicalcluster.Name("root"))
if err != nil {
log.Error().Err(err).Msgf("Failed to get root client")
os.Exit(1)
}
var wt kcptenancyv1alphav1.WorkspaceType
if err := rootClient.Get(cmd.Context(), client.ObjectKey{
Name: terminatorCfg.WorkspaceTypeName,
}, &wt); err != nil {
log.Error().Err(err).Msgf("Failed to get WorkspaceType %s", terminatorCfg.WorkspaceTypeName)
os.Exit(1)
}
if len(wt.Status.VirtualWorkspaces) == 0 {
log.Error().Err(err).Msgf("No VirtualWorkspaces found in WorkspaceType %s", terminatorCfg.WorkspaceTypeName)
os.Exit(1)
}

virtualWorkspaceCfg := rest.CopyConfig(kcpCfg)
virtualWorkspaceCfg.Host = wt.Status.VirtualWorkspaces[0].URL
log.Info().Msgf("Created config with %s host", virtualWorkspaceCfg.Host)
Comment on lines +81 to +95
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is needed, the terminatingWorkspaceProvider should determine the vws url based on the workspace type name


provider, err := terminatingworkspaces.New(kcpCfg, initializerCfg.WorkspaceTypeName,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have a terminatorCfg? or do the initializer / terminator share the same config structure, possibly then rename it to avoid confusion

terminatingworkspaces.Options{
Scheme: mgrOpts.Scheme,
},
)

mgr, err := mcmanager.New(kcpCfg, provider, mgrOpts)
if err != nil {
log.Error().Err(err).Msg("Failed to create manager")
os.Exit(1)
}

conn, err := grpc.NewClient(terminatorCfg.FGA.Target, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Error().Err(err).Msg("unable to create grpc client")
os.Exit(1)
}
fga := openfgav1.NewOpenFGAServiceClient(conn)

if err := controller.NewAccountLogicalClusterReconciler(log, terminatorCfg, fga, mcc, mgr).
SetupWithManager(mgr, defaultCfg, predicate.Not(predicates.LogicalClusterIsAccountTypeOrg())); err != nil {
log.Error().Err(err).Msg("Unable to create AccountLogicalClusterTerminator")
os.Exit(1)
}

if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
log.Error().Err(err).Msg("unable to set up health check")
os.Exit(1)
}
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
log.Error().Err(err).Msg("unable to set up ready check")
os.Exit(1)
}

setupLog.Info("starting manager")

return mgr.Start(ctrl.SetupSignalHandler())
},
}

func init() {
rootCmd.AddCommand(terminatorCmd)

terminatorV := viper.NewWithOptions(
viper.EnvKeyReplacer(strings.NewReplacer("-", "_")),
)
terminatorV.AutomaticEnv()
if err := platformeshconfig.BindConfigToFlags(terminatorV, terminatorCmd, &terminatorCfg); err != nil {
panic(err)
}
}
23 changes: 17 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
module github.com/platform-mesh/security-operator

go 1.25.0
go 1.25.7

replace (
k8s.io/api => k8s.io/api v0.34.0
k8s.io/apiserver => k8s.io/apiserver v0.34.0
k8s.io/client-go => k8s.io/client-go v0.34.0
k8s.io/component-base => k8s.io/component-base v0.34.0
)

require (
github.com/coreos/go-oidc v2.5.0+incompatible
Expand All @@ -9,16 +16,18 @@ require (
github.com/go-logr/logr v1.4.3
github.com/google/gnostic-models v0.7.1
github.com/kcp-dev/logicalcluster/v3 v3.0.5
github.com/kcp-dev/multicluster-provider v0.4.0
github.com/kcp-dev/multicluster-provider v0.5.0
github.com/kcp-dev/sdk v0.30.0
github.com/openfga/api/proto v0.0.0-20260217232149-f917ddb000ce
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20251027165255-0f8f255e5f6c
github.com/platform-mesh/account-operator v0.11.4
github.com/platform-mesh/golang-commons v0.9.40
github.com/rs/zerolog v1.34.0
github.com/spf13/cobra v1.10.2
github.com/spf13/pflag v1.0.10
github.com/spf13/viper v1.21.0
github.com/stretchr/testify v1.11.1
go.uber.org/zap v1.27.1
golang.org/x/oauth2 v0.35.0
google.golang.org/grpc v1.79.1
google.golang.org/protobuf v1.36.11
Expand All @@ -27,8 +36,8 @@ require (
k8s.io/apimachinery v0.35.1
k8s.io/client-go v0.35.1
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2
sigs.k8s.io/controller-runtime v0.22.4
sigs.k8s.io/multicluster-runtime v0.22.4-beta.1
sigs.k8s.io/controller-runtime v0.23.1
sigs.k8s.io/multicluster-runtime v0.23.1
sigs.k8s.io/yaml v1.6.0
)

Expand All @@ -50,11 +59,13 @@ require (
github.com/getsentry/sentry-go v0.42.0 // indirect
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-logr/zerologr v1.2.3 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/uuid v1.6.0 // indirect
Expand Down Expand Up @@ -87,7 +98,6 @@ require (
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/vektah/gqlparser/v2 v2.5.31 // indirect
Expand All @@ -101,6 +111,7 @@ require (
go.opentelemetry.io/otel/sdk v1.40.0 // indirect
go.opentelemetry.io/otel/trace v1.40.0 // indirect
go.opentelemetry.io/proto/otlp v1.9.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.47.0 // indirect
Expand All @@ -122,5 +133,5 @@ require (
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 // indirect
)
Loading
Loading