Amazon Ec2 Instance Management with C#: Part 1 – Creating a Key Pair

Before getting started

Skill Level: Beginner

Assumptions:

  1. You already have Visual Studio installed.
  2. You are familiar with creating projects in Visual Studio.
  3. We assume you have already gone to AWS and registered with them. If you haven’t done that already, stop and go there now. Amazon has a free tier and you can create an account here: https://aws.amazon.com/free
  4. Some of the points that were discussed in the Amazon S3 article series will not be repeated here.

Additional Information: I sometimes cover small sub-topics in a post. Along with AWS, you will also be exposed to:

  • .NET Core 2.0 – If you use .NET Framework, the steps will be slightly different, but as this is a beginner level tutorial, it should be simple.
  • async, await, Task
  • Rhyous.SimpleArgs
  • Reflection

Note: As this is the first post of a series, there is going to be some setup. If you just want the quick and code, look at the code in Step 3.

EC2 Instance Prerequisites

Before creating an instance, there are some prerequisites. This Part 1 discusses the first of these prerequisites: creating a Key pair.

Step 1 – Create the project

  1. Open Visual Studio.
  2. Go to File | New Project.
  3. Choose Console Application.
    Give it any name you want.
    I am going to call my project Rhyous.AmazonEc2InstanceManager.

Step 2 – Add NuGet Packages

  1. Right-click on your project and choose Management NuGet Packages.
  2. Search for AWSSDK.EC2.
  3. Install the NuGet package and all the dependencies.
  4. Search for System.Configuration.ConfigurationManager.
  5. Install it.
  6. Search for Rhyous.SimpleArgs.
  7. Install it.

Step 3 – Create an InstanceManager.cs file

  1. Create a new class file called InstanceManager.cs.
  2. Add a method to generate the key pair.
  3. Add a method to save the key pair to disc as a .pem file.
  4. using Amazon.EC2;
    using Amazon.EC2.Model;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Threading.Tasks;
    
    namespace Rhyous.AmazonEc2InstanceManager
    {
        public class InstanceManager
        {
            public static async Task<KeyPair> CreateKeyPair(AmazonEC2Client ec2Client, string keyName, bool writePem = false, string keyOutputDirectory = null)
            {
                var keyPair = (await ec2Client.CreateKeyPairAsync(new CreateKeyPairRequest { KeyName = keyName }))?.KeyPair;
                if (writePem)
                    await SaveKeyPairToDisc(keyName, keyOutputDirectory, keyPair);
                return keyPair;
            }
    
            public static async Task SaveKeyPairToDisc(string keyName, string keyOutputDirectory, KeyPair keyPair)
            {
                var path = Path.Combine(keyOutputDirectory, $"{keyName}.pem");
                await File.WriteAllTextAsync(path, keyPair.KeyMaterial);
                Console.WriteLine($"They key pair was saved to: {path}");
            }
        }
    }
    

    Notice: To create the Key pair, we use an instance of an AmazonEC2Client with a simple CreateKeyPairRequest model.
    Notice: Saving the Key pair has really nothing to do with Amazon EC2 Instance management. This is just a simple File.WriteAllTextAsync call.

Step 4 – Create/Edit the App.config

Of course, it is important to know what Amazon Web Services account we are working with, so we will store this in the app.config.

  1. If there isn’t an app.config in your project, create one.
  2. Right-click on your project and choose Add | New Item.
  3. Search for Application Configuration File.
    Rename it to app.config.
  4. Add an appSetting for your AWS profile name.
  5. Add an additional appSetting for your chosen AWS region.
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <appSettings>
        <add key="AWSProfileName" value="yourprofilename"/>
        <add key="AWSRegion" value="us-west-2" />
      </appSettings>
    </configuration>
    

Step 5 – Configure command line Arguments.

