From d6ed8afc5895206b63a75e6af4fbfbec9d53e626 Mon Sep 17 00:00:00 2001 From: Brad Davidson Date: Tue, 26 Nov 2024 21:33:06 +0000 Subject: [PATCH] Move AWS hostname support behind new flag For now, the new flag is automatically set when cloud-provider-name=aws, but this will be removed in the future following our normal deprecation timeline. This also adds IMDSv2 support, and support for setting the hostname on windows. Signed-off-by: Brad Davidson --- pkg/cli/cmds/root.go | 6 ++++ pkg/rke2/rke2.go | 55 +++++++++++++++++++++++++++++++++ pkg/rke2/rke2_linux.go | 67 ++++++++++++---------------------------- pkg/rke2/rke2_windows.go | 40 ++++++++++++++++++++++-- 4 files changed, 118 insertions(+), 50 deletions(-) diff --git a/pkg/cli/cmds/root.go b/pkg/cli/cmds/root.go index 69afc4a6c0b..a64e04c73a8 100644 --- a/pkg/cli/cmds/root.go +++ b/pkg/cli/cmds/root.go @@ -82,6 +82,12 @@ var ( EnvVar: "RKE2_CLOUD_PROVIDER_CONFIG", Destination: &config.CloudProviderConfig, }, + &cli.BoolFlag{ + Name: "node-name-from-cloud-provider-metadata", + Usage: "(cloud provider) Set node name from instance metadata service hostname", + EnvVar: "RKE2_NODE_NAME_FROM_CLOUD_PROVIDER_METADATA", + Destination: &config.CloudProviderMetadataHostname, + }, &cli.StringFlag{ Name: "profile", Usage: "(security) Validate system configuration against the selected benchmark (valid items: cis)", diff --git a/pkg/rke2/rke2.go b/pkg/rke2/rke2.go index d18820c5ab1..9782aa119bd 100644 --- a/pkg/rke2/rke2.go +++ b/pkg/rke2/rke2.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "io/ioutil" + "net/http" "os" "os/exec" "path/filepath" @@ -36,6 +37,7 @@ type Config struct { PodSecurityAdmissionConfigFile string CloudProviderConfig string CloudProviderName string + CloudProviderMetadataHostname bool Images images.ImageOverrideConfig KubeletPath string ControlPlaneResourceRequests cli.StringSlice @@ -406,3 +408,56 @@ func terminateRunningContainers(ctx context.Context, containerRuntimeEndpoint st return len(disabledItems) == 0, nil }) } + +func hostnameFromMetadataEndpoint(ctx context.Context) string { + var token string + + // Get token, required for IMDSv2 + tokenCtx, tokenCancel := context.WithTimeout(ctx, time.Second) + defer tokenCancel() + if req, err := http.NewRequestWithContext(tokenCtx, http.MethodPut, "http://169.254.169.254/latest/api/token", nil); err != nil { + logrus.Debugf("Failed to create request for token endpoint: %v", err) + } else { + req.Header.Add("x-aws-ec2-metadata-token-ttl-seconds", "60") + if resp, err := http.DefaultClient.Do(req); err != nil { + logrus.Debugf("Failed to get token from token endpoint: %v", err) + } else { + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + logrus.Debugf("Token endpoint returned unacceptable status code %d", resp.StatusCode) + } else { + if b, err := ioutil.ReadAll(resp.Body); err != nil { + logrus.Debugf("Failed to read response body from token endpoint: %v", err) + } else { + token = string(b) + } + } + } + } + + // Get hostname frim IMDS, with token if available + metaCtx, metaCancel := context.WithTimeout(ctx, time.Second) + defer metaCancel() + if req, err := http.NewRequestWithContext(metaCtx, http.MethodGet, "http://169.254.169.254/latest/meta-data/local-hostname", nil); err != nil { + logrus.Debugf("Failed to create request for metadata endpoint: %v", err) + } else { + if token != "" { + req.Header.Add("x-aws-ec2-metadata-token", token) + } + if resp, err := http.DefaultClient.Do(req); err != nil { + logrus.Debugf("Failed to get hostname from metadata endpoint: %v", err) + } else { + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + logrus.Debugf("Metadata endpoint returned unacceptable status code %d", resp.StatusCode) + } else { + if b, err := ioutil.ReadAll(resp.Body); err != nil { + logrus.Debugf("Failed to read response body from metadata endpoint: %v", err) + } else { + return strings.TrimSpace(string(b)) + } + } + } + } + return "" +} diff --git a/pkg/rke2/rke2_linux.go b/pkg/rke2/rke2_linux.go index 3bf5c9e3c9d..d9c47e574e0 100644 --- a/pkg/rke2/rke2_linux.go +++ b/pkg/rke2/rke2_linux.go @@ -7,13 +7,10 @@ import ( "bytes" "context" "fmt" - "io/ioutil" - "net/http" "os/exec" "path/filepath" "strconv" "strings" - "time" "github.com/k3s-io/k3s/pkg/agent/config" "github.com/k3s-io/k3s/pkg/cli/cmds" @@ -92,22 +89,29 @@ func initExecutor(clx *cli.Context, cfg Config, isServer bool) (*podexecutor.Sta return nil, fmt.Errorf("--cloud-provider-config requires --cloud-provider-name to be provided") } if cfg.CloudProviderName != "" { - cpConfig = &podexecutor.CloudProviderConfig{ - Name: cfg.CloudProviderName, - Path: cfg.CloudProviderConfig, - } - if clx.String("node-name") == "" && cfg.CloudProviderName == "aws" { - fqdn := hostnameFromMetadataEndpoint(context.Background()) - if fqdn == "" { - hostFQDN, err := hostnameFQDN() - if err != nil { - return nil, err - } - fqdn = hostFQDN + if cfg.CloudProviderName == "aws" { + logrus.Warnf("--cloud-provider-name=aws is deprecated due to removal of the in-tree aws cloud provider; if you want the legacy hostname behavior associated with this flag please use --node-name-from-cloud-provider-metadata") + cfg.CloudProviderMetadataHostname = true + cfg.CloudProviderName = "" + } else { + cpConfig = &podexecutor.CloudProviderConfig{ + Name: cfg.CloudProviderName, + Path: cfg.CloudProviderConfig, } - if err := clx.Set("node-name", fqdn); err != nil { + } + } + + if cfg.CloudProviderMetadataHostname { + fqdn := hostnameFromMetadataEndpoint(context.Background()) + if fqdn == "" { + hostFQDN, err := hostnameFQDN() + if err != nil { return nil, err } + fqdn = hostFQDN + } + if err := clx.Set("node-name", fqdn); err != nil { + return nil, err } } @@ -502,34 +506,3 @@ func hostnameFQDN() (string, error) { return strings.TrimSpace(b.String()), nil } - -func hostnameFromMetadataEndpoint(ctx context.Context) string { - ctx, cancel := context.WithTimeout(ctx, time.Second) - defer cancel() - - req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://169.254.169.254/latest/meta-data/local-hostname", nil) - if err != nil { - logrus.Debugf("Failed to create request for metadata endpoint: %v", err) - return "" - } - - resp, err := http.DefaultClient.Do(req) - if err != nil { - logrus.Debugf("Failed to get local-hostname from metadata endpoint: %v", err) - return "" - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - logrus.Debugf("Metadata endpoint returned unacceptable status code %d", resp.StatusCode) - return "" - } - - b, err := ioutil.ReadAll(resp.Body) - if err != nil { - logrus.Debugf("Failed to read response body from metadata endpoint: %v", err) - return "" - } - - return strings.TrimSpace(string(b)) -} diff --git a/pkg/rke2/rke2_windows.go b/pkg/rke2/rke2_windows.go index ba011275ff1..a4a58a2bd1f 100644 --- a/pkg/rke2/rke2_windows.go +++ b/pkg/rke2/rke2_windows.go @@ -4,8 +4,10 @@ package rke2 import ( + "context" "fmt" "path/filepath" + "unsafe" "github.com/k3s-io/k3s/pkg/agent/config" "github.com/k3s-io/k3s/pkg/cli/cmds" @@ -15,7 +17,9 @@ import ( "github.com/rancher/rke2/pkg/cli/defaults" "github.com/rancher/rke2/pkg/images" "github.com/rancher/rke2/pkg/pebinaryexecutor" + "github.com/sirupsen/logrus" "github.com/urfave/cli" + "golang.org/x/sys/windows" ) func initExecutor(clx *cli.Context, cfg Config, isServer bool) (*pebinaryexecutor.PEBinaryConfig, error) { @@ -48,9 +52,29 @@ func initExecutor(clx *cli.Context, cfg Config, isServer bool) (*pebinaryexecuto return nil, fmt.Errorf("--cloud-provider-config requires --cloud-provider-name to be provided") } if cfg.CloudProviderName != "" { - cpConfig = &pebinaryexecutor.CloudProviderConfig{ - Name: cfg.CloudProviderName, - Path: cfg.CloudProviderConfig, + if cfg.CloudProviderName == "aws" { + logrus.Warnf("--cloud-provider-name=aws is deprecated due to removal of the in-tree aws cloud provider; if you want the legacy node-name behavior associated with this flag please use --node-name-from-cloud-provider-metadata") + cfg.CloudProviderMetadataHostname = true + cfg.CloudProviderName = "" + } else { + cpConfig = &pebinaryexecutor.CloudProviderConfig{ + Name: cfg.CloudProviderName, + Path: cfg.CloudProviderConfig, + } + } + } + + if cfg.CloudProviderMetadataHostname { + fqdn := hostnameFromMetadataEndpoint(context.Background()) + if fqdn == "" { + hostFQDN, err := hostnameFQDN() + if err != nil { + return nil, err + } + fqdn = hostFQDN + } + if err := clx.Set("node-name", fqdn); err != nil { + return nil, err } } @@ -78,3 +102,13 @@ func initExecutor(clx *cli.Context, cfg Config, isServer bool) (*pebinaryexecuto CNIName: "", }, nil } + +func hostnameFQDN() (string, error) { + var domainName *uint16 + var domainNameLen uint32 = 256 + err := windows.GetComputerNameEx(windows.ComputerNameDnsFullyQualified, &domainName, &domainNameLen) + if err != nil { + return "", err + } + return windows.UTF16ToString((*[1 << 16]uint16)(unsafe.Pointer(domainName))[:domainNameLen-1]), nil +}