How to Create, Launch, and Terminate EC2 Instance using AWS SDK for .NET

Introduction

 
You may have created many instances using the AWS Console, but if you want to develop applications that consume the AWS services, you must know how to use the SDK provided by AWS. AWS has provided support for almost all the popular programming languages/ frameworks. Today, however, we are going to work with the .NET Core SDK.
 

Prerequisites

  • An AWS account
  • Basic understanding of Amazon EC2
  • Understanding of programming using C# .NET Core
  • Keys to access AWS resources outside the console (If you don’t have them, don’t worry. I’ll show you how to get them later in the tutorial)

Road Map

  1. Creating an ASP.NET Core Web API Project
  2. Installing required packages
  3. Setting up the Controller Class
  4. Creating Services
    • Launch
    • Terminate
  5. Implementing methods
  6. Getting the AWS Access/Secret keys (optional)
  7. Test using Postman
  8. Use Cases

Creating a Web API Project

 
Step 1
 
Open Visual Studio, select Create a New project and select ASP.NET Core Web Application.
 
create-new-project-image 
Step 2
 
Provide a meaningful name and select Create.
 
configure-new-project-image
 
Step 3
 
Select API in the next screen and click on Create.
 
create-new-asp.new-web-application 
 

Installing Required Packages

 
Step 1
 
We will be needing two NuGet packages, the first one is AWSSDK.Extensions.NETCore.Setup.
 
required-packages
 
Step 2
 
Install the second one. The second one is AWSSDK.EC2.
 
AWSSDK.EC2-install-image
 
Step 3
 
Add the following lines of code in the ConfigureServices() method of Startup.cs.
  1. public void ConfigureServices(IServiceCollection services) {  
  2.  services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);  
  3.  services.AddSingleton < IEC2Service, EC2Service > ();  
  4.  services.AddAWSService < IAmazonEC2 > ();  
  5. } 
configure-startup-service-image 
 

Setting up the Controller class

 
Step 1
 
First rename the Controller as EC2InstanceController, remove the auto generated code and the following code (Don’t worry about the errors, we will create IEC2Service interface in a bit).
  1. [Produces("application/json")]  
  2. [Route("api/EC2Instance")]  
  3. [ApiController]  
  4. public class ValuesController: ControllerBase {  
  5.  private readonly IEC2Service _service;  
  6.   
  7.  public EC2InstanceController(IEC2Service service) {  
  8.    _service = service;  
  9.   }  
  10.   [HttpPost("{amiID}")]  
  11.  public async Task < IActionResult > CreateEC2Instance([FromRoute] string amiID) {  
  12.    var response = await _service.CreateInstanceAsync(amiID);  
  13.    return Ok(response);  
  14.   }  
  15.   [HttpDelete("{instanceId}")]  
  16.  public async Task < IActionResult > DeleteEC2Instance([FromRoute] string instanceId) {  
  17.   var response = await _service.TerminateInstanceAsync(instanceId);  
  18.   return Ok(response);  
  19.  }  
  20. }
setting-up-controller-class
 
Step 2
 
Go to launchSettings.json file and delete the following line.
 
setting.json-image
 

Creating Services and Implementing methods

 
Step 1
 
Create a folder named Services in the project.
 
services-folder-creationg-image 
 
Step 2
 
Create an interface IEC2Service in this folder and add the following code.
  1. public interface IEC2Service {  
  2.  Task < EC2Response > CreateInstanceAsync(string amiID);  
  3.  Task < EC2Response > TerminateInstanceAsync(string instanceId);  
  4. } 
creation-interface-image
 
Step 3
 
Create a class EC2Service which will implement this interface, and add the following code.
  1. private readonly IAmazonEC2 _client;  
  2. public EC2Service(IAmazonEC2 client) {  
  3.  _client = client;  
  4.   
  5. } 
creation-service-class-image
 
To remove the error for IAmazonEC2, add the reference of the SDK that we installed earlier.
 
Step 4
 
Create a new folder Models, and add a new class EC2response. This class will be used to send response back from the API. Add the following code in that class.
  1. public class EC2Response {  
  2.  public HttpStatusCode Status {  
  3.   get;  
  4.   set;  
  5.  }  
  6.  public string Message {  
  7.   get;  
  8.   set;  
  9.  }  
  10. } 
model-folder-creationg-image
 
Step 5
 
Let’s implement the first method CreateInstanceAsync().
  1. First we will have to create a security group for that instance, write the following code.
    1. var createRequest = new CreateSecurityGroupRequest {  
    2.  GroupName = "testSecGroup",  
    3.   Description = "My sample security group for EC2-Classic"  
    4. };  
    5.   
    6. var createResponse = await _client.CreateSecurityGroupAsync(createRequest);  
    7.   
    8. var Groups = new List < string > () {  
    9.  createResponse.GroupId  
    10. };  
    11. var describeRequest = new DescribeSecurityGroupsRequest() {  
    12.  GroupIds = Groups  
    13. };  
    14. var describeResponse = await _client.DescribeSecurityGroupsAsync(describeRequest);
    We will use the GroupId of this group later.
    security-group-creation-image
     
  2. Create an IP Range permission in order to connect to this instance using SSH, use the following code.
    1. IpRange ipRange = new IpRange {  
    2.  CidrIp = "1.1.1.1/1"  
    3. };  
    4. List < IpRange > ranges = new List < IpRange > {  
    5.  ipRange  
    6. };  
    7.   
    8. var ipPermission = new IpPermission {  
    9.  IpProtocol = "tcp",  
    10.   FromPort = 22,  
    11.   ToPort = 22,  
    12.   Ipv4Ranges = ranges  
    13. };  
    14.   
    15. var ingressRequest = new AuthorizeSecurityGroupIngressRequest {  
    16.  GroupId = describeResponse.SecurityGroups[0].GroupId  
    17. };  
    18. ingressRequest.IpPermissions.Add(ipPermission);  
    19. var ingressResponse = await _client.AuthorizeSecurityGroupIngressAsync(ingressRequest);
    CidrIp = 1.1.1.1/1 means that it will allow any ip address to connect to the instance from Putty.
    ip-range-permission-image
  3. Create a Key Pair that will be used to connect to the instance with Putty and save in a .pem file. Use the following code.
    1. var request = new CreateKeyPairRequest {  
    2.  KeyName = "testKeyPair"  
    3. };  
    4.   
    5. var response = await _client.CreateKeyPairAsync(request);  
    6. Console.WriteLine();  
    7. Console.WriteLine("New key: " + "testKeyPair");  
    8.   
    9. // Save the private key in a .pem file    
    10. using(FileStream s = new FileStream("privatekeyFike.pem", FileMode.Create))  
    11. using(StreamWriter writer = new StreamWriter(s)) {  
    12.  writer.WriteLine(response.KeyPair.KeyMaterial);  
    13. }
    key-pair-creation-image
     
  4. Now create a launch request and try to run the instance. The AMI ID will be passed from the request, you can use any AMI to launch an instance. Provide the Min, Max count, Instance type, KeyPair and Securitygroup configuration. Use the following code.
    1. string keyPairName = "testKeyPair";  
    2.   
    3. List < string > groups = new List < string > () {  
    4.  describeResponse.SecurityGroups[0].GroupId  
    5. };  
    6. var launchRequest = new RunInstancesRequest() {  
    7.  ImageId = amiID,  
    8.   InstanceType = InstanceType.T2Micro,  
    9.   MinCount = 1,  
    10.   MaxCount = 1,  
    11.   KeyName = keyPairName,  
    12.   SecurityGroupIds = groups,  
    13. };  
    14.   
    15. var launchResponse = await _client.RunInstancesAsync(launchRequest);  
    16.   
    17. return new EC2Response {  
    18.  Message = launchResponse.ResponseMetadata.RequestId,  
    19.   Status = launchResponse.HttpStatusCode  
    20. }; 
    AMI-id-passing-image
     
    Now you are able to create and launch an EC2 instance based on any AMI.
Step 6
 
Let’s implement the second method, TerminateInstanceAsync(string instanceId), which will take instanceId as an input and terminate that instance. Keep in mind that stop and terminate are two different things, you won’t be able to start that instance again if you terminate it.
 
Use the following code.
  1. public async Task < EC2Response > TerminateInstanceAsync(string instanceId) {  
  2.  var request = new TerminateInstancesRequest {  
  3.   InstanceIds = new List < string > () {  
  4.    instanceId  
  5.   }  
  6.  };  
  7.   
  8.  var response = await _client.TerminateInstancesAsync(request);  
  9.  foreach(InstanceStateChange item in response.TerminatingInstances) {  
  10.   return new EC2Response {  
  11.    Message = "Terminated instance: " + item.InstanceId + "--State:" + item.CurrentState.Name,  
  12.     Status = response.HttpStatusCode,  
  13.   
  14.   };  
  15.   
  16.  }  
  17.  return new EC2Response {  
  18.   Status = HttpStatusCode.InternalServerError,  
  19.    Message = "Something Went Wrong"  
  20.  };  
  21. } 
terminate-instance-image 
 

Getting AWS Access/Secret keys (Optional)

 
This step is optional if you already know how to get the keys, or already have the keys configured in the .aws folder. This would be common for people that use AWS CLI. But keep in mind that you can’t connect to AWS outside the management console if you don’t have access keys and you’ll get exceptions and your code won’t work as desired.
  1. The easiest way is to install AWS CLI from the following link https://docs.aws.amazon.com/cli/latest/userguide/install-windows.html
  2. Get your Access/Secret keys by following this link https://help.bittitan.com/hc/en-us/articles/115008255268-How-do-I-find-my-AWS-Access-Key-and-Secret-Access-Key-
  3. Now go to cmd and type the following command and hit enter
  1. aws config 
You’ll be prompted to enter your keys and your default region, e.g.
  1. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  
  2. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  
  3. us-west-2 
Now you’re good to go. Now you can access the resources outside the management console of AWS. 
 

Testing using Postman

 
Now when you have successfully created an API that will launch and terminate an EC2 instance on a REST request, let’s test it using postman.
 
  1. First test the Create Instance (POST) request as follows.
  2. create-instance-post
    See we have a status code of OK which means our instance has been created successfully. Let’s check this out on management console.
  3. Go to the management console and see the result.
    management-console-image
     
    We can see that the instance is created and it is now running.
  4. Let’s copy its Instance ID and try to terminate it using the HTTP DELETE request.
    copy-instanceid-for-terminate
    We have an OK response which means our instance is terminated successfully.
  5. Let’s check this on the management console.
    management-console-test

Use Cases:

  1. Developing any application that needs EC2 instance to be created programmatically
  2. Getting to know how to use the AWS SDK for .NET, .NET Core
  3. Building applications where you need to create security groups or key pairs for other instances using code.

Summary

 
In this article, we learned about how to Create, Launch, and terminate an EC2 instance using AWS SDK for .NET.