internal/system/networking.go (85 lines of code) (raw):

package system import ( "bytes" _ "embed" "fmt" "os" "os/exec" "text/template" "go.uber.org/zap" "github.com/aws/eks-hybrid/internal/api" "github.com/aws/eks-hybrid/internal/util" ) const ( networkingAspectName = "networking" // The local administration network directory for systemd.network administrationNetworkDir = "/etc/systemd/network" // the name of ec2 network configuration setup by amazon-ec2-net-utils: // https://github.com/amazonlinux/amazon-ec2-net-utils/blob/c6626fb5cd094bbfeb62c456fe088011dbab3f95/systemd/network/80-ec2.network ec2NetworkConfigurationName = "80-ec2.network" eksPrimaryENIOnlyConfName = "10-eks_primary_eni_only.conf" networkConfDropInDirPerms = 0o755 networkConfFilePerms = 0o644 ) var ( //go:embed _assets/10-eks_primary_eni_only.conf.template eksPrimaryENIOnlyConfTemplateData string eksPrimaryENIOnlyConfTemplate = template.Must(template.New(eksPrimaryENIOnlyConfName).Parse(eksPrimaryENIOnlyConfTemplateData)) ) // NewNetworkingAspect constructs new networkingAspect. func NewNetworkingAspect(cfg *api.NodeConfig) *networkingAspect { return &networkingAspect{nodeConfig: cfg} } var _ SystemAspect = &networkingAspect{} // networkingAspect setups eks-specific networking configurations. type networkingAspect struct { nodeConfig *api.NodeConfig } // Name returns the name of this aspect. func (a *networkingAspect) Name() string { return networkingAspectName } // Setup executes the logic of this aspect. func (a *networkingAspect) Setup() error { if err := a.ensureEKSNetworkConfiguration(); err != nil { return fmt.Errorf("failed to ensure eks network configuration: %w", err) } return nil } // ensureEKSNetworkConfiguration will install eks specific network configuration into system. // NOTE: this is a temporary fix for AL2023, where the `80-ec2.network` setup by amazon-ec2-net-utils will cause systemd.network // to manage all ENIs on host, and that can potentially result in multiple issues including: // 1. systemd.network races against vpc-cni to configure secondary enis and might cause routing rules/routes setup by vpc-cni to be flushed resulting in issues with pod networking. // 2. routes for those secondary ENIs obtained from dhcp will appear in main route table, which is a drift from our AL2 behavior. // // To address this issue temporarily, we use drop-ins to alter configuration of `80-ec2.network` after boot to make it match against primary ENI only. // TODO: there are limitations on current solutions as well, and we should figure long term solution for this: // 1. the altNames for ENIs(a new feature in AL2023) were setup by amazon-ec2-net-utils via udev rules, but it's disabled by eks. func (a *networkingAspect) ensureEKSNetworkConfiguration() error { networkCfgDropInDir := fmt.Sprintf("%s/%s.d", administrationNetworkDir, ec2NetworkConfigurationName) eksPrimaryENIOnlyConfPathName := fmt.Sprintf("%s/%s", networkCfgDropInDir, eksPrimaryENIOnlyConfName) if exists, err := util.IsFilePathExists(eksPrimaryENIOnlyConfPathName); err != nil { return fmt.Errorf("failed to check eks_primary_eni_only network configuration existance: %w", err) } else if exists { zap.L().Info("eks_primary_eni_only network configuration already exists, skipping configuration") return nil } eksPrimaryENIOnlyConfContent, err := a.generateEKSPrimaryENIOnlyConfiguration() if err != nil { return fmt.Errorf("failed to generate eks_primary_eni_only network configuration: %w", err) } zap.L().Info("writing eks_primary_eni_only network configuration") if err := os.MkdirAll(networkCfgDropInDir, networkConfDropInDirPerms); err != nil { return fmt.Errorf("failed to create network configuration drop-in directory %s: %w", networkCfgDropInDir, err) } if err := os.WriteFile(eksPrimaryENIOnlyConfPathName, eksPrimaryENIOnlyConfContent, networkConfFilePerms); err != nil { return fmt.Errorf("failed to write eks_primary_eni_only network configuration: %w", err) } if err := a.reloadNetworkConfigurations(); err != nil { return fmt.Errorf("failed to reload network configurations: %w", err) } return nil } // eksPrimaryENIOnlyTemplateVars holds the variables for eksPrimaryENIOnlyConfTemplate type eksPrimaryENIOnlyTemplateVars struct { PermanentMACAddress string } // generateEKSPrimaryENIOnlyConfiguration generates the eks primary eni only network configuration. func (a *networkingAspect) generateEKSPrimaryENIOnlyConfiguration() ([]byte, error) { primaryENIMac := a.nodeConfig.Status.Instance.MAC templateVars := eksPrimaryENIOnlyTemplateVars{ PermanentMACAddress: primaryENIMac, } var buf bytes.Buffer if err := eksPrimaryENIOnlyConfTemplate.Execute(&buf, templateVars); err != nil { return nil, err } return buf.Bytes(), nil } func (a *networkingAspect) reloadNetworkConfigurations() error { cmd := exec.Command("networkctl", "reload") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr return cmd.Run() }