Painless Code-Signing Assets

Lyndsey Ferguson
6 min readJul 28, 2020

--

Background

As I wrote in “Bring Customers Joy With Automation,” we at Appian need to create customized versions of our Appian mobile application for our customers.

To create these customized applications for iOS, we need several pieces of information from each customer (as required by Apple’s Developer website):

  • A p12 file, which is a special file format that contains a private key¹ and a certificate generated by Apple. It is used as part of the code-signing process of an app.
  • A provisioning profile which is embedded into the mobile application and serves to control how the application can be distributed via the App Store, an Intranet, or Xcode; it also controls onto which devices the mobile app can be installed.
  • Another provisioning profile and a copy of their APNS key if they want push notifications. An APNS key is a private key that is used to authenticate with the Apple Push Notification service.

Prior to our efforts to automate the process, our customers used to follow a 20-page document to manually create the assets we needed to customize their application and code sign it.

The Problem

Customers found the whole process very confusing — there was far too much to read, the instructions assumed technical familiarity, and correctly packaging up the files was difficult. This is not what our customers signed up for. They wanted to build low-code applications, not become code-signing experts.

We needed to simplify the process and target the source of most problems: generating the code-signing assets.

The Concept

What we needed was an automated way for our customers to access their Apple Developer Account and securely create only the correctly formatted files that we needed. We already knew that the open source platform fastlane could automate every aspect of deploying and releasing Android and iOS apps. As a huge fan² of fastlane, my first thought was, “why can’t we just use fastlane? It does everything!”.

Let’s take a look at what we did and find out where I was wrong: fastlane does not do everything 🤪.

The Pretty Result

As I wrote in Bring Customers Joy With Automation, we made a tool called the Appian Provisioner that generates the code-signing and provisioning assets for the customer. We wrote it in Bash so that it can run on any Mac computer and we didn’t have to worry about missing dependencies. We installed it into a signed Disk Image³ so that the customer can be confident that they are running a script that came from us.

The script file performs the following steps:

  • Install (or update) the Command Line Tools on their Mac⁴ to use tools that are not installed by default.
  • Install a known version of fastlane to ensure that the customer has a bug free installation of that toolset.
  • Authenticate with Apple to create files within Apple’s Developer site.
  • Create a new bundle id⁵ or select an existing bundle id to update attributes associated with it. See fastlane’s Spaceship::Portal::App to learn how to do this.
  • Create an App Group⁶ to tie together the mobile app and the Push Notification service so that they can communicate securely. See fastlane’s produce action for more information.
  • Create a certificate using fastlane’s cert tool. It requires a private key and its associated password. We wanted to secure that password, so the script creates a random password and encrypts it with a public key that only Appian’s automated system can decrypt.
  • Create the provisioning profile for the app using fastlane’s sigh tool. Also create the provisioning profile for the Push Notification service (if it was requested).
  • Create a compressed zip file which contains a keychain with the private key and certificate, an encrypted copy of the keychain password, the provisioning profiles, an encrypted copy of the APNS key, and a manifest file describing which configuration options the customer chose.
An animation of the Appian Provisioner starting up

When the customer uploads those files to Appian, we can instruct our automated system to open up the file and safely store the files in our secure backend.

The Pain

So that was the pretty version of the story. I’m going to pull the curtain all the way back and reveal the pain behind this approach.

  1. We had to manage two processes. The “frontend” is written in Bash to manage the coordination of calls to fastlane. Each time we need something from fastlane, it makes a call that starts a second process.
    This approach is problematic whenever fastlane needs to prompt the user for more information. The Bash script has to wait for fastlane to respond in pre-programmed ways and anticipate what it expects. As we didn’t build the backend, it was difficult at first to capture all the possible ways that fastlane would request information.
    The script had to act as a real-time translator from techno-speak to human speech. Not only does it have to anticipate the changes that may happen, debugging problems can be tricky as both processes have to be examined to find the root cause of any bugs.
  2. Users must have a Mac to use the Apple tools that our Bash script and fastlane rely on. For some, this is an unexpected and unwanted cost.
  3. Users found the Terminal interface scary and intimidating. They felt like they were “hacking.” Think The Matrix:
Jahbor’s Digital Rain used in the movie, The Matrix
The Appian Provisioner script feels like hacking

We did what we could to make the Appian Provisioner visually appealing and simple, but users would have been much more comfortable with what we show in our other Appian environments: a nice, curated user interface that keeps the options simple and self-evident.

The Dream

I’ve laid out the pain that we experienced with our chosen approach, but we did benefit from the lessons. Most importantly, we found that for our limited needs, we could have just used the underlying technology that fastlane interacts with to build the code signing and provisioning assets.

Fastlane uses Apple-provided REST endpoints to login, request certificates and provisioning profiles, build application bundle ids, and associate them with iCloud and Push Notifications. Instead of a desktop application that only runs on a Macintosh, we could provide an interactive website that communicates with the same REST endpoints to create all of the assets necessary for code-signing and provisioning a mobile application. This would have the added benefit of working from any desktop computer or mobile device with internet connectivity.

A potential Appian website application

Using these lessons, we’re planning to improve this feature as the backlog and our priorities allow us to focus on it. Apple is always improving their REST framework for this system, so we at Appian may be able to take advantage of those updates when we resume work on this feature.

The Conclusion

This should give you an idea of how we built up this automated system in the event that you want to do something similar. I’ve shared with you the problems with the approach that we chose. When you are going to use a technology in a different environment from its intended one, consider how you are going to handle the communication issues. Can you use its underlying technology to better effect to reduce the friction between systems?

If you have any questions, please feel free to ask in the Comments section below. And, if you find this kind of work interesting and want to work with creative, passionate, and smart people, there are plenty of other projects to work on like this at Appian. Apply today!

Notes

[1]: A private key is used to generate a public key that was bundled in a Certificate Signing Request (CSR). https://en.wikipedia.org/wiki/Certificate_signing_request

[2]: I’m such a huge fan of fastlane, that I converted Appian’s entire build system from bash to fastlane, I’ve contributed back to fastlane, and I’ve built the popular fastlane plugin, test_center.

[3]: https://stackoverflow.com/a/52244477/71877

[4]: We used this Ansible Role, ansible-osx-command-line-tools, as a reference to write up our own Bash method to ensure that the Command Line Tools are installed.

[5] bundle ids: identifiers that are unique to each application in the App Store. Usually of the form of com.your-company.your-app.

[6]: App Groups allow different “apps” to share information.

--

--

Lyndsey Ferguson

Born in Canada. Software Engineer. I love reading, films, music, scuba diving, strength training, and travelling.