mirror of https://github.com/kubernetes/kops.git
Use AWS SDK to fetch metadata
Previously the EC2 metadata service was straightforward HTTP, but IMDS v2 now requires managing a session token (and is more secure for it). We now use the AWS SDK when retrieving metadata; it automatically supports IMDS v2.
This commit is contained in:
parent
f94371075b
commit
7d7b8969ea
|
@ -27,6 +27,8 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
"github.com/denverdino/aliyungo/oss"
|
"github.com/denverdino/aliyungo/oss"
|
||||||
"github.com/gophercloud/gophercloud"
|
"github.com/gophercloud/gophercloud"
|
||||||
"google.golang.org/api/option"
|
"google.golang.org/api/option"
|
||||||
|
@ -69,11 +71,13 @@ func WithBackoff(backoff wait.Backoff) VFSOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadLocation reads a file from a vfs URL
|
// ReadFile reads a file from a vfs URL
|
||||||
// It supports additional schemes which don't (yet) have full VFS implementations:
|
// It supports additional schemes which don't (yet) have full VFS implementations:
|
||||||
// metadata: reads from instance metadata on GCE/AWS
|
// metadata: reads from instance metadata on GCE/AWS
|
||||||
// http / https: reads from HTTP
|
// http / https: reads from HTTP
|
||||||
func (c *VFSContext) ReadFile(location string, options ...VFSOption) ([]byte, error) {
|
func (c *VFSContext) ReadFile(location string, options ...VFSOption) ([]byte, error) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
var opts vfsOptions
|
var opts vfsOptions
|
||||||
// Exponential backoff, starting with 500 milliseconds, doubling each time, 5 steps
|
// Exponential backoff, starting with 500 milliseconds, doubling each time, 5 steps
|
||||||
opts.backoff = wait.Backoff{
|
opts.backoff = wait.Backoff{
|
||||||
|
@ -102,8 +106,7 @@ func (c *VFSContext) ReadFile(location string, options ...VFSOption) ([]byte, er
|
||||||
httpHeaders["Metadata-Flavor"] = "Google"
|
httpHeaders["Metadata-Flavor"] = "Google"
|
||||||
return c.readHTTPLocation(httpURL, httpHeaders, opts)
|
return c.readHTTPLocation(httpURL, httpHeaders, opts)
|
||||||
case "aws":
|
case "aws":
|
||||||
httpURL := "http://169.254.169.254/latest/" + u.Path
|
return c.readAWSMetadata(ctx, u.Path)
|
||||||
return c.readHTTPLocation(httpURL, nil, opts)
|
|
||||||
case "digitalocean":
|
case "digitalocean":
|
||||||
httpURL := "http://169.254.169.254/metadata/v1" + u.Path
|
httpURL := "http://169.254.169.254/metadata/v1" + u.Path
|
||||||
return c.readHTTPLocation(httpURL, nil, opts)
|
return c.readHTTPLocation(httpURL, nil, opts)
|
||||||
|
@ -169,6 +172,24 @@ func (c *VFSContext) BuildVfsPath(p string) (Path, error) {
|
||||||
return nil, fmt.Errorf("unknown / unhandled path type: %q", p)
|
return nil, fmt.Errorf("unknown / unhandled path type: %q", p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// readAWSMetadata reads the specified path from the AWS EC2 metadata service
|
||||||
|
func (c *VFSContext) readAWSMetadata(ctx context.Context, path string) ([]byte, error) {
|
||||||
|
awsSession, err := session.NewSession()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error building AWS session: %v", err)
|
||||||
|
}
|
||||||
|
client := ec2metadata.New(awsSession)
|
||||||
|
if strings.HasPrefix(path, "/meta-data/") {
|
||||||
|
s, err := client.GetMetadataWithContext(ctx, strings.TrimPrefix(path, "/meta-data/"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error reading from AWS metadata service: %v", err)
|
||||||
|
}
|
||||||
|
return []byte(s), nil
|
||||||
|
}
|
||||||
|
// There are others (e.g. user-data), but as we don't use them yet let's not expose them
|
||||||
|
return nil, fmt.Errorf("unhandled aws metadata path %q", path)
|
||||||
|
}
|
||||||
|
|
||||||
// readHTTPLocation reads an http (or https) url.
|
// readHTTPLocation reads an http (or https) url.
|
||||||
// It returns the contents, or an error on any non-200 response. On a 404, it will return os.ErrNotExist
|
// It returns the contents, or an error on any non-200 response. On a 404, it will return os.ErrNotExist
|
||||||
// It will retry a few times on a 500 class error
|
// It will retry a few times on a 500 class error
|
||||||
|
|
Loading…
Reference in New Issue