Skip to content

Instantly share code, notes, and snippets.

@mitchellh
Last active Aug 31, 2021
Embed
What would you like to do?
macOS Catalina (10.15+) Notarization Requirement for Go

macOS 10.15 Catalina requires binaries are notarized to run without annoying additional steps. See the issue here: https://github.com/hashicorp/terraform/issues/23033

These are steps to notarize a direct binary. This does not cover stapling, installers (pkg), etc. This is primarily useful for static binary developers such as Go developers.

Manual Steps

Apple Developer Account

You first need an Apple Developer Account ($99/year). You need to accept all the agreements and stuff.

Get a Developer ID Cert

You first need a "Developer ID Application" certificate. You get this by:

  1. Open Xcode
  2. "Xcode => Preferences" in menu bar
  3. "Accounts"
  4. Add your Apple ID account if its not there. This has to be the one associated with the Apple developer account we want to use for builds.
  5. Click "Manage Certs"
  6. TO ADD: click "+" in bottom left and choose "Developer ID Application"
  7. Right click the cert, hit "export" and it'll export as a p12. You can copy this wherever.

Next, find the developer ID to use:

$ security find-identity -v
  1) 8F5E555F64B68F2BA5DA6FBD4F8414CF8F48BA46 "com.apple.idms.appleid.prd.2b6c4f417a324d417363384362744a71694448484b773d3d"
  2) 42C333379546C93C3B2624E40D3029D735CA3EA9 "Developer ID Application: Mitchell Hashimoto (GK79KXBE4F)"

In this case, the value is 42C333379546C93C3B2624E40D3029D735CA3EA9

Automatable Steps

Codesign

First step is to sign the binary. You sign the binary, not the zip.

$ codesign -s <cert ID> -v --timestamp --options runtime <binary>

# example:
$ codesign -s 42C333379546C93C3B2624E40D3029D735CA3EA9 -v --timestamp --options runtime ./terraform

The flags -v --timestamp --options runtime are critical. These are necessary requirements for notarization to succeed.

Note: This will pop-up requesting the password for the certificate. There is a way to automate around this. I don't directly remember what it is but we did it for Vagrant Mac builds years ago, so the answer is there.

Make a Zip

We use ditto cause the Apple docs tell us to, I guess to make a "valid" zip format.

$ ditto -c -k <binary> <zip name>

# example:
$ ditto -c -k ./terraform ./terraform.zip

Submit for Notarization

Now you submit for notarization:

$ xcrun altool \
    --notarize-app \
    --primary-bundle-id "com.example.terraform" \
    -u "jane.doe@gmail.com" \
    -p "abcd1234" \
    -f ./terraform.zip

The primary-bundle-id doesn't really matter, but we should use some consistent value like the one proposed.

The -u and -p are the username and password of the Apple account in use. The password should probably be an app-specific password.

This will output a request ID. Copy that!

Poll Status

Next you poll the status:

$ xcrun altool \
    --notarization-info fa18dd71-2789-429d-b4d8-008de9ge1d19 \
    -u "jane.doe@gmail.com" \
    -p "abcd1234"
No errors getting notarization info.

          Date: 2019-10-30 22:57:35 +0000
          Hash: 5730fbe04f67746c786d7fd2a7141bf11c2c6a69402b11dc8db6bc4faf5506d1
    LogFileURL: https://osxapps-ssl.itunes.apple.com/itunes-assets/Enigma113/v4/26/9b/3c/269b3cdf-bd72-a35b-25b2-4cb7769fb19b/developer_log.json?accessKey=denied
   RequestUUID: fa18dd71-2789-429d-b4d8-008de9ge1d19
        Status: success
   Status Code: 0
Status Message: Package Approved

You want to wait for "success". I forget the failure values.

Some notes:

  • The message will go to "Packaged Approved" before the status is actually "success". You have to wait for the latter otherwise it means it isn't propagated yet.
  • The log file is really good. It is also JSON. That's useful.

Upload the Zip. Success!

You can now upload the exact same zip you submitted for notarization. The SHA-256 hash must match for Catalina machines to verify the notarization.

You do not need to staple. The downside to this is that the computer that downloads the package must have internet to verify the signature on first run. It is then cached and subsequent execution can happen offline. If you insist on stapling, you'll need to package your binary into an App Bundle (.app/ directory structure) and probably wrap that up in a dmg and resign that. It is quite an additional process.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment