diff --git a/controllers/clusterwidenetworkpolicy_controller.go b/controllers/clusterwidenetworkpolicy_controller.go index a89cf211..9ef03a16 100644 --- a/controllers/clusterwidenetworkpolicy_controller.go +++ b/controllers/clusterwidenetworkpolicy_controller.go @@ -7,6 +7,7 @@ import ( "go4.org/netipx" + apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" "github.com/metal-stack/firewall-controller/v2/pkg/dns" "github.com/metal-stack/firewall-controller/v2/pkg/helper" "github.com/metal-stack/firewall-controller/v2/pkg/nftables" @@ -45,6 +46,9 @@ type ClusterwideNetworkPolicyReconciler struct { Interval time.Duration DnsProxy *dns.DNSProxy SkipDNS bool + + DefaultRouteIp string + MachineAllocation *apiv2.MachineAllocation } // SetupWithManager configures this controller to run in schedule @@ -103,7 +107,7 @@ func (r *ClusterwideNetworkPolicyReconciler) Reconcile(ctx context.Context, _ ct } cwnps.Items = validCwnps - nftablesFirewall := nftables.NewFirewall(f, &cwnps, &services, r.DnsProxy, r.Log, r.Recorder) + nftablesFirewall := nftables.NewFirewall(f, &cwnps, &services, r.DnsProxy, r.Log, r.Recorder, r.MachineAllocation) if err := r.manageDNSProxy(f, cwnps, nftablesFirewall); err != nil { return ctrl.Result{}, err } @@ -147,6 +151,7 @@ func (r *ClusterwideNetworkPolicyReconciler) manageDNSProxy( DNSServer: f.Spec.DNSServerAddress, Port: f.Spec.DNSPort, ShootClient: r.ShootClient, + BindAddress: r.DefaultRouteIp, } if r.DnsProxy, err = dns.NewDNSProxy(r.Ctx, dnsProxyConfig); err != nil { return fmt.Errorf("failed to init DNS proxy: %w", err) diff --git a/controllers/firewall_controller.go b/controllers/firewall_controller.go index 3872bf64..82e18515 100644 --- a/controllers/firewall_controller.go +++ b/controllers/firewall_controller.go @@ -11,6 +11,7 @@ import ( "github.com/Masterminds/semver/v3" "github.com/go-logr/logr" + apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" mn "github.com/metal-stack/metal-lib/pkg/net" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -52,7 +53,8 @@ type FirewallReconciler struct { SeedUpdatedFunc func() - FrrVersion *semver.Version + FrrVersion *semver.Version + MachineAllocation *apiv2.MachineAllocation } const ( @@ -93,8 +95,10 @@ func (r *FirewallReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c defaultFw := nftables.NewFirewall( &firewallv2.Firewall{}, &firewallv1.ClusterwideNetworkPolicyList{}, - &corev1.ServiceList{}, nil, logr.Discard(), + &corev1.ServiceList{}, + nil, logr.Discard(), r.Recorder, + r.MachineAllocation, ) flushErr := defaultFw.Flush() @@ -124,7 +128,8 @@ func (r *FirewallReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c r.Log.Info("reconciling network settings") var errs []error - changed, err := network.ReconcileNetwork(r.Log, f, r.FrrVersion) + + changed, err := network.ReconcileNetwork(r.Log, f, r.MachineAllocation, r.FrrVersion) if changed && err == nil { r.recordFirewallEvent(f, corev1.EventTypeNormal, "Network settings", "reconciliation succeeded (frr.conf)") } else if changed && err != nil { @@ -169,16 +174,16 @@ type firewallService struct { // reconcileFirewallServices reconciles the services and endpoints exposed by the firewall func (r *FirewallReconciler) reconcileFirewallServices(ctx context.Context, f *firewallv2.Firewall) error { services := []firewallService{ - { - name: nodeExporterService, - port: nodeExporterPort, - namedPort: nodeExporterNamedPort, - }, { name: nftablesExporterService, port: nftablesExporterPort, namedPort: nftablesExporterNamedPort, }, + { + name: nodeExporterService, + port: nodeExporterPort, + namedPort: nodeExporterNamedPort, + }, } var errs []error diff --git a/go.mod b/go.mod index 9f9b9175..4102a762 100644 --- a/go.mod +++ b/go.mod @@ -10,16 +10,17 @@ require ( github.com/google/go-cmp v0.7.0 github.com/google/nftables v0.3.0 github.com/ks2211/go-suricata v0.0.0-20200823200910-986ce1470707 - github.com/metal-stack/firewall-controller-manager v0.6.1 - github.com/metal-stack/metal-go v0.45.0 + github.com/metal-stack/api v0.8.2 + github.com/metal-stack/firewall-controller-manager v0.6.2-0.20261013093056-8814016e6683 github.com/metal-stack/metal-lib v0.26.3 - github.com/metal-stack/metal-networker v0.47.0 + github.com/metal-stack/os-installer v0.3.2 github.com/metal-stack/v v1.0.3 github.com/miekg/dns v1.1.73 github.com/stretchr/testify v1.12.1 github.com/txn2/txeh v1.8.1 github.com/vishvananda/netlink v1.3.1 go4.org/netipx v0.0.0-20260823151212-3075585bcbeb + google.golang.org/protobuf v1.36.12 k8s.io/api v0.36.3 k8s.io/apiextensions-apiserver v0.36.3 k8s.io/apimachinery v0.36.3 @@ -31,6 +32,10 @@ require ( replace github.com/imdario/mergo => dario.cat/mergo v1.0.0 require ( + buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.12-20260825204119-511051f7f437.2 // indirect + dario.cat/mergo v1.0.2 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/sprig/v3 v3.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -38,13 +43,8 @@ require ( github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/fsnotify/fsnotify v1.10.1 // indirect github.com/fxamacker/cbor/v2 v2.9.6 // indirect - github.com/go-openapi/analysis v1.0.1 // indirect - github.com/go-openapi/errors v0.22.9 // indirect github.com/go-openapi/jsonpointer v1.0.2 // indirect github.com/go-openapi/jsonreference v1.0.3 // indirect - github.com/go-openapi/loads v0.25.3 // indirect - github.com/go-openapi/spec v1.0.1 // indirect - github.com/go-openapi/strfmt v0.27.3 // indirect github.com/go-openapi/swag v0.29.2 // indirect github.com/go-openapi/swag/cmdutils v0.29.2 // indirect github.com/go-openapi/swag/conv v0.29.2 // indirect @@ -57,33 +57,37 @@ require ( github.com/go-openapi/swag/stringutils v0.29.2 // indirect github.com/go-openapi/swag/typeutils v0.29.2 // indirect github.com/go-openapi/swag/yamlutils v0.29.2 // indirect - github.com/go-openapi/validate v1.0.0 // indirect - github.com/go-viper/mapstructure/v2 v2.5.0 // indirect + github.com/go-openapi/testify/enable/yaml/v2 v2.8.0 // indirect github.com/godbus/dbus/v5 v5.2.4 // indirect github.com/google/gnostic-models v0.7.1 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/huandu/xstrings v1.6.2 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.16 // indirect github.com/mattn/go-isatty v0.0.24 // indirect github.com/mdlayher/netlink v1.11.2 // indirect github.com/mdlayher/socket v0.8.0 // indirect - github.com/metal-stack/metal-hammer v0.13.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/oklog/ulid/v2 v2.1.2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.25.0 // indirect github.com/prometheus/client_model v0.6.3 // indirect github.com/prometheus/common v0.72.1 // indirect github.com/prometheus/procfs v0.22.0 // indirect + github.com/samber/lo v1.53.0 // indirect + github.com/shopspring/decimal v1.5.0 // 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.8.0 // indirect github.com/vishvananda/netns v0.0.5 // indirect github.com/x448/float16 v0.8.4 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.5 // indirect + golang.org/x/crypto v0.58.0 // indirect golang.org/x/net v0.61.0 // indirect golang.org/x/oauth2 v0.37.0 // indirect golang.org/x/sync v0.24.0 // indirect @@ -91,11 +95,10 @@ require ( golang.org/x/term v0.47.0 // indirect golang.org/x/text v0.43.0 // indirect golang.org/x/time v0.16.0 // indirect + golang.org/x/tools v0.52.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect - google.golang.org/protobuf v1.36.12 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.140.0 // indirect k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 // indirect diff --git a/go.sum b/go.sum index ebe74c09..04422f6c 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,21 @@ -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.12-20260709200747-435963d16310.1 h1:6nlcxMOui23ZRVAfJM451duu79P1npA5JRdZqMilrrQ= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.12-20260709200747-435963d16310.1/go.mod h1:TCt1lluMFnctISJXvkIQ4x3ABrPuUKCWKyjKdkJNBpw= -buf.build/go/protovalidate v1.3.0 h1:8ITcnZGkAHx6TyhZvro+iET/AyqU8gEWQJK2WsT62ms= -buf.build/go/protovalidate v1.3.0/go.mod h1:82s5g+rFRj1CZPiLv6OTA31jBu2fpq7mLXHwa9mZfEs= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.12-20260825204119-511051f7f437.2 h1:NbnlmV26O7oZ1iM5tsCI+GEx+3ZSdrhvnKQ/eWSrLiY= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.12-20260825204119-511051f7f437.2/go.mod h1:TCt1lluMFnctISJXvkIQ4x3ABrPuUKCWKyjKdkJNBpw= +buf.build/go/protovalidate v1.4.0 h1:UjLrYbt5VX7+TMOs2+pG5FhZhIG1mSfK4EIopbb4LcM= +buf.build/go/protovalidate v1.4.0/go.mod h1:8vJfzNT6NIG2qm3uFsJDXMlRmG+bQJzbcIn1Aa0vPGs= buf.build/go/protoyaml v0.7.0 h1:z4oVoFicbpPefhT7WAykxUdfp0yEQlhMQ2mCZOY5V38= buf.build/go/protoyaml v0.7.0/go.mod h1:+a0cavd0uMvirb87xdu2ZMMmjlIQoiH/N2Ich5MGSQ0= -cel.dev/expr v0.25.2 h1:K6j46C81hXtZQfuX60cVWQFBJahKSE2gfRbNuvr5bFs= -cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= +cel.dev/cel-go v0.32.0 h1:irvpFKr5EuGPyxeME03ERh0rii1TX+BDAnB9eL3IvNk= +cel.dev/cel-go v0.32.0/go.mod h1:DnVip7tpJSsgZymwfT+m1tnEVy3ivAjSMXPx12YrMkU= +cel.dev/expr v0.25.3 h1:A2jO8jwOugrrovveCWfj0KEZOfqiLgAcwjpHPhzIGw0= +cel.dev/expr v0.25.3/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE= github.com/Masterminds/semver/v3 v3.5.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= +github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -20,7 +28,6 @@ github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJ github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA= github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -33,6 +40,8 @@ github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjT github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= github.com/fxamacker/cbor/v2 v2.9.6 h1:NHZPxuUjJXQjX9itA785y/5NKSlI4HQ+S7noZsmI7hs= @@ -41,18 +50,12 @@ github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8= github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-openapi/analysis v1.0.1 h1:JTEyujgl4GyFj8pbMUY2yZx5ak1Ozt/DaqzQjQBnBWM= -github.com/go-openapi/analysis v1.0.1/go.mod h1:f3gYbXmnXSQIZB02DqE4f8JX969PdOEnaY7gDBLeJjI= github.com/go-openapi/errors v0.22.9 h1:HI9+SyVYiRzyeBQGv0CbWbQa+u2S0nny7G7AhY+UMiM= github.com/go-openapi/errors v0.22.9/go.mod h1:R73q66sXP2smzAGgFOI4nqtusRK2xN5pYCjsij+KX58= github.com/go-openapi/jsonpointer v1.0.2 h1:NbW7xT2b+l7x+JefiPGDsZWsrLk1ogrz4AHK1TTzMt8= github.com/go-openapi/jsonpointer v1.0.2/go.mod h1:N0rI4MbNKD7xAFTiHtB+5Nhrg2j/wwYg7m7Fmb4/jk8= github.com/go-openapi/jsonreference v1.0.3 h1:5rDbq+JsjCv6/nUDDJt83nLZoADI4w03uvHXer+4aYQ= github.com/go-openapi/jsonreference v1.0.3/go.mod h1:OJSlMXHysgH272D9z2tiy2MGe5A9vQLHaCPb6KbYdE4= -github.com/go-openapi/loads v0.25.3 h1:V+jKy/thXWdLJUuYC8sZX2dICyAa8M3DokF70jj34P0= -github.com/go-openapi/loads v0.25.3/go.mod h1:LgLyCSOLBL2Qnj0Ps1oo2YH8jZoEKsMeVZCc+ALIxFo= -github.com/go-openapi/spec v1.0.1 h1:lj2vdGpNDcVgwRc6qXdw6qt/KQpCtSa9tnUH6vpDPDk= -github.com/go-openapi/spec v1.0.1/go.mod h1:M//GWQGtDUAjnP37gE6fInLgaczB+FatoipV3H1fYw8= github.com/go-openapi/strfmt v0.27.3 h1:cyf4J5Wjpd6bFpAs44MF8PsbWF/mWXhn82Ck/hgQZgw= github.com/go-openapi/strfmt v0.27.3/go.mod h1:Bl+xadPLa3nhBiaCAxNND1vrQfzyEjF0vBrLx96n/4E= github.com/go-openapi/swag v0.29.2 h1:9n8frkcsuQRA0INU31VbxNxt1zBaHxrHYGEf5BUjFi4= @@ -81,24 +84,20 @@ github.com/go-openapi/swag/typeutils v0.29.2 h1:O7aVvkTs3pXwikgtrPLenigEMdQFgONK github.com/go-openapi/swag/typeutils v0.29.2/go.mod h1:7+GDG+uz9Ke+eVt4rClZg7wklSDp8hT/mKNh/pC26TE= github.com/go-openapi/swag/yamlutils v0.29.2 h1:IFKFFeDnuIwzfsuWRQU+rI8iL3g4XyAYjV/RlnlxPLM= github.com/go-openapi/swag/yamlutils v0.29.2/go.mod h1:7MGqtcrK73sxQ4ceiyIf8qiXS/s09JLMdR5esK5euYQ= -github.com/go-openapi/testify/enable/yaml/v2 v2.7.0 h1:wPW6YRgx3+SID1yUy/Xwa17L8kFEaEKod2VRbJDZNUs= -github.com/go-openapi/testify/enable/yaml/v2 v2.7.0/go.mod h1:mI1M88etYbc3PhgHsWQK2kwvNwW5aGFqMPbmib+SGIs= +github.com/go-openapi/testify/enable/yaml/v2 v2.8.0 h1:dvOQNZ2ovOdogn902NYq7i6jUI9Dma4qyjTXABY5YTY= +github.com/go-openapi/testify/enable/yaml/v2 v2.8.0/go.mod h1:3VwZZUT6nWcAjhIr2RypXxlsxd3mPPtXh3T8z65aRlQ= github.com/go-openapi/testify/v2 v2.8.0 h1:19QDx5b57p8KjO2E4sgs/woL4Akp+FGLRlVm2xn0Rho= github.com/go-openapi/testify/v2 v2.8.0/go.mod h1:4gUN8jC+RqOE2qjW/vDmfyTvl5BCht4qL7oca0odrak= -github.com/go-openapi/validate v1.0.0 h1:dFsYCLVUQUL6Vi2lQSexgwmCXDuHe7eWRDhQxkE+xYA= -github.com/go-openapi/validate v1.0.0/go.mod h1:wwXGRqMQzOZ7PCqBcgNk+DD9+Cacnxv7we5T0M/eA3Y= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU= -github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-json v0.11.2 h1:jdZv93Tt4ioR8yW1CoNsvSxrcZlCXAUU1aZXN7gpXUA= +github.com/goccy/go-json v0.11.2/go.mod h1:3NdmfEkZlB7YI5UFw/qdFKq8XN1aiWR0YyRPWZNQltY= github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/godbus/dbus/v5 v5.2.4 h1:F2gUCy++NMIxGmo9J+z5le/+ZC8W1OgeR51P4i9ZB/U= github.com/godbus/dbus/v5 v5.2.4/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= -github.com/google/cel-go v0.31.0 h1:H0bhpFTqOvmHrBGrWKp7ZlhBm5Hh8PYUEXnwxT1LL7A= -github.com/google/cel-go v0.31.0/go.mod h1:X0bD6iVNR8pkROSOoHVdgTkzmRcosof7WQqCD6wcMc8= github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -108,16 +107,18 @@ 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/nftables v0.3.0 h1:bkyZ0cbpVeMHXOrtlFc8ISmfVqq5gPJukoYieyVmITg= github.com/google/nftables v0.3.0/go.mod h1:BCp9FsrbF1Fn/Yu6CLUc9GGZFw/+hsxfluNXXmxBfRM= -github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= -github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 h1:EwtI+Al+DeppwYX2oXJCETMO23COyaKGP6fHVpkpWpg= +github.com/google/pprof v0.0.0-20260402051712-545e8a4df936/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= 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/huandu/xstrings v1.6.2 h1:+X5X6N46b40cmDw7FFJFU6Eoq0yJS8lbYigT2EFau4c= +github.com/huandu/xstrings v1.6.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/compress v1.20.1 h1:T7kKElXUMXrUJ2E9QhQhxFtcK5rPyLdsGZvdbLMPdiQ= -github.com/klauspost/compress v1.20.1/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI= +github.com/klauspost/compress v1.20.3 h1:zWNoFqq/lSuYQRim3dUXlXeA0IqwuZGicdG5ZTfY5j4= +github.com/klauspost/compress v1.20.3/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -136,20 +137,22 @@ github.com/mdlayher/netlink v1.11.2 h1:HKh2jqe+omdSWcQ88nrT7INE61B0NXfiSPFdgL4Yb github.com/mdlayher/netlink v1.11.2/go.mod h1:uT2Yc/QLaZubzDpZIBi9d4GoeLwtp3x1AMeqSRrK2sA= github.com/mdlayher/socket v0.8.0 h1:1lIVvHAs3sT623kPkPDa+I0nLVusskwnpWzp6ZUcNyc= github.com/mdlayher/socket v0.8.0/go.mod h1:EhNb63aXqexVoTJDblxvDOSuIGIJinC4H5ZktnaJ6Rk= -github.com/metal-stack/firewall-controller-manager v0.6.1 h1:JM5oCuye9GBY/QivK9qxY14hNh0xoidAGVkY7td8gnY= -github.com/metal-stack/firewall-controller-manager v0.6.1/go.mod h1:bQjb3pVL3R6XPUqWA/WX8ktlzcgVYWDbsFANKcrW3FA= -github.com/metal-stack/metal-go v0.45.0 h1:X5BCppdE3RYNScfwQxv9JTehyFIv6LhVzhbG25k27KQ= -github.com/metal-stack/metal-go v0.45.0/go.mod h1:GSfXrAj55LGsUSMHWGDsmq5n056NG0yb1JM8bgfvKOw= -github.com/metal-stack/metal-hammer v0.13.17 h1:W2IrWmnz6IXpL7Y35RfVgSVO66EVdqeF+/WeopgycMI= -github.com/metal-stack/metal-hammer v0.13.17/go.mod h1:N+AEexkInMf1YHe40CkCSaAK4mkKh8ubB3Zsy1s6uzQ= +github.com/metal-stack/api v0.8.2 h1:GWgtAqN2jp5TTkmjVlIUKQptc80KY4cSH0/cwYLYKIs= +github.com/metal-stack/api v0.8.2/go.mod h1:mx2KOLoCwogU/riKSYTYAb1DXtP7n4A0+FitzOxlCUE= +github.com/metal-stack/firewall-controller-manager v0.6.2-0.20261013093056-8814016e6683 h1:OtwZfm+R3RvWQAONEuwQag0UrYs6QdkDW2GyLSv8m+Y= +github.com/metal-stack/firewall-controller-manager v0.6.2-0.20261013093056-8814016e6683/go.mod h1:sYlFUCZDo1l60edNKAGzJ2PmligSwC5942ucY7b7F/Q= github.com/metal-stack/metal-lib v0.26.3 h1:K5gLoD65m6p3l6qCPrfavIdvNdWfmF2QdXrvU2URaZs= github.com/metal-stack/metal-lib v0.26.3/go.mod h1:cNXjPBs8SFnjqfBobuSbm5mDk6E/jS8PVeIOrV/7POE= -github.com/metal-stack/metal-networker v0.47.0 h1:DsA7cLfcd/LtTv+bMqCX7a+uGRB4cTbNAguBu0EHNvI= -github.com/metal-stack/metal-networker v0.47.0/go.mod h1:IoxAZQXAc4h5mFGqSKOo7EAp7pYr+qK2B6qgf3kBu+U= +github.com/metal-stack/os-installer v0.3.2 h1:TQOW5av/mTWuQhjTr4NX0AxhiIGpyqLfSk5vdRnKr+M= +github.com/metal-stack/os-installer v0.3.2/go.mod h1:vMOW7otAMwe8ReQxCPb/VE5KLvA9+q9VauDBhYwInEc= github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= github.com/metal-stack/v v1.0.3/go.mod h1:YTahEu7/ishwpYKnp/VaW/7nf8+PInogkfGwLcGPdXg= github.com/miekg/dns v1.1.73 h1:uhT8nJxmTrPJYClxVxTCX+CVn6qnzSiybRk72Z6DgrE= github.com/miekg/dns v1.1.73/go.mod h1:RW2Obtfd5NZHvOFe3zYG0W8koWOQtAzyHaLo8vASBuQ= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -168,11 +171,10 @@ github.com/olekukonko/ll v0.1.8 h1:ysHCJRGHYKzmBSdz9w5AySztx7lG8SQY+naTGYUbsz8= github.com/olekukonko/ll v0.1.8/go.mod h1:RPRC6UcscfFZgjo1nulkfMH5IM0QAYim0LfnMvUuozw= github.com/olekukonko/tablewriter v1.1.4 h1:ORUMI3dXbMnRlRggJX3+q7OzQFDdvgbN9nVWj1drm6I= github.com/olekukonko/tablewriter v1.1.4/go.mod h1:+kedxuyTtgoZLwif3P1Em4hARJs+mVnzKxmsCL/C5RY= -github.com/onsi/ginkgo/v2 v2.27.5 h1:ZeVgZMx2PDMdJm/+w5fE/OyG6ILo1Y3e+QX4zSR0zTE= -github.com/onsi/ginkgo/v2 v2.27.5/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= -github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q= -github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4= -github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= +github.com/onsi/ginkgo/v2 v2.33.0 h1:C8gBA6Uc2ZEubiV+SXiu5tZnMTwEmXHgkJwGozKtZf8= +github.com/onsi/ginkgo/v2 v2.33.0/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44= +github.com/onsi/gomega v1.44.0 h1:eAiGl3Pw5jz5GQdDff0BcxYpAX1JxW8xD7mFUuwNfZQ= +github.com/onsi/gomega v1.44.0/go.mod h1:e/C2HwaZ1DhvjzXXuFhcR7hY7Sh9pl7MmoWKEjzwcdA= github.com/pelletier/go-toml/v2 v2.4.3 h1:GTRvJQutkOSftxIFD5xw9aepkYNuPWmVJpffdDPYVpY= github.com/pelletier/go-toml/v2 v2.4.3/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -188,10 +190,14 @@ github.com/prometheus/common v0.72.1 h1:ZAiQed/nk8IIcsdzb2TlJu23NEUDyDLQ9TXTN2WR github.com/prometheus/common v0.72.1/go.mod h1:1IoBY4IRaJnhs2ESjNzjilP1cJ/P8pimGoomq7zRXrA= github.com/prometheus/procfs v0.22.0 h1:6q9+/JL9IKAPbCmBrv9n5O5Ty3NKnciV5X7YGw0oics= github.com/prometheus/procfs v0.22.0/go.mod h1:CvmFr/GVhIjIvWJZW3tgkODBQMRIf0EyWMQLHCHab58= -github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= -github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/rogpeppe/go-internal v1.16.0 h1:O9DK+vNMDVGLr2BeZqmpLeMjiMNkuXfcqntWbZV6S5g= +github.com/rogpeppe/go-internal v1.16.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= +github.com/samber/lo v1.53.0 h1:t975lj2py4kJPQ6haz1QMgtId2gtmfktACxIXArw3HM= +github.com/samber/lo v1.53.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= +github.com/shopspring/decimal v1.5.0 h1:HxSWk31RmJv0EyY4oLiGQB9u7WPludUwPBdvQZnYFPc= +github.com/shopspring/decimal v1.5.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= @@ -232,10 +238,12 @@ go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= go4.org/netipx v0.0.0-20260823151212-3075585bcbeb h1:XBM4hvfwGAttkkiTIFfeigdfcL1xIfdKXqFdgiHGtDs= go4.org/netipx v0.0.0-20260823151212-3075585bcbeb/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= -golang.org/x/exp v0.0.0-20260811152304-ee035b5b010f h1:iXpLj9sdDH/RLYsnOMpbETK6KWtrHwvegcc4psWJHV8= -golang.org/x/exp v0.0.0-20260811152304-ee035b5b010f/go.mod h1:EdfpwwqSu+0Li0mzskwHU6FWDV3t9Q+RZDo3QMUtL3Q= -golang.org/x/mod v0.41.0 h1:qJmnOUb4YB+FsEuM3HcWucdZASCPGhsX6uljO6pog0c= -golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o= +golang.org/x/crypto v0.58.0 h1:COkYLr4k7nDI4r6QtMML2AfzeIswWHAJthLS6K/M/54= +golang.org/x/crypto v0.58.0/go.mod h1:Xh+kl5A+M0gMiWDytH2Hhr5Z7WbNCpv/eB/EFgfSk+w= +golang.org/x/exp v0.0.0-20261014143641-f0251eb4aa3e h1:HgI6W1OolKK6tcV74is+rl9SMT0njsHlp0TbQiGXI/A= +golang.org/x/exp v0.0.0-20261014143641-f0251eb4aa3e/go.mod h1:DBoxwWhjaW8DJJw/YeM4zpeOKMC1FMXSblsYy+1mFSw= +golang.org/x/mod v0.42.0 h1:ICeL3t2L30ljSPHHxDnR4fqVcBt/zR2zJAb9juavmQg= +golang.org/x/mod v0.42.0/go.mod h1:u5fzIrRInkL8MaO1cbRkUHT64v303YIT5KEqpNr7jRs= golang.org/x/net v0.61.0 h1:RR+6j/BTBCrggOLugxa+66R8FvoN6MHlzDlZIbN9YFw= golang.org/x/net v0.61.0/go.mod h1:WgDCOTH8iwtB66T4/GfI94AHo/hhdb7Hah9NDseQfiI= golang.org/x/oauth2 v0.37.0 h1:JUlcxA8oAtauLfiH8FX2/FkAWHAdi0QtGCGc+hofE98= @@ -252,19 +260,16 @@ golang.org/x/text v0.43.0 h1:1QivrlhwAsnMOcqgOdl9my7s9OyZl8O5/UGUTJVXoWc= golang.org/x/text v0.43.0/go.mod h1:hbSIYA/amXcRXTFSZqh8tWHEoqRvvbKPJ2uz/KU+a+s= golang.org/x/time v0.16.0 h1:vMb6ptszcQMkcwiRTAuNNU50gom6++Q/6gY2hDM6VDE= golang.org/x/time v0.16.0/go.mod h1:rVKOqvZeKvrDKTQiAHJ7wmwP0RzleSphoEA9RcdLA0s= -golang.org/x/tools v0.51.0 h1:k4Xc/1Om9jwkBJBo4NVLMSARBoWtK10mx+W5BnXCeAI= -golang.org/x/tools v0.51.0/go.mod h1:9eEncMayCV6zRMGhR5eZEC2iBx98qWcF1HZ9Z7wJOoA= +golang.org/x/tools v0.52.0 h1:ryxg4U63oaUYk7uOLTF37n43f4qgtGvqV4Ioit1BaEs= +golang.org/x/tools v0.52.0/go.mod h1:ItcP5UNaVGG+Yc4eIYmaFLNJ4soEopkx5Y2d4lcEurs= gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0= gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8= -google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/genproto/googleapis/api v0.0.0-20261012220534-4341edf3f941 h1:DS/w3N8rsfrwxwgGSj6WhMsPo7aNQGmDx74J81zd0NQ= +google.golang.org/genproto/googleapis/api v0.0.0-20261012220534-4341edf3f941/go.mod h1:AuGAdi9KnXss7xbLxIKhCvk+Ro/SxpET/iS45DNYN+M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20261012220534-4341edf3f941 h1:QG6hS4zFplRZvOQedzei4t2pT/zkQc3VR1u+S9/rcAw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20261012220534-4341edf3f941/go.mod h1:OaIUM3+LpYcK2GXM4FTmhWoIq371Owdr+Cc7/BsYHHc= google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc= google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= diff --git a/main.go b/main.go index e995b8e0..7c2777a7 100644 --- a/main.go +++ b/main.go @@ -2,12 +2,16 @@ package main import ( "context" + "errors" "flag" "fmt" "log/slog" "os" "time" + "github.com/metal-stack/api/go/enum" + apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" + "github.com/metal-stack/metal-lib/pkg/pointer" "github.com/metal-stack/v" "github.com/go-logr/logr" @@ -32,6 +36,8 @@ import ( "github.com/metal-stack/firewall-controller/v2/pkg/frr" "github.com/metal-stack/firewall-controller/v2/pkg/sysctl" "github.com/metal-stack/firewall-controller/v2/pkg/updater" + + osnet "github.com/metal-stack/os-installer/pkg/network" // +kubebuilder:scaffold:imports ) @@ -233,21 +239,41 @@ func main() { } l.Info("detected frr", "version", frrVersion.String()) + allocation, err := getMachineAllocation(fw) + if err != nil { + l.Error("converting machine allocation from firewall spec", "error", err) + panic(err) + } + + l.Info("machine allocation", "allocation", allocation) + + defaultRouteNetwork, err := osnet.New(allocation).GetDefaultRouteNetwork() + if err != nil { + l.Error("unable to get a default route network", "error", err) + panic(err) + } + if len(defaultRouteNetwork.Ips) == 0 { + l.Error("default route network does not have ips") + panic(errors.New("default route network does not have ips")) + } + defaultRouteIp := defaultRouteNetwork.Ips[0] + updater := updater.New(ctrl.Log.WithName("updater"), shootMgr.GetEventRecorderFor("FirewallController")) // nolint:staticcheck // Firewall Reconciler if err = (&controllers.FirewallReconciler{ - SeedClient: seedMgr.GetClient(), - ShootClient: shootClient, - Log: ctrl.Log.WithName("controllers").WithName("Firewall"), - Scheme: scheme, - Namespace: seedNamespace, - FirewallName: firewallName, - Recorder: shootMgr.GetEventRecorderFor("FirewallController"), // nolint:staticcheck - Updater: updater, - SeedUpdatedFunc: fwmReconciler.SeedUpdated, - TokenUpdater: accessTokenUpdater, - FrrVersion: frrVersion, + SeedClient: seedMgr.GetClient(), + ShootClient: shootClient, + Log: ctrl.Log.WithName("controllers").WithName("Firewall"), + Scheme: scheme, + Namespace: seedNamespace, + FirewallName: firewallName, + Recorder: shootMgr.GetEventRecorderFor("FirewallController"), // nolint:staticcheck + Updater: updater, + SeedUpdatedFunc: fwmReconciler.SeedUpdated, + TokenUpdater: accessTokenUpdater, + FrrVersion: frrVersion, + MachineAllocation: allocation, }).SetupWithManager(seedMgr); err != nil { l.Error("unable to create firewall controller", "error", err) panic(err) @@ -265,13 +291,15 @@ func main() { // ClusterwideNetworkPolicy Reconciler if err = (&controllers.ClusterwideNetworkPolicyReconciler{ - SeedClient: seedMgr.GetClient(), - ShootClient: shootMgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("ClusterwideNetworkPolicy"), - Ctx: ctx, - Recorder: shootMgr.GetEventRecorderFor("FirewallController"), // nolint:staticcheck - FirewallName: firewallName, - SeedNamespace: seedNamespace, + SeedClient: seedMgr.GetClient(), + ShootClient: shootMgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("ClusterwideNetworkPolicy"), + Ctx: ctx, + Recorder: shootMgr.GetEventRecorderFor("FirewallController"), // nolint:staticcheck + FirewallName: firewallName, + SeedNamespace: seedNamespace, + DefaultRouteIp: defaultRouteIp, + MachineAllocation: allocation, }).SetupWithManager(shootMgr); err != nil { l.Error("unable to create clusterwidenetworkpolicy controller", "error", err) panic(err) @@ -378,3 +406,57 @@ func getSeedNamespace(rawKubeconfig []byte) (string, error) { return "", fmt.Errorf("unable to figure out seed namespace from kubeconfig") } + +func getMachineAllocation(f *firewallv2.Firewall) (*apiv2.MachineAllocation, error) { + var vpn *apiv2.MachineVPN + if f.Status.VPN != nil { + vpn = &apiv2.MachineVPN{ + // Authkey is omitted for security reasons + ControlPlaneAddress: pointer.SafeDeref(&f.Status.VPN.ControlPlaneAddress), + } + } + + var networks []*apiv2.MachineNetwork + for _, nw := range f.Status.FirewallNetworks { + + natType := apiv2.NATType_NAT_TYPE_NONE + if nw.Nat != nil && *nw.Nat { + natType = apiv2.NATType_NAT_TYPE_IPV4_MASQUERADE + } + + networkType, err := enum.GetEnum[apiv2.NetworkType](pointer.SafeDeref(nw.NetworkTypeV2)) + if err != nil { + return nil, err + } + + networks = append(networks, &apiv2.MachineNetwork{ + Network: pointer.SafeDeref(nw.NetworkID), + Prefixes: nw.Prefixes, + DestinationPrefixes: nw.DestinationPrefixes, + Ips: nw.IPs, + Vrf: uint64(pointer.SafeDeref(nw.Vrf)), + Asn: uint32(pointer.SafeDeref(nw.ASN)), + Project: nw.Project, + NatType: natType, + NetworkType: networkType, + }) + } + + hostname, err := os.Hostname() + if err != nil { + return nil, err + } + machineAllocation := &apiv2.MachineAllocation{ + Project: f.Spec.Project, + Hostname: hostname, + AllocationType: apiv2.MachineAllocationType_MACHINE_ALLOCATION_TYPE_FIREWALL, + Networks: networks, + // TODO the following properties are not required during reconciliation + // FirewallRules: firewallRules, + // DnsServers: dnsservers, + // NtpServers: ntpservers, + Vpn: vpn, + } + + return machineAllocation, nil +} diff --git a/pkg/dns/dnsproxy.go b/pkg/dns/dnsproxy.go index e89aa279..ea57490d 100644 --- a/pkg/dns/dnsproxy.go +++ b/pkg/dns/dnsproxy.go @@ -3,20 +3,16 @@ package dns import ( "context" "fmt" - "log/slog" "net" "strconv" "time" - "github.com/metal-stack/metal-networker/pkg/netconf" "sigs.k8s.io/controller-runtime/pkg/client" firewallv1 "github.com/metal-stack/firewall-controller/v2/api/v1" "github.com/go-logr/logr" dnsgo "github.com/miekg/dns" - - "github.com/metal-stack/firewall-controller/v2/pkg/network" ) const ( @@ -39,6 +35,8 @@ type ( tcpServer *dnsgo.Server handler DNSHandler + + bindAddress string } DNSProxyConfig struct { @@ -46,6 +44,8 @@ type ( Port *uint ShootClient client.Client Log logr.Logger + // BindAddress is the first ip of the defaultRouteNetwork + BindAddress string } ) @@ -54,16 +54,11 @@ func NewDNSProxy(ctx context.Context, cfg *DNSProxyConfig) (*DNSProxy, error) { cfg.DNSServer = defaultDNSServerAddr } - host, err := getHost() - if err != nil { - return nil, err - } - p := defaultDNSPort if cfg.Port != nil { p = *cfg.Port } - udpConn, tcpListener, err := bindToPort(host, int(p), cfg.Log) // nolint:gosec + udpConn, tcpListener, err := bindToPort(cfg.BindAddress, int(p), cfg.Log) // nolint:gosec if err != nil { return nil, fmt.Errorf("failed to bind to port: %w", err) } @@ -89,6 +84,8 @@ func NewDNSProxy(ctx context.Context, cfg *DNSProxyConfig) (*DNSProxy, error) { tcpServer: tcpServer, handler: handler, + + bindAddress: cfg.BindAddress, }, nil } @@ -146,22 +143,8 @@ func (p *DNSProxy) IsInitialized() bool { return p != nil } -func (p *DNSProxy) CacheAddr() (string, error) { - return getHost() -} - -func getHost() (string, error) { - c, err := netconf.New(slog.Default(), network.MetalNetworkerConfig) - if err != nil || c == nil { - return "", fmt.Errorf("failed to init networker config: %w", err) - } - - defaultNetwork := c.GetDefaultRouteNetwork() - if defaultNetwork == nil || len(defaultNetwork.Ips) < 1 { - return "", fmt.Errorf("failed to retrieve host IP for DNS Proxy") - } - - return defaultNetwork.Ips[0], nil +func (p *DNSProxy) CacheAddr() string { + return p.bindAddress } // bindToPort attempts to bind to port for both UDP and TCP diff --git a/pkg/network/network.go b/pkg/network/network.go index ecee96d3..b664fe9b 100644 --- a/pkg/network/network.go +++ b/pkg/network/network.go @@ -1,16 +1,18 @@ package network import ( + "context" + "errors" "fmt" "log/slog" - "os" - "path/filepath" "github.com/Masterminds/semver/v3" "github.com/go-logr/logr" + apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" firewallv2 "github.com/metal-stack/firewall-controller-manager/api/v2" - "github.com/metal-stack/metal-go/api/models" - "github.com/metal-stack/metal-networker/pkg/netconf" + "github.com/metal-stack/os-installer/pkg/frr" + osnet "github.com/metal-stack/os-installer/pkg/network" + "google.golang.org/protobuf/proto" ) const ( @@ -19,7 +21,7 @@ const ( ) // GetNewNetworks returns updated network models -func GetNewNetworks(log logr.Logger, f *firewallv2.Firewall, oldNetworks []*models.V1MachineNetwork) []*models.V1MachineNetwork { +func GetNewNetworks(log logr.Logger, f *firewallv2.Firewall, oldNetworks []*apiv2.MachineNetwork) []*apiv2.MachineNetwork { networkMap := map[string]firewallv2.FirewallNetwork{} for _, n := range f.Status.FirewallNetworks { if n.NetworkType == nil { @@ -28,15 +30,19 @@ func GetNewNetworks(log logr.Logger, f *firewallv2.Firewall, oldNetworks []*mode networkMap[*n.NetworkID] = n } - newNetworks := []*models.V1MachineNetwork{} + newNetworks := []*apiv2.MachineNetwork{} for _, n := range oldNetworks { if n == nil { continue } - newNet := n - newNet.Prefixes = networkMap[*n.Networkid].Prefixes - newNetworks = append(newNetworks, newNet) + newNet := proto.CloneOf(n) + if newNetwork, ok := networkMap[n.Network]; ok { + newNet.Prefixes = newNetwork.Prefixes + newNetworks = append(newNetworks, newNet) + } else { + log.Error(errors.New("network not present firewall networks"), "network", n.Network) + } } return newNetworks @@ -44,42 +50,19 @@ func GetNewNetworks(log logr.Logger, f *firewallv2.Firewall, oldNetworks []*mode // ReconcileNetwork reconciles the network settings for a firewall // Changes both the FRR-Configuration and Nftable rules when network prefixes or FRR template changes -func ReconcileNetwork(log logr.Logger, f *firewallv2.Firewall, frrVersion *semver.Version) (changed bool, err error) { - tmpFile, err := tmpFile(frrConfig) - if err != nil { - return false, fmt.Errorf("error during network reconciliation %v: %w", tmpFile, err) - } - defer func() { - _ = os.Remove(tmpFile) - }() +func ReconcileNetwork(log logr.Logger, f *firewallv2.Firewall, allocation *apiv2.MachineAllocation, frrVersion *semver.Version) (bool, error) { + allocation.Networks = GetNewNetworks(log, f, allocation.Networks) - c, err := netconf.New(slog.Default(), MetalNetworkerConfig) - if err != nil || c == nil { - return false, fmt.Errorf("failed to init networker config: %w", err) - } - c.Networks = GetNewNetworks(log, f, c.Networks) - - a := netconf.NewFrrConfigApplier(netconf.Firewall, *c, tmpFile, frrVersion) - tpl := netconf.MustParseTpl(netconf.TplFirewallFRR) - - changed, err = a.Apply(*tpl, tmpFile, frrConfig, true) + changed, err := frr.Render(context.Background(), &frr.Config{ + Log: slog.New(logr.ToSlogHandler(log)), + Reload: true, + Validate: true, + Network: osnet.New(allocation), + FRRVersion: frrVersion, + }) if err != nil { - return changed, fmt.Errorf("error during network reconciliation: %v: %w", tmpFile, err) + return changed, fmt.Errorf("error during network reconciliation: %w", err) } return changed, nil } - -func tmpFile(file string) (string, error) { - f, err := os.CreateTemp(filepath.Dir(file), filepath.Base(file)) - if err != nil { - return "", err - } - - err = f.Close() - if err != nil { - return "", err - } - - return f.Name(), nil -} diff --git a/pkg/nftables/firewall.go b/pkg/nftables/firewall.go index a33da38b..3359b12d 100644 --- a/pkg/nftables/firewall.go +++ b/pkg/nftables/firewall.go @@ -1,6 +1,7 @@ package nftables import ( + "context" "embed" "errors" "fmt" @@ -10,6 +11,7 @@ import ( "os/exec" "path/filepath" + apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" "github.com/metal-stack/firewall-controller/v2/pkg/dns" "github.com/metal-stack/firewall-controller/v2/pkg/network" @@ -21,7 +23,8 @@ import ( "k8s.io/client-go/tools/record" mn "github.com/metal-stack/metal-lib/pkg/net" - "github.com/metal-stack/metal-networker/pkg/netconf" + osnet "github.com/metal-stack/os-installer/pkg/network" + "github.com/metal-stack/os-installer/pkg/nftables" firewallv2 "github.com/metal-stack/firewall-controller-manager/api/v2" firewallv1 "github.com/metal-stack/firewall-controller/v2/api/v1" @@ -41,7 +44,7 @@ type FQDNCache interface { GetSetsForRendering(fqdns []firewallv1.FQDNSelector) (result []dns.RenderIPSet) GetSetsForFQDN(fqdn firewallv1.FQDNSelector) (result []firewallv1.IPSet) IsInitialized() bool - CacheAddr() (string, error) + CacheAddr() string } // Firewall assembles nftable rules based on k8s entities @@ -57,6 +60,7 @@ type Firewall struct { primaryPrivateNet *firewallv2.FirewallNetwork networkMap networkMap cache FQDNCache + allocation *apiv2.MachineAllocation enableDNS bool dryRun bool @@ -80,6 +84,7 @@ func NewFirewall( cache FQDNCache, log logr.Logger, recorder record.EventRecorder, + allocation *apiv2.MachineAllocation, ) *Firewall { networkMap := networkMap{} var primaryPrivateNet *firewallv2.FirewallNetwork @@ -105,6 +110,7 @@ func NewFirewall( enableDNS: len(cwnps.GetFQDNs()) > 0, log: log, recorder: recorder, + allocation: allocation, } } @@ -174,30 +180,30 @@ func (f *Firewall) Reconcile() (updated bool, err error) { } func (f *Firewall) ReconcileNetconfTables() error { - c, err := netconf.New(slog.Default(), network.MetalNetworkerConfig) - if err != nil || c == nil { - return fmt.Errorf("failed to init networker config: %w", err) - } - - c.Networks = network.GetNewNetworks(f.log, f.firewall, c.Networks) - - configurator, err := netconf.NewConfigurator(netconf.Firewall, *c, f.enableDNS) + f.allocation.Networks = network.GetNewNetworks(f.log, f.firewall, f.allocation.Networks) + + changed, err := nftables.Render(context.Background(), &nftables.Config{ + Log: slog.New(logr.ToSlogHandler(f.log)), + Reload: true, + Validate: true, + EnableDNSProxy: f.enableDNS, + ForwardPolicy: nftables.ForwardPolicyAccept, + Network: osnet.New(f.allocation), + }) if err != nil { - return fmt.Errorf("failed to init networker configurator: %w", err) + return fmt.Errorf("failed to render nftables: %w", err) + } + if changed { + f.log.Info("nftables rules have changed") } - configurator.ConfigureNftables(netconf.ForwardPolicyAccept) return nil } -func getConfiguredIPs(networkID string) []string { - c, err := netconf.New(slog.Default(), network.MetalNetworkerConfig) - if err != nil || c == nil { - return nil - } +func (f *Firewall) getConfiguredIPs(networkID string) []string { var ips []string - for _, nw := range c.Networks { - if nw.Networkid == nil || *nw.Networkid != networkID { + for _, nw := range osnet.New(f.allocation).AllocationNetworks() { + if nw.Network != networkID { continue } for _, ip := range nw.Ips { @@ -252,7 +258,7 @@ func (f *Firewall) reconcileIfaceAddresses() error { continue } - configureIPs := getConfiguredIPs(*n.NetworkID) + configureIPs := f.getConfiguredIPs(*n.NetworkID) wantedIPs := sets.NewString(configureIPs...) for _, i := range f.firewall.Spec.EgressRules { @@ -267,6 +273,7 @@ func (f *Firewall) reconcileIfaceAddresses() error { if err != nil { if _, ok := errors.AsType[netlink.LinkNotFoundError](err); ok { f.log.Info("skipping link because not found", "name", linkName) + continue } return fmt.Errorf("unable to detect link by name: %w", err) } diff --git a/pkg/nftables/mocks/pkg/nftables/FQDNCache.go b/pkg/nftables/mocks/pkg/nftables/FQDNCache.go index b17eba5d..e47dcc2f 100644 --- a/pkg/nftables/mocks/pkg/nftables/FQDNCache.go +++ b/pkg/nftables/mocks/pkg/nftables/FQDNCache.go @@ -47,7 +47,7 @@ func (_m *FQDNCache) EXPECT() *FQDNCache_Expecter { } // CacheAddr provides a mock function for the type FQDNCache -func (_mock *FQDNCache) CacheAddr() (string, error) { +func (_mock *FQDNCache) CacheAddr() string { ret := _mock.Called() if len(ret) == 0 { @@ -55,21 +55,12 @@ func (_mock *FQDNCache) CacheAddr() (string, error) { } var r0 string - var r1 error - if returnFunc, ok := ret.Get(0).(func() (string, error)); ok { - return returnFunc() - } if returnFunc, ok := ret.Get(0).(func() string); ok { r0 = returnFunc() } else { r0 = ret.Get(0).(string) } - if returnFunc, ok := ret.Get(1).(func() error); ok { - r1 = returnFunc() - } else { - r1 = ret.Error(1) - } - return r0, r1 + return r0 } // FQDNCache_CacheAddr_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CacheAddr' @@ -89,12 +80,12 @@ func (_c *FQDNCache_CacheAddr_Call) Run(run func()) *FQDNCache_CacheAddr_Call { return _c } -func (_c *FQDNCache_CacheAddr_Call) Return(s string, err error) *FQDNCache_CacheAddr_Call { - _c.Call.Return(s, err) +func (_c *FQDNCache_CacheAddr_Call) Return(s string) *FQDNCache_CacheAddr_Call { + _c.Call.Return(s) return _c } -func (_c *FQDNCache_CacheAddr_Call) RunAndReturn(run func() (string, error)) *FQDNCache_CacheAddr_Call { +func (_c *FQDNCache_CacheAddr_Call) RunAndReturn(run func() string) *FQDNCache_CacheAddr_Call { _c.Call.Return(run) return _c } diff --git a/pkg/nftables/networkpolicy.go b/pkg/nftables/networkpolicy.go index 4e13de38..ebc95b5a 100644 --- a/pkg/nftables/networkpolicy.go +++ b/pkg/nftables/networkpolicy.go @@ -60,10 +60,7 @@ func clusterwideNetworkPolicyIngressRules(np firewallv1.ClusterwideNetworkPolicy } func clusterwideNetworkPolicyEgressDNSCacheRules(cache FQDNCache, logAcceptedConnections bool) (nftablesRules, error) { - addr, err := cache.CacheAddr() - if err != nil { - return nil, err - } + addr := cache.CacheAddr() base := []string{"ip saddr == @cluster_prefixes", fmt.Sprintf("ip daddr { %s }", addr)} comment := "accept intercepted traffic for dns cache" return nftablesRules{ diff --git a/pkg/nftables/networkpolicy_test.go b/pkg/nftables/networkpolicy_test.go index 5590ed67..24291b5b 100644 --- a/pkg/nftables/networkpolicy_test.go +++ b/pkg/nftables/networkpolicy_test.go @@ -12,8 +12,10 @@ import ( ) func TestClusterwideNetworkPolicyRules(t *testing.T) { - tcp := corev1.ProtocolTCP - udp := corev1.ProtocolUDP + var ( + tcp = corev1.ProtocolTCP + udp = corev1.ProtocolUDP + ) type want struct { ingress nftablesRules diff --git a/pkg/nftables/ratelimit_test.go b/pkg/nftables/ratelimit_test.go index 814ef94f..90fc97a1 100644 --- a/pkg/nftables/ratelimit_test.go +++ b/pkg/nftables/ratelimit_test.go @@ -80,7 +80,7 @@ func TestRateLimitRules(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - f := NewFirewall(&firewallv2.Firewall{Spec: tt.input.Spec, Status: tt.input.Status}, &firewallv1.ClusterwideNetworkPolicyList{}, nil, nil, logr.Discard(), nil) + f := NewFirewall(&firewallv2.Firewall{Spec: tt.input.Spec, Status: tt.input.Status}, &firewallv1.ClusterwideNetworkPolicyList{}, nil, nil, logr.Discard(), nil, nil) got := rateLimitRules(f) if !cmp.Equal(got, tt.want) { t.Errorf("rateLimitRules() diff: %v", cmp.Diff(got, tt.want)) diff --git a/pkg/nftables/snat_test.go b/pkg/nftables/snat_test.go index 8b9bde97..2d291ceb 100644 --- a/pkg/nftables/snat_test.go +++ b/pkg/nftables/snat_test.go @@ -196,7 +196,7 @@ func TestSnatRules(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - f := NewFirewall(&firewallv2.Firewall{Spec: tt.input.Spec, Status: tt.input.Status}, &tt.cwnps, nil, nil, logr.Discard(), nil) + f := NewFirewall(&firewallv2.Firewall{Spec: tt.input.Spec, Status: tt.input.Status}, &tt.cwnps, nil, nil, logr.Discard(), nil, nil) got, err := snatRules(f) if (err != nil) != tt.wantErr { t.Errorf("snatRules() error = %v, wantErr %v", err, tt.err)