본문 바로가기
IT/개발환경

OSX Codesign with PowerShell

by rapker 2023. 5. 18.
반응형
 
OSX용 .app을 만들고 배포를 위해 .pkg를 생성하여 배포하면 확인되지 않은 개발자가 되어 버립니다.
확인된 개발자가 되기위해 .pkg파일에 signing 과정이 필요합니다.
 
 
사이닝에 관한 글을 찾아보면 90%가 곧(2023년 하반기) 지원종료되는 altool을 사용하는 글이고,
notarytool 관련한 글들에서도 설명을 해주고는 있지만 실제로 적절치 못한 경우가 태반이라...
 
결국 저에게 맞는 최적의 사이닝 프로세스 찾기는 했지만 많은 삽질이 필요했습니다.

 

728x90
 
 

Signing에 필요한 정보

 
  • 인증서
  • CI/CD에서 signing에 사용될 애플 계정
  • TeamID
  • AppPassword
 
signing에 필요한 정보들 얻는 방법은 아랫쪽에 기록했습니다.
 
 
 
 

Signing 절차

 
build - codesign - packaging - codesign - notarization - staple
 
  • build : .app파일 생성
  • codesign : .app파일에 개발자 각인
  • packaging : .pkg파일 생성
  • codesign : .pkg 파일에 개발자 각인
  • notarization : .pkg에 각인된 개발자 정보 공증
  • staple : .pkg 개발자정보 봉인
 
반응형
 
 
 
 

주요사항

 

폴더구조

 
.app 파일과 .pkg 파일의 위치는 아래와 같습니다.
 

Contents 내부

 
Dependencies 폴더는 앱 실행중에 참조하는 외부 프로그램의 위치입니다.
 
codesign 진행 시 --deep 옵션을 사용하기 때문에 .app 파일 내부의 lib, bundle, framework등 자동으로 서명이 되지만
Custom Folder(프로젝트에서 추가한 프로그램들을 모아둔 )의 파일들은 사이닝에서 제외되었습니다.
 
그래서 custom folder의 파일들 먼저 사이닝 진행 후 .app 사이닝 했습니다.
$dependenciesPath = "${appNameWithExt}/Contents/Dependencies"  # 프로젝트에서 사용하는 외부 프로그램들의 경로
$itemList = Get-ChildItem $targetFolder -Recurse
foreach ($item in $itemList)
{
    codesign --deep --verify --verbose --force --timestamp --options runtime --sign $OSX_CERT_APPLICATION $item.FullName
}
codesign --deep --verify --verbose --force --timestamp --options runtime --entitlements "${appName}.entitlements" --sign $OSX_CERT_APPLICATION $appNameWithExt
 

.entitlements

 
Hardened Runtime 자격을 갖추기 위한 자격 리스트가 필요하다고 합니다.
 
Unity documentation 참고하여

Unity post build processor 에서 아래 내용이 담긴 파일을 .app파일과 같은 위치에 생성 하도록 했습니다.

 
.entitlements 파일의 이름은 .app 파일의 이름과 동일해야 합니다.
  • myappname.app
  • myappname.entitlements
<?xml version="1.0" encoding="UTF-8"?>
http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
      <key>com.apple.security.cs.disable-library-validation</key>
      <true/>
      <key>com.apple.security.cs.disable-executable-page-protection</key>
      <true/>
    </dict>
</plist>
 

productbuild 스킵

 
가이드 문서들은 하나같이 둘 중 하나로 사이닝을 진행 하라고 이야기 합니다.
 
pkg 빌드 하면서 signing진행
pkgbuild --component "./Release/${appNameWithExt}" --install-location /Applications --sign $OSX_CERT_INSTALLER $pkgName
productbuild --package $pkgName --content "./Release/${appNameWithExt}" --sign $OSX_CERT_INSTALLER $pkgNameWithSign
or
productsign --sign $OSX_CERT_INSTALLER $pkgName $pkgNameWithSign
 
pkgbuild 후 productbuild를 진행하면 .pkg파일의 용량도 두 배로 커지고 .pkg파일이 손상되었다며 설치도 진행되지 않습니다.
왠지 .pkg파일을 감사는 .pkg파일이 생성되는 것 같습니다.
 
productsign은 사이닝 진행은 되지만 공증 때 .pkg 내부 파일들의 사이닝이 하나도 안되었다며 실패를 뱉어냅니다.
 
 
그래서 결국 pkgbuild만 사용하게 되었습니다.
pkgbuild --component "./Release/${appNameWithExt}" --install-location /Applications --sign $OSX_CERT_INSTALLER $pkgNameWithSign
 
 

