Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add notarization support #42

Merged
merged 16 commits into from
May 28, 2021
Merged

Add notarization support #42

merged 16 commits into from
May 28, 2021

Conversation

MichalMMac
Copy link
Contributor

@MichalMMac MichalMMac commented Jun 6, 2019

This PR adds the ability to notarize signed installer packages. Implementation is inspired by Apple document Customizing the Notarization Workflow.

Code style is currently the same as in #39 after applying formatters. If you don't like the #39 changes I can format the code in this PR to match the original code style.

Possible improvements:

  • Better English description in README.md since I am not a native speaker.
  • Imporoved handling of the time delay between xcrun altool and xcrun stapler. Current approach just runs the stapler on the package again and again (for limited amount of tries) until it succedes.

@gregneagle
Copy link
Contributor

This is really interesting.

Since, if I merge this, people will expect me to support it and fix it when it breaks, I'll need to take a long hard look at it and make sure I really understand it. I have not yet had any need to investigate notarization (and frankly, so far have and almost no internal need for signing) so this is not something I've paid a lot of attention to.

@erikng
Copy link
Contributor

erikng commented Jun 6, 2019

Given that every package built after June 1st requires signing/notarization, I think it would be worth the effort to merge this.

@gregneagle
Copy link
Contributor

"Given that every package built after June 1st requires signing/notarization" I have not found that to be the case...

README.md Outdated Show resolved Hide resolved
@poundbangbash
Copy link

poundbangbash commented Jun 6, 2019 via email

@gregneagle
Copy link
Contributor

And yet Munki's Managed Software Center, which is neither signed nor notarized, runs just fine in Catalina.

README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
@homebysix
Copy link
Contributor

Mac apps, installer packages, and kernel extensions that are signed with Developer ID must also be notarized by Apple in order to run on macOS Catalina.

I think what that means is unsigned/non-notarized is still OK, but if you're distributing signed pkgs they also need to be notarized to work with Catalina. Will probably affect a small but not insignificant portion of MunkiPkg users.

@gregneagle
Copy link
Contributor

"I think what that means" is most of the problem here.

@gregneagle
Copy link
Contributor

gregneagle commented Jun 6, 2019

I created a signed (but not notarized) pkg containing a signed (but not notarized) MSC.app and installed on a machine running the Catalina beta. I was not prompted or blocked or warned or challenged in any way when installing the pkg, either via /usr/sbin/installer or manually double-clicking it, and I also could launch MSC.app without any harrassment.

@homebysix
Copy link
Contributor

We should ask somebody at Apple what the word "must" means in the above context. Maybe enforcement hasn't been turned on yet (similar to the path UAMDM and kext whitelisting followed in early versions of High Sierra).

@erikng
Copy link
Contributor

erikng commented Jun 6, 2019 via email

munkipkg Outdated
# notarize the pkg
if "notarization" in build_info and not options.skip_notarization:
try:
notarize(build_info, options)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my (brief) testing I'm seeing it take far longer than 120 seconds for stapling to become available, and of course if there are errors in the notarization process it will never become available. Perhaps we should be running xcrun altool --notarization-info {output["notarization-upload"]["RequestUUID"]} periodically waiting for a status .

On status: success proceed to staple, on status: in progress, sleep and try again, on status: invalid (or other error status, print the error (better still, retrieve the log from the LogFileURL) and exit...

I'm not suggesting we get all this in before I'll merge this -- but I think it's needed for a good implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can improve this before the merge. I admit current approach is a bit naive. Even mentioned this problem is PR comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check using altool --notarization-info now implemented in 9a6e0d0. Default timeout increased to 300 seconds.

Not sure about the retrieving the log from LogFileURL though. Currently we display the Status, Status Code, Status Message and LogFileURL after a failed notarization attempt. Log can be a very long json. We could download it and put someplace in the munki-pkg project directory (Perhaps create log directory?).

munkipkg Outdated Show resolved Hide resolved
munkipkg Outdated Show resolved Hide resolved
munkipkg Outdated Show resolved Hide resolved
munkipkg Outdated Show resolved Hide resolved
munkipkg Outdated Show resolved Hide resolved
@MichalMMac MichalMMac force-pushed the notarization branch 2 times, most recently from cbf1c3f to ee6520c Compare June 13, 2019 14:43
@MichalMMac
Copy link
Contributor Author

MichalMMac commented Jun 13, 2019

Added new key primary_bundle_id for situations where altool --primary-bundle-id must be different from package identifier. See 2eb8273

@MichalMMac
Copy link
Contributor Author

MichalMMac commented Jun 14, 2019

Added big commit 9a6e0d0.

After successful upload of the signed package to the Apple notary service munki-pkg now uses to altool --notarization-info to check for notarization result. No more blind stapling attempts.

Other changes:

  • Increase STAPLE_TIMEOUT to 300 seconds
  • Start using incremental time delay between notary process check
  • Change wording of some docstrings

There are a lot of fixup commits. When all threads with references to them are resolved I'll squash them using rebase.

README.md Outdated
| username | String | Yes | Login email adress of your developer Apple ID |
| password | String | Yes | 2FA app specific password. For information about the password and saving it to the login keychain see the web page [Customizing the Notarization Workflow](https://developer.apple.com/documentation/security/notarizing_your_app_before_distribution/customizing_the_notarization_workflow) |
| asc_provider | String | No | Only needed when a user account is associated with multiple providers |
| primary_bundle_id | String | No | Defaults to `identifier`. `primary_bundle_id` is usefull when `identifier` contains characters such as '_' Apple notary service does not like |
Copy link
Contributor

@gregneagle gregneagle Jun 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think providing this option is fine, but since we know that Apple's notary service does not like underscores in the primary bundle id, if this option is not provided and you/we "auto-generate" the primary bundle id from the pkg id, why don't we automatically substitute hyphens for underscores?

Also: s/usefull/useful/

Copy link
Contributor Author

@MichalMMac MichalMMac Jun 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is basic string.replace() like this 81fec0e ok?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment on that commit.

README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved

if notarization_done(state, sleep_time, options):
break

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it will exit "normally" after the staple_timeout -- in other words, when wait_for_notarization returns notarization might have been successful, or we might have just timed out. So in lines 880 and 881 we might proceed to staple even if the notarization is not complete.

I think it would be better to recognize the timeout and 1) Not try to staple, and 2) Print out information that would allow the admin to manually staple later if/when they get notification of a successful notarization.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. Definitely bug I created.

