Codesigning Python.framework

158 views
Skip to first unread message

Michal Moravec

unread,
Mar 24, 2020, 8:20:28 AM3/24/20
to munki-dev
I build Munki "enroll" packages for my colleagues to enroll Macs into our Munki.
For ease of use I want these packages notarized so they can install them without any hassle.
-> Every binary inside that package must be signed and be able to be notarized.

Munki 4 embeded Python gave me a little challange. Here are my notes. Somebody else might find them useful.
I am not sure if any of these could be incorporated into munki build scripts. Maybe...

1. Change directory into Munki git repo.
2. Build Python framework using `./code/tools/build_python_framework.sh`.
3. Find all executable files in `lib` and `bin` directories and codesign them:

find Python.framework/Versions/3.7/lib/ -type f -perm -u=x -exec codesign --deep --verbose -s 'Developer ID Application: YourCompany (SomeID)' {} \;
find
Python.framework/Versions/3.7/bin/ -type f -perm -u=x -exec codesign --deep --verbose -s 'Developer ID Application: YourCompany (SomeID)' {} \;

4. Find all `dylib` libraries in `lib and codesign them:

find Python.framework/Versions/3.7/lib/ -type f -name "*dylib" -exec codesign --deep --verbose -s 'Developer ID Application: YourCompany (SomeID)' {} \;


5. Create file `entitlements.plist`:

```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
 <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
 <true/>
</dict>
</plist>
```

6. Resign `Python.app` with `--force`. Also use `--options runtime` to opt into hardened runtime environemt together with `--entitlements entitlements.plist`:

codesign --force --options runtime --entitlements entitlements.plist --deep --verbose -s 'Developer ID Application: YourCompany (SomeID)' Python.framework/Versions/3.7/Resources/Python.app/


`codesign` man pages says:

runtime  On macOS versions >= 10.14.0, opts signed processes into a hard-ened runtime environment which includes runtime code signing enforcement, library validation, hard, kill, and debugging restrictions.  These restrictions can be selectively relaxed via entitlements. Note: macOS versions older than 10.14.0 ignore the presence of this flag in the code signature.

7. Do the same for `python3.7` and `python3.7m` binaries:

codesign --force --options runtime --entitlements entitlements.plist --deep --verbose -s 'Developer ID Application: YourCompany (SomeID)' Python.framework/Versions/3.7/bin/python3.7
codesign
--force --options runtime --entitlements entitlements.plist --deep --verbose -s 'Developer ID Application: YourCompany (SomeID)' Python.framework/Versions/3.7/bin/python3.7m


8. Finally use `codesign` on the entire framework:

codesign --deep --verbose -s 'Developer ID Application: YourCompany (SomeID)' Python.framework


9. Build Munki distribution package and notarize it:

sudo ./code/tools/make_munki_mpkg.sh -i "com.googlecode.munki" -S "Developer ID Application: YourCompany (SomeID)" -s 'Developer ID Installer: YourCompany (SomeID)'
chown youruser munkitools
-4.1.0.3914.pkg
xcrun altool
--notarize-app --primary-bundle-id "com.googlecode.munki" --username appleid@somedomain.tld --password "@keychain:AC_PASSWORD" --file munkitools-4.1.0.3914.pkg
xcrun stapler staple munkitools
-4.1.0.3914.pkg


Notes:
  • `--deep` flag might not be necessary in most  cases since we are signing everything from the bottom up
  • Codesigning with `--options runtime` but without `com.apple.security.cs.allow-unsigned-executable-memory` entitlement makes Munki code crash.
  • I am not sure if codesigning with hardened runtime have any more unintended consequences

hunted think

unread,
Apr 2, 2020, 8:49:34 AM4/2/20
to munki-dev
Thank you so much :)

asdas adsi

unread,
Apr 7, 2020, 9:31:24 AM4/7/20
to munki-dev
I made a script that is based on what you did, Greag Neagle and Michal Moravec.
The script below automates the processes of bulding the python framework, signing and notarizing it before it runs the build script for making munkitools.pkg and at last its uploads the script for notarization.

Rod Christiansen

unread,
Mar 10, 2021, 12:02:45 AMMar 10
to munki-dev
If anyone is interested, this script worked for me to sign the latest 3.9.2 universal python:

```
#!/bin/zsh

MunkiPythonPath=/Repository/packages/MunkiPython/payload

DevApp="Developer ID Application: NAME (#####)"

find $MunkiPythonPath/Python.framework/Versions/3.9/lib/ -type f -perm -u=x -exec codesign --force --deep --verbose -s "$DevApp" {} \;
find $MunkiPythonPath/Python.framework/Versions/3.9/bin/ -type f -perm -u=x -exec codesign --force --deep --verbose -s "$DevApp" {} \;
find $MunkiPythonPath/Python.framework/Versions/3.9/lib/ -type f -name "*dylib" -exec codesign --force --deep --verbose -s "$DevApp" {} \;
find $MunkiPythonPath/Python.framework/Versions/3.9/lib/ -type f -name "*so" -exec codesign --force --deep --verbose -s "$DevApp" {} \;
find $MunkiPythonPath/Python.framework/Versions/3.9/lib/ -type f -name "*libitclstub*" -exec codesign --force --deep --verbose -s "$DevApp" {} \;
find $MunkiPythonPath/Python.framework/Versions/3.9/lib/ -type f -name "*.o" -exec codesign --force --deep --verbose -s "$DevApp" {} \;

/usr/libexec/PlistBuddy -c "Add :com.apple.security.cs.allow-unsigned-executable-memory bool true" $MunkiPythonPath/entitlements.plist

codesign --force --options runtime --entitlements $MunkiPythonPath/entitlements.plist --deep --verbose -s "$DevApp" $MunkiPythonPath/Python.framework/Versions/3.9/Resources/Python.app/
codesign --force --options runtime --entitlements $MunkiPythonPath/entitlements.plist --deep --verbose -s "$DevApp" $MunkiPythonPath/Python.framework/Versions/3.9/bin/python3.9
codesign --force --deep --verbose -s  "$DevApp" $MunkiPythonPath/Python.framework
```

Reply all
Reply to author
Forward
0 new messages