kubernetes/kops · error

failed to load AWS config: %w

Error message

failed to load AWS config: %w

What it means

GetMetadataLocalIP resolves the node's internal IP from cloud metadata. On AWS it first loads an AWS SDK v2 default config; if that fails (no region, bad credentials/IMDS availability config) it wraps the SDK error. Without a usable config the EC2 IMDS client cannot be built, so the function returns early.

Source

Thrown at nodeup/pkg/model/context.go:595

// RunningOnGCE returns true if we are running on GCE
func (c *NodeupModelContext) RunningOnGCE() bool {
	return c.CloudProvider() == kops.CloudProviderGCE
}

// RunningOnAzure returns true if we are running on Azure
func (c *NodeupModelContext) RunningOnAzure() bool {
	return c.CloudProvider() == kops.CloudProviderAzure
}

// GetMetadataLocalIP returns the local IP address read from metadata
func (c *NodeupModelContext) GetMetadataLocalIP(ctx context.Context) (string, error) {
	var internalIP string

	switch c.BootConfig.CloudProvider {
	case kops.CloudProviderAWS:
		config, err := awsconfig.LoadDefaultConfig(ctx)
		if err != nil {
			return "", fmt.Errorf("failed to load AWS config: %w", err)
		}
		metadata := imds.NewFromConfig(config)
		localIPv4, err := getMetadata(ctx, metadata, "local-ipv4")
		if err != nil {
			return "", fmt.Errorf("failed to get local-ipv4 address from ec2 metadata: %w", err)
		}
		internalIP = localIPv4

	case kops.CloudProviderHetzner:
		client := hcloudmetadata.NewClient()
		privateNetworksYaml, err := client.PrivateNetworks()
		if err != nil {
			return "", fmt.Errorf("failed to get private networks from hetzner cloud metadata: %w", err)
		}
		var privateNetworks []struct {
			IP           net.IP   `json:"ip"`
			AliasIPs     []net.IP `json:"alias_ips"`
			InterfaceNum int      `json:"interface_num"`

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Fix instance metadata access: ensure metadata options are enabled and IMDSv2 hop limit ≥ 2 (`aws ec2 modify-instance-metadata-options --http-tokens required --http-put-response-hop-limit 2`)
  2. Check network/firewall rules allow 169.254.169.254 from the node
  3. Verify BootConfig.CloudProvider is correct — this path only runs for AWS; a misconfigured provider should be corrected in the cluster spec and `kops update cluster` re-run
  4. Set AWS_REGION / AWS_DEFAULT_REGION env on the node config if IMDS is intentionally unavailable
Defensive patterns

Strategy: try-catch

Validate before calling

// check IMDS reachability before nodeup runs
if !curl -s --max-time 2 http://169.254.169.254/latest/api/token >/dev/null; then
  echo "EC2 IMDS unreachable; fix metadata options before nodeup"
fi

Try / catch

ip, err := c.GetMetadataLocalIP(ctx)
if err != nil {
    if strings.Contains(err.Error(), "failed to load AWS config") {
        klog.Errorf("AWS SDK config unavailable — check IMDS enabled, hop limit >= 2, and AWS_REGION: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: awsconfig.LoadDefaultConfig fails inside GetMetadataLocalIP on an AWS node — typically no region resolvable (no IMDS, no env/AWS_REGION) because IMDS is unreachable or disabled (IMDSv2 hop limit, metadata options set to disabled).

Common situations: EC2 instance metadata disabled or blocked by iptables/network policy; running nodeup outside AWS (e.g. in CI) with BootConfig.CloudProvider misconfigured as AWS; IMDSv2 hop limit too low for container/pod-based execution.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/e86366d41e2a229a. Report an issue: GitHub.