See the fixup 5af2ae3.

btw I do nothing with exit codes. munkipkg exits with 0 when notaratization fails or times out. I was thinking primary job of munkipkg is to build packages. If package is built correctly process should exit with code 0 even when notarization failed. Do you agree?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I do. Primary job might be to build pkgs, but if you give it extra jobs it should tell if if/when it fails.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See 1b13928.

In case of problem or failed notarization we return with -1 from build() and it gets passed to sys.exit().
When we give up on waiting for notarization we still exit with 0.

@sts
Copy link

sts commented Aug 18, 2020

Error handling might still need some improvement, at least when the account is not enabled for notarization the following exception is raised:

Traceback (most recent call last):
  File "./munkipkg", line 1311, in <module>
    main()
  File "./munkipkg", line 1307, in main
    result = build(arguments[0], options)
  File "./munkipkg", line 929, in build
    request_uuid = upload_to_notary(build_info, options)
  File "./munkipkg", line 729, in upload_to_notary
    if proc_stdout.startswith('Generated JWT'):
TypeError: startswith first arg must be bytes or a tuple of bytes, not str

In this case proc_stdout is set to the following xml string:

b'<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n\t<key>os-version</key>\n\t<string>10.15.5</string>\n\t<key>product-errors</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>code</key>\n\t\t\t<integer>1048</integer>\n\t\t\t<key>message</key>\n\t\t\t<string>You must first sign the relevant contracts online. (1048)</string>\n\t\t\t<key>userInfo</key>\n\t\t\t<dict>\n\t\t\t\t<key>NSLocalizedDescription</key>\n\t\t\t\t<string>You must first sign the relevant contracts online. (1048)</string>\n\t\t\t\t<key>NSLocalizedFailureReason</key>\n\t\t\t\t<string>You must first sign the relevant contracts online. (1048)</string>\n\t\t\t\t<key>NSLocalizedRecoverySuggestion</key>\n\t\t\t\t<string>You must first sign the relevant contracts online. (1048)</string>\n\t\t\t</dict>\n\t\t</dict>\n\t</array>\n\t<key>tool-path</key>\n\t<string>/Applications/Xcode.app/Contents/SharedFrameworks/ContentDeliveryServices.framework/Versions/A/Frameworks/AppStoreService.framework</string>\n\t<key>tool-version</key>\n\t<string>4.01.1182</string>\n</dict>\n</plist>\n\n'

@MichalMMac
Copy link
Contributor Author

MichalMMac commented Aug 18, 2020

@sts I suspect you run munkipkg with Python 3. Although munkipkg should be mostly compatible with Python 3 shebang still point to macOS default 2.7 Python.

Described problem is not caused by (lack of) error handling. Problem is only with Python 3 compatibility I did not test.

I've added new commit 72d30e2 to deal with this. Please test and report issues if you find any

@MichalMMac
Copy link
Contributor Author

Rebased against latest code. Updated version changing commit.

@gregneagle
Copy link
Contributor

You've done a lot of work on this and you've kept it rebased so it can be merged and it's clear that at least some people want this functionality. I'm going to merge it. My one hesitation is that because I personally won't be using the functionality and I didn't write the functionality, if there are issues reported against the notarization functionality, I cannot promise to fix those issues in a timely manner, and I hope you will be able to "stick around" and maintain it.

@gregneagle gregneagle merged commit 71d2708 into munki:main May 28, 2021
@MichalMMac
Copy link
Contributor Author

Sure. I use notarization quite often so I guess I will keep using this as long as I do Mac Admin stuff :-)

@rodchristiansen
Copy link
Contributor

Nice to see this merged into main.
Been using this notarization pull request since inception.
Works great!

@gregneagle
Copy link
Contributor

…and now altool is deprecated in macOS Monterey…

@erikng
Copy link
Contributor

erikng commented Jun 8, 2021

I must admit I chuckled when I saw that earlier. I immediately thought about this PR.

@flammable
Copy link

Ah nuts, I was excited to use this. I hope there's an alternative way to do this on Monterey.

@rodchristiansen
Copy link
Contributor

@MichalMMac
Copy link
Contributor Author

MichalMMac commented Jun 8, 2021

I wake up in the morning and go check the Twitter. I Learn altool is deprecated and immediately go to this thread. 4 people beat me to it 😁

@gregneagle Don't worry. I'll look into it

I haven't downloaded the beta yet. Can anyone confirm altool is still present and working in Xcode 13? (I presume it is. It even got new features in Xcode 12.5)

I'll take a look at notarytool this week. I hope it has feature parity with altool. If it does it should not be that hard to replace it within munki-pkg. There might be even possible to do some changes like using new --wait instead of current polling implementation.

@MichalMMac
Copy link
Contributor Author

I've created a new issue #53 where I shall discuss the altool deprecation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants