mirror of
https://github.com/gravitational/teleport.git
synced 2026-10-12 02:15:01 +00:00
Refactor imds/gcp to no longer depend on lib/cloud/gcp (#43122)
The imds pacakges are inteneded to be very lightweight and consumable by client tools without any additional cloud specific dependencies. By inverting dependencies such that lib/cloud/gcp depends on lib/cloud/imds/gcp client tools no longer transatively import the very large `cloud.google.com/go/compute/apiv1`. The depguard rules were also updated to prevent any accidental regressions.
This commit is contained in:
@@ -128,6 +128,7 @@ linters-settings:
|
||||
- '**/lib/service/servicecfg/**'
|
||||
- '**/lib/reversetunnelclient/**'
|
||||
- '**/lib/auth/authclient/**'
|
||||
- '**/lib/cloud/imds/**'
|
||||
allow:
|
||||
- github.com/gravitational/teleport/lib/cloud/imds
|
||||
deny:
|
||||
|
||||
+24
-1
@@ -77,6 +77,9 @@ import (
|
||||
"github.com/gravitational/teleport/lib/cloud/azure"
|
||||
"github.com/gravitational/teleport/lib/cloud/gcp"
|
||||
"github.com/gravitational/teleport/lib/cloud/imds"
|
||||
awsimds "github.com/gravitational/teleport/lib/cloud/imds/aws"
|
||||
azureimds "github.com/gravitational/teleport/lib/cloud/imds/azure"
|
||||
gcpimds "github.com/gravitational/teleport/lib/cloud/imds/gcp"
|
||||
"github.com/gravitational/teleport/lib/modules"
|
||||
"github.com/gravitational/teleport/lib/utils"
|
||||
)
|
||||
@@ -946,7 +949,27 @@ func (c *cloudClients) initInstanceMetadata(ctx context.Context) (imds.Client, e
|
||||
return c.instanceMetadata, nil
|
||||
}
|
||||
logrus.Debug("Initializing instance metadata client.")
|
||||
client, err := DiscoverInstanceMetadata(ctx)
|
||||
|
||||
providers := []func(ctx context.Context) (imds.Client, error){
|
||||
func(ctx context.Context) (imds.Client, error) {
|
||||
clt, err := awsimds.NewInstanceMetadataClient(ctx)
|
||||
return clt, trace.Wrap(err)
|
||||
},
|
||||
func(ctx context.Context) (imds.Client, error) {
|
||||
return azureimds.NewInstanceMetadataClient(), nil
|
||||
},
|
||||
func(ctx context.Context) (imds.Client, error) {
|
||||
instancesClient, err := gcp.NewInstancesClient(ctx)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
clt, err := gcpimds.NewInstanceMetadataClient(instancesClient)
|
||||
return clt, trace.Wrap(err)
|
||||
},
|
||||
}
|
||||
|
||||
client, err := DiscoverInstanceMetadata(ctx, providers)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
+83
-126
@@ -47,6 +47,7 @@ import (
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
"github.com/gravitational/teleport/api/utils/sshutils"
|
||||
"github.com/gravitational/teleport/lib/auth/native"
|
||||
gcpimds "github.com/gravitational/teleport/lib/cloud/imds/gcp"
|
||||
)
|
||||
|
||||
// sshUser is the user to log in as on GCP VMs.
|
||||
@@ -72,18 +73,18 @@ func convertAPIError(err error) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// InstanceClient is a client to interact with GCP VMs.
|
||||
// InstancesClient is a client to interact with GCP VMs.
|
||||
type InstancesClient interface {
|
||||
// ListInstances lists the GCP VMs that belong to the given project and
|
||||
// zone.
|
||||
// zone supports wildcard "*".
|
||||
ListInstances(ctx context.Context, projectID, zone string) ([]*Instance, error)
|
||||
ListInstances(ctx context.Context, projectID, zone string) ([]*gcpimds.Instance, error)
|
||||
// StreamInstances streams the GCP VMs that belong to the given project and
|
||||
// zone.
|
||||
// zone supports wildcard "*".
|
||||
StreamInstances(ctx context.Context, projectID, zone string) stream.Stream[*Instance]
|
||||
StreamInstances(ctx context.Context, projectID, zone string) stream.Stream[*gcpimds.Instance]
|
||||
// GetInstance gets a GCP VM.
|
||||
GetInstance(ctx context.Context, req *InstanceRequest) (*Instance, error)
|
||||
GetInstance(ctx context.Context, req *gcpimds.InstanceRequest) (*gcpimds.Instance, error)
|
||||
// AddSSHKey adds an SSH key to a GCP VM's metadata.
|
||||
AddSSHKey(ctx context.Context, req *SSHKeyRequest) error
|
||||
// RemoveSSHKey removes an SSH key from a GCP VM's metadata.
|
||||
@@ -91,7 +92,7 @@ type InstancesClient interface {
|
||||
// GetInstanceTags gets the GCP tags associated with an instance (which are
|
||||
// distinct from its labels). It is separate from GetInstance because fetching
|
||||
// tags requires its own permissions.
|
||||
GetInstanceTags(ctx context.Context, req *InstanceRequest) (map[string]string, error)
|
||||
GetInstanceTags(ctx context.Context, req *gcpimds.InstanceRequest) (map[string]string, error)
|
||||
}
|
||||
|
||||
// InstancesClientConfig is the client configuration for InstancesClient.
|
||||
@@ -110,34 +111,6 @@ func (c *InstancesClientConfig) CheckAndSetDefaults(ctx context.Context) (err er
|
||||
return nil
|
||||
}
|
||||
|
||||
// Instance represents a GCP VM.
|
||||
type Instance struct {
|
||||
// Name is the instance's name.
|
||||
Name string
|
||||
// Zone is the instance's zone.
|
||||
Zone string
|
||||
// ProjectID is the ID of the project the VM is in.
|
||||
ProjectID string
|
||||
// ServiceAccount is the email address of the VM's service account, if any.
|
||||
ServiceAccount string
|
||||
// Labels is the instance's labels.
|
||||
Labels map[string]string
|
||||
|
||||
internalIPAddress string
|
||||
externalIPAddress string
|
||||
hostKeys []ssh.PublicKey
|
||||
metadata *computepb.Metadata
|
||||
}
|
||||
|
||||
// InstanceRequest formats an instance request based on an instance.
|
||||
func (i *Instance) InstanceRequest() InstanceRequest {
|
||||
return InstanceRequest{
|
||||
ProjectID: i.ProjectID,
|
||||
Zone: i.Zone,
|
||||
Name: i.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// NewInstancesClient creates a new InstancesClient.
|
||||
func NewInstancesClient(ctx context.Context) (InstancesClient, error) {
|
||||
var cfg InstancesClientConfig
|
||||
@@ -171,7 +144,7 @@ func isExternalNAT(s string) bool {
|
||||
return slices.Contains(externalNATKeys, s)
|
||||
}
|
||||
|
||||
func toInstance(origInstance *computepb.Instance, projectID string) *Instance {
|
||||
func toInstance(origInstance *computepb.Instance, projectID string) *gcpimds.Instance {
|
||||
zoneParts := strings.Split(origInstance.GetZone(), "/")
|
||||
zone := zoneParts[len(zoneParts)-1]
|
||||
var internalIP string
|
||||
@@ -189,14 +162,24 @@ func toInstance(origInstance *computepb.Instance, projectID string) *Instance {
|
||||
}
|
||||
}
|
||||
}
|
||||
inst := &Instance{
|
||||
|
||||
items := make(map[string]string, len(origInstance.GetMetadata().GetItems()))
|
||||
for _, item := range origInstance.GetMetadata().GetItems() {
|
||||
if item.Key == nil {
|
||||
continue
|
||||
}
|
||||
items[item.GetKey()] = item.GetValue()
|
||||
}
|
||||
|
||||
inst := &gcpimds.Instance{
|
||||
Name: origInstance.GetName(),
|
||||
ProjectID: projectID,
|
||||
Zone: zone,
|
||||
Labels: origInstance.GetLabels(),
|
||||
internalIPAddress: internalIP,
|
||||
externalIPAddress: externalIP,
|
||||
metadata: origInstance.GetMetadata(),
|
||||
InternalIPAddress: internalIP,
|
||||
ExternalIPAddress: externalIP,
|
||||
Fingerprint: origInstance.GetFingerprint(),
|
||||
MetadataItems: items,
|
||||
}
|
||||
// GCP VMs can have at most one service account.
|
||||
if len(origInstance.ServiceAccounts) > 0 {
|
||||
@@ -205,8 +188,8 @@ func toInstance(origInstance *computepb.Instance, projectID string) *Instance {
|
||||
return inst
|
||||
}
|
||||
|
||||
func toInstances(origInstances []*computepb.Instance, projectID string) []*Instance {
|
||||
instances := make([]*Instance, 0, len(origInstances))
|
||||
func toInstances(origInstances []*computepb.Instance, projectID string) []*gcpimds.Instance {
|
||||
instances := make([]*gcpimds.Instance, 0, len(origInstances))
|
||||
for _, inst := range origInstances {
|
||||
instances = append(instances, toInstance(inst, projectID))
|
||||
}
|
||||
@@ -216,26 +199,26 @@ func toInstances(origInstances []*computepb.Instance, projectID string) []*Insta
|
||||
// ListInstances lists the GCP VMs that belong to the given project and
|
||||
// zone.
|
||||
// zone supports wildcard "*".
|
||||
func (clt *instancesClient) ListInstances(ctx context.Context, projectID, zone string) ([]*Instance, error) {
|
||||
func (clt *instancesClient) ListInstances(ctx context.Context, projectID, zone string) ([]*gcpimds.Instance, error) {
|
||||
instances, err := stream.Collect(clt.StreamInstances(ctx, projectID, zone))
|
||||
return instances, trace.Wrap(err)
|
||||
}
|
||||
|
||||
func (clt *instancesClient) StreamInstances(ctx context.Context, projectID, zone string) stream.Stream[*Instance] {
|
||||
func (clt *instancesClient) StreamInstances(ctx context.Context, projectID, zone string) stream.Stream[*gcpimds.Instance] {
|
||||
if len(projectID) == 0 {
|
||||
return stream.Fail[*Instance](trace.BadParameter("projectID must be set"))
|
||||
return stream.Fail[*gcpimds.Instance](trace.BadParameter("projectID must be set"))
|
||||
}
|
||||
if len(zone) == 0 {
|
||||
return stream.Fail[*Instance](trace.BadParameter("location must be set"))
|
||||
return stream.Fail[*gcpimds.Instance](trace.BadParameter("location must be set"))
|
||||
}
|
||||
|
||||
var getInstances func() ([]*Instance, error)
|
||||
var getInstances func() ([]*gcpimds.Instance, error)
|
||||
|
||||
if zone == types.Wildcard {
|
||||
it := clt.InstanceClient.AggregatedList(ctx, &computepb.AggregatedListInstancesRequest{
|
||||
Project: projectID,
|
||||
})
|
||||
getInstances = func() ([]*Instance, error) {
|
||||
getInstances = func() ([]*gcpimds.Instance, error) {
|
||||
resp, err := it.Next()
|
||||
if resp.Value == nil {
|
||||
return nil, trace.Wrap(err)
|
||||
@@ -247,16 +230,16 @@ func (clt *instancesClient) StreamInstances(ctx context.Context, projectID, zone
|
||||
Project: projectID,
|
||||
Zone: zone,
|
||||
})
|
||||
getInstances = func() ([]*Instance, error) {
|
||||
getInstances = func() ([]*gcpimds.Instance, error) {
|
||||
resp, err := it.Next()
|
||||
if resp == nil {
|
||||
return nil, trace.Wrap(convertAPIError(err))
|
||||
}
|
||||
return []*Instance{toInstance(resp, projectID)}, trace.Wrap(convertAPIError(err))
|
||||
return []*gcpimds.Instance{toInstance(resp, projectID)}, trace.Wrap(convertAPIError(err))
|
||||
}
|
||||
}
|
||||
|
||||
return stream.PageFunc(func() ([]*Instance, error) {
|
||||
return stream.PageFunc(func() ([]*gcpimds.Instance, error) {
|
||||
instances, err := getInstances()
|
||||
if errors.Is(err, iterator.Done) {
|
||||
return instances, io.EOF
|
||||
@@ -265,36 +248,8 @@ func (clt *instancesClient) StreamInstances(ctx context.Context, projectID, zone
|
||||
})
|
||||
}
|
||||
|
||||
// InstanceRequest contains parameters for making a request to a specific instance.
|
||||
type InstanceRequest struct {
|
||||
// ProjectID is the ID of the VM's project.
|
||||
ProjectID string
|
||||
// Zone is the instance's zone.
|
||||
Zone string
|
||||
// Name is the instance's name.
|
||||
Name string
|
||||
// ID is the instance's ID.
|
||||
ID uint64
|
||||
// WithoutHostKeys indicates that the client should not request the instance's
|
||||
// host keys.
|
||||
WithoutHostKeys bool
|
||||
}
|
||||
|
||||
func (req *InstanceRequest) CheckAndSetDefaults() error {
|
||||
if len(req.ProjectID) == 0 {
|
||||
trace.BadParameter("projectID must be set")
|
||||
}
|
||||
if len(req.Zone) == 0 {
|
||||
trace.BadParameter("zone must be set")
|
||||
}
|
||||
if len(req.Name) == 0 {
|
||||
trace.BadParameter("name must be set")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getHostKeys gets the SSH host keys from the VM, if available.
|
||||
func (clt *instancesClient) getHostKeys(ctx context.Context, req *InstanceRequest) ([]ssh.PublicKey, error) {
|
||||
func (clt *instancesClient) getHostKeys(ctx context.Context, req *gcpimds.InstanceRequest) ([]ssh.PublicKey, error) {
|
||||
guestAttributes, err := clt.InstanceClient.GetGuestAttributes(ctx, &computepb.GetGuestAttributesInstanceRequest{
|
||||
Instance: req.Name,
|
||||
Project: req.ProjectID,
|
||||
@@ -306,20 +261,20 @@ func (clt *instancesClient) getHostKeys(ctx context.Context, req *InstanceReques
|
||||
}
|
||||
items := guestAttributes.GetQueryValue().GetItems()
|
||||
keys := make([]ssh.PublicKey, 0, len(items))
|
||||
var errors []error
|
||||
var errs []error
|
||||
for _, item := range items {
|
||||
key, _, _, _, err := ssh.ParseAuthorizedKey([]byte(fmt.Sprintf("%v %v", item.GetKey(), item.GetValue())))
|
||||
if err == nil {
|
||||
keys = append(keys, key)
|
||||
} else {
|
||||
errors = append(errors, err)
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return keys, trace.NewAggregate(errors...)
|
||||
return keys, trace.NewAggregate(errs...)
|
||||
}
|
||||
|
||||
// GetInstance gets a GCP VM.
|
||||
func (clt *instancesClient) GetInstance(ctx context.Context, req *InstanceRequest) (*Instance, error) {
|
||||
func (clt *instancesClient) GetInstance(ctx context.Context, req *gcpimds.InstanceRequest) (*gcpimds.Instance, error) {
|
||||
if err := req.CheckAndSetDefaults(); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
@@ -337,7 +292,7 @@ func (clt *instancesClient) GetInstance(ctx context.Context, req *InstanceReques
|
||||
if !req.WithoutHostKeys {
|
||||
hostKeys, err := clt.getHostKeys(ctx, req)
|
||||
if err == nil {
|
||||
inst.hostKeys = hostKeys
|
||||
inst.HostKeys = hostKeys
|
||||
} else if !trace.IsNotFound(err) {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
@@ -356,7 +311,7 @@ func (clt *instancesClient) getTagBindingsClient(ctx context.Context, zone strin
|
||||
}
|
||||
|
||||
// GetInstanceTags gets the GCP tags for the instance.
|
||||
func (clt *instancesClient) GetInstanceTags(ctx context.Context, req *InstanceRequest) (map[string]string, error) {
|
||||
func (clt *instancesClient) GetInstanceTags(ctx context.Context, req *gcpimds.InstanceRequest) (map[string]string, error) {
|
||||
tagClient, err := clt.getTagBindingsClient(ctx, req.Zone)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
@@ -388,7 +343,7 @@ func (clt *instancesClient) GetInstanceTags(ctx context.Context, req *InstanceRe
|
||||
// SSHKeyRequest contains parameters to add/removed SSH keys from an instance.
|
||||
type SSHKeyRequest struct {
|
||||
// Instance is the instance to add/remove keys form.
|
||||
Instance *Instance
|
||||
Instance *gcpimds.Instance
|
||||
// PublicKey is the key to add. Ignored when removing a key.
|
||||
PublicKey ssh.PublicKey
|
||||
// Expires is the expiration time of the key. Ignored when removing a key.
|
||||
@@ -422,26 +377,14 @@ func formatSSHKey(pubKey ssh.PublicKey, expires time.Time) string {
|
||||
// keys.
|
||||
const sshKeyName = "ssh-keys"
|
||||
|
||||
func addSSHKey(meta *computepb.Metadata, pubKey ssh.PublicKey, expires time.Time) {
|
||||
var sshKeyItem *computepb.Items
|
||||
for _, item := range meta.GetItems() {
|
||||
if item.GetKey() == sshKeyName {
|
||||
sshKeyItem = item
|
||||
break
|
||||
}
|
||||
}
|
||||
if sshKeyItem == nil {
|
||||
sshKeyItem = &computepb.Items{Key: googleapi.String(sshKeyName)}
|
||||
meta.Items = append(meta.Items, sshKeyItem)
|
||||
func addSSHKey(instance *gcpimds.Instance, pubKey ssh.PublicKey, expires time.Time) {
|
||||
var existingKeys []string
|
||||
if keys, ok := instance.MetadataItems[sshKeyName]; ok {
|
||||
existingKeys = strings.Split(keys, "\n")
|
||||
}
|
||||
|
||||
var existingKeys []string
|
||||
if rawKeys := sshKeyItem.GetValue(); rawKeys != "" {
|
||||
existingKeys = strings.Split(rawKeys, "\n")
|
||||
}
|
||||
existingKeys = append(existingKeys, formatSSHKey(pubKey, expires))
|
||||
newKeys := strings.Join(existingKeys, "\n")
|
||||
sshKeyItem.Value = &newKeys
|
||||
instance.MetadataItems[sshKeyName] = strings.Join(existingKeys, "\n")
|
||||
}
|
||||
|
||||
// AddSSHKey adds an SSH key to a GCP VM's metadata.
|
||||
@@ -452,10 +395,11 @@ func (clt *instancesClient) AddSSHKey(ctx context.Context, req *SSHKeyRequest) e
|
||||
if req.PublicKey == nil {
|
||||
return trace.BadParameter("public key not set")
|
||||
}
|
||||
addSSHKey(req.Instance.metadata, req.PublicKey, req.Expires)
|
||||
addSSHKey(req.Instance, req.PublicKey, req.Expires)
|
||||
|
||||
op, err := clt.InstanceClient.SetMetadata(ctx, &computepb.SetMetadataInstanceRequest{
|
||||
Instance: req.Instance.Name,
|
||||
MetadataResource: req.Instance.metadata,
|
||||
MetadataResource: convertInstanceMetadata(req.Instance),
|
||||
Project: req.Instance.ProjectID,
|
||||
Zone: req.Instance.Zone,
|
||||
})
|
||||
@@ -468,21 +412,33 @@ func (clt *instancesClient) AddSSHKey(ctx context.Context, req *SSHKeyRequest) e
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeSSHKey(meta *computepb.Metadata) {
|
||||
for _, item := range meta.GetItems() {
|
||||
if item.GetKey() != sshKeyName {
|
||||
continue
|
||||
}
|
||||
existingKeys := strings.Split(item.GetValue(), "\n")
|
||||
newKeys := make([]string, 0, len(existingKeys))
|
||||
for _, key := range existingKeys {
|
||||
if !strings.HasPrefix(key, sshUser) {
|
||||
newKeys = append(newKeys, key)
|
||||
}
|
||||
}
|
||||
item.Value = googleapi.String(strings.TrimSpace(strings.Join(newKeys, "\n")))
|
||||
func removeSSHKey(instance *gcpimds.Instance) {
|
||||
keys, ok := instance.MetadataItems[sshKeyName]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
existingKeys := strings.Split(keys, "\n")
|
||||
newKeys := make([]string, 0, len(existingKeys))
|
||||
for _, key := range existingKeys {
|
||||
if !strings.HasPrefix(key, sshUser) {
|
||||
newKeys = append(newKeys, key)
|
||||
}
|
||||
}
|
||||
|
||||
instance.MetadataItems[sshKeyName] = strings.TrimSpace(strings.Join(newKeys, "\n"))
|
||||
}
|
||||
|
||||
func convertInstanceMetadata(i *gcpimds.Instance) *computepb.Metadata {
|
||||
items := make([]*computepb.Items, 0, len(i.MetadataItems))
|
||||
for k, v := range i.MetadataItems {
|
||||
items = append(items, &computepb.Items{Key: googleapi.String(k), Value: googleapi.String(v)})
|
||||
}
|
||||
|
||||
return &computepb.Metadata{
|
||||
Fingerprint: googleapi.String(i.Fingerprint),
|
||||
Items: items,
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveSSHKey removes an SSH key from a GCP VM's metadata.
|
||||
@@ -490,10 +446,11 @@ func (clt *instancesClient) RemoveSSHKey(ctx context.Context, req *SSHKeyRequest
|
||||
if err := req.CheckAndSetDefaults(); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
removeSSHKey(req.Instance.metadata)
|
||||
removeSSHKey(req.Instance)
|
||||
|
||||
op, err := clt.InstanceClient.SetMetadata(ctx, &computepb.SetMetadataInstanceRequest{
|
||||
Instance: req.Instance.Name,
|
||||
MetadataResource: req.Instance.metadata,
|
||||
MetadataResource: convertInstanceMetadata(req.Instance),
|
||||
Project: req.Instance.ProjectID,
|
||||
Zone: req.Instance.Zone,
|
||||
})
|
||||
@@ -511,7 +468,7 @@ type RunCommandRequest struct {
|
||||
// Client is the instance client to use.
|
||||
Client InstancesClient
|
||||
// InstanceRequest is the set of parameters identifying the instance.
|
||||
InstanceRequest
|
||||
gcpimds.InstanceRequest
|
||||
// Script is the script to execute.
|
||||
Script string
|
||||
// SSHPort is the ssh server port to connect to. Defaults to 22.
|
||||
@@ -570,16 +527,16 @@ func RunCommand(ctx context.Context, req *RunCommandRequest) error {
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if len(instance.hostKeys) == 0 {
|
||||
if len(instance.HostKeys) == 0 {
|
||||
return trace.NotFound(`Instance %v is missing host keys. Did you enable guest attributes on the instance?
|
||||
https://cloud.google.com/solutions/connecting-securely#storing_host_keys_by_enabling_guest_attributes`, req.Name)
|
||||
}
|
||||
var ipAddrs []string
|
||||
if instance.externalIPAddress != "" {
|
||||
ipAddrs = append(ipAddrs, instance.externalIPAddress)
|
||||
if instance.ExternalIPAddress != "" {
|
||||
ipAddrs = append(ipAddrs, instance.ExternalIPAddress)
|
||||
}
|
||||
if instance.internalIPAddress != "" {
|
||||
ipAddrs = append(ipAddrs, instance.internalIPAddress)
|
||||
if instance.InternalIPAddress != "" {
|
||||
ipAddrs = append(ipAddrs, instance.InternalIPAddress)
|
||||
}
|
||||
if len(ipAddrs) == 0 {
|
||||
return trace.NotFound("Instance %v is missing an IP address.", req.Name)
|
||||
@@ -607,7 +564,7 @@ https://cloud.google.com/solutions/connecting-securely#storing_host_keys_by_enab
|
||||
}()
|
||||
|
||||
// Configure the SSH client.
|
||||
callback, err := sshutils.HostKeyCallback(instance.hostKeys, true)
|
||||
callback, err := sshutils.HostKeyCallback(instance.HostKeys, true)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
+13
-13
@@ -27,7 +27,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/compute/apiv1/computepb"
|
||||
"github.com/googleapis/gax-go/v2/apierror"
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -37,6 +36,7 @@ import (
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/gravitational/teleport/api/internalutils/stream"
|
||||
gcpimds "github.com/gravitational/teleport/lib/cloud/imds/gcp"
|
||||
"github.com/gravitational/teleport/lib/sshutils"
|
||||
"github.com/gravitational/teleport/lib/utils"
|
||||
)
|
||||
@@ -91,7 +91,7 @@ type mockInstance struct {
|
||||
sshServer *sshutils.Server
|
||||
execCount int
|
||||
|
||||
instance *Instance
|
||||
instance *gcpimds.Instance
|
||||
}
|
||||
|
||||
func newMockInstance(t *testing.T, hostSigner ssh.Signer, listener net.Listener) *mockInstance {
|
||||
@@ -159,19 +159,19 @@ func (m *mockInstance) userKeyAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (*s
|
||||
return nil, trace.AccessDenied("unknown public key for user %q", conn.User())
|
||||
}
|
||||
|
||||
func (m *mockInstance) ListInstances(ctx context.Context, projectID, location string) ([]*Instance, error) {
|
||||
return []*Instance{m.instance}, nil
|
||||
func (m *mockInstance) ListInstances(ctx context.Context, projectID, location string) ([]*gcpimds.Instance, error) {
|
||||
return []*gcpimds.Instance{m.instance}, nil
|
||||
}
|
||||
|
||||
func (m *mockInstance) StreamInstances(ctx context.Context, projectID, location string) stream.Stream[*Instance] {
|
||||
func (m *mockInstance) StreamInstances(ctx context.Context, projectID, location string) stream.Stream[*gcpimds.Instance] {
|
||||
return stream.Once(m.instance)
|
||||
}
|
||||
|
||||
func (m *mockInstance) GetInstance(ctx context.Context, req *InstanceRequest) (*Instance, error) {
|
||||
func (m *mockInstance) GetInstance(ctx context.Context, req *gcpimds.InstanceRequest) (*gcpimds.Instance, error) {
|
||||
return m.instance, nil
|
||||
}
|
||||
|
||||
func (m *mockInstance) GetInstanceTags(ctx context.Context, req *InstanceRequest) (map[string]string, error) {
|
||||
func (m *mockInstance) GetInstanceTags(ctx context.Context, req *gcpimds.InstanceRequest) (map[string]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -185,8 +185,8 @@ func (m *mockInstance) RemoveSSHKey(ctx context.Context, req *SSHKeyRequest) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockInstance) setInstance(inst *Instance) {
|
||||
inst.hostKeys = m.hostKeys
|
||||
func (m *mockInstance) setInstance(inst *gcpimds.Instance) {
|
||||
inst.HostKeys = m.hostKeys
|
||||
m.instance = inst
|
||||
}
|
||||
|
||||
@@ -230,18 +230,18 @@ func TestRunCommand(t *testing.T) {
|
||||
t.Cleanup(mock.Stop)
|
||||
mock.hostKeys = []ssh.PublicKey{publicKey}
|
||||
|
||||
inst := &Instance{
|
||||
inst := &gcpimds.Instance{
|
||||
Name: "my-instance",
|
||||
Zone: "my-zone",
|
||||
ProjectID: "my-project-id",
|
||||
internalIPAddress: "test.example.com",
|
||||
metadata: &computepb.Metadata{},
|
||||
InternalIPAddress: "test.example.com",
|
||||
MetadataItems: map[string]string{},
|
||||
}
|
||||
mock.setInstance(inst)
|
||||
|
||||
require.NoError(t, RunCommand(ctx, &RunCommandRequest{
|
||||
Client: mock,
|
||||
InstanceRequest: InstanceRequest{
|
||||
InstanceRequest: gcpimds.InstanceRequest{
|
||||
ProjectID: "my-project-id",
|
||||
Zone: "my-zone",
|
||||
Name: "my-instance",
|
||||
|
||||
+6
-34
@@ -24,46 +24,18 @@ import (
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
"github.com/gravitational/teleport/lib/cloud/imds"
|
||||
"github.com/gravitational/teleport/lib/cloud/imds/aws"
|
||||
"github.com/gravitational/teleport/lib/cloud/imds/azure"
|
||||
"github.com/gravitational/teleport/lib/cloud/imds/gcp"
|
||||
)
|
||||
|
||||
const (
|
||||
// discoverInstanceMetadataTimeout is the maximum amount of time allowed
|
||||
// to discover an instance metadata service. The timeout is short to
|
||||
// minimize Teleport's startup time when it isn't running on any cloud
|
||||
// instance. Checking for instance metadata typically takes less than 30ms.
|
||||
discoverInstanceMetadataTimeout = 500 * time.Millisecond
|
||||
)
|
||||
|
||||
type imConstructor func(ctx context.Context) (imds.Client, error)
|
||||
|
||||
var providers = map[types.InstanceMetadataType]imConstructor{
|
||||
types.InstanceMetadataTypeEC2: initEC2,
|
||||
types.InstanceMetadataTypeAzure: initAzure,
|
||||
types.InstanceMetadataTypeGCP: initGCP,
|
||||
}
|
||||
|
||||
func initEC2(ctx context.Context) (imds.Client, error) {
|
||||
im, err := aws.NewInstanceMetadataClient(ctx)
|
||||
return im, trace.Wrap(err)
|
||||
}
|
||||
|
||||
func initAzure(ctx context.Context) (imds.Client, error) {
|
||||
return azure.NewInstanceMetadataClient(), nil
|
||||
}
|
||||
|
||||
func initGCP(ctx context.Context) (imds.Client, error) {
|
||||
im, err := gcp.NewInstanceMetadataClient(ctx)
|
||||
return im, trace.Wrap(err)
|
||||
}
|
||||
// discoverInstanceMetadataTimeout is the maximum amount of time allowed
|
||||
// to discover an instance metadata service. The timeout is short to
|
||||
// minimize Teleport's startup time when it isn't running on any cloud
|
||||
// instance. Checking for instance metadata typically takes less than 30ms.
|
||||
const discoverInstanceMetadataTimeout = 500 * time.Millisecond
|
||||
|
||||
// DiscoverInstanceMetadata checks which cloud instance type Teleport is
|
||||
// running on, if any.
|
||||
func DiscoverInstanceMetadata(ctx context.Context) (imds.Client, error) {
|
||||
func DiscoverInstanceMetadata(ctx context.Context, providers []func(ctx context.Context) (imds.Client, error)) (imds.Client, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, discoverInstanceMetadataTimeout)
|
||||
defer cancel()
|
||||
|
||||
|
||||
+76
-24
@@ -27,13 +27,12 @@ import (
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"cloud.google.com/go/compute/metadata"
|
||||
"github.com/gravitational/trace"
|
||||
"golang.org/x/crypto/ssh"
|
||||
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
"github.com/gravitational/teleport/lib/cloud/gcp"
|
||||
"github.com/gravitational/teleport/lib/defaults"
|
||||
)
|
||||
|
||||
@@ -53,24 +52,80 @@ func (rt contextRoundTripper) RoundTrip(req *http.Request) (*http.Response, erro
|
||||
|
||||
type metadataGetter func(ctx context.Context, path string) (string, error)
|
||||
|
||||
// InstanceRequest contains parameters for making a request to a specific instance.
|
||||
type InstanceRequest struct {
|
||||
// ProjectID is the ID of the VM's project.
|
||||
ProjectID string
|
||||
// Zone is the instance's zone.
|
||||
Zone string
|
||||
// Name is the instance's name.
|
||||
Name string
|
||||
// ID is the instance's ID.
|
||||
ID uint64
|
||||
// WithoutHostKeys indicates that the client should not request the instance's
|
||||
// host keys.
|
||||
WithoutHostKeys bool
|
||||
}
|
||||
|
||||
func (req *InstanceRequest) CheckAndSetDefaults() error {
|
||||
if req.ProjectID == "" {
|
||||
return trace.BadParameter("projectID must be set")
|
||||
}
|
||||
if req.Zone == "" {
|
||||
return trace.BadParameter("zone must be set")
|
||||
}
|
||||
if req.Name == "" {
|
||||
return trace.BadParameter("name must be set")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Instance represents a GCP VM.
|
||||
type Instance struct {
|
||||
// Name is the instance's name.
|
||||
Name string
|
||||
// Zone is the instance's zone.
|
||||
Zone string
|
||||
// ProjectID is the ID of the project the VM is in.
|
||||
ProjectID string
|
||||
// ServiceAccount is the email address of the VM's service account, if any.
|
||||
ServiceAccount string
|
||||
// Labels is the instance's labels.
|
||||
Labels map[string]string
|
||||
// InternalIPAddress is the instance's private ip.
|
||||
InternalIPAddress string
|
||||
// ExternalIPAddress is the instance's public ip.
|
||||
ExternalIPAddress string
|
||||
// HostKeys contain any public keys associated with the instance.
|
||||
HostKeys []ssh.PublicKey
|
||||
// Fingerprint is generated server-side and used to enforce optimistic
|
||||
// locking. It must be unaltered and provided to any update requests to
|
||||
// prevent requests being rejected.
|
||||
Fingerprint string
|
||||
// MetadataItems are key value pairs associated with the instance.
|
||||
MetadataItems map[string]string
|
||||
}
|
||||
|
||||
// InstanceGetter provides a mechanism to retrieve information about a
|
||||
// particular instannce.
|
||||
type InstanceGetter interface {
|
||||
// GetInstance gets a GCP VM.
|
||||
GetInstance(ctx context.Context, req *InstanceRequest) (*Instance, error)
|
||||
// GetInstanceTags gets the GCP tags for the instance.
|
||||
GetInstanceTags(ctx context.Context, req *InstanceRequest) (map[string]string, error)
|
||||
}
|
||||
|
||||
// InstanceMetadataClient is a client for GCP instance metadata.
|
||||
type InstanceMetadataClient struct {
|
||||
instancesClient gcp.InstancesClient
|
||||
getMetadata metadataGetter
|
||||
|
||||
labelPermissionErrorOnce sync.Once
|
||||
tagPermissionErrorOnce sync.Once
|
||||
getMetadata metadataGetter
|
||||
instanceGetter InstanceGetter
|
||||
}
|
||||
|
||||
// NewInstanceMetadataClient creates a new instance metadata client.
|
||||
func NewInstanceMetadataClient(ctx context.Context) (*InstanceMetadataClient, error) {
|
||||
instancesClient, err := gcp.NewInstancesClient(ctx)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
func NewInstanceMetadataClient(getter InstanceGetter) (*InstanceMetadataClient, error) {
|
||||
return &InstanceMetadataClient{
|
||||
instancesClient: instancesClient,
|
||||
getMetadata: getMetadata,
|
||||
getMetadata: getMetadata,
|
||||
instanceGetter: getter,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -92,7 +147,7 @@ func (client *InstanceMetadataClient) getNumericID(ctx context.Context) (uint64,
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// GetTags gets all of the GCP instance's labels and tags.
|
||||
// GetTags gets all the GCP instance's labels and tags.
|
||||
func (client *InstanceMetadataClient) GetTags(ctx context.Context) (map[string]string, error) {
|
||||
// Get a bunch of info from instance metadata.
|
||||
projectID, err := client.GetProjectID(ctx)
|
||||
@@ -112,7 +167,7 @@ func (client *InstanceMetadataClient) GetTags(ctx context.Context) (map[string]s
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
req := &gcp.InstanceRequest{
|
||||
req := &InstanceRequest{
|
||||
ProjectID: projectID,
|
||||
Zone: zone,
|
||||
Name: name,
|
||||
@@ -121,23 +176,20 @@ func (client *InstanceMetadataClient) GetTags(ctx context.Context) (map[string]s
|
||||
}
|
||||
// Get labels.
|
||||
var gcpLabels map[string]string
|
||||
inst, err := client.instancesClient.GetInstance(ctx, req)
|
||||
inst, err := client.instanceGetter.GetInstance(ctx, req)
|
||||
if err == nil {
|
||||
gcpLabels = inst.Labels
|
||||
} else if trace.IsAccessDenied(err) {
|
||||
client.labelPermissionErrorOnce.Do(func() {
|
||||
slog.WarnContext(ctx, "Access denied to instance labels, does the instance have compute.instances.get permission?")
|
||||
})
|
||||
slog.WarnContext(ctx, "Access denied to instance labels, does the instance have compute.instances.get permission?")
|
||||
|
||||
} else {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
// Get tags.
|
||||
gcpTags, err := client.instancesClient.GetInstanceTags(ctx, req)
|
||||
gcpTags, err := client.instanceGetter.GetInstanceTags(ctx, req)
|
||||
if trace.IsAccessDenied(err) {
|
||||
client.tagPermissionErrorOnce.Do(func() {
|
||||
slog.WarnContext(ctx, "Access denied to resource management tags, does the instance have compute.instances.listEffectiveTags permission?")
|
||||
})
|
||||
slog.WarnContext(ctx, "Access denied to resource management tags, does the instance have compute.instances.listEffectiveTags permission?")
|
||||
} else if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
@@ -25,8 +25,6 @@ import (
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/gravitational/teleport/lib/cloud/gcp"
|
||||
)
|
||||
|
||||
func makeMetadataGetter(values map[string]string) metadataGetter {
|
||||
@@ -40,18 +38,18 @@ func makeMetadataGetter(values map[string]string) metadataGetter {
|
||||
}
|
||||
|
||||
type mockInstanceGetter struct {
|
||||
gcp.InstancesClient
|
||||
instance *gcp.Instance
|
||||
InstanceGetter
|
||||
instance *Instance
|
||||
instanceErr error
|
||||
tags map[string]string
|
||||
tagsErr error
|
||||
}
|
||||
|
||||
func (m *mockInstanceGetter) GetInstance(ctx context.Context, req *gcp.InstanceRequest) (*gcp.Instance, error) {
|
||||
func (m *mockInstanceGetter) GetInstance(ctx context.Context, req *InstanceRequest) (*Instance, error) {
|
||||
return m.instance, m.instanceErr
|
||||
}
|
||||
|
||||
func (m *mockInstanceGetter) GetInstanceTags(ctx context.Context, req *gcp.InstanceRequest) (map[string]string, error) {
|
||||
func (m *mockInstanceGetter) GetInstanceTags(ctx context.Context, req *InstanceRequest) (map[string]string, error) {
|
||||
return m.tags, m.tagsErr
|
||||
}
|
||||
|
||||
@@ -106,7 +104,7 @@ func TestIsInstanceMetadataAvailable(t *testing.T) {
|
||||
if os.Getenv("TELEPORT_TEST_GCP") == "" {
|
||||
t.Skip("not on gcp")
|
||||
}
|
||||
client, err := NewInstanceMetadataClient(context.Background())
|
||||
client, err := NewInstanceMetadataClient(nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, client.IsAvailable(context.Background()))
|
||||
})
|
||||
@@ -121,7 +119,7 @@ func TestGetTags(t *testing.T) {
|
||||
"instance/name": "myname",
|
||||
"instance/id": "12345678",
|
||||
})
|
||||
defaultInstance := &gcp.Instance{
|
||||
defaultInstance := &Instance{
|
||||
ProjectID: "myproject",
|
||||
Zone: "myzone",
|
||||
Name: "myname",
|
||||
@@ -203,8 +201,8 @@ func TestGetTags(t *testing.T) {
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
client := &InstanceMetadataClient{
|
||||
getMetadata: tc.getMetadata,
|
||||
instancesClient: tc.instancesClient,
|
||||
getMetadata: tc.getMetadata,
|
||||
instanceGetter: tc.instancesClient,
|
||||
}
|
||||
tags, err := client.GetTags(context.Background())
|
||||
tc.assertErr(t, err)
|
||||
|
||||
+25
-1
@@ -101,6 +101,11 @@ import (
|
||||
"github.com/gravitational/teleport/lib/bpf"
|
||||
"github.com/gravitational/teleport/lib/cache"
|
||||
"github.com/gravitational/teleport/lib/cloud"
|
||||
"github.com/gravitational/teleport/lib/cloud/gcp"
|
||||
"github.com/gravitational/teleport/lib/cloud/imds"
|
||||
awsimds "github.com/gravitational/teleport/lib/cloud/imds/aws"
|
||||
"github.com/gravitational/teleport/lib/cloud/imds/azure"
|
||||
gcpimds "github.com/gravitational/teleport/lib/cloud/imds/gcp"
|
||||
"github.com/gravitational/teleport/lib/defaults"
|
||||
"github.com/gravitational/teleport/lib/events"
|
||||
"github.com/gravitational/teleport/lib/events/athena"
|
||||
@@ -954,7 +959,26 @@ func NewTeleport(cfg *servicecfg.Config) (*TeleportProcess, error) {
|
||||
// Check if we're on a cloud instance, and if we should override the node's hostname.
|
||||
imClient := cfg.InstanceMetadataClient
|
||||
if imClient == nil {
|
||||
imClient, err = cloud.DiscoverInstanceMetadata(supervisor.ExitContext())
|
||||
providers := []func(ctx context.Context) (imds.Client, error){
|
||||
func(ctx context.Context) (imds.Client, error) {
|
||||
clt, err := awsimds.NewInstanceMetadataClient(ctx)
|
||||
return clt, trace.Wrap(err)
|
||||
},
|
||||
func(ctx context.Context) (imds.Client, error) {
|
||||
return azure.NewInstanceMetadataClient(), nil
|
||||
},
|
||||
func(ctx context.Context) (imds.Client, error) {
|
||||
instancesClient, err := gcp.NewInstancesClient(ctx)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
clt, err := gcpimds.NewInstanceMetadataClient(instancesClient)
|
||||
return clt, trace.Wrap(err)
|
||||
},
|
||||
}
|
||||
|
||||
imClient, err = cloud.DiscoverInstanceMetadata(supervisor.ExitContext(), providers)
|
||||
if err == nil {
|
||||
cfg.Logger.InfoContext(supervisor.ExitContext(),
|
||||
"Found an instance metadata service. Teleport will import labels from this cloud instance.",
|
||||
|
||||
@@ -48,7 +48,7 @@ import (
|
||||
"github.com/gravitational/teleport/api/utils/retryutils"
|
||||
"github.com/gravitational/teleport/lib/auth/authclient"
|
||||
"github.com/gravitational/teleport/lib/cloud"
|
||||
"github.com/gravitational/teleport/lib/cloud/gcp"
|
||||
gcpimds "github.com/gravitational/teleport/lib/cloud/imds/gcp"
|
||||
"github.com/gravitational/teleport/lib/integrations/awsoidc"
|
||||
"github.com/gravitational/teleport/lib/services"
|
||||
"github.com/gravitational/teleport/lib/srv/discovery/common"
|
||||
@@ -788,8 +788,8 @@ func genAzureInstancesLogStr(instances []*armcompute.VirtualMachine) string {
|
||||
})
|
||||
}
|
||||
|
||||
func genGCPInstancesLogStr(instances []*gcp.Instance) string {
|
||||
return genInstancesLogStr(instances, func(i *gcp.Instance) string {
|
||||
func genGCPInstancesLogStr(instances []*gcpimds.Instance) string {
|
||||
return genInstancesLogStr(instances, func(i *gcpimds.Instance) string {
|
||||
return i.Name
|
||||
})
|
||||
}
|
||||
@@ -1137,7 +1137,7 @@ func (s *Server) filterExistingGCPNodes(instances *server.GCPInstances) {
|
||||
_, nameOK := labels[types.NameLabel]
|
||||
return projectIDOK && zoneOK && nameOK
|
||||
})
|
||||
var filtered []*gcp.Instance
|
||||
var filtered []*gcpimds.Instance
|
||||
outer:
|
||||
for _, inst := range instances.Instances {
|
||||
for _, node := range nodes {
|
||||
|
||||
@@ -77,6 +77,7 @@ import (
|
||||
"github.com/gravitational/teleport/lib/cloud"
|
||||
"github.com/gravitational/teleport/lib/cloud/azure"
|
||||
"github.com/gravitational/teleport/lib/cloud/gcp"
|
||||
gcpimds "github.com/gravitational/teleport/lib/cloud/imds/gcp"
|
||||
"github.com/gravitational/teleport/lib/cloud/mocks"
|
||||
libevents "github.com/gravitational/teleport/lib/events"
|
||||
"github.com/gravitational/teleport/lib/modules"
|
||||
@@ -2526,22 +2527,22 @@ func TestAzureVMDiscovery(t *testing.T) {
|
||||
}
|
||||
|
||||
type mockGCPClient struct {
|
||||
vms []*gcp.Instance
|
||||
vms []*gcpimds.Instance
|
||||
}
|
||||
|
||||
func (m *mockGCPClient) ListInstances(_ context.Context, _, _ string) ([]*gcp.Instance, error) {
|
||||
func (m *mockGCPClient) ListInstances(_ context.Context, _, _ string) ([]*gcpimds.Instance, error) {
|
||||
return m.vms, nil
|
||||
}
|
||||
|
||||
func (m *mockGCPClient) StreamInstances(_ context.Context, _, _ string) stream.Stream[*gcp.Instance] {
|
||||
func (m *mockGCPClient) StreamInstances(_ context.Context, _, _ string) stream.Stream[*gcpimds.Instance] {
|
||||
return stream.Slice(m.vms)
|
||||
}
|
||||
|
||||
func (m *mockGCPClient) GetInstance(_ context.Context, _ *gcp.InstanceRequest) (*gcp.Instance, error) {
|
||||
func (m *mockGCPClient) GetInstance(_ context.Context, _ *gcpimds.InstanceRequest) (*gcpimds.Instance, error) {
|
||||
return nil, trace.NotFound("disabled for test")
|
||||
}
|
||||
|
||||
func (m *mockGCPClient) GetInstanceTags(_ context.Context, _ *gcp.InstanceRequest) (map[string]string, error) {
|
||||
func (m *mockGCPClient) GetInstanceTags(_ context.Context, _ *gcpimds.InstanceRequest) (map[string]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -2606,7 +2607,7 @@ func TestGCPVMDiscovery(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
presentVMs []types.Server
|
||||
foundGCPVMs []*gcp.Instance
|
||||
foundGCPVMs []*gcpimds.Instance
|
||||
discoveryConfig *discoveryconfig.DiscoveryConfig
|
||||
staticMatchers Matchers
|
||||
wantInstalledInstances []string
|
||||
@@ -2614,7 +2615,7 @@ func TestGCPVMDiscovery(t *testing.T) {
|
||||
{
|
||||
name: "no nodes present, 1 found",
|
||||
presentVMs: []types.Server{},
|
||||
foundGCPVMs: []*gcp.Instance{
|
||||
foundGCPVMs: []*gcpimds.Instance{
|
||||
{
|
||||
ProjectID: "myproject",
|
||||
Zone: "myzone",
|
||||
@@ -2644,7 +2645,7 @@ func TestGCPVMDiscovery(t *testing.T) {
|
||||
},
|
||||
},
|
||||
staticMatchers: defaultStaticMatcher,
|
||||
foundGCPVMs: []*gcp.Instance{
|
||||
foundGCPVMs: []*gcpimds.Instance{
|
||||
{
|
||||
ProjectID: "myproject",
|
||||
Zone: "myzone",
|
||||
@@ -2672,7 +2673,7 @@ func TestGCPVMDiscovery(t *testing.T) {
|
||||
},
|
||||
},
|
||||
staticMatchers: defaultStaticMatcher,
|
||||
foundGCPVMs: []*gcp.Instance{
|
||||
foundGCPVMs: []*gcpimds.Instance{
|
||||
{
|
||||
ProjectID: "myproject",
|
||||
Zone: "myzone",
|
||||
@@ -2687,7 +2688,7 @@ func TestGCPVMDiscovery(t *testing.T) {
|
||||
{
|
||||
name: "no nodes present, 1 found usind dynamic matchers",
|
||||
presentVMs: []types.Server{},
|
||||
foundGCPVMs: []*gcp.Instance{
|
||||
foundGCPVMs: []*gcpimds.Instance{
|
||||
{
|
||||
ProjectID: "myproject",
|
||||
Zone: "myzone",
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
|
||||
apievents "github.com/gravitational/teleport/api/types/events"
|
||||
"github.com/gravitational/teleport/lib/cloud/gcp"
|
||||
gcpimds "github.com/gravitational/teleport/lib/cloud/imds/gcp"
|
||||
)
|
||||
|
||||
// GCPInstaller handles running commands that install Teleport on GCP
|
||||
@@ -40,7 +41,7 @@ type GCPInstaller struct {
|
||||
// virtual machines.
|
||||
type GCPRunRequest struct {
|
||||
Client gcp.InstancesClient
|
||||
Instances []*gcp.Instance
|
||||
Instances []*gcpimds.Instance
|
||||
Params []string
|
||||
Zone string
|
||||
ProjectID string
|
||||
@@ -60,8 +61,12 @@ func (gi *GCPInstaller) Run(ctx context.Context, req GCPRunRequest) error {
|
||||
inst := inst
|
||||
g.Go(func() error {
|
||||
runRequest := gcp.RunCommandRequest{
|
||||
Client: req.Client,
|
||||
InstanceRequest: inst.InstanceRequest(),
|
||||
Client: req.Client,
|
||||
InstanceRequest: gcpimds.InstanceRequest{
|
||||
ProjectID: inst.ProjectID,
|
||||
Zone: inst.Zone,
|
||||
Name: inst.Name,
|
||||
},
|
||||
Script: getGCPInstallerScript(
|
||||
req.ScriptName,
|
||||
req.PublicProxyAddr,
|
||||
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
"github.com/gravitational/teleport/api/types/installers"
|
||||
"github.com/gravitational/teleport/lib/cloud/gcp"
|
||||
gcpimds "github.com/gravitational/teleport/lib/cloud/imds/gcp"
|
||||
"github.com/gravitational/teleport/lib/services"
|
||||
)
|
||||
|
||||
@@ -50,7 +51,7 @@ type GCPInstances struct {
|
||||
// Parameters are the parameters passed to the installation script
|
||||
Parameters []string
|
||||
// Instances is a list of discovered GCP virtual machines.
|
||||
Instances []*gcp.Instance
|
||||
Instances []*gcpimds.Instance
|
||||
}
|
||||
|
||||
// MakeEvents generates MakeEvents for these instances.
|
||||
@@ -143,16 +144,16 @@ func (*gcpInstanceFetcher) GetMatchingInstances(_ []types.Server, _ bool) ([]Ins
|
||||
// GetInstances fetches all GCP virtual machines matching configured filters.
|
||||
func (f *gcpInstanceFetcher) GetInstances(ctx context.Context, _ bool) ([]Instances, error) {
|
||||
// Key by project ID, then by zone.
|
||||
instanceMap := make(map[string]map[string][]*gcp.Instance)
|
||||
instanceMap := make(map[string]map[string][]*gcpimds.Instance)
|
||||
for _, projectID := range f.ProjectIDs {
|
||||
instanceMap[projectID] = make(map[string][]*gcp.Instance)
|
||||
instanceMap[projectID] = make(map[string][]*gcpimds.Instance)
|
||||
for _, zone := range f.Zones {
|
||||
instanceMap[projectID][zone] = make([]*gcp.Instance, 0)
|
||||
instanceMap[projectID][zone] = make([]*gcpimds.Instance, 0)
|
||||
vms, err := f.GCP.ListInstances(ctx, projectID, zone)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
filteredVMs := make([]*gcp.Instance, 0, len(vms))
|
||||
filteredVMs := make([]*gcpimds.Instance, 0, len(vms))
|
||||
for _, vm := range vms {
|
||||
if len(f.ServiceAccounts) > 0 && !slices.Contains(f.ServiceAccounts, vm.ServiceAccount) {
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user