We are going to be adding to this program in subsequent posts. For this reason, we are going to use Rhyous.SimpleArgs library for our command line arguments as it provides ready-made command line argument features. If you have been through the S3 series, you will already be familiar with Arguments and the convention we chose to match command line arguments to the method parameter names.
Note: You should have already installed the Rhyous.SimpleArgs NuGet package.

  1. Create an ArgsHandler.cs file to define the arguments:
    Note: If you used a .NET core project you have to create this file. If you created a .NET Framework file, this file should have been created for you and you have but to edit it.
  2. Add an Action argument.
    Note: We are going to keep the exact same convention of having an Action argument that allows us to choose which method to run and for each method and have an Argument to match each method parameter name.

  3. Add an Argument for each dynamic parameter in the CreateKeyPair method.
    • string keyName
    • string keyOutputDirectory

    Note: The AmazonEC2Client parameter is not a dynamic parameter. It is fixed and doesn’t change.

  4. Also, make sure to call Program.OnArgsHandled() in the HandleArgs method.
  5. using Amazon.EC2.Util;
    using Rhyous.SimpleArgs;
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    
    namespace Rhyous.AmazonEc2InstanceManager
    {
        public class ArgsHandler : ArgsHandlerBase
        {
            public override void InitializeArguments(IArgsManager argsManager)
            {
                Arguments.AddRange(new List<Argument>
                {
                    new Argument
                    {
                        Name = "Action",
                        ShortName = "a",
                        Description = "The action to run.",
                        Example = "{name}=default",
                        DefaultValue = "Default",
                        AllowedValues = new ObservableCollection<string>
                        {
                            "CreateKeyPair"
                        },
                        IsRequired = true,
                        Action = (value) =>
                        {
                            Console.WriteLine(value);
                        }
                    },
                    new Argument
                    {
                        Name = "KeyName",
                        ShortName = "k",
                        Description = "A key pair name.",
                        Example = "{name}=MyKeyPair",
                        Action = (value) =>
                        {
                            Console.WriteLine(value);
                        }
                    },
                    new Argument
                    {
                        Name = "keyOutputDirectory",
                        ShortName = "k",
                        Description = "A key pair name.",
                        Example = "{name}=MyKeyPair",
                        Action = (value) =>
                        {
                            Console.WriteLine(value);
                        }
                    }
                });
            }
    
            public override void HandleArgs(IReadArgs inArgsHandler)
            {
                base.HandleArgs(inArgsHandler);
                Program.OnArgumentsHandled();
            }
        }
    }
    

Step 6 – Add the MethodInfoExtension

This has nothing to do with AWS, but we built it in the S3 series, so were are going to use it for this series as well. It is a class file that uses reflection to dynamically detect the needed parameters of our action methods. I am not going to go into it any more that that in this post. I’ve modified this file to work for this project. Just add it to your project. If you want to understand it more, go through the S3 posts.

  1. Create a MethodInfoExtensions.cs.
    using Amazon;
    using Amazon.EC2;
    using Rhyous.SimpleArgs;
    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Reflection;
    
    namespace Rhyous.AmazonEc2InstanceManager
    {
        public static class MethodInfoExtensions
        {
            public static List<object> DynamicallyGenerateParameters(this MethodInfo mi)
            {
                var parameterInfoArray = mi.GetParameters();
                var parameters = new List<object>();
                var region = RegionEndpoint.GetBySystemName(ConfigurationManager.AppSettings["AWSRegion"]);
                foreach (var paramInfo in parameterInfoArray)
                {
                    if (paramInfo.ParameterType == typeof(AmazonEC2Client))
                        parameters.Add(Activator.CreateInstance(paramInfo.ParameterType, region));
                    if (paramInfo.ParameterType == typeof(string))
                        parameters.Add(Args.Value(paramInfo.Name));
                }
    
                return parameters;
            }
        }
    }
    

Step 7 – Edit the Program.cs

  1. Update Program.cs as follows:
    using Rhyous.SimpleArgs;
    using System;
    
    namespace Rhyous.AmazonS3BucketManager
    {
        class Program
        {
            static void Main(string[] args)
            {
                new ArgsManager<ArgsHandler>().Start(args);
            }
    
            internal static void OnArgumentsHandled()
            {
                var bucketName = Args.Value("Bucket");
                var task = BucketManager.CreateBucket(bucketName);
                task.Wait();
            }
        }
    }
    

Now for fun, you can delete the app.config and change them to parameters.

Next: Deleting a key pair
Return to: Managing Amazon AWS with C#

Leave a Reply

How to post code in comments?