Checking out AWS CodeCommit

Recently the git cloud server landscape became very interesting with the announcement by GitHub that the new pricing would be much more friendly toward users with many private repositories.

Recently the git cloud server landscape became very interesting with the announcement by GitHub that the new pricing would be much more friendly toward users with many private repositories.

Probably one reason for this is that the alternatives out there for low cost git hosting keep expanding, and GitHub must have seen the writing on the wall that it needed to get less stingy about private repositories.

But while GitHub is the most well known cloud repo offering, it’s not the only game in town. BitBucket, GitLab, and Microsoft Visual Studio Online are among other highly respectable code repository hosting platforms I’ve used that offer compelling services at similar prices.

Last year Amazon introduced its own Git-based repo offering, called CodeCommit. I’ve been intending to try it out, and finally have gotten around to it. Based on my initial experience, I’m glad I did!

AWS CodeCommit

I suspect one of the reasons pushing GitHub in th direction of free private repos is the introduction of CodeCommit by AWS last year. CodeCommit offers a very economical solution for private repos based on its uber-dependable AWS public cloud hosting platform.

While AWS isn’t providing all that GitHub has on offer — yet — it’s still a viable alternative for the basics of git hosting, and like everything else in AWS will probably evolve to compete beyond core functions over time.

The rest of this post is just a quick test I decided to do to create an XCode git repo on AWS CodeCommit in a similar way that I would usually do with GitHub. Then a quick summary with some thoughts at the end.

Uploading SSH Keys & Setting up IAM

As with GitHub and other git hosting services, the first step is to have a user account, and upload your public SSH key to that account.

Since CodeCommit is on AWS, the user account you need is an IAM Account. I already had one in my AWS account, so all I needed to do was to create a new SSH key pair on my Mac, add the public key to my IAM account on AWS, and add my IAM user to the policies as outlined in the getting started guide.

I found this process more complex than the same configuration on GitHub or BitBucket. For those not already familiar with AWS policies and the general flow of AWS portal administration, this could be off-putting. While I don’t ever remember reading the detailed instructions on GitHub (and I survived just fine), you definitely can’t skip reading the AWS CodeCommit documentation (though it is brief and well illustrated, so not a big chore). On the other hand, AWS is offering quite a bit more granular control and security with its platform — this is a trade-off. For my part I’ll gladly take extra security control in exchange for the effort of learning how to configure it.

Updating the SSH config file

The local side of the SSH authentication is to update the file ~/.ssh/config to let git know which private key to use when connecting to the CodeCommit server. These entries are similar to what you would have done using GitHub or BitBucket. Same process — this is a git thing, not an AWS thing.

Follow the instructions in points 10 and 11 in the the getting started guide, which explains how to do this quite clearly: CodeCommit Getting Started Guide. Thanks again AWS for great documentation!

Creating a shell repo

I tend to create a repo on a cloud provider’s system, and then connect my local git repo to it as a remote. CodeCommit supports this just like other providers. It also supports creating a remote and pulling the local from there — just like the providers.

Overall if you’ve used GitHub, this part of the process will feel very familiar.

Creating the repo can be done from the web console, which I found very simple. Alternatively, it can be done from the AWS CLI, which I found quite convenient, and easier to illustrate in a blog post, so I’ll use CLI from here.

My next step was to enter the command to create a repo, executed from any folder on my Mac:

$ aws codecommit create-repository --repository-name Test1 --repository-description "Quick test repo"

CodeCommit responded as such.

"Quick test repo" { "repositoryMetadata": { "repositoryName": "Test1", "cloneUrlSsh": "ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/Test1", "lastModifiedDate": 1463989097.607, "repositoryDescription": "Quick test repo", "cloneUrlHttp": "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/Test1", "creationDate": 1463989097.607, "repositoryId": "e889d5cf-7c80-498e-ba56-884b468eba97", "Arn": "arn:aws:codecommit:us-east-1:************:Test1", "accountId": "*************" } }

So far, so good. Note the cloneUrlSsh, which is used n subsequent steps.

Connecting the XCode Project

I created my original project with XCode, and ticked the box to create a local git repository — so my local git work is 99% done, and all I need to do is add CodeConnect as a remote repo to the local one XCode created for me. Again, I’ll do that at the command line, but this time executed from the XCode project folder:

$ git remote add origin ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/Test1

There’s no response to this command, but for the curious, the effect of it can be checked in the .git/config file underneath the project folder:

