mirror of
https://github.com/cozystack/cozystack.git
synced 2026-10-27 15:17:13 +09:00
Add a controller that keeps each SecurityGroup's membership label (securitygroup.sdn.cozystack.io/<name>) in sync with its attachments: it stamps the label onto the pods of every attached application and removes it when an application is detached or the SecurityGroup is deleted. The backing CiliumNetworkPolicy's endpointSelector matches that label, so this is what makes a SecurityGroup apply to its members. The controller watches the marked backing policies and managed-app pods. It resolves each attachment through the lineage labels the lineage webhook already stamps — never the attachment list directly — and only ever labels pods in the SecurityGroup's own namespace, using single-key merge patches so it cannot clobber another group's label or a pod's lineage labels. A finalizer on the backing policy guarantees the labels are stripped before the policy is removed. Informer caches are bounded to managed pods and SecurityGroup-owned policies. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
121 lines
3.9 KiB
Go
121 lines
3.9 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
// Copyright 2026 The Cozystack Authors.
|
|
|
|
package main
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"flag"
|
|
"os"
|
|
|
|
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
|
|
// to ensure that exec-entrypoint and run can make use of them.
|
|
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
|
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
|
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
|
ctrl "sigs.k8s.io/controller-runtime"
|
|
"sigs.k8s.io/controller-runtime/pkg/cache"
|
|
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
|
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
|
"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
|
|
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
|
|
|
|
sgc "github.com/cozystack/cozystack/internal/securitygroupcontroller"
|
|
)
|
|
|
|
var (
|
|
scheme = runtime.NewScheme()
|
|
setupLog = ctrl.Log.WithName("setup")
|
|
)
|
|
|
|
func init() {
|
|
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
|
|
utilruntime.Must(sgc.AddToScheme(scheme))
|
|
}
|
|
|
|
func main() {
|
|
var metricsAddr string
|
|
var enableLeaderElection bool
|
|
var probeAddr string
|
|
var secureMetrics bool
|
|
var enableHTTP2 bool
|
|
var tlsOpts []func(*tls.Config)
|
|
flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+
|
|
"Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.")
|
|
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
|
|
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
|
|
"Enable leader election for controller manager. "+
|
|
"Enabling this will ensure there is only one active controller manager.")
|
|
flag.BoolVar(&secureMetrics, "metrics-secure", true,
|
|
"If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.")
|
|
flag.BoolVar(&enableHTTP2, "enable-http2", false,
|
|
"If set, HTTP/2 will be enabled for the metrics server")
|
|
opts := zap.Options{
|
|
Development: false,
|
|
}
|
|
opts.BindFlags(flag.CommandLine)
|
|
flag.Parse()
|
|
|
|
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
|
|
|
|
// Disable HTTP/2 by default to avoid the Stream Cancellation and Rapid Reset
|
|
// CVEs (GHSA-qppj-fm5r-hxr3, GHSA-4374-p667-p6c8).
|
|
disableHTTP2 := func(c *tls.Config) {
|
|
setupLog.Info("disabling http/2")
|
|
c.NextProtos = []string{"http/1.1"}
|
|
}
|
|
if !enableHTTP2 {
|
|
tlsOpts = append(tlsOpts, disableHTTP2)
|
|
}
|
|
|
|
metricsServerOptions := metricsserver.Options{
|
|
BindAddress: metricsAddr,
|
|
SecureServing: secureMetrics,
|
|
TLSOpts: tlsOpts,
|
|
}
|
|
if secureMetrics {
|
|
metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization
|
|
}
|
|
|
|
// Configure rate limiting for the Kubernetes client.
|
|
config := ctrl.GetConfigOrDie()
|
|
config.QPS = 50.0
|
|
config.Burst = 100
|
|
|
|
mgr, err := ctrl.NewManager(config, ctrl.Options{
|
|
Scheme: scheme,
|
|
Metrics: metricsServerOptions,
|
|
HealthProbeBindAddress: probeAddr,
|
|
LeaderElection: enableLeaderElection,
|
|
LeaderElectionID: "securitygroup-controller.sdn.cozystack.io",
|
|
// Bound the informer caches to the only objects this controller acts on.
|
|
Cache: cache.Options{ByObject: sgc.CacheByObject()},
|
|
})
|
|
if err != nil {
|
|
setupLog.Error(err, "unable to start manager")
|
|
os.Exit(1)
|
|
}
|
|
|
|
if err := (&sgc.Reconciler{Client: mgr.GetClient()}).SetupWithManager(mgr); err != nil {
|
|
setupLog.Error(err, "unable to setup controller", "controller", "SecurityGroupMembership")
|
|
os.Exit(1)
|
|
}
|
|
|
|
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
|
|
setupLog.Error(err, "unable to set up health check")
|
|
os.Exit(1)
|
|
}
|
|
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
|
|
setupLog.Error(err, "unable to set up ready check")
|
|
os.Exit(1)
|
|
}
|
|
|
|
setupLog.Info("starting manager")
|
|
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
|
|
setupLog.Error(err, "problem running manager")
|
|
os.Exit(1)
|
|
}
|
|
}
|