In this tutorial, we will look at how we can use the AWS Go SDK to perform various operations on AWS EC2.

Table of contents

Prerequisites

  • Install AWS Go SDK: Run go get -u github.com/aws/aws-sdk-go/... to install the SDK
  • AWS Credentials: If you haven’t setup AWS credentials before, this resource from AWS is helpful.

How to create an EC2 key pair?

A key pair consists of a private key and a public key. A Key Pair is required to securely access an EC2 instance. We will be storing the generated private key on our computer where Amazon stores the public key.


package main

import (
	"os"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"

	"fmt"
)

func CreateKeyPair(client *ec2.EC2, keyName string) (*ec2.CreateKeyPairOutput, error) {
	result, err := client.CreateKeyPair(&ec2.CreateKeyPairInput{
		KeyName: aws.String(keyName),
	})

	if err != nil {
		return nil, err
	}

	return result, nil
}

func WriteKey(fileName string, fileData *string) error {
	err := os.WriteFile(fileName, []byte(*fileData), 0400)
	return err
}


func main() {
	sess, err := session.NewSessionWithOptions(session.Options{
		Profile: "default",
		Config: aws.Config{
			Region: aws.String("us-west-2"),
		},
	})

	if err != nil {
		fmt.Printf("Failed to initialize new session: %v", err)
		return
	}

	ec2Client := ec2.New(sess)

	keyName := "ec2-go-tutorial-key-name"
	createRes, err := CreateKeyPair(ec2Client, keyName)
	if err != nil {
		fmt.Printf("Couldn't create key pair: %v", err)
		return
	}

	err = WriteKey("/tmp/aws_ec2_key.pem", createRes.KeyMaterial)
	if err != nil {
		fmt.Printf("Couldn't write key pair to file: %v", err)
		return
	}
	fmt.Println("Created key pair: ", *createRes.KeyName)
}

The function above creates an EC2 key pair with the name ec2-go-tutorial-key-name and then stores that locally at /tmp/ec2-go-tutorial-key-name.pem with the 400 permissions that will be needed when we use the private key to access the EC2 instance.

How to list all existing KeyPairs?

We will be using the DescribeKeyPairs method from the SDK to list all of the existing Key Pairs in the AWS account.


package main

import (
	"os"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"

	"fmt"
)

func DescribeKeyPairs(client *ec2.EC2) (*ec2.DescribeKeyPairsOutput, error) {
	result, err := client.DescribeKeyPairs(nil)
	if err != nil {
		return nil, err
	}

	return result, err
}


func main() {
	sess, err := session.NewSessionWithOptions(session.Options{
		Profile: "default",
		Config: aws.Config{
			Region: aws.String("us-west-2"),
		},
	})

	if err != nil {
		fmt.Printf("Failed to initialize new session: %v", err)
		return
	}

	ec2Client := ec2.New(sess)

	keyPairRes, err := DescribeKeyPairs(ec2Client)
	if err != nil {
		fmt.Printf("Couldn't fetch key pairs: %v", err)
		return
	}

	fmt.Println("Key Pairs: ")
	for _, pair := range keyPairRes.KeyPairs {
		fmt.Printf("%s \n", *pair.KeyName)
	}
}


How to create a new EC2 instance using AWS Go SDK?

Requirements for creating an EC2 instance

  • ImageId: An Amazon Machine Image (AMI) is required to launch an EC2 instance. You can either use one of the freely available AMIs provided by Amazon or create your own. For this tutorial, we will use the Amazon Linux 2 AMI in us-west-2. /assets/img/boto3-ec2/ami.png
  • MinCount: Minimum number of EC2 instances to create
  • MaxCount: Maximum number of EC2 instances to create
  • InstanceType: The instance type for the EC2 instance. Information about all the instance types is available here.
  • KeyName: The name of the key pair that will be used to access the EC2 instance. If no KeyName is specified, we won’t be able to SSH into the EC2 instance.
  • SecurityGroupIds: Security groups allow you to control access into and out of your EC2 instance.
  • IamInstanceProfile: The name of the IAM profile that will be attached to the EC2 instance.

Information on all available parameters is available in the SDK docs.

package main

import (
	"os"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"

	"fmt"
)

func CreateInstance(client *ec2.EC2, imageId string, minCount int, maxCount int, instanceType string, keyName string) (*ec2.Reservation, error) {
	res, err := client.RunInstances(&ec2.RunInstancesInput{
		ImageId:      aws.String(imageId),
		MinCount:     aws.Int64(int64(minCount)),
		MaxCount:     aws.Int64(int64(maxCount)),
		InstanceType: aws.String(instanceType),
		KeyName:      aws.String(keyName),
	})

	if err != nil {
		return nil, err
	}

	return res, nil
}


