diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index df291729..350380ac 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -23,7 +23,7 @@ jobs: steps: - name: Log in to the container registry - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: registry: ${{ env.REGISTRY }} username: ${{ secrets.DOCKER_REGISTRY_USER }} @@ -75,10 +75,10 @@ jobs: output-file: ./bin/${{ env.SBOM_NAME }}1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v4 - name: Push Docker image - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: context: . push: true diff --git a/Makefile b/Makefile index 5a143f79..d168e9ca 100644 --- a/Makefile +++ b/Makefile @@ -89,4 +89,4 @@ go-mocks: --tmpfs /.cache:uid=$$(id -u),gid=$$(id -g) \ -w /work \ -v ${PWD}:/work \ - vektra/mockery:v3.6.4 \ No newline at end of file + vektra/mockery:v3.7.0 \ No newline at end of file diff --git a/controllers/clusterwidenetworkpolicy_controller.go b/controllers/clusterwidenetworkpolicy_controller.go index 3fba5316..9441c902 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" @@ -46,6 +47,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 @@ -106,7 +110,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 } @@ -145,7 +149,14 @@ func (r *ClusterwideNetworkPolicyReconciler) manageDNSProxy( if enableDNS && r.DnsProxy == nil { r.Log.Info("DNS Proxy is initialized") - if r.DnsProxy, err = dns.NewDNSProxy(r.Ctx, f.Spec.DNSServerAddress, f.Spec.DNSPort, r.ShootClient, ctrl.Log.WithName("DNS proxy")); err != nil { + dnsProxyConfig := &dns.DNSProxyConfig{ + Log: ctrl.Log.WithName("DNS proxy"), + 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) } go r.DnsProxy.Run() diff --git a/controllers/firewall_controller.go b/controllers/firewall_controller.go index 63f84754..57fb3afc 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 ( @@ -90,7 +92,14 @@ func (r *FirewallReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c if apierrors.IsNotFound(err) { r.Log.Info("flushing k8s firewall rules") - defaultFw := nftables.NewFirewall(&firewallv2.Firewall{}, &firewallv1.ClusterwideNetworkPolicyList{}, &corev1.ServiceList{}, nil, logr.Discard(), r.Recorder) + defaultFw := nftables.NewFirewall( + &firewallv2.Firewall{}, + &firewallv1.ClusterwideNetworkPolicyList{}, + &corev1.ServiceList{}, + nil, logr.Discard(), + r.Recorder, + r.MachineAllocation, + ) flushErr := defaultFw.Flush() if flushErr != nil { @@ -119,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(f, r.FrrVersion) + nw := network.NewNetwork(r.Log, r.MachineAllocation) + changed, err := nw.ReconcileNetwork(f, r.FrrVersion) if changed && err == nil { r.recordFirewallEvent(f, corev1.EventTypeNormal, "Network settings", "reconciliation succeeded (frr.conf)") } else if changed && err != nil { diff --git a/go.mod b/go.mod index ba31d4a7..c9e4dede 100644 --- a/go.mod +++ b/go.mod @@ -10,10 +10,10 @@ 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/api v0.0.55-0.20260316085710-1f98c8226b9e github.com/metal-stack/firewall-controller-manager v0.6.0 - github.com/metal-stack/metal-go v0.43.0 github.com/metal-stack/metal-lib v0.24.0 - github.com/metal-stack/metal-networker v0.46.3 + github.com/metal-stack/os-installer v0.2.1-0.20260319072654-2f5a75d683f8 github.com/metal-stack/v v1.0.3 github.com/miekg/dns v1.1.72 github.com/stretchr/testify v1.11.1 @@ -31,20 +31,28 @@ require ( replace github.com/imdario/mergo => dario.cat/mergo v1.0.0 require ( + buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1 // indirect + buf.build/go/protovalidate v1.1.3 // indirect + buf.build/go/protoyaml v0.6.0 // indirect + cel.dev/expr v0.25.1 // 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/ajeddeloh/go-json v0.0.0-20200220154158-5ae607161559 // indirect + github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/coreos/go-semver v0.3.1 // indirect + github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect + github.com/flatcar/ignition v0.36.2 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect - github.com/go-openapi/analysis v0.24.2 // indirect - github.com/go-openapi/errors v0.22.7 // indirect github.com/go-openapi/jsonpointer v0.22.5 // indirect github.com/go-openapi/jsonreference v0.21.5 // indirect - github.com/go-openapi/loads v0.23.2 // indirect - github.com/go-openapi/spec v0.22.4 // indirect - github.com/go-openapi/strfmt v0.25.0 // indirect + github.com/go-openapi/strfmt v0.26.1 // indirect github.com/go-openapi/swag v0.25.5 // indirect github.com/go-openapi/swag/cmdutils v0.25.5 // indirect github.com/go-openapi/swag/conv v0.25.5 // indirect @@ -57,46 +65,55 @@ require ( github.com/go-openapi/swag/stringutils v0.25.5 // indirect github.com/go-openapi/swag/typeutils v0.25.5 // indirect github.com/go-openapi/swag/yamlutils v0.25.5 // indirect - github.com/go-openapi/validate v0.25.1 // indirect - github.com/go-viper/mapstructure/v2 v2.5.0 // indirect + github.com/go-openapi/testify/enable/yaml/v2 v2.4.1 // indirect + github.com/go-openapi/testify/v2 v2.4.1 // indirect github.com/godbus/dbus/v5 v5.2.2 // indirect github.com/google/btree v1.1.3 // indirect + github.com/google/cel-go v0.27.0 // indirect github.com/google/gnostic-models v0.7.1 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/huandu/xstrings v1.5.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.18.4 // indirect - github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mdlayher/netlink v1.9.0 // indirect github.com/mdlayher/socket v0.5.1 // 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 v1.3.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.5 // indirect github.com/prometheus/procfs v0.20.1 // indirect + github.com/samber/lo v1.53.0 // indirect + github.com/shopspring/decimal v1.4.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.5.3 // indirect + github.com/vincent-petithory/dataurl v1.0.0 // indirect github.com/vishvananda/netns v0.0.5 // indirect github.com/x448/float16 v0.8.4 // indirect - go.mongodb.org/mongo-driver v1.17.9 // indirect - go.yaml.in/yaml/v2 v2.4.3 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/mod v0.33.0 // indirect - golang.org/x/net v0.51.0 // indirect - golang.org/x/oauth2 v0.35.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.41.0 // indirect - golang.org/x/term v0.40.0 // indirect - golang.org/x/text v0.34.0 // indirect - golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.42.0 // indirect + go4.org v0.0.0-20260112195520-a5071408f32f // indirect + golang.org/x/crypto v0.49.0 // indirect + golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 // indirect + golang.org/x/mod v0.34.0 // indirect + golang.org/x/net v0.52.0 // indirect + golang.org/x/oauth2 v0.36.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/term v0.41.0 // indirect + golang.org/x/text v0.35.0 // indirect + golang.org/x/time v0.15.0 // indirect + golang.org/x/tools v0.43.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260316180232-0b37fe3546d5 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index f2623ca2..b4a93070 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,29 @@ +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1 h1:PMmTMyvHScV9Mn8wc6ASge9uRcHy0jtqPd+fM35LmsQ= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM= +buf.build/go/protovalidate v1.1.3 h1:m2GVEgQWd7rk+vIoAZ+f0ygGjvQTuqPQapBBdcpWVPE= +buf.build/go/protovalidate v1.1.3/go.mod h1:9XIuohWz+kj+9JVn3WQneHA5LZP50mjvneZMnbLkiIE= +buf.build/go/protoyaml v0.6.0 h1:Nzz1lvcXF8YgNZXk+voPPwdU8FjDPTUV4ndNTXN0n2w= +buf.build/go/protoyaml v0.6.0/go.mod h1:RgUOsBu/GYKLDSIRgQXniXbNgFlGEZnQpRAUdLAFV2Q= +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/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.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= github.com/Masterminds/semver/v3 v3.4.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/ajeddeloh/go-json v0.0.0-20160803184958-73d058cf8437/go.mod h1:otnto4/Icqn88WCcM4bhIJNSgsh9VLBuspyyCfvof9c= +github.com/ajeddeloh/go-json v0.0.0-20200220154158-5ae607161559 h1:4SPQljF/GJ8Q+QlCWMWxRBepub4DresnOm4eI2ebFGc= +github.com/ajeddeloh/go-json v0.0.0-20200220154158-5ae607161559/go.mod h1:otnto4/Icqn88WCcM4bhIJNSgsh9VLBuspyyCfvof9c= +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/aws/aws-sdk-go v1.8.39/go.mod h1:ZRmQr0FajVIyZ4ZzBYKG5P3ZqPz9IHG41ZoMu1ADI3k= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4= +github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/clipperhouse/displaywidth v0.6.2 h1:ZDpTkFfpHOKte4RG5O/BOyf3ysnvFswpyYrV7z2uAKo= @@ -10,9 +32,14 @@ github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfa github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4= github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= +github.com/coreos/go-semver v0.1.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= +github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= +github.com/coreos/go-systemd v0.0.0-20181031085051-9002847aa142/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= +github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 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= @@ -25,28 +52,27 @@ 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.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/flatcar/ignition v0.36.2 h1:xGHgScUe0P4Fkprjqv7L2CE58emiQgP833OCCn9z2v4= +github.com/flatcar/ignition v0.36.2/go.mod h1:uk1tpzLFRXus4RrvzgMI+IqmmB8a/RGFSBlI+tMTbbA= +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.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/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 v0.24.2 h1:6p7WXEuKy1llDgOH8FooVeO+Uq2za9qoAOq4ZN08B50= -github.com/go-openapi/analysis v0.24.2/go.mod h1:x27OOHKANE0lutg2ml4kzYLoHGMKgRm1Cj2ijVOjJuE= github.com/go-openapi/errors v0.22.7 h1:JLFBGC0Apwdzw3484MmBqspjPbwa2SHvpDm0u5aGhUA= github.com/go-openapi/errors v0.22.7/go.mod h1://QW6SD9OsWtH6gHllUCddOXDL0tk0ZGNYHwsw4sW3w= github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA= github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0= github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE= github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw= -github.com/go-openapi/loads v0.23.2 h1:rJXAcP7g1+lWyBHC7iTY+WAF0rprtM+pm8Jxv1uQJp4= -github.com/go-openapi/loads v0.23.2/go.mod h1:IEVw1GfRt/P2Pplkelxzj9BYFajiWOtY2nHZNj4UnWY= -github.com/go-openapi/spec v0.22.4 h1:4pxGjipMKu0FzFiu/DPwN3CTBRlVM2yLf/YTWorYfDQ= -github.com/go-openapi/spec v0.22.4/go.mod h1:WQ6Ai0VPWMZgMT4XySjlRIE6GP1bGQOtEThn3gcWLtQ= -github.com/go-openapi/strfmt v0.25.0 h1:7R0RX7mbKLa9EYCTHRcCuIPcaqlyQiWNPTXwClK0saQ= -github.com/go-openapi/strfmt v0.25.0/go.mod h1:nNXct7OzbwrMY9+5tLX4I21pzcmE6ccMGXl3jFdPfn8= +github.com/go-openapi/strfmt v0.26.1 h1:7zGCHji7zSYDC2tCXIusoxYQz/48jAf2q+sF6wXTG+c= +github.com/go-openapi/strfmt v0.26.1/go.mod h1:Zslk5VZPOISLwmWTMBIS7oiVFem1o1EI6zULY8Uer7Y= github.com/go-openapi/swag v0.25.5 h1:pNkwbUEeGwMtcgxDr+2GBPAk4kT+kJ+AaB+TMKAg+TU= github.com/go-openapi/swag v0.25.5/go.mod h1:B3RT6l8q7X803JRxa2e59tHOiZlX1t8viplOcs9CwTA= github.com/go-openapi/swag/cmdutils v0.25.5 h1:yh5hHrpgsw4NwM9KAEtaDTXILYzdXh/I8Whhx9hKj7c= @@ -73,22 +99,23 @@ github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzz github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc= github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ= github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ= -github.com/go-openapi/testify/enable/yaml/v2 v2.4.0 h1:7SgOMTvJkM8yWrQlU8Jm18VeDPuAvB/xWrdxFJkoFag= -github.com/go-openapi/testify/enable/yaml/v2 v2.4.0/go.mod h1:14iV8jyyQlinc9StD7w1xVPW3CO3q1Gj04Jy//Kw4VM= -github.com/go-openapi/testify/v2 v2.4.0 h1:8nsPrHVCWkQ4p8h1EsRVymA2XABB4OT40gcvAu+voFM= -github.com/go-openapi/testify/v2 v2.4.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= -github.com/go-openapi/validate v0.25.1 h1:sSACUI6Jcnbo5IWqbYHgjibrhhmt3vR6lCzKZnmAgBw= -github.com/go-openapi/validate v0.25.1/go.mod h1:RMVyVFYte0gbSTaZ0N4KmTn6u/kClvAFp+mAVfS/DQc= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.1 h1:NZOrZmIb6PTv5LTFxr5/mKV/FjbUzGE7E6gLz7vFoOQ= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.1/go.mod h1:r7dwsujEHawapMsxA69i+XMGZrQ5tRauhLAjV/sxg3Q= +github.com/go-openapi/testify/v2 v2.4.1 h1:zB34HDKj4tHwyUQHrUkpV0Q0iXQ6dUCOQtIqn8hE6Iw= +github.com/go-openapi/testify/v2 v2.4.1/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/godbus/dbus v0.0.0-20181025153459-66d97aec3384/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/cel-go v0.27.0 h1:e7ih85+4qVrBuqQWTW4FKSqZYokVuc3HnhH5keboFTo= +github.com/google/cel-go v0.27.0/go.mod h1:tTJ11FWqnhw5KKpnWpvW9CJC3Y9GK4EIS0WXnBbebzw= 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= @@ -102,10 +129,15 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= 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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= +github.com/huandu/xstrings v1.5.0/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/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 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/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -126,20 +158,22 @@ github.com/mdlayher/netlink v1.9.0 h1:G8+GLq2x3v4D4MVIqDdNUhTUC7TKiCy/6MDkmItfKc github.com/mdlayher/netlink v1.9.0/go.mod h1:YBnl5BXsCoRuwBjKKlZ+aYmEoq0r12FDA/3JC+94KDg= github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= +github.com/metal-stack/api v0.0.55-0.20260316085710-1f98c8226b9e h1:ixdWJR5ltPm4e4FMU+f1QgopdnN/GnFXvpDhNnXjsDg= +github.com/metal-stack/api v0.0.55-0.20260316085710-1f98c8226b9e/go.mod h1:OU8KDSOw5JEfeEs9q8FY5TcaklBAiGx+Q9Em0BMZrlY= github.com/metal-stack/firewall-controller-manager v0.6.0 h1:+/VV/VXJa4NRFBRHBw5NxkT2Ap1vXjkFdfBRO5t4MfA= github.com/metal-stack/firewall-controller-manager v0.6.0/go.mod h1:bQjb3pVL3R6XPUqWA/WX8ktlzcgVYWDbsFANKcrW3FA= -github.com/metal-stack/metal-go v0.43.0 h1:uODD0YCwnAYzyvFxWNakZrymBoMz1FAvP5hkhsR83VQ= -github.com/metal-stack/metal-go v0.43.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/metal-lib v0.24.0 h1:wvQQPWIXcA2tP+I6zAHUNdtVLLJfQnnV9yG2SoqUkz4= github.com/metal-stack/metal-lib v0.24.0/go.mod h1:oITaqj/BtB9vDKM66jCXkeA+4D0eTZElgIKal5vtiNY= -github.com/metal-stack/metal-networker v0.46.3 h1:0suUDm6trfwMElZsf9cuewJmrYmsBSpxlVYcOAGWsPk= -github.com/metal-stack/metal-networker v0.46.3/go.mod h1:FFER+4gOERGz3eTCoWqyfQ5eXwHNlYC00j5hdEJhqDU= +github.com/metal-stack/os-installer v0.2.1-0.20260319072654-2f5a75d683f8 h1:CoCGULUCPzd2e0rGKQCXDnZVA1jNASFOOijKgyL4/P8= +github.com/metal-stack/os-installer v0.2.1-0.20260319072654-2f5a75d683f8/go.mod h1:D149fycdjmpTQ8SQWUDvSUjO91FE+hb7TgBDMWt6RYY= 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.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= +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= @@ -149,7 +183,8 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWu github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s= +github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc= github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0= github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM= @@ -162,8 +197,10 @@ 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/uuid v0.0.0-20170612153648-e790cca94e6c/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pin/tftp v2.1.0+incompatible/go.mod h1:xVpZOMCXTy+A5QMjEVN0Glwa1sUvaJhFXbr/aAxuxGY= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -177,10 +214,20 @@ github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTU github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= +github.com/rodaine/protogofakeit v0.1.1 h1:ZKouljuRM3A+TArppfBqnH8tGZHOwM/pjvtXe9DaXH8= +github.com/rodaine/protogofakeit v0.1.1/go.mod h1:pXn/AstBYMaSfc1/RqH3N82pBuxtWgejz1AlYpY1mI0= 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/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.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/sigma/bdoor v0.0.0-20160202064022-babf2a4017b0/go.mod h1:WBu7REWbxC/s/J06jsk//d+9DOz9BbsmcIrimuGRFbs= +github.com/sigma/vmw-guestinfo v0.0.0-20160204083807-95dd4126d6e8/go.mod h1:JrRFFC0veyh0cibh0DAhriSY7/gV3kDdNaVUOmfx01U= +github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= 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= @@ -197,55 +244,77 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/txn2/txeh v1.8.0 h1:G1vZgom6+P/xWwU53AMOpcZgC5ni382ukcPP1TDVYHk= github.com/txn2/txeh v1.8.0/go.mod h1:rRI3Egi3+AFmEXQjft051YdYbxeCT3nFmBLsNCZZaxM= +github.com/vincent-petithory/dataurl v1.0.0 h1:cXw+kPto8NLuJtlMsI152irrVw9fRDX8AbShPRpg2CI= +github.com/vincent-petithory/dataurl v1.0.0/go.mod h1:FHafX5vmDzyP+1CQATJn7WFKc9CvnvxyvZy6I1MrG/U= github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0= github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4= github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/vmware/vmw-guestinfo v0.0.0-20170707015358-25eff159a728/go.mod h1:x9oS4Wk2s2u4tS29nEaDLdzvuHdB19CvSGJjPgkZJNk= +github.com/vmware/vmw-ovflib v0.0.0-20170608004843-1f217b9dc714/go.mod h1:jiPk45kn7klhByRvUq5i2vo1RtHKBHj+iWGFpxbXuuI= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -go.mongodb.org/mongo-driver v1.17.9 h1:IexDdCuuNJ3BHrELgBlyaH9p60JXAvdzWR128q+U5tU= -go.mongodb.org/mongo-driver v1.17.9/go.mod h1:LlOhpH5NUEfhxcAwG0UEkMqwYcc4JU18gtCdGudk/tQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= -go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +go4.org v0.0.0-20160314031811-03efcb870d84/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +go4.org v0.0.0-20260112195520-a5071408f32f h1:ziUVAjmTPwQMBmYR1tbdRFJPtTcQUI12fH9QQjfb0Sw= +go4.org v0.0.0-20260112195520-a5071408f32f/go.mod h1:ZRJnO5ZI4zAwMFp+dS1+V6J6MSyAowhRqAE+DPa1Xp0= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= -golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= -golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= -golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= -golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA= +golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ= +golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= +golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= -golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= -golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= -golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= -golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= +golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= +golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= 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-20260316180232-0b37fe3546d5 h1:CogIeEXn4qWYzzQU0QqvYBM8yDF9cFYzDq9ojSpv0Js= +google.golang.org/genproto/googleapis/api v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:EIQZ5bFCfRQDV4MhRle7+OgjNtZ6P1PiZBgAKuxXu/Y= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 h1:aJmi6DVGGIStN9Mobk/tZOOQUBbj0BPjZjjnOdoZKts= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -255,6 +324,8 @@ gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnf gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= k8s.io/api v0.35.0 h1:iBAU5LTyBI9vw3L5glmat1njFK34srdLmktWwLTprlY= diff --git a/main.go b/main.go index 6f359da8..3d8f35af 100644 --- a/main.go +++ b/main.go @@ -2,12 +2,15 @@ package main import ( "context" + "errors" "flag" "fmt" "log/slog" "os" "time" + 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 +35,10 @@ 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" + + installerv1 "github.com/metal-stack/os-installer/api/v1" + "github.com/metal-stack/os-installer/pkg/installer" + osnet "github.com/metal-stack/os-installer/pkg/network" // +kubebuilder:scaffold:imports ) @@ -233,21 +240,38 @@ func main() { } l.Info("detected frr", "version", frrVersion.String()) + allocation, err := getMachineAllocation() + if err != nil { + l.Error("reading machine allocation", "error", err) + panic(err) + } + 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 +289,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) @@ -365,3 +391,165 @@ func getSeedNamespace(rawKubeconfig []byte) (string, error) { return "", fmt.Errorf("unable to figure out seed namespace from kubeconfig") } + +func getMachineAllocation() (*apiv2.MachineAllocation, error) { + // TODO: check what we can take from the Firewall Object + _, err := os.Stat(installerv1.MachineAllocationPath) + if errors.Is(err, os.ErrNotExist) { + _, err = os.Stat(installerv1.LegacyInstallPath) + if errors.Is(err, os.ErrNotExist) { + return nil, fmt.Errorf("neither %s nor %s exists, exiting", installerv1.MachineAllocationPath, installerv1.LegacyInstallPath) + } + // /etc/metal/install.yaml exists but /etc/metal/machine-allocation does not + legacyInstallConfig, err := installer.ReadLegacyInstallYaml() + if err != nil { + return nil, err + } + + return convertLegacyInstallConfig(legacyInstallConfig) + } + + _, allocation, err := installer.ReadConfigurations() + if err != nil { + return nil, err + } + + return allocation, nil +} + +func convertLegacyInstallConfig(config *installerv1.InstallerConfig) (*apiv2.MachineAllocation, error) { + var vpn *apiv2.MachineVPN + if config.VPN != nil { + vpn = &apiv2.MachineVPN{ + ControlPlaneAddress: pointer.SafeDeref(config.VPN.Address), + AuthKey: pointer.SafeDeref(config.VPN.AuthKey), + Connected: pointer.SafeDeref(config.VPN.Connected), + } + } + + allocationType := apiv2.MachineAllocationType_MACHINE_ALLOCATION_TYPE_MACHINE + if config.Role == "firewall" { + allocationType = apiv2.MachineAllocationType_MACHINE_ALLOCATION_TYPE_FIREWALL + } + + var dnsservers []*apiv2.DNSServer + for _, dns := range config.DNSServers { + dnsservers = append(dnsservers, &apiv2.DNSServer{ + Ip: pointer.SafeDeref(dns.IP), + }) + } + var ntpservers []*apiv2.NTPServer + for _, ntp := range config.NTPServers { + ntpservers = append(ntpservers, &apiv2.NTPServer{ + Address: pointer.SafeDeref(ntp.Address), + }) + } + + var firewallRules *apiv2.FirewallRules + if config.FirewallRules != nil { + var egressrules []*apiv2.FirewallEgressRule + + for _, egress := range config.FirewallRules.Egress { + var proto apiv2.IPProtocol + if egress.Protocol == "tcp" { + proto = apiv2.IPProtocol_IP_PROTOCOL_TCP + } + if egress.Protocol == "udp" { + proto = apiv2.IPProtocol_IP_PROTOCOL_UDP + } + var ports []uint32 + for _, port := range egress.Ports { + ports = append(ports, uint32(port)) + } + + egressrules = append(egressrules, &apiv2.FirewallEgressRule{ + Comment: egress.Comment, + Protocol: proto, + Ports: ports, + To: egress.To, + }) + } + + var ingressrules []*apiv2.FirewallIngressRule + for _, ingress := range config.FirewallRules.Ingress { + var proto apiv2.IPProtocol + if ingress.Protocol == "tcp" { + proto = apiv2.IPProtocol_IP_PROTOCOL_TCP + } + if ingress.Protocol == "udp" { + proto = apiv2.IPProtocol_IP_PROTOCOL_UDP + } + var ports []uint32 + for _, port := range ingress.Ports { + ports = append(ports, uint32(port)) + } + + ingressrules = append(ingressrules, &apiv2.FirewallIngressRule{ + Comment: ingress.Comment, + Protocol: proto, + Ports: ports, + To: ingress.To, + From: ingress.From, + }) + } + + firewallRules = &apiv2.FirewallRules{ + Egress: egressrules, + Ingress: ingressrules, + } + } + + var networks []*apiv2.MachineNetwork + for _, nw := range config.Networks { + + natType := apiv2.NATType_NAT_TYPE_NONE + if nw.Nat != nil && *nw.Nat { + natType = apiv2.NATType_NAT_TYPE_IPV4_MASQUERADE + } + + var networkType apiv2.NetworkType + switch pointer.SafeDeref(nw.Networktypev2) { + case "external": + networkType = apiv2.NetworkType_NETWORK_TYPE_EXTERNAL + case "underlay": + networkType = apiv2.NetworkType_NETWORK_TYPE_UNDERLAY + case "super": + networkType = apiv2.NetworkType_NETWORK_TYPE_SUPER + case "super-namespaced": + networkType = apiv2.NetworkType_NETWORK_TYPE_SUPER_NAMESPACED + case "child": + networkType = apiv2.NetworkType_NETWORK_TYPE_CHILD + case "child-shared": + networkType = apiv2.NetworkType_NETWORK_TYPE_CHILD_SHARED + } + + 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)), + // FIXME This is most probably empty as well, but can be taken from + // firewall.Status.FirewallNetworks.Project which must be added there + Project: nw.Projectid, + NatType: natType, + NetworkType: networkType, + }) + } + + machineAllocation := &apiv2.MachineAllocation{ + // FIXME Project of the machine is not stored in old install.yaml + // Maybe we take it from firewallv2.Firewall.Spec.Project ? + // Project: config.Projectid, + Hostname: config.Hostname, + AllocationType: allocationType, + FirewallRules: firewallRules, + Networks: networks, + DnsServers: dnsservers, + NtpServers: ntpservers, + Vpn: vpn, + } + + return machineAllocation, nil +} diff --git a/pkg/dns/dnsproxy.go b/pkg/dns/dnsproxy.go index b9a16212..ea57490d 100644 --- a/pkg/dns/dnsproxy.go +++ b/pkg/dns/dnsproxy.go @@ -7,70 +7,75 @@ import ( "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 ( defaultDNSPort uint = 53 ) -type DNSHandler interface { - ServeDNS(w dnsgo.ResponseWriter, r *dnsgo.Msg) - UpdateDNSServerAddr(addr string) error -} +type ( + DNSHandler interface { + ServeDNS(w dnsgo.ResponseWriter, r *dnsgo.Msg) + UpdateDNSServerAddr(addr string) error + } -type DNSProxy struct { - log logr.Logger - ctx context.Context - cancelFunc context.CancelFunc - cache *DNSCache + DNSProxy struct { + log logr.Logger + ctx context.Context + cancelFunc context.CancelFunc + cache *DNSCache - udpServer *dnsgo.Server - tcpServer *dnsgo.Server + udpServer *dnsgo.Server + tcpServer *dnsgo.Server - handler DNSHandler -} + handler DNSHandler -func NewDNSProxy(ctx context.Context, dns string, port *uint, shootClient client.Client, log logr.Logger) (*DNSProxy, error) { - if dns == "" { - dns = defaultDNSServerAddr + bindAddress string } - host, err := getHost() - if err != nil { - return nil, err + DNSProxyConfig struct { + DNSServer string + Port *uint + ShootClient client.Client + Log logr.Logger + // BindAddress is the first ip of the defaultRouteNetwork + BindAddress string + } +) + +func NewDNSProxy(ctx context.Context, cfg *DNSProxyConfig) (*DNSProxy, error) { + if cfg.DNSServer == "" { + cfg.DNSServer = defaultDNSServerAddr } p := defaultDNSPort - if port != nil { - p = *port + if cfg.Port != nil { + p = *cfg.Port } - udpConn, tcpListener, err := bindToPort(host, int(p), 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) } backgroundCtx, cancel := context.WithCancel(ctx) - cache, err := newDNSCache(backgroundCtx, dns, true, false, shootClient, log.WithName("DNS cache")) + cache, err := newDNSCache(backgroundCtx, cfg.DNSServer, true, false, cfg.ShootClient, cfg.Log.WithName("DNS cache")) if err != nil { cancel() return nil, err } - handler := NewDNSProxyHandler(log, cache) + handler := NewDNSProxyHandler(cfg.Log, cache) udpServer := &dnsgo.Server{PacketConn: udpConn, Addr: udpConn.LocalAddr().String(), Net: "udp", Handler: handler} tcpServer := &dnsgo.Server{Listener: tcpListener, Addr: udpConn.LocalAddr().String(), Net: "tcp", Handler: handler} return &DNSProxy{ - log: log, + log: cfg.Log, ctx: backgroundCtx, cancelFunc: cancel, cache: cache, @@ -79,6 +84,8 @@ func NewDNSProxy(ctx context.Context, dns string, port *uint, shootClient client tcpServer: tcpServer, handler: handler, + + bindAddress: cfg.BindAddress, }, nil } @@ -136,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(network.GetLogger(), 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 c2306371..83ecad78 100644 --- a/pkg/network/network.go +++ b/pkg/network/network.go @@ -1,37 +1,32 @@ package network import ( + "context" "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" ) -const ( - MetalNetworkerConfig = "/etc/metal/install.yaml" - frrConfig = "/etc/frr/frr.conf" -) - -var logger *slog.Logger - -func init() { - jsonHandler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{}) - l := slog.New(jsonHandler) - - logger = l.WithGroup("networker") +type network struct { + log logr.Logger + allocation *apiv2.MachineAllocation } -func GetLogger() *slog.Logger { - return logger +func NewNetwork(log logr.Logger, allocation *apiv2.MachineAllocation) *network { + return &network{ + log: log, + allocation: allocation, + } } // GetNewNetworks returns updated network models -func GetNewNetworks(f *firewallv2.Firewall, oldNetworks []*models.V1MachineNetwork) []*models.V1MachineNetwork { +func GetNewNetworks(f *firewallv2.Firewall, oldNetworks []*apiv2.MachineNetwork) []*apiv2.MachineNetwork { networkMap := map[string]firewallv2.FirewallNetwork{} for _, n := range f.Status.FirewallNetworks { if n.NetworkType == nil { @@ -40,14 +35,14 @@ func GetNewNetworks(f *firewallv2.Firewall, oldNetworks []*models.V1MachineNetwo 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 + newNet.Prefixes = networkMap[n.Network].Prefixes newNetworks = append(newNetworks, newNet) } @@ -56,42 +51,19 @@ func GetNewNetworks(f *firewallv2.Firewall, oldNetworks []*models.V1MachineNetwo // 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(f *firewallv2.Firewall, frrVersion *semver.Version) (changed bool, err error) { - tmpFile, err := tmpFile(frrConfig) +func (n *network) ReconcileNetwork(f *firewallv2.Firewall, frrVersion *semver.Version) (bool, error) { + n.allocation.Networks = GetNewNetworks(f, n.allocation.Networks) + + changed, err := frr.Render(context.Background(), &frr.Config{ + Log: slog.New(logr.ToSlogHandler(n.log)), + Reload: true, + Validate: true, + Network: osnet.New(n.allocation), + FRRVersion: frrVersion, + }) if err != nil { - return false, fmt.Errorf("error during network reconciliation %v: %w", tmpFile, err) - } - defer func() { - _ = os.Remove(tmpFile) - }() - - c, err := netconf.New(GetLogger(), MetalNetworkerConfig) - if err != nil || c == nil { - return false, fmt.Errorf("failed to init networker config: %w", err) - } - c.Networks = GetNewNetworks(f, c.Networks) - - a := netconf.NewFrrConfigApplier(netconf.Firewall, *c, tmpFile, frrVersion) - tpl := netconf.MustParseTpl(netconf.TplFirewallFRR) - - changed, err = a.Apply(*tpl, tmpFile, frrConfig, true) - 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 9dbdab84..433351e5 100644 --- a/pkg/nftables/firewall.go +++ b/pkg/nftables/firewall.go @@ -1,14 +1,17 @@ package nftables import ( + "context" "embed" "errors" "fmt" + "log/slog" "net/netip" "os" "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" @@ -20,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" @@ -40,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 @@ -56,6 +60,7 @@ type Firewall struct { primaryPrivateNet *firewallv2.FirewallNetwork networkMap networkMap cache FQDNCache + allocation *apiv2.MachineAllocation enableDNS bool dryRun bool @@ -79,6 +84,7 @@ func NewFirewall( cache FQDNCache, log logr.Logger, recorder record.EventRecorder, + allocation *apiv2.MachineAllocation, ) *Firewall { networkMap := networkMap{} var primaryPrivateNet *firewallv2.FirewallNetwork @@ -104,6 +110,7 @@ func NewFirewall( enableDNS: len(cwnps.GetFQDNs()) > 0, log: log, recorder: recorder, + allocation: allocation, } } @@ -173,32 +180,29 @@ func (f *Firewall) Reconcile() (updated bool, err error) { } func (f *Firewall) ReconcileNetconfTables() error { - c, err := netconf.New(network.GetLogger(), network.MetalNetworkerConfig) - if err != nil || c == nil { - return fmt.Errorf("failed to init networker config: %w", err) - } - - c.Networks = network.GetNewNetworks(f.firewall, c.Networks) - - configurator, err := netconf.NewConfigurator(netconf.Firewall, *c, f.enableDNS) + f.allocation.Networks = network.GetNewNetworks(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(network.GetLogger(), 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 { - continue - } + for _, nw := range osnet.New(f.allocation).AllocationNetworks() { ips = append(ips, nw.Ips...) } return ips @@ -245,7 +249,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 { diff --git a/pkg/nftables/mocks/pkg/nftables/FQDNCache.go b/pkg/nftables/mocks/pkg/nftables/FQDNCache.go index 2c219fe6..1369fa8c 100644 --- a/pkg/nftables/mocks/pkg/nftables/FQDNCache.go +++ b/pkg/nftables/mocks/pkg/nftables/FQDNCache.go @@ -38,7 +38,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 { @@ -46,21 +46,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' @@ -80,12 +71,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 85b56812..8ddfd987 100644 --- a/pkg/nftables/networkpolicy.go +++ b/pkg/nftables/networkpolicy.go @@ -61,10 +61,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 fe4bcea6..4c06f22c 100644 --- a/pkg/nftables/networkpolicy_test.go +++ b/pkg/nftables/networkpolicy_test.go @@ -12,11 +12,6 @@ import ( mocks "github.com/metal-stack/firewall-controller/v2/pkg/nftables/mocks/pkg/nftables" ) -func port(p int) *intstr.IntOrString { - intstr := intstr.FromInt(p) - return &intstr -} - func TestClusterwideNetworkPolicyRules(t *testing.T) { tcp := corev1.ProtocolTCP udp := corev1.ProtocolUDP @@ -51,15 +46,15 @@ func TestClusterwideNetworkPolicyRules(t *testing.T) { Ports: []networking.NetworkPolicyPort{ { Protocol: &tcp, - Port: port(53), + Port: new(intstr.FromInt(53)), }, { Protocol: &udp, - Port: port(53), + Port: new(intstr.FromInt(53)), }, { Protocol: &tcp, - Port: port(443), + Port: new(intstr.FromInt(443)), EndPort: new(int32(448)), }, }, @@ -76,11 +71,11 @@ func TestClusterwideNetworkPolicyRules(t *testing.T) { Ports: []networking.NetworkPolicyPort{ { Protocol: &tcp, - Port: port(80), + Port: new(intstr.FromInt(80)), }, { Protocol: &tcp, - Port: port(443), + Port: new(intstr.FromInt(443)), EndPort: new(int32(448)), }, }, @@ -160,11 +155,11 @@ func TestClusterwideNetworkPolicyEgressRules(t *testing.T) { Ports: []networking.NetworkPolicyPort{ { Protocol: &tcp, - Port: port(53), + Port: new(intstr.FromInt(53)), }, { Protocol: &udp, - Port: port(53), + Port: new(intstr.FromInt(53)), }, }, }, @@ -200,11 +195,11 @@ func TestClusterwideNetworkPolicyEgressRules(t *testing.T) { Ports: []networking.NetworkPolicyPort{ { Protocol: &tcp, - Port: port(53), + Port: new(intstr.FromInt(53)), }, { Protocol: &udp, - Port: port(53), + Port: new(intstr.FromInt(53)), }, }, }, 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/service_test.go b/pkg/nftables/service_test.go index a6c7b6c6..7f2b6ae1 100644 --- a/pkg/nftables/service_test.go +++ b/pkg/nftables/service_test.go @@ -8,6 +8,7 @@ import ( "go4.org/netipx" corev1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" ) func helpMustParseIPSet(ips []string) *netipx.IPSet { @@ -39,7 +40,7 @@ func TestServiceRules(t *testing.T) { Ports: []corev1.ServicePort{ { Port: 443, - TargetPort: *port(30443), + TargetPort: intstr.FromInt(30443), Protocol: corev1.ProtocolTCP, }, }, @@ -72,7 +73,7 @@ func TestServiceRules(t *testing.T) { Ports: []corev1.ServicePort{ { Port: 443, - TargetPort: *port(30443), + TargetPort: intstr.FromInt(30443), Protocol: corev1.ProtocolTCP, }, }, @@ -88,7 +89,7 @@ func TestServiceRules(t *testing.T) { Ports: []corev1.ServicePort{ { Port: 443, - TargetPort: *port(30443), + TargetPort: intstr.FromInt(30443), Protocol: corev1.ProtocolTCP, }, }, @@ -109,7 +110,7 @@ func TestServiceRules(t *testing.T) { Ports: []corev1.ServicePort{ { Port: 443, - TargetPort: *port(30443), + TargetPort: intstr.FromInt(30443), Protocol: corev1.ProtocolTCP, }, }, @@ -147,7 +148,7 @@ func TestServiceRules(t *testing.T) { Ports: []corev1.ServicePort{ { Port: 443, - TargetPort: *port(30443), + TargetPort: intstr.FromInt(30443), Protocol: corev1.ProtocolTCP, }, }, @@ -185,7 +186,7 @@ func TestServiceRules(t *testing.T) { Ports: []corev1.ServicePort{ { Port: 443, - TargetPort: *port(30443), + TargetPort: intstr.FromInt(30443), Protocol: corev1.ProtocolTCP, }, }, diff --git a/pkg/nftables/snat_test.go b/pkg/nftables/snat_test.go index f7837fb4..aed193e8 100644 --- a/pkg/nftables/snat_test.go +++ b/pkg/nftables/snat_test.go @@ -9,6 +9,7 @@ import ( mn "github.com/metal-stack/metal-lib/pkg/net" corev1 "k8s.io/api/core/v1" networking "k8s.io/api/networking/v1" + "k8s.io/apimachinery/pkg/util/intstr" firewallv2 "github.com/metal-stack/firewall-controller-manager/api/v2" firewallv1 "github.com/metal-stack/firewall-controller/v2/api/v1" @@ -135,11 +136,11 @@ func TestSnatRules(t *testing.T) { Ports: []networking.NetworkPolicyPort{ { Protocol: &tcp, - Port: port(53), + Port: new(intstr.FromInt(53)), }, { Protocol: &udp, - Port: port(53), + Port: new(intstr.FromInt(53)), }, }, }, @@ -197,7 +198,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)