[core] bare = false filemode = true ignorecase = true precomposeunicode = true logallrefupdates = true [core] repositoryformatversion = 0 [remote "origin"] url = ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/Test1 fetch = +refs/heads/*:refs/remotes/origin/*

Pushing the content

With all the setup complete, the proof is in the ability to push the repo content into AWS. Just for good measure, I’ll add files, execute a first commit, and then a push.

$ git add . $ git commit -m "First commit" $ git push origin master

Adding the ssh key passphrase to keychain

I did encounter one glitch — when trying to use git to push to the repo to the remote, I encountered a public key error, and my ssh key passphrase was failing to add to keychain via the interactive popup dialog box. To overcome this, I manually added the passphrase to keychain.

/usr/bin/ssh-add -k ~/.ssh/rob_kerr_aws_ssh

After the manual key add, the push worked just fine, and lightning fast:

Counting objects: 25, done. Delta compression using up to 4 threads. Compressing objects: 100% (21/21), done. Writing objects: 100% (25/25), 11.74 KiB | 0 bytes/s, done. Total 25 (delta 1), reused 0 (delta 0) remote: To ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/Test1 * [new branch] master -> master

Confirming the files made it to the remote repo

At this point all seemed to be OK, and the experience very much like using GitHub, BitBucket, or even a repo on OSX Server.

Just to check, I took a peek at the repo from the AWS portal — and found my files in the remote repo as expeted:

Generally I like AWS CodeCommit. Granted this entire try-out took just a few minutes, and I haven’t evaluated the full breadth of features nor used CodeCommit in a real project workflow as yet. But, for what it does, it looks pretty great, and the [CodeCommit pricing](CodeCommit pricing) for my use case would effectively be free — even less than the $7/month GitHub now charges for unlimited private repos on individual accounts.

Will I be switching to CodeCommit? Possibly. While GitHub provides more features and a more mature portal experience, at first glance CodeCommit seems to have the basic block and tackle hosted git covered, and the free tier limits seem to give me plenty of headroom. I’m happy to save some coin without losing many features I use. And since I use AWS already, I wouldn’t mind having one less cloud services account to keep track of.

Tutorial: Using Amazon AWS S3 storage with your iOS Swift App

While the Amazon Mobile SDK documentation is very complete, it can be confusing for someone getting started. Like any backend service, AWS has a lot of moving parts, and you need to get them all working together before your app works.

While the Amazon Mobile SDK documentation is very complete, it can be confusing for someone getting started. Like any backend service, AWS has a lot of moving parts, and you need to get them all working together before your app works.

This tutorial will get you started using Amazon AWS by building an iOS app using XCode 6 and Apple Swift that reads data from the AWS S3 (Simple Storage Service). Of course your production app will need to do much more than this, and all of those other function points will build on the setup we’ll do in this tutorial. Ready? Let’s get started!

Overview of the process

To have your app up and running reading from S3, there are a few things you need to do. The first is to create an Amazon developer ID. I assume you’ve done this already, but if not, head over to the Amazon AWS developer home page, and click the orange Try AWS for Free button at the top-right of the page. Then come back to this tutorial so we can get started.

Here’s a summary of what we’ll do in this tutorial to get things working:

  • Create an S3 Bucket
  • Upload some images into the S3 Bucket
  • Create a Cognito Identity pool for the app to use
  • Use IAM to authorize the app to read from the S3 bucket
  • Setup our XCode environment to use the Amazon Mobile SDK for iOS
  • Code the app so it can access the AWS S3 bucket via the SDK

It sounds like a lot of steps (and it is!). But just follow along, and you’ll have an app working against AWS in no time!

Amazon S3 works a lot like a cloud-based file system. The basic unit of storage you’ll use is a “Bucket”. A bucket is analogous to a hard disk volume. Typically you create a bucket to store data for your application. You can also create folders within buckets. You can’t create buckets within buckets, though — just as you can’t create hard disks within hard disks.

User authorizations are created against the bucket, and we’ll create a single authorization policy for all users of the tutorial app. In this application we’ll create a bucket, and store some images in the bucket (without folders). Our app will be authorized to access the images via a Cognito identity pool.

Create an S3 Bucket

First head over to the AWS Management Console, and click on the S3 link under Storage and Content Delivery.

In the popup window, provide a unique Bucket Name for the bucket, select your preferred AWS Region, and then click on the Create button.

The Bucket Name you select must be unique among all users (not just within your own account). You can prepend the bucket name with characters that are specific to your company to make it less frustrating to create unique names.

With the bucket created, let’s upload a few images to use in our application. From the S3 console, click on the name of the bucket you just created, and then click on the Upload button.

Next select a file from your computer to upload and save it. I’ve uploaded a single image to the S3 bucket. After you save the file, it will be in the S3 bucket list, as below.

At this point we have a bucket with a file to display in our iOS app. Next we need to create an authorization using Cognito so the mobile app will be able to read the file from the bucket.

Cognito is the AWS authorization facility used to provide remote application authentication for AWS resources. Once a user is authorized with Cognito, the Identity and Access Management service is used to map authorizations between Cognito authorized users and AWS resources.

Cognito can support both unauthenticated and authenticated users simultaneously. It can delegate authentication to various Identity systems, like Google, Twitter and your custom authentication provider to meet various requirements.

In this introductory tutorial, we’ll use an unauthenticated identity — essentially letting anyone who uses our app to access the image we put in the S3 bucket. This is common for B2C applications. Layering user authentication on top of this design can certainly be done without changing the basic design of the app.

With that introduction, let’s setup Cognito! First navigate back to the AWS Management Console, and then click the link to Cognito underneath the Mobile Services heading.

At the top of the Amazon Cognito console, click the New Identity Pool button.

On the first step screen:

  • Give the identity pool a name (which must be unique in your account)
  • Click the checkbox to allow unauthenticated identities. This will enable us to authorize our app to read from the S3 bucket without authenticating users with an authentication provider
  • Click the create pool button

If our application was to be restricted to authenticated users only, we would use the to define Public, OpenID and/or Developer Authenticated Identities sections to integrate Cognito with the authentication provider we chose to use.

On the next screen (step 2), by default you’ll create two Identity and Access Management (IAM) roles — one for authenticated users, and the other for unauthenticated users. As you can probably guess, authenticated users can have different privileges to AWS resources than unauthenticated ones. In an application like ours, we might allow unauthenticated users to view images, but only authenticated users to upload images.

The default settings on this screen are fine and the names are sensible for our purposes. Review the screen, and click the Update Roles button.

Next we need to authorize app users who use the Cognito role we created to have read access to the image we uploaded to the S3 bucket.

Head over to the IAM Management Console, click on the Roles link in the left-hand navigation, then click on the unauthenticated role you created in the previous step (in this example it’s called Cognito_s3tutorialUnauth_DefaultRole).

On the next screen, you can see the role and policies that were assigned when the role was created. By default, there is a role policy that allows user profile data to be saved.

Before going further, make a note of the Role ARN, and copy it to the clipboard, then save it in a text editor. You’ll need this later when configuring your iOS application in XCode.

Once you copy the ARN, click the Create Role Policy button to create the role that will allow reading of the S3 bucket images.

The Set Permissions form allows you to use a Policy Generator or a Custom Policy. Click the Select button to choose the former option so we can use a configuration GUI to generate the policy instead of typing in the JSON syntax by hand.

In the Policy Generator make the following selections:

  • Select Amazon S3 as the AWS Service
  • Select only the GetObject action
  • Enter the ARN for the S3 bucket we created, in this format: arn:aws:s3:::com.mobiletoolworks.s3tutorial/*
  • Click the Add Statement button.
  • After you click this button, the statement will be added to a table underneath the entry fields
  • Verify the statement looks correct, and then click the Next Step button

The next page shows you a JSON version of the policy created in the dialog box.
Click the Apply Policy button.

After you Apply the Policy, you’re returned to the role summary screen. Note the new policy you added for the application is now listed in the Policy list at the bottom of the form.

Create the XCode Project

Now that we have the AWS Backend Service created and configured, let’s create our iOS Application and configure it to read from the S3 Bucket.

Launch XCode, select File/New Project, select Single View Application, and click the Next button.

Give your project a name, set the language to Swift, choose iPhone as the device, clear the User Core Data checkbox and click the Next button.

Use CocoaPods to add AWS frameworks

Next we need to add the Amazon AWS frameworks to the XCode project. You can download frameworks and add them manually if you like, but it’s much easier to use the CocoaPods dependency manager to do it for you.

If you don’t have CocoaPods configured on your system, follow these instructions to configure your XCode environment to use it.

Create a file named “podfile” in your project root folder, and add the following lines to it:

source 'https://github.com/CocoaPods/Specs.git' pod 'AWSiOSSDKv2'

Then close XCode, open a terminal window, and navigate to the folder where you created your podfile.

From that folder, type the following command to have CocoaPods:

Now wait while CocoaPods downloads the AWS SDK (and dependencies), and configures your XCode workspace.

After the workspace is configured, note the instruction on the console that you should now open your project by double-clicking on the .xcworkspace file rather than the .xcodeproj file as you did previously.

Double-click the .xcworkspace file to re-open the XCode project. Note how CocoaPods has configured the AWS runtime libraries for you within the XCode workspace.

Since we’re using Swift, and the AWS libraries are actually Objective-C, we need to create a bridging header, and configure the project for it.

First, add a bridging header to you iPhone app. I’ve called mine “BridgingHeader.h”, but you can use any name you like.

To configure the project to use the Bridging Header, click on your iPhone app target, click on Build Settings, and search for the word “Bridging”. Then change the setting for Objective-C Bridging Header to the name you gave your Bridging Header file.

The project is now configured for AWS, so next let’s implement some code to connect to AWS, download and display the file we uploaded at the beginning!

Connecting to AWS

Since our objective is to retrieve the image file uploaded to the S3 bucket, the first thing we’ll do is put a UIImageView on the main screen’s view controller so we can display the image once we have it.

Open your Main.storyboard, drag an Image View from the Object Library on to the main View Controller Scene. Then create an outlet in the ViewController class for the UIImageView. I assume you know how to do this, so I won’t go through all the steps in detail.

Now that you have a UIImageView where the image will be displayed, replace the viewDidLoad() method with the following. Of course, this is just a tutorial — a production application wouldn’t do all of this in viewDidLoad, but this will at least let you test your AWS connection and make sure you’ve got the hang of configuring your project and can use Swift to connect to AWS services.

class ViewController: UIViewController { @IBOutlet weak var imageView: UIImageView! override func viewDidLoad() { super.viewDidLoad() // Hard-coded names for the tutorial bucket and the file uploaded at the beginning let s3BucketName = "com.mobiletoolworks.s3tutorial" let fileName = "MobileToolworks-Logo.jpg" let downloadFilePath = NSTemporaryDirectory().stringByAppendingPathComponent(fileName) let downloadingFileURL = NSURL.fileURLWithPath(downloadFilePath) // Set the logging to verbose so we can see in the debug console what is happening AWSLogger.defaultLogger().logLevel = .Verbose // Create a credential provider for AWS requests let credentialsProvider = AWSCognitoCredentialsProvider.credentialsWithRegionType( AWSRegionType.USEast1, accountId: "999999999999", identityPoolId: "us-east-1:ac328da6-63f3-4748-9b8f-25b564422968", unauthRoleArn: "arn:aws:iam::696446148911:role/Cognito_s3tutorialUnauth_DefaultRole", authRoleArn: "arn:aws:iam::696446148911:role/Cognito_s3tutorialAuth_DefaultRole") // Create a service configuration for AWS requests let defaultServiceConfiguration = AWSServiceConfiguration( region: AWSRegionType.USEast1, credentialsProvider: credentialsProvider) // Create a new download request to S3, and set its properties AWSServiceManager.defaultServiceManager() .setDefaultServiceConfiguration(defaultServiceConfiguration) let downloadRequest = AWSS3TransferManagerDownloadRequest() downloadRequest.bucket = s3BucketName downloadRequest.key = fileName downloadRequest.downloadingFileURL = downloadingFileURL let transferManager = AWSS3TransferManager.defaultS3TransferManager() transferManager.download(downloadRequest).continueWithBlock { (task: BFTask!) -> AnyObject! in if task.error != nil { println("Error downloading") println(task.error.description) } else { // Set the UIImageView to show the file that was downloaded let image = UIImage(contentsOfFile: downloadFilePath) self.imageView.image = image } return nil } // end closure }

When you run your program, it will make an asynchronous connection to the AWS S3 service to fetch the file previously uploaded. The file will be downloaded to the iOS temporary folder, and then loaded into the Image View Controller.

There will be a delay while all this happens, and in a production application you should make sure the user experience is excellent even while waiting for content to load over the network.

We set the AWS logging to “verbose”, so you can read through the debug console to see the various things happening under the hood:

You should see the message “Download Complete” that we put into our code, as well as various status and update messages from the AWS SDK as it makes progress.

In the iOS simulator, you should finally see the image we uploaded to S3, giving a visual confirmation that the entire process worked successfully!

Whew! We made it! There were a lot of steps, but now that you’ve got the hang of configuring AWS and XCode to work together, you’re well on your way to building more apps and using more AWS services within XCode!


Originally published at rekerrsive.ghost.io on February 14, 2015.