From 01f88493a06c7c36bc2d0336111efabbb548f343 Mon Sep 17 00:00:00 2001 From: Stephen Benjamin Date: Fri, 7 Feb 2020 12:55:36 -0500 Subject: [PATCH] baremetal: only respond to dhcp for control plane mac's The bootstrap can now co-exist with machine-api being online. That means there could be an instance of Ironic, dnsmasq, etc running in both the cluster and the bootstrap. This causes problems, as it's not deterministic which dnsmasq instance the worker provisioned by the machine-api will use. If it uses the bootstrap, then the worker will not come online. This is causing a percentage of baremetal installs to fail, with the worker being offline, ingress and other operators never come up. This change blocks dhcp requests from anything but control plane hosts, using iptables. DHCPv6 relies on DUID's instead which makes things more complicated to use dnsmasq's dhcp-host abilities, which prefers DUIDS for IPv6. --- .../usr/local/bin/startironic.sh.template | 17 ++++++++++++++++ .../ignition/bootstrap/baremetal/template.go | 13 ++++++++++++ .../bootstrap/baremetal/template_test.go | 20 +++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/data/data/bootstrap/baremetal/files/usr/local/bin/startironic.sh.template b/data/data/bootstrap/baremetal/files/usr/local/bin/startironic.sh.template index 99523089848..be564056864 100755 --- a/data/data/bootstrap/baremetal/files/usr/local/bin/startironic.sh.template +++ b/data/data/bootstrap/baremetal/files/usr/local/bin/startironic.sh.template @@ -94,7 +94,24 @@ for port in 80 5050 6385 ; do fi done +# It is possible machine-api-operator comes up while the bootstrap is +# online, meaning there could be two DHCP servers on the network. To +# avoid bootstrap responding to a worker, which would cause a failed +# deployment, we filter out requests from anyone else than the control +# plane. We are using iptables instead of dnsmasq's dhcp-host because +# DHCPv6 wants to use DUID's instead of mac addresses. +{{if .PlatformData.BareMetal.ProvisioningDHCPAllowList}} +$IPTABLES -t raw -N DHCP +$IPTABLES -t raw -A PREROUTING -p udp --dport 67 -j DHCP +$IPTABLES -t raw -A PREROUTING -p udp --dport 546 -j DHCP + +for mac in {{.PlatformData.BareMetal.ProvisioningDHCPAllowList}} +do + $IPTABLES -t raw -A DHCP -m mac --mac-source "$mac" -j ACCEPT +done +$IPTABLES -t raw -A DHCP -j DROP +{{end}} # Wait for images to be downloaded/ready podman wait -i 1000 ipa-downloader diff --git a/pkg/asset/ignition/bootstrap/baremetal/template.go b/pkg/asset/ignition/bootstrap/baremetal/template.go index 526481e64f0..7a92de1f46f 100644 --- a/pkg/asset/ignition/bootstrap/baremetal/template.go +++ b/pkg/asset/ignition/bootstrap/baremetal/template.go @@ -2,6 +2,7 @@ package baremetal import ( "github.com/openshift/installer/pkg/types/baremetal" + "strings" ) // TemplateData holds data specific to templates used for the baremetal platform. @@ -18,6 +19,10 @@ type TemplateData struct { // ProvisioningDHCPRange has the DHCP range, if DHCP is not external. Otherwise it // should be blank. ProvisioningDHCPRange string + + // ProvisioningDHCPAllowList contains a space-separated list of all of the control plane's boot + // MAC addresses. Requests to bootstrap DHCP from other hosts will be ignored. + ProvisioningDHCPAllowList string } // GetTemplateData returns platform-specific data for bootstrap templates. @@ -33,6 +38,14 @@ func GetTemplateData(config *baremetal.Platform) *TemplateData { if !config.ProvisioningDHCPExternal { templateData.ProvisioningDHCPRange = config.ProvisioningDHCPRange + + var dhcpAllowList []string + for _, host := range config.Hosts { + if host.Role == "master" { + dhcpAllowList = append(dhcpAllowList, host.BootMACAddress) + } + } + templateData.ProvisioningDHCPAllowList = strings.Join(dhcpAllowList, " ") } return &templateData diff --git a/pkg/asset/ignition/bootstrap/baremetal/template_test.go b/pkg/asset/ignition/bootstrap/baremetal/template_test.go index 2e2d837dbb0..016dbb72ce7 100644 --- a/pkg/asset/ignition/bootstrap/baremetal/template_test.go +++ b/pkg/asset/ignition/bootstrap/baremetal/template_test.go @@ -13,6 +13,24 @@ func TestTemplatingIPv4(t *testing.T) { BootstrapProvisioningIP: "172.22.0.2", ProvisioningDHCPExternal: false, ProvisioningDHCPRange: "172.22.0.10,172.22.0.100", + Hosts: []*baremetal.Host{ + { + Role: "master", + BootMACAddress: "c0:ff:ee:ca:fe:00", + }, + { + Role: "master", + BootMACAddress: "c0:ff:ee:ca:fe:01", + }, + { + Role: "master", + BootMACAddress: "c0:ff:ee:ca:fe:02", + }, + { + Role: "worker", + BootMACAddress: "c0:ff:ee:ca:fe:03", + }, + }, } result := GetTemplateData(&bareMetalConfig) @@ -21,6 +39,7 @@ func TestTemplatingIPv4(t *testing.T) { assert.Equal(t, result.ProvisioningCIDR, 24) assert.Equal(t, result.ProvisioningIPv6, false) assert.Equal(t, result.ProvisioningIP, "172.22.0.2") + assert.Equal(t, result.ProvisioningDHCPAllowList, "c0:ff:ee:ca:fe:00 c0:ff:ee:ca:fe:01 c0:ff:ee:ca:fe:02") } func TestTemplatingIPv6(t *testing.T) { @@ -36,4 +55,5 @@ func TestTemplatingIPv6(t *testing.T) { assert.Equal(t, result.ProvisioningCIDR, 64) assert.Equal(t, result.ProvisioningIPv6, true) assert.Equal(t, result.ProvisioningIP, "fd2e:6f44:5dd8:b856::2") + assert.Equal(t, result.ProvisioningDHCPAllowList, "") }