.app 파일 notarization 스킵

 
.pkg 파일로 배포를 할 것이기 때문에 .pkg파일의 공증이 필수입니다.
.pkg파일 내에 .app이 포함되어 있기 때문에 .app은 사이닝만하고 공증은 하지 않아도 됩니다.

 

 

 
 

Signing 스크립트

 
Signing과정을 CI/CD에 연동하기 위해 powershell 스크립트로 작성했습니다.
 
$ErrorActionPreference = "Stop"

$BUILDER_IDENTIFYER    = $env:C_APPLE_MAC_BUILDER_IDENTIFYER  # Bundle IDentifier of App
$OSX_SIGN_ID            = $env:C_APPLE_OSX_SIGN_ID              # Apple Account
$OSX_SIGN_PW            = $env:C_APPLE_OSX_SIGN_PW              # App Password
$APPLE_TEAM_ID          = $env:C_APPLE_TEAM_ID                  # Team ID
$OSX_CERT_APPLICATION  = $env:C_APPLE_OSX_CERT_APPLICATION    # Certification Name of Application
$OSX_CERT_INSTALLER    = $env:C_APPLE_OSX_CERT_INSTALLER      # Certification Name of Installer
$appName                = 'myappname'
$appNameWithExt        = "${appName}.app"

$pkgName                = "${appName}Installer.pkg"            # signing전 임시 pkg 파일이름
$pkgNameWithSign        = $env:BUILDER_INSTALLER_NAME          # signing된 pkg 파일이름

cd $env:C_BUILD_PATH                                            # .app 파일이 있는 경로로 이동

$dependenciesPath = "${appNameWithExt}/Contents/Dependencies"  # 프로젝트에서 사용하는 외부 프로그램들의 경로
$itemList = Get-ChildItem $targetFolder -Recurse
foreach ($item in $itemList)
{
    codesign --deep --verify --verbose --force --timestamp --options runtime --sign $OSX_CERT_APPLICATION $item.FullName
}
codesign --deep --verify --verbose --force --timestamp --options runtime --entitlements "${appName}.entitlements" --sign $OSX_CERT_APPLICATION $appNameWithExt
codesign -vvv --deep --strict $appNameWithExt

cd ..

pkgbuild --component "./Release/${appNameWithExt}" --install-location /Applications --sign $OSX_CERT_INSTALLER $pkgNameWithSign

$resultSubmit = xcrun notarytool submit $pkgNameWithSign --apple-id "${OSX_SIGN_ID}" --password "${OSX_SIGN_PW}" --team-id "${APPLE_TEAM_ID}" --wait -f json | ConvertFrom-Json
xcrun notarytool log $resultSubmit.id --apple-id "${OSX_SIGN_ID}" --password "${OSX_SIGN_PW}" --team-id "${APPLE_TEAM_ID}"

codesign -vvv --deep --strict $pkgNameWithSign
pkgutil --check-signature $pkgNameWithSign

if ($resultSubmit.status -ne "Accepted")
{
    Write-Host "notarytool submit result is not Accepted. ${pkgName}"
    Exit -100
}

xcrun stapler staple $pkgNameWithSign

Write-Host "Success"
 
 

 

 

Signing에 필요한 정보들 얻는 방법

 

인증서 이름

자세한 내용은 Appstore 외 배포용 인증서 생성하기 참고하기 바라며 아래와 같이 인증서를 준비 하고,

Application, Installer 두 인증서의 full name 을 챙겨 둡니다.

 
 
 

Team ID 확인

https://developer.apple.com/account 에 로그인 후 아래쪽에 멤버십 세부 사항 항목에서 Team ID 확인
 
 
 

AppleID에서 App Password 생성

 
Signing에 개발자 ID를 사용되지만 비밀번호는 개발자 ID의 비밀번호를 사용하지 않고 App Password를 요구 합니다.
AppleID 페이지에 로그인 후 앱 암호 버튼을 클릭 합니다.
 
 
 
암호가 사용될 용도를 적어 줍니다.
 
 
계정의 비밀번호를 확인합니다.
 
 
생성된 비밀번호는 다시 확인할 수 없으니 잘 갖고 있어야 합니다.
 
생성 된 App password의 모습
 
반응형
LIST