O2 Script to create an Amazon EC2 Image
If you want to automate the creation of an EC2 image (for example the O2 Platform one) , here is a script that does that:
Gui Screenshot:
Source Code:
//var topPanel = panel.clear().add_Panel(); var topPanel = "start amazon instance".popupWindow(); var apiKey = @"C:\....\accounts.xml".credential("AmazonAWS"); var amazonEC2 = new API_AmazonEC2(apiKey); var ec2Client = amazonEC2.getEC2Client(); var width = 400; var height = 150; var createPanel = topPanel.add_GroupBox("Create amazon EC2 Instance") .fill(false) .width(width).height(height) .add_Panel(); var imageID = createPanel.add_Label("Image Id:",5,0) .append_Control<ComboBox>() .width(200) .top(0).left(90); imageID.append_Link("View Image's List", ()=>amazonEC2.show_ImagesList_In_TreeView(ec2Client)) .top(5); var imageSize =createPanel.add_Label("Image Size:",30,0) .append_Control<ComboBox>() .dropDownList() .top(25).left(90); var securityGroup = createPanel.add_TextBox(60,"Security Group","").left(90).width(120); var keyName = createPanel.add_TextBox(80,"Pem Key name","").left(90).width(120); var defaultImages = new Dictionary<string,string>(); defaultImages.add("O2 Platform Image", "OWASP O2 Platform - Windows 2008") .add("Amazon Win 2008 32bit IIS+SQL", "Windows-Server2008-i386-SqlExpress-v103") .add("Amazon Win 2008 64bit IIS+SQL", "Windows-2008R2-SP1-English-SQLExpress-v101") .add("Amazon Win 2008 64bit IIS+SQL", "Windows-Server2003R2-i386-SqlExpress-v109") .add("Microsoft Win 2008 64bit IIS+SQL", "Optimized-SQL-Server-2008R2-3-2-11"); imageID.add_Items(defaultImages.keys()); imageSize.add_Items(new List<string> {"m1.small", "t1.micro", "c1.medium","m1.large", "m1.xlarge"}); imageID.select_Item(0); imageSize.select_Item(0); securityGroup.set_Text("O2 Boxes"); keyName.set_Text("O2 Key"); var statusMessage = createPanel.add_Label("...", 90,230); createPanel.add_Button("Launch Image", 60,230) .align_Right(createPanel).widthAdd(-10) .onClick(()=>{ statusMessage.set_Text("...launching image").textColor(Color.DarkBlue); try { var imageId = imageID.get_Text(); if (defaultImages.hasKey(imageId)) imageId = amazonEC2.getImagesList(ec2Client).name(defaultImages[imageId]).ImageId; "using imageId: {0}".info(imageId); var runningInstance = ec2Client.launchInstance(imageId, imageSize.get_Text(), securityGroup.get_Text(), keyName.get_Text()); statusMessage.set_Text("done, created instance: {0}".format(runningInstance.InstanceId)).textColor(Color.DarkGreen); } catch(Exception ex) { statusMessage.set_Text(ex.Message).textColor(Color.Red); ex.log(); } }); return "done"; //here are a number of code snippets that show the multiple methods available in the API_AmazonEC2 //using Amazon.EC2.Model //using Amazon.EC2 //return images.description("WebMatrix Hosting Server provided by Microsoft"); //return images.description_Contains("Amazon Linux"); //return images.amazon().description_RegEx("windows.*32"); //return images.name_Contains("amzn-ami"); //return images.name_RegEx("amzn.*i386"); //return images.imageId("....."); //return images.imageId("ami-9d1043d8"); //return <a href="mailto:images.@public().amazon().windows">images.@public().amazon().windows</a>(); //return <a href="mailto:images.@public().amazon()._32Bit">images.@public().amazon()._32Bit</a>(); //return <a href="mailto:images.@public().amazon()._64Bit">images.@public().amazon()._64Bit</a>(); //return <a href="mailto:images.@public().amazon">images.@public().amazon</a>(); //return <a href="mailto:images.@public().microsoft">images.@public().microsoft</a>(); //return <a href="mailto:images.@public()._32Bit">images.@public()._32Bit</a>(); //return <a href="mailto:images.@public()._64Bit">images.@public()._64Bit</a>(); //return <a href="mailto:images.@private">images.@private</a>(); //return <a href="mailto:images.@private">images.@private</a>(); //amazonEC2.show_ImagesList_In_TreeView(ec2Client,topPanel); return "ok"; //O2File:API_AmazonEC2.cs //O2Ref:AWSSDK.dll
O2 Platform EC2 Image
Note: if you want to use the Amazon Web Interface to start the O2 AMI, here is how to find it (NOTE that this is in US West):
O2 Platform Amazon EC2 Image (AMI)
If you want to take O2 for a test drive and don’t have a windows box (or VM) at hand, now you can use Amazon EC2.
Here are the steps to take:
- Login to Amazon AWS account,
- Go to EC2 (if needed choose the desired region)
- Go to the Instances Section
- Click on ‘Launch Instance
- Search for O2 (the full name of this AMI is ‘727618846505/OWASP O2 Platform – Windows 2008’)
- Click Select (and follow the wizard till the end)
After a couple minutes, you will be able to RDP into your VM.
The default administrator password is: mK-jv7sj@L
After login, start O2 so that it updates the rules, and you are all set 🙂
Let me know if you have any issues using this Amazon EC2 image
Using ‘Amazon S3 Browser’ script to upload files to Amazon S3
If you have an Amazon S3 account (http://aws.amazon.com/s3/) then you might find useful to use the ‘Amazon S3 Browser.h2’ script to upload files to the S3 servers (you can also create folders and delete files)
To upload files, select the target foldder (top left treeview) and just drop the desired file on the the bottom left treeview (the red color indicates that the file is being uploaded)
When the upload has completed, the bottom treeview will refresh and show the uploaded file there:
To get the link to the file, click on it and copy it from the top right textbox
For small files (like images or html files) you can get a quick preview by selecting the ‘Auto Preview Selected File’ checkbox
Note that when you upload files using this GUI/Script the file permission will be set to public (the default is to make it private).
The ‘Amazon S3 Browser.h2‘ script (shown below) consumes the API_AmazonS3.cs file and is mainly focused on building the GUI:
//O2Ref:WatiN.Core.1x.dll var topPanel = O2Gui.open<Panel>("Amazon S3 Browser",700,400); var autoPreviewSelectedFile = false; var amazonS3 = new API_AmazonS3(); </pre> topPanel.add_Label("Logging in to S3", 150,300); amazonS3.login(); topPanel.clear(); var statusLabel = topPanel.parentForm().add_StatusStrip(); statusLabel.set_Text("Welcome to O2's Amazon S3 Browser (click on folder to see files)"); var foldersTreeView = topPanel.add_TreeView() .showSelection(); var previewArea = foldersTreeView.insert_Right<Panel>(topPanel.width() /2 ).add_1x1("Selected File Url", "Selected File Contents",false, 65) ; var previewPanel = previewArea[1]; var selectFile = previewArea[0].add_TextBox().fill(); previewArea[0].add_CheckBox("Auto Preview selected File (to see single files just press enter above)",40,4, (value) => autoPreviewSelectedFile = value).autoSize(); var filesTreeView = foldersTreeView.insert_Below<TreeView>(topPanel.height()/2) .showSelection(); MethodInvoker refreshFolders = ()=>{ foldersTreeView.clear(); foldersTreeView.add_Nodes(amazonS3.folders()); }; MethodInvoker refreshFileView = ()=>{ amazonS3.showFilesInTreeView(filesTreeView, foldersTreeView.selected().get_Text()); }; foldersTreeView.insert_Below<Panel>(25) .add_LabelAndTextAndButton("New folder name:", "", "create", (newFolderName)=> { statusLabel.set_Text("Creating folder:{0}".format(newFolderName)); if (amazonS3.create_Folder(newFolderName).valid()) { foldersTreeView.clear(); foldersTreeView.add_Nodes(amazonS3.folders()); }; }); filesTreeView.onDrop( (fileOrFolder)=>{ if (fileOrFolder.isFile()) { filesTreeView.backColor(Color.LightPink); O2Thread.mtaThread( ()=>{ statusLabel.set_Text("adding file:{0}".format(fileOrFolder)); var currentFolder = foldersTreeView.selected().get_Text(); amazonS3.add_S3_Object(currentFolder, fileOrFolder); amazonS3.showFilesInTreeView(filesTreeView, currentFolder); statusLabel.set_Text("Done"); filesTreeView.backColor(Color.White); }); } }); var foldersContextMenu = foldersTreeView.add_ContextMenu(); var filesContextMenu = filesTreeView.add_ContextMenu(); //menu actions foldersContextMenu.add_MenuItem("Delete Folder", ()=>{ var folderToDelete = foldersTreeView.selected().get_Text(); if ("Are you sure you want to Delete the folder: {0}".format(folderToDelete).askUserQuestion()) if (amazonS3.delete_Folder(folderToDelete).valid()) { statusLabel.set_Text("Deleting folder:{0}".format(folderToDelete)); refreshFolders(); } }); filesContextMenu.add_MenuItem("Delete File", ()=>{ //filesTreeView.SelectedNode = var currentFolder = foldersTreeView.selected().get_Text(); var fileToDelete = filesTreeView.selected().get_Text(); if ("Are you sure you want to Delete the file: {0}".format(fileToDelete).askUserQuestion()) { statusLabel.set_Text("Deleting File:{0}".format(fileToDelete)); if (amazonS3.delete_File(currentFolder, fileToDelete).valid()) amazonS3.showFilesInTreeView(filesTreeView, currentFolder); } }); // events foldersTreeView.afterSelect<string>( (folder) =>{ statusLabel.set_Text("Showing files in folder: {0}".format(folder)); refreshFileView(); }); filesTreeView.afterSelect<Uri>( (uri)=> { var url = uri.str(); "url: {0}".info(url); statusLabel.set_Text("Showing details for file: {0} ".format(url)); selectFile.set_Text(url); if (autoPreviewSelectedFile) amazonS3.showFileInControl(previewPanel, uri); }); selectFile.onEnter( (url)=> { amazonS3.showFileInControl(previewPanel, url.uri()); }); // ContextMenu filesContextMenu.add_MenuItem("Refresh", refreshFileView); var folders = amazonS3.folders(); foldersTreeView.add_Nodes(folders); amazonS3.showFilesInTreeView(filesTreeView,""); return "done"; //using O2.External.IE.ExtensionMethods //O2File:API_AmazonS3.cs //O2Ref:AWSSDK.dll //O2Ref:O2_External_IE.dll //O2Ref:System.Xml.dll //O2Ref:System.Xml.Linq.dll
New Amazon EC2 ‘image filtering focused’ Extension Methods
I just added a number of extension methods to the O2 Amazon EC2 API that help to easily find images
Here are the new ‘image filtering focused’ extension methods in action
var apiKey = @"C:\O2\_USERDATA\accounts.xml".credential("AmazonAWS"); var amazonEC2 = new API_AmazonEC2(apiKey); var ec2Client = amazonEC2.getEC2Client(); amazonEC2.CachedImageListRequest = @"C:\O2\_tempDir\4-16-2011\tmp8DC3.tmp.xml"; var images = amazonEC2.getImagesList(ec2Client); //return images.description("WebMatrix Hosting Server provided by Microsoft"); //return images.description_Contains("Amazon Linux"); return images.amazon().description_RegEx("windows.*32"); //return images.name("WebMatrixHostingServer"); //return images.name_Contains("amzn-ami"); //return images.name_RegEx("amzn.*i386"); </pre> //return images.imageId("....."); //return images.imageId("ami-9d1043d8"); //return images.@public().amazon().windows(); //return images.@public().amazon()._32Bit(); //return images.@public().amazon()._64Bit(); //return images.@public().amazon(); //return images.@public().microsoft(); //return images.@public()._32Bit(); //return images.@public()._64Bit(); //return images.@private(); //return images.@private();
And here is the class added to the O2 Amazon EC2 API
public static class API_AmazonEC2_ExtensionMethods_Images { //Visibility public static List<Image> @public(this List<Image> images) { return images.where(image=>image.Visibility == "Public"); } public static List<Image> @private(this List<Image> images) { return images.where(image=>image.Visibility == "Private"); } //Architecture public static List<Image> _32Bit(this List<Image> images) { return images.where(image=>image.Architecture == "i386"); } public static List<Image> _64Bit(this List<Image> images) { return images.where(image=>image.Architecture == "x86_64"); } //ImageOwnerAlias public static List<Image> amazon(this List<Image> images) { return images.where(image=>image.ImageOwnerAlias == "amazon"); } public static List<Image> microsoft(this List<Image> images) { return images.where(image=>image.ImageOwnerAlias == "microsoft"); } //Platform public static List<Image> windows(this List<Image> images) { return images.where(image=>image.Platform == "windows"); } //ImageId public static Image imageId(this List<Image> images, string imageId) { return images.where(image=>image.ImageId == imageId).first(); } //Name public static Image name(this List<Image> images, string name) { return images.where(image=>image.Name == name).first(); } public static List<Image> name_Contains(this List<Image> images, string name) { return images.where(image=>image.Name.contains(name)); } public static List<Image> name_RegEx(this List<Image> images, string name) { return images.where(image=>image.Name.regEx(name)); } //Description public static Image description(this List<Image> images, string description) { return images.where(image=>image.Description == description).first(); } public static List<Image> description_Contains(this List<Image> images, string description) { return images.where(image=>image.Description.contains(description)); } public static List<Image> description_RegEx(this List<Image> images, string description) { return images.where(image=>image.Description.regEx(description)); } //this quite an expensive operation (3M of data retrieved) - so I added caching support public static List<Image> getImagesList(this API_AmazonEC2 amazonEC2, AmazonEC2Client ec2Client) { if (amazonEC2.CachedImageListRequest.fileExists()) return amazonEC2.CachedImageListRequest.load<List<Amazon.EC2.Model.Image>>(); var describeImagesRequest = new DescribeImagesRequest(); "Retrieving ImagesList from Amazon..".info(); var images = ec2Client.DescribeImages(describeImagesRequest) .DescribeImagesResult.Image; if (images.isNull() || images.size()==0) { "in getImagesList, there was an error retrieving list (are we online?)".error(); } else { amazonEC2.CachedImageListRequest = images.save(); "The Image List was saved to : {0}".info(amazonEC2.CachedImageListRequest); } return images; } }
I also made a change in the formula used to populate the TreeView with the available images so that the images with the same name are all grouped together
Script to view Amazon EC2 Images List
I just added a couple new methods to the O2’s Amazon EC2 API which provide details about the available AMIs (Amazon Machine Images).
The new capabilities are now avaialble on the Amazon EC2 Browser:
… click on the View Available Images (AMIs) link a
…which will popup a new window:
… that will load the data from Amazon (the blue color indicates that it is fetching data):
To help to navigate through the large amount of AMIs available, a couple filters were added:
When expanded will show the list of Images on that category , and when clicked on a AMI node, its details will show on the right:
Source code
Here is how to consume directly this feature
var apiKey = @"C:\O2\_USERDATA\accounts.xml".credential("AmazonAWS"); var amazonEC2 = new API_AmazonEC2(apiKey); var ec2Client = amazonEC2.getEC2Client(); </pre> amazonEC2.show_ImagesList_In_TreeView(ec2Client); //O2File:API_AmazonEC2.cs //O2Ref:AWSSDK.dll
the code above has no cache support, which is show below:
var apiKey = @"C:\O2\_USERDATA\accounts.xml".credential("AmazonAWS"); var amazonEC2 = new API_AmazonEC2(apiKey); var ec2Client = amazonEC2.getEC2Client(); </pre> amazonEC2.CachedImageListRequest = @"C:\O2\_tempDir\4-16-2011\tmp8DC3.tmp.xml"; amazonEC2.show_ImagesList_In_TreeView(ec2Client); //O2File:API_AmazonEC2.cs //O2Ref:AWSSDK.dll
Here are the new methods thare were added to O2’s Amazon EC2 API :
//this quite an expensive operation (3M of data retrieved) - so I added caching support public static List<Image> getImagesList(this API_AmazonEC2 amazonEC2, AmazonEC2Client ec2Client) { if (amazonEC2.CachedImageListRequest.fileExists()) return amazonEC2.CachedImageListRequest.load<List<Amazon.EC2.Model.Image>>(); var describeImagesRequest = new DescribeImagesRequest(); "Retrieving ImagesList from Amazon..".info(); var images = ec2Client.DescribeImages(describeImagesRequest) .DescribeImagesResult.Image; if (images.isNull() || images.size()==0) { "in getImagesList, there was an error retrieving list (are we online?)".error(); } else { amazonEC2.CachedImageListRequest = images.save(); "The Image List was saved to : {0}".info(amazonEC2.CachedImageListRequest); } return images; }</pre> public static List<Image> show_ImagesList_In_TreeView(this API_AmazonEC2 amazonEC2) { return amazonEC2.show_ImagesList_In_TreeView(amazonEC2.getEC2Client()); } public static List<Image> show_ImagesList_In_TreeView(this API_AmazonEC2 amazonEC2, AmazonEC2Client ec2Client) { return amazonEC2.show_ImagesList_In_TreeView(ec2Client, "Amazon EC2 Images List".popupWindow()); } public static List<Image> show_ImagesList_In_TreeView(this API_AmazonEC2 amazonEC2, AmazonEC2Client ec2Client, Control control) { var treeView = control.clear().add_TreeView_with_PropertyGrid(false).sort(); treeView.backColor(System.Drawing.Color.Azure); Application.DoEvents(); var imagesList = amazonEC2.getImagesList(ec2Client); Func<Amazon.EC2.Model.Image,string> imageName = (image)=> (image.Description.valid()) ? "{0} - {1}".format(image.Description, image.Name) : "{0}".format(image.Name); Action<string> mapByProperty = (propertyName)=>{ var visibilityNode = treeView.add_Node("by {0}".format(propertyName)); foreach(var visibility in imagesList.Select((image)=>image.property(propertyName).str()).Distinct()) visibilityNode.add_Node(visibility) .add_Nodes(imagesList.Where((image) => image.property(propertyName).str() == visibility), imageName); }; mapByProperty("Visibility"); mapByProperty("ImageOwnerAlias"); mapByProperty("Platform"); mapByProperty("Architecture"); "Completed processing show_ImagesList_In_TreeView".info(); if (treeView.nodes().size()>0) treeView.backColor(System.Drawing.Color.White); return imagesList; }
Using the O2’s Amazon EC2 API
Here are a number of code snippets that show how to use the O2’s Amazon EC2 API.
All scripts should be executed from an O2 Script Editor (ideally a ‘Quick Development Gui’ since we will be using the provided panel in a couple examples:
Getting a fully logged-in AmazonEC2Client instance
var apiKey = @"C:\O2\_USERDATA\accounts.xml".credential("AmazonAWS"); var amazonEC2 = new API_AmazonEC2(apiKey); var ec2Client = amazonEC2.getEC2Client(); return ec2Client.typeName(); //O2File:API_AmazonEC2.cs //O2Ref:AWSSDK.dll
Getting a fully logged-in AmazonEC2Client instance in a specific region
The previous example connects to the default region on this API, which is set to
DefaultRegion = "us-west-1";
If you want to open a specific region, you can specify it as a parameter to the getEC2Client method. This next example returns is equivalent to the previous one
var amazonEC2 = new API_AmazonEC2(apiKey); var ec2Client = amazonEC2.getEC2Client(amazonEC2.DefaultRegion); return ec2Client;
and this one will connect to the europan EC2 data center:
var amazonEC2 = new API_AmazonEC2(apiKey); var ec2Client = amazonEC2.getEC2Client("eu-west-1"); return ec2Client;
Retrieve list of Instances in default region
var amazonEC2 = new API_AmazonEC2(apiKey); return amazonEC2.getEC2Instances();
Retrieve list of Instances in all regions
var amazonEC2 = new API_AmazonEC2(apiKey); return amazonEC2.getEC2Instances(false);
Visualize in a TreeView the data received from the getEC2Instances
var amazonEC2 = new API_AmazonEC2(apiKey); var instancesData = amazonEC2.getEC2Instances(); var instancesViewer = topPanel.add_TreeView(); foreach(var instanceMapping in instancesData) instancesViewer.add_Node(instanceMapping.Key) .add_Nodes(instanceMapping.Value , (runningInstance)=>amazonEC2.getRunningInstanceSignature(runningInstance));
Get an Instance Object
To get an instance object you will need to drill the object returned from the getEC2Instances method
var amazonEC2 = new API_AmazonEC2(apiKey); var instance = amazonEC2.getEC2Instances().Values.First()[0]; return instance;
View Instance details – Mode 1
var amazonEC2 = new API_AmazonEC2(apiKey); var instancesData = amazonEC2.getEC2Instances(); var instance = amazonEC2.getEC2Instances().Values.First()[0]; instance.showInfo();
View instance details – Mode 2
var amazonEC2 = new API_AmazonEC2(apiKey); var instancesData = amazonEC2.getEC2Instances(); var instance = amazonEC2.getEC2Instances().Values.First()[0]; instance.details();
Starting and Stopping Instances
var amazonEC2 = new API_AmazonEC2(apiKey); var instancesData = amazonEC2.getEC2Instances(); var instance = amazonEC2.getEC2Instances().Values.First()[0]; amazonEC2.startInstance(instance); amazonEC2.stopInstance(instance);
Viewing Console Out in separate window
var amazonEC2 = new API_AmazonEC2(apiKey); var instancesData = amazonEC2.getEC2Instances(); var instance = amazonEC2.getEC2Instances()["SI Boxes"][1]; amazonEC2.showConsoleOut(instance);
Retrieving Instance Password
var amazonEC2 = new API_AmazonEC2(apiKey); var instancesData = amazonEC2.getEC2Instances(); var instance = amazonEC2.getEC2Instances()["SI Boxes"][2]; amazonEC2.ApiRsa = new API_RSA(); return amazonEC2.getPassword(instance);
If you don’t provide the path of a PEM file in the API_RSA(…) constructor you will be prompt for it
once you provide the PEM key, you can see the fetched data in the Log Viewer
or in the case of the script above, in the Invoke and Result output TextArea
New Amazon EC2 .Net API
I just refactored the Amazon EC2 Browser so that most of its scripts are now in the API_AmazonEC2.cs file (which is a great API to access Amazon EC2 images)
This is what the new version of the Amazon EC2 Browser tool looks like (I added support for decrypting the Instance’s passwords using a *.pem file)
You can open it by executing the Tool – Amazon EC2 Browser.h2 script
Amazon_EC2.cs
This is what the Amazon_EC2.cs API looks like
// This file is part of the OWASP O2 Platform (<a href="http://www.owasp.org/index.php/OWASP_O2_Platform">http://www.owasp.org/index.php/OWASP_O2_Platform</a>) and is released under the Apache 2.0 License (<a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>) using System; using System.Threading; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Windows.Forms; using System.Text; using O2.Kernel; using O2.Kernel.ExtensionMethods; using O2.DotNetWrappers.DotNet; using O2.DotNetWrappers.ExtensionMethods; using O2.Views.ASCX.ExtensionMethods; using O2.Views.ASCX.classes.MainGUI; using O2.XRules.Database.Utils; using O2.External.SharpDevelop.ExtensionMethods; using Amazon.EC2; using Amazon.EC2.Model;</pre> //O2Ref:AWSSDK.dll //O2File:ascx_AskUserForLoginDetails.cs //O2File:API_GuiAutomation.cs //O2File:API_RSA.cs //O2File:_Extra_methods_To_Add_to_Main_CodeBase.cs namespace O2.XRules.Database.APIs { public class API_AmazonEC2 { public ICredential ApiKey { get; set; } public string DefaultRegion { get; set; } public API_RSA ApiRsa { get; set; } public int TimerCount = 60; public int TimerSleep = 60 * 1000; public API_AmazonEC2() : this(null) { } public API_AmazonEC2(ICredential apiKey) { DefaultRegion = "us-west-1";//"eu-west-1"; if (apiKey.isNull()) apiKey = ascx_AskUserForLoginDetails.ask(); ApiKey = apiKey; } } public static class API_AmazonEC2_ExtensionMethods { public static List<string> getEC2Regions(this API_AmazonEC2 amazonEC2) { var ec2Client = new AmazonEC2Client(amazonEC2.ApiKey.UserName, amazonEC2.ApiKey.Password); return (from region in ec2Client.DescribeRegions(new DescribeRegionsRequest()) .DescribeRegionsResult.Region select region.RegionName).toList(); } public static AmazonEC2Client getEC2Client(this API_AmazonEC2 amazonEC2, string region) { return new AmazonEC2Client(amazonEC2.ApiKey.UserName, amazonEC2.ApiKey.Password, new AmazonEC2Config() {ServiceURL = "<a href="http://%7b0%7d.ec2.amazonaws.com%22.format(region/">http://{0}.ec2.amazonaws.com".format(region</a>)}); } public static List<Reservation> getReservationsInRegion(this API_AmazonEC2 amazonEC2, string region) { "Gettting Reservations in region: {0}".info(region); var ec2ClientInRegion = amazonEC2.getEC2Client(region); var describesInstance = new DescribeInstancesRequest(); var reservations = ec2ClientInRegion.DescribeInstances(describesInstance) .DescribeInstancesResult .Reservation; return reservations; } public static Dictionary<string,List<RunningInstance>> getEC2Instances(this API_AmazonEC2 amazonEC2,bool onlyShowDefaultRegion) { var instances = new Dictionary<string,List<RunningInstance>>(); var reservations = new List<Reservation>(); if (onlyShowDefaultRegion) reservations.add(amazonEC2.getReservationsInRegion(amazonEC2.DefaultRegion)); else foreach(var region in amazonEC2.getEC2Regions()) reservations.add(amazonEC2.getReservationsInRegion(region)); foreach(var reservation in reservations) foreach(var runningInstance in reservation.RunningInstance) instances.add(reservation.GroupName.Aggregate((a, b) => a + ',' + b), runningInstance); return instances; } } public static class API_AmazonEC2_ExtensionMethods_RunningInstance { public static RunningInstance startInstance(this API_AmazonEC2 amazonEC2, RunningInstance runningInstance) { "Starting instance with ID: {0}".info(runningInstance.InstanceId); var ec2Client = amazonEC2.getEC2Client(runningInstance.Placement.AvailabilityZone.removeLastChar()); var result = ec2Client.StartInstances(new StartInstancesRequest() .WithInstanceId(runningInstance.InstanceId)); return runningInstance; } public static RunningInstance stopInstance(this API_AmazonEC2 amazonEC2, RunningInstance runningInstance) { "Stopping instance with ID: {0}".info(runningInstance.InstanceId); var ec2Client = amazonEC2.getEC2Client(runningInstance.Placement.AvailabilityZone.removeLastChar()); var result = ec2Client.StopInstances(new StopInstancesRequest() .WithInstanceId(runningInstance.InstanceId)); return runningInstance; } public static RunningInstance showConsoleOut(this API_AmazonEC2 amazonEC2, RunningInstance runningInstance) { "Getting Console out instance with ID: {0}".info(runningInstance.InstanceId); var ec2Client = amazonEC2.getEC2Client(runningInstance.Placement.AvailabilityZone.removeLastChar()); var consoleOutResult = ec2Client.GetConsoleOutput(new GetConsoleOutputRequest() .WithInstanceId(runningInstance.InstanceId)); var consoleOut = consoleOutResult.GetConsoleOutputResult.ConsoleOutput.Output.base64Decode(); consoleOut.showInCodeViewer(".bat"); return runningInstance; } public static string getPassword(this API_AmazonEC2 amazonEC2, RunningInstance runningInstance) { "Tests on instance with ID: {0}".info(runningInstance.InstanceId); var ec2Client = amazonEC2.getEC2Client(runningInstance.Placement.AvailabilityZone.removeLastChar()); var passwordResponse = ec2Client.GetPasswordData(new GetPasswordDataRequest().WithInstanceId(runningInstance.InstanceId)); "raw password data : {0}".info(passwordResponse.GetPasswordDataResult.ToXML()); var decryptedPassword = amazonEC2.ApiRsa.decryptPasswordUsingPem(passwordResponse.GetPasswordDataResult.PasswordData.Data); "decrypted password: {0}".info(decryptedPassword); return decryptedPassword; } public static string getRunningInstanceSignature(this API_AmazonEC2 amazonEC2, RunningInstance runningInstance) { var signature = "{0} - {1} - {2} - {3} - {4} ".format( runningInstance.InstanceId, runningInstance.InstanceType, runningInstance.IpAddress, runningInstance.Placement.AvailabilityZone, runningInstance.InstanceState.Name); foreach(var tag in runningInstance.Tag) //signature = "{0}= {1} - {2}".format(tag.Key, tag.Value, signature); signature = "{1} - {2}".format(tag.Key, tag.Value, signature); return signature; } } public static class API_AmazonEC2_ExtensionMethods_GUIs { public static API_AmazonEC2 addStopInstanceGui(this API_AmazonEC2 amazonEC2, Panel targetPanel, TreeView treeViewWithInstances) { Action startTimer = null; Action stopTimer = null; var instancesToStop = targetPanel.add_GroupBox("Stop Instance in {0} minutes".format((amazonEC2.TimerCount * amazonEC2.TimerCount / 60))) .add_TreeView(); var timerBar = instancesToStop.insert_Below(20).add_ProgressBar(); instancesToStop.add_ContextMenu().add_MenuItem("Stop now",true, ()=>{ "Stopping {0} instances now".debug(instancesToStop.nodes().size()); foreach(var node in instancesToStop.nodes()) amazonEC2.stopInstance((RunningInstance)node.get_Tag()); }) .add_MenuItem("Clear list", ()=>instancesToStop.clear()); var startTimerLink = instancesToStop.insert_Above(15).add_Link("Add instance to list",0,0, ()=>{ var selectedNode = treeViewWithInstances.selected(); if (selectedNode.notNull()) { var tag = selectedNode.get_Tag(); if (tag is RunningInstance) { var selectedInstance = (RunningInstance)tag; var nodeText = "{0} - {1}".format(selectedInstance.InstanceId, selectedInstance.IpAddress); instancesToStop.add_Node(nodeText, selectedInstance); } } //treeViewWithInstances.nodes().showInfo(); }) .append_Link("Start timer", ()=>startTimer()); var timerEnabled = false; var stopTimerLink = startTimerLink.append_Link("Stop timer", ()=>stopTimer()).enabled(false); startTimer = ()=>{ "starting timer".info(); timerEnabled = true; timerBar.maximum(amazonEC2.TimerCount); timerBar.value(0); startTimerLink.enabled(false); stopTimerLink.enabled(true); while(timerEnabled && timerBar.Value < amazonEC2.TimerCount) { "In StopInstances Timer [{0}/{1}], sleeping for {2} seconds".info(timerBar.Value, amazonEC2.TimerCount, amazonEC2.TimerSleep/1000); timerBar.sleep(amazonEC2.TimerSleep, false); timerBar.increment(1); } if (timerEnabled) { "Timer is completed stopping {0} instances now".debug(instancesToStop.nodes().size()); foreach(var node in instancesToStop.nodes()) amazonEC2.stopInstance((RunningInstance)node.get_Tag()); } else "Timer was stopped so nothing to do".debug(); startTimerLink.enabled(true); stopTimerLink.enabled(false); }; stopTimer = ()=>{ "stopping timer".info(); timerEnabled = false; startTimerLink.enabled(true); stopTimerLink.enabled(false); }; targetPanel.onClosed(()=> timerEnabled=false); return amazonEC2; } } }
Tool – Amazon EC2 Browser.h2
And here it the refactored code that creates the GUI that is show in the Tool – Amazon EC2 Browser.h2 script (before all of the above code was inside the script below: )
//var topPanel = panel.clear().add_Panel(); var topPanel = O2Gui.open<Panel>("AmazonEC2",580,400); topPanel.insert_Below(100).add_LogViewer(); var apiKey = @"C:\O2\_USERDATA\accounts.xml".credential("AmazonAWS"); var amazonEC2 = new API_AmazonEC2(apiKey); Action<RunningInstance> rdpIntoBox = (runningInstance)=>{ "Creating RDP connection to instance with ID: {0} and IP ".info(runningInstance.InstanceId,runningInstance.IpAddress ); new API_RDP().launchRdpClient(runningInstance.IpAddress); };</pre> /*Action<RunningInstance> testInstance = (runningInstance)=>{ "Tests on instance with ID: {0}".info(runningInstance.InstanceId); var ec2Client = getEC2Client(runningInstance.Placement.AvailabilityZone.removeLastChar()); var passwordResponse = ec2Client.GetPasswordData(new GetPasswordDataRequest().WithInstanceId(runningInstance.InstanceId)); "password: {0}".info(passwordResponse.GetPasswordDataResult.ToXML()); "Done".info(); }; */ Action<Panel> showRunningInstancesDetails = (targetPanel)=> { var treeView = targetPanel.add_GroupBox("Amazon EC Instances").add_TreeView(); var actionsPanel = treeView.insert_Below(100); treeView.beforeExpand<List<RunningInstance>>( (treeNode, runningInstanceList) =>{ treeNode.clear(); treeNode.add_Nodes(runningInstanceList , (runningInstance)=>amazonEC2.getRunningInstanceSignature(runningInstance)); foreach(var node in treeNode.nodes()) if (node.get_Text().contains("stopped")) node.color(Color.DarkGreen); else if (node.get_Text().contains("running")) node.color(Color.DarkRed); else node.color(Color.DarkBlue); }); Action<bool> refresh = (onlyShowDefaultRegion)=>{ treeView.backColor(Color.Azure); O2Thread.mtaThread( ()=>{ var ec2Instances = amazonEC2.getEC2Instances(onlyShowDefaultRegion); treeView.clear(); treeView.add_Nodes(ec2Instances.keys(), (text)=>text, (text) => ec2Instances.value(text), (text) => ec2Instances.value(text).size() > 0); treeView.selectFirst().selected().expand().nodes()[0].selected(); treeView.backColor(Color.White); }); }; actionsPanel.add_Link("Refresh Instances list (default Region)", 0,0, ()=> refresh(true)).click(); actionsPanel.add_Link("Refresh Instances list (all Regions)",20,0, ()=> refresh(false)); RunningInstance selectedInstance = null; actionsPanel.add_Link("Show Instance Details", 40,0, ()=> selectedInstance.details()); actionsPanel.add_Link("View Instance Console Out", 60,0, ()=> amazonEC2.showConsoleOut(selectedInstance)); var link = actionsPanel.add_Link("Show Decrypted password ", 80,0, ()=> amazonEC2.getPassword(selectedInstance)); actionsPanel.add_Link("Start Instance ", 0,220, ()=> amazonEC2.startInstance(selectedInstance)); actionsPanel.add_Link("Stop Instance ", 20,220, ()=> amazonEC2.stopInstance(selectedInstance)); actionsPanel.add_Link("RDP Instance ", 40,220, ()=> rdpIntoBox(selectedInstance)); amazonEC2.addStopInstanceGui(actionsPanel.insert_Right(240),treeView); /*var link = actionsPanel.add_Link("Test request Instance ", 80,220, ()=> testInstance(selectedInstance)); O2Thread.mtaThread(()=>{ link.sleep(1000); link.click(); });*/ treeView.afterSelect<RunningInstance>((runningInstance)=> selectedInstance = runningInstance); }; showRunningInstancesDetails(topPanel); //O2File:API_AmazonEC2.cs //O2File:API_RDP.cs //using Amazon.EC2 //using Amazon.EC2.Model //O2Ref:AWSSDK.dll //O2File:ascx_AskUserForLoginDetails.cs //O2Ref:White.Core.dll
Solved the problem with decryping AmazonEC2 Instance’s password
I was able to solve the problem I had with decrypting the AmazonEC2 instance’s password.
Here is the code that is part of the API_AmazonEC2.cs script
public static string getPassword(this API_AmazonEC2 amazonEC2, RunningInstance runningInstance) { "Tests on instance with ID: {0}".info(runningInstance.InstanceId); var ec2Client = amazonEC2.getEC2Client(runningInstance.Placement.AvailabilityZone.removeLastChar()); var passwordResponse = ec2Client.GetPasswordData(new GetPasswordDataRequest().WithInstanceId(runningInstance.InstanceId)); "raw password data : {0}".info(passwordResponse.GetPasswordDataResult.ToXML()); var decryptedPassword = amazonEC2.ApiRsa.decryptPasswordUsingPem(passwordResponse.GetPasswordDataResult.PasswordData.Data); "decrypted password: {0}".info(decryptedPassword); return decryptedPassword; }
which calls the ApiRsa.decryptPasswordUsingPem(passwordResponse.GetPasswordDataResult.PasswordData.Data) method from the newly created API_RSA.cs script:
// This file is part of the OWASP O2 Platform (<a href="http://www.owasp.org/index.php/OWASP_O2_Platform">http://www.owasp.org/index.php/OWASP_O2_Platform</a>) and is released under the Apache 2.0 License (<a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>) using System; using System.IO; using System.Text; using O2.Kernel; using O2.Kernel.ExtensionMethods; using O2.DotNetWrappers.ExtensionMethods; using O2.DotNetWrappers.Windows; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Encodings; using Org.BouncyCastle.OpenSsl; using Org.BouncyCastle.Crypto.Engines; //O2Ref:itextsharp.dll //O2Ref:O2_DotNetWrappers.dll //O2Ref:O2_Kernel.dll</pre> namespace O2.XRules.Database.APIs { public class API_RSA { public string PathToPemKey { get;set;} public API_RSA() {} public API_RSA(string pathToPemKey) { PathToPemKey = pathToPemKey; } public string decryptPasswordUsingPem(string password) { try { var passwordBytes = Convert.FromBase64String(password); AsymmetricCipherKeyPair keyPair; PathToPemKey = PathToPemKey ?? "Where is the PEM private Key".askUser(); using (var reader = File.OpenText(PathToPemKey)) keyPair = (AsymmetricCipherKeyPair) new PemReader(reader).ReadObject(); var decryptEngine = new Pkcs1Encoding(new RsaEngine()); decryptEngine.Init(false, keyPair.Private); var decryptedPassword = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(passwordBytes, 0, passwordBytes.Length)); return decryptedPassword; } catch(Exception ex) { "[API_RSA] in decryptPasswordUsingPem: {0}".error(ex.Message); return ""; } } } }
Trying to Decrypt Amazon EC2 password using BouncyCastle and it is not working
For O2’s Amazon EC2 Browser, I was adding the ability to decrypt the Instance’s Password (retrieved using the AWSSDK.dll GetPassswordDataRequest) but I can’t seem to decrypt its value, any ideas on how to do it?
Here is my the code that doesn’t work (uses BouncyCastle API)
var bytesToDecrypt = Convert.FromBase64String("...");</pre> AsymmetricCipherKeyPair keyPair; var pemFile = @"C:\...\SI_Key.pem"; using (var reader = File.OpenText(pemFile)) { keyPair = (AsymmetricCipherKeyPair) new PemReader(reader).ReadObject(); var decryptEngine = new Pkcs1Encoding(new RsaEngine()); decryptEngine.Init(false, keyPair.Private); var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length)); return decrypted; }
When that code executes I get the following error:
at Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.DecodeBlock(Byte[] input, Int32 inOff, Int32 inLen) at Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.ProcessBlock(Byte[] input, Int32 inOff, Int32 length) at DynamicType.dynamicMethod(Object returnData, Panel panel) StackTrace:</pre> at Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.DecodeBlock(Byte[] input, Int32 inOff, Int32 inLen) at Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.ProcessBlock(Byte[] input, Int32 inOff, Int32 length)
(the above code sample was based on this StackOverflow answer: http://stackoverflow.com/questions/243646/how-to-read-a-pem-rsa-private-key-from-net)
Amazon EC2 Browser – Timer to Stop Instances
When using the new O2 Amazon EC browser tool (which works really well and is really helping me to better manage my EC2 usage), I reallized that what I really wanted was a way to stop instances after a certain period.
The problem is that Amazon EC2 can be quite expensive if we leave the instances running for a while (and in a lot of cases they are not needed to be up for longer periods of time). The lack of automatically stopping instances (after a while) was really preventing me from trying a couple ‘high performace’ instances (since they can be up to 11USD per day).
The solution was to add a feature to the O2 Amazon EC browser where we could set-up a timer that would stop the instances after 1h (60m), with the ability to reset the clock if we wanted more time).
This feature is now availbale on the latest version of the Tool – Amazon EC2 Browser.h2 O2 script (see ‘Stop Instances in 60 minutes panel on the bottom right):
This will also allow me to better manage the O2 images that I am providing to the O2 Subscribers