go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/connection/ssh/awsinstanceconnect/ec2instanceconnect.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package awsinstanceconnect
     5  
     6  import (
     7  	"context"
     8  	"net"
     9  
    10  	"github.com/aws/aws-sdk-go-v2/aws"
    11  	"github.com/aws/aws-sdk-go-v2/service/ec2"
    12  	ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
    13  	"github.com/aws/aws-sdk-go-v2/service/ec2instanceconnect"
    14  	"github.com/cockroachdb/errors"
    15  	"github.com/sethvargo/go-password/password"
    16  	"go.mondoo.com/cnquery/providers/os/connection/ssh/keypair"
    17  )
    18  
    19  type generator struct {
    20  	cfg aws.Config
    21  }
    22  
    23  func New(cfg aws.Config) *generator {
    24  	return &generator{cfg: cfg}
    25  }
    26  
    27  type InstanceCredentials struct {
    28  	InstanceId      string
    29  	KeyPair         *keypair.SSH
    30  	PublicDnsName   string
    31  	PrivateDnsName  string
    32  	PublicIpAddress string
    33  }
    34  
    35  // Note: target can either be the IP (ipv4) address or the instance id of the machine
    36  func (c *generator) GenerateCredentials(target string, user string) (*InstanceCredentials, error) {
    37  	ctx := context.Background()
    38  	ec2srv := ec2.NewFromConfig(c.cfg)
    39  	input := &ec2.DescribeInstancesInput{}
    40  	ip := net.ParseIP(target)
    41  	if ip != nil && ip.To4() != nil {
    42  		filter := "ip-address"
    43  		input.Filters = []ec2types.Filter{
    44  			{
    45  				Name:   &filter,
    46  				Values: []string{target},
    47  			},
    48  		}
    49  	} else {
    50  		input.InstanceIds = []string{target}
    51  	}
    52  	resp, err := ec2srv.DescribeInstances(ctx, input)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	if len(resp.Reservations) != 1 || len(resp.Reservations[0].Instances) != 1 {
    58  		return nil, errors.New("could not find the instance")
    59  	}
    60  
    61  	instance := resp.Reservations[0].Instances[0]
    62  
    63  	// generate random passphrase
    64  	passphrase, err := password.Generate(64, 10, 10, false, false)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	sshkeypair, err := keypair.NewRSAKeys(keypair.DefaultRsaBits, []byte(passphrase))
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  
    74  	ec2ic := ec2instanceconnect.NewFromConfig(c.cfg)
    75  	_, err = ec2ic.SendSSHPublicKey(ctx, &ec2instanceconnect.SendSSHPublicKeyInput{
    76  		InstanceId:       instance.InstanceId,
    77  		AvailabilityZone: instance.Placement.AvailabilityZone,
    78  		InstanceOSUser:   aws.String(user),
    79  		SSHPublicKey:     aws.String(string(sshkeypair.PublicKey)),
    80  	})
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  
    85  	ic := &InstanceCredentials{
    86  		KeyPair: sshkeypair,
    87  	}
    88  
    89  	if instance.PublicDnsName != nil {
    90  		ic.PublicDnsName = *instance.PublicDnsName
    91  	}
    92  
    93  	if instance.PrivateDnsName != nil {
    94  		ic.PrivateDnsName = *instance.PrivateDnsName
    95  	}
    96  
    97  	if instance.PublicIpAddress != nil {
    98  		ic.PublicIpAddress = *instance.PublicIpAddress
    99  	}
   100  
   101  	if instance.InstanceId != nil {
   102  		ic.InstanceId = *instance.InstanceId
   103  	}
   104  
   105  	return ic, nil
   106  }