func main() {
	sess, err := session.NewSessionWithOptions(session.Options{
		Profile: "default",
		Config: aws.Config{
			Region: aws.String("us-west-2"),
		},
	})

	if err != nil {
		fmt.Printf("Failed to initialize new session: %v", err)
		return
	}

	ec2Client := ec2.New(sess)

	keyName := "ec2-go-tutorial-key-name"
	instanceType := "t4g.nano"
	minCount := 1
	maxCount := 1
	imageId := "ami-0b0154d3d8011b0cd"
	newInstance, err := CreateInstance(ec2Client, imageId, minCount, maxCount, instanceType, keyName)
	if err != nil {
		fmt.Printf("Couldn't create new instance: %v", err)
		return
	}

	fmt.Printf("Created new instance: %v\n", newInstance.Instances)
}

In this example, we create an EC2 instance using the t4g.nano instance type and the key pair we created earlier.


Created new instance: [{
  AmiLaunchIndex: 0,
  Architecture: "arm64",
  CapacityReservationSpecification: {
    CapacityReservationPreference: "open"
  },
  ClientToken: "A9A3CDC5-BF00-461B-BACA-EA0F34D2B174",
  CpuOptions: {
    CoreCount: 2,
    ThreadsPerCore: 1
  },
  EbsOptimized: false,
  EnaSupport: true,
  EnclaveOptions: {
    Enabled: false
  },
  Hypervisor: "xen",
  ImageId: "ami-0b0154d3d8011b0cd",
  InstanceId: "i-083af8ae3eb0ea1dc",

  ....

How to list all running EC2 instances?

We will use the DescribeInstances method to get a list of all running instances. We will use the Filters arguments to only return instances that are in the Running state.

package main

import (
	"os"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"

	"fmt"
)

func GetRunningInstances(client *ec2.EC2) (*ec2.DescribeInstancesOutput, error) {
	result, err := client.DescribeInstances(&ec2.DescribeInstancesInput{
		Filters: []*ec2.Filter{
			{
				Name: aws.String("instance-state-name"),
				Values: []*string{
					aws.String("running"),
				},
			},
		},
	})

	if err != nil {
		return nil, err
	}

	return result, err
}


func main() {
	sess, err := session.NewSessionWithOptions(session.Options{
		Profile: "default",
		Config: aws.Config{
			Region: aws.String("us-west-2"),
		},
	})

	if err != nil {
		fmt.Printf("Failed to initialize new session: %v", err)
		return
	}

	ec2Client := ec2.New(sess)

	runningInstances, err := GetRunningInstances(ec2Client)
	if err != nil {
		fmt.Printf("Couldn't retrieve running instances: %v", err)
		return
	}

	for _, reservation := range runningInstances.Reservations {
		for _, instance := range reservation.Instances {
			fmt.Printf("Found running instance: %s\n", *instance.InstanceId)
		}
	}
}

Output:

Found running instance: i-01f702b40bba89a19

How to stop an EC2 instance?

An EC2 instance can be shut down using the StopInstances method. AWS doesn’t charge for stopped EC2 instances (except for any EBS volumes).

package main

import (
	"os"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"

	"fmt"
)

func StopInstance(client *ec2.EC2, instanceId string) error {
	_, err := client.StopInstances(&ec2.StopInstancesInput{
		InstanceIds: []*string{&instanceId},
	})

	return err
}

func main() {
	sess, err := session.NewSessionWithOptions(session.Options{
		Profile: "default",
		Config: aws.Config{
			Region: aws.String("us-west-2"),
		},
	})

	if err != nil {
		fmt.Printf("Failed to initialize new session: %v", err)
		return
	}

	ec2Client := ec2.New(sess)

	instanceId := "i-01f702b40bba89a19"
	err = StopInstance(ec2Client, instanceId)
	if err != nil {
		fmt.Printf("Couldn't stop instance: %v", err)
	}

	fmt.Println("Stopped instance with id: ", instanceId)
}


Stopped instance with id: i-01f702b40bba89a19

How to terminate an EC2 instance?

We will use the TerminateInstances method to terminate and remove EC2 instances.

package main

import (
	"os"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"

	"fmt"
)

func TerminateInstance(client *ec2.EC2, instanceId string) error {
	_, err := client.TerminateInstances(&ec2.TerminateInstancesInput{
		InstanceIds: []*string{&instanceId},
	})

	return err
}

func main() {
	sess, err := session.NewSessionWithOptions(session.Options{
		Profile: "default",
		Config: aws.Config{
			Region: aws.String("us-west-2"),
		},
	})

	if err != nil {
		fmt.Printf("Failed to initialize new session: %v", err)
		return
	}

	ec2Client := ec2.New(sess)

	instanceId := "i-01f702b40bba89a19"
	err = TerminateInstance(ec2Client, instanceId)
	if err != nil {
		fmt.Printf("Couldn't terimate instance: %v", err)
	}

	fmt.Println("Terminated instance with id: ", instanceId)
}


Terminated instance with id: i-01f702b40bba89a19