간단히 만든 exe파일을 공유하려면, "signing" 이라는 알람이 자주 뜬다.
이 것에 대한 좋은 글이 있어서 브라우저 번역으로 스크랩 합니다.
Azure Trusted Signing은 마이크로소프트의 클라우드 기반 코드 서명 서비스로, 다음과 같은 기능을 수행합니다:
- 하드웨어 토큰 없음 - 모든 작업이 클라우드에서 이루어집니다
- 자동 인증서 관리 - 인증서는 자동으로 발급 및 갱신됩니다
- GitHub Actions 통합 - CI/CD 파이프라인 중에 서명하세요. 저는 GH Actions를 사용했습니다.
- 좀 저렴해요 - 작은 프로젝트는 월 약 10달러 정도요. 연 10달러였으면 좋겠어요. 연간 자격증보다는 저렴하지만, 시간이 지나면 쌓이기 때문에 항상 더 저렴하고 쉬운 옵션을 찾고 있어요.
- Trusted by Windows - Microsoft 자체 앱과 동일한 인증 기관을 사용하므로 EXE를 더 빨리 신뢰받을 수 있습니다
전제 조건
시작하기 전에 필요한 서류는 다음과 같습니다:
- Azure 구독
- Azure CLI - Install from here
- 신원 확인 서류 - 개별 개발자용 운전면허증 또는 여권. 참고로 저는 미국에 있으니 상황에 따라 다를 수 있지만, 기본적으로 계정을 만들고 QR 코드를 스캔한 뒤 면허증 사진을 찍고 셀카를 찍고 기다렸습니다.
- Windows PC - 로컬 서명용(선택 사항)이지만 결국 닷넷 서명 도구를 사용했습니다. 있습니다
- GitHub 저장소 - 자동 서명용(선택 사항)
1부: Azure 신뢰 서명 설정
1단계: 리소스 제공자 등록
먼저, 구독에서 Azure Trusted Signing 서비스를 활성화해야 합니다. 이 작업은 포털이나 CLI에서 할 수 있습니다.
# Login to Azure
az login
# Register the Microsoft.CodeSigning resource provider
az provider register --namespace Microsoft.CodeSigning
# Wait for registration to complete (takes 2-3 minutes)
az provider show --namespace Microsoft.CodeSigning --query "registrationState"
출력이 나올 때까지 기다려 보세요. "Registered"
2단계: 신뢰할 수 있는 서명 계정 만들기
이제 실제 서명 계정을 만드세요. Azure 포털이나 CLI를 통해 할 수 있습니다.
옵션 A: Azure 포털 (처음 사용하는 사람에게 더 쉬움)
- Go to Azure Portal
- "신뢰받는 서명 계정"을 검색하세요
- 만들기 클릭
- 채우기:
- 구독: 당신의 구독
- 리소스 그룹: 새 항목을 생성하거나 기존 (예: "MyAppSigning")
- 계정 이름: 고유 이름 (예: "myapp-signing")
- 지역: 가장 가까운 곳을 선택하세요 (예: "West US 2")
- SKU: 기본 (대부분의 앱에 충분함)
- 리뷰 + 생성 버튼을 클릭한 후 생성
옵션 B: Azure CLI (CLI 사용자이거나 수동 변속 운전을 좋아한다면 더 빠릅니다)
# Create a resource group
az group create --name MyAppSigning --location westus2
# Create the Trusted Signing account
az trustedsigning create \
--resource-group MyAppSigning \
--account-name myapp-signing \
--location westus2 \
--sku-name Basic
중요: 지역 엔드포인트를 기록하세요. 일반적인 것들은 다음과 같습니다:
- 동부 미국:
https://eus.codesigning.azure.net/ - 웨스트 US 2:
https://wus2.codesigning.azure.net/ - 귀하의 지역: Azure 포털에서 계정 개요 페이지에서 확인해 보세요
저는 이 URL이 중요하고 계정에 특화된 것임을 깨닫고 10분 정도 이것저것 시도했어요. 이 종점을 기억하세요.
3단계: 완전한 신원 확인
이것이 가장 중요한 단계입니다. 마이크로소프트는 당신이 실제 사람이나 조직인지 확인해야 합니다.
- Azure Portal에서 신뢰받는 서명 계정으로 가세요
- 왼쪽 메뉴에서 신원 확인을 클릭하세요
- 신원 확인 추가를 클릭하세요
- 검증 유형을 선택하세요:
- 개인: 1인 개발자(운전면허/여권 사용 가능)
- 조직: 기업 (사업자 등록 서류 사용)
- 개인 검증을 위해:
- 정부에서 발급한 신분증의 명확한 사진을 업로드하세요
- 법적 본명을 제공하세요(신분증과 정확히 일치해야 함)
- 이메일 주소를 제공하세요
- 제출하고 승인을 기다리세요
승인 기간:
- 개인: 보통 1-3영업일
- 조직: 3-5영업일
- 저: 이 과정이 약 4시간 걸렸으니, 다시 말하지만 사람마다 다를 수 있습니다. 저는 개인 계정과 개인 Azure를 사용했는데(MSFT 직원들은 무제한 Azure 크레딧을 믿지 마세요, 제가 직접 비용을 내고 있습니다) 그래서 그들은 저인 줄 몰랐습니다. 저는 사전 확인 줄이 아니라 일반 줄을 통해 갔어요 ᄏᄏ.
승인되면 이메일을 받게 됩니다. 승인되기 전까지는 어떤 코드에도 서명할 수 없습니다.
4단계: 인증서 프로필 생성
신원이 확인되면 인증서 프로필을 만드세요. 이것이 실제로 서명 인증서를 발급하는 방식입니다.
- 신뢰받는 서명 계정에서 인증서 프로필을 클릭하세요
- 인증서 프로필 추가를 클릭하세요
- 채우기:
- 프로필 이름: 설명 이름 (예: "MyAppProfile")
- 프로필 유형: 공공 신뢰 선택 (SmartScreen 방지 필수)
- 신원 확인: 승인된 신원을 선택하세요
- 인증서 유형: 코드 서명
- 추가 클릭
중요: "공용 신뢰" 프로필만이 SmartScreen 경고를 방지합니다. "Private Trust"는 내부 앱에만 해당됩니다. 이 이름이 직관적이지 않아서 깨닫는 데 잠시 시간이 걸렸어요.
5단계: 설정 확인
# List your Trusted Signing accounts
az trustedsigning show \
--resource-group MyAppSigning \
--account-name myapp-signing
# Should show status: "Succeeded"
이 값들을 적어두세요 - 나중에 필요할 것입니다:
- 계좌명:
myapp-signing - 인증서 프로필 이름:
MyAppProfile - 엔드포인트 URL: (또는 귀하의 지역)
https://wus2.codesigning.azure.net/ - 구독 ID: Azure 포털에서 찾을 수 있음
- 자료 그룹:
MyAppSigning
2부: 지역 코드 서명
이제 당신의 내 컴퓨터에 실행 파일에 서명해 봅시다. 꼭 해야 하는 건 아니지만, CI/CD 실행을 피하려고 로컬에서 시도해보고 싶었고, EXE를 우클릭해서 Properties에서 인증서를 보고 싶었어요. 좋은 점은 인증서를 조작할 필요가 없다는 거예요.
1단계: 서명 역할을 스스로 지정하기
서명 서비스를 실제로 사용하려면 허가가 필요합니다.
옵션 A: Azure Portal
- 신뢰받는 서명 계정으로 가세요
- 접근 제어(IAM) 버튼을 클릭하세요
- 추가 → 역할 할당 추가를 클릭하세요
- '신뢰받는 서명 인증서 프로필 서명자'를 검색하여 선택하세요.이건 중요해. "code"로 검색해봤지만 아무것도 찾지 못했어요. "trusted" 검색해 보세요
- 다음 클릭
- 회원 선택을 클릭하여 사용자 계정을 찾으세요
- 선택을 클릭한 후 리뷰 + 할당
Option B: Azure CLI
# Get your user object ID
$userId = az ad signed-in-user show --query id -o tsv
# Assign the role
az role assignment create \
--role "Trusted Signing Certificate Profile Signer" \
--assignee-object-id $userId \
--scope /subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/MyAppSigning/providers/Microsoft.CodeSigning/codeSigningAccounts/myapp-signing
실제 구독 ID로 교체하세요. YOUR_SUBSCRIPTION_ID
2단계: 올바른 범위로 로그인하기
이 점이 매우 중요합니다 - 특정 공동 설계 범위로 로그인해야 합니다.
# Logout first to clear old tokens
az logout
# Login with codesigning scope
az login --use-device-code --scope "https://codesigning.azure.net/.default"
이 코드를 통해 https://microsoft.com/devicelogin 에 입력할 수 있습니다. 안내를 따라가세요.
왜 기기 코드 플로우인가요? 제 경험상 Azure CLI의 기본 인증이 Visual Studio 자격 증명과 충돌할 수 있기 때문입니다. 장치 코드 흐름은 코드 서명에 더 신뢰할 수 있습니다.
3단계: 표지판 도구 다운로드
옵션 A: 전역 설치 (일반 사용 권장)
# Install as a global tool (available everywhere)
dotnet tool install --global --prerelease sign
# Verify installation
sign --version
옵션 B: 로컬 설치 (프로젝트별 적용)
# Install to current directory
dotnet tool install --tool-path . --prerelease sign
# Use with .\sign.exe
어떤 걸 사용해야 할까요?
- 글로벌: 여러 프로젝트를 계약하거나 자주 서명할 경우
- 로컬: 특정 프로젝트에 도구를 계속 사용하고 싶거나 PATH에 포함시키고 싶지 않을 때
4단계: 실행 부재 서명하기
코드 서명 URL은 본인에게 특화된 것임을 다시 한 번 참고하세요. tscp는 신뢰받는 서명 인증서 프로필 이름이고, tsa는 신뢰받는 서명 계정 이름입니다. 폴더 내 모든 EXE에 *.exe를 서명하도록 설정했고, -b 기본 디렉터리가 상대 경로가 아니라 절대 경로임을 확인했습니다. 저는 d:\github\WindowsEdgeLight\publish였고, 사람마다 다를 수 있습니다.
# Navigate to your project folder
cd C:\MyProject
# Sign the executable
.\sign.exe code trusted-signing `
-b "C:\MyProject\publish" `
-tse "https://wus2.codesigning.azure.net" `
-tscp "MyAppProfile" `
-tsa "myapp-signing" `
*.exe `
-v Information
설명된 매개변수:
-b: 서명할 파일이 포함된 기본 디렉터리-tse: 신뢰받는 서명 엔드포인트 (귀하의 지역)-tscp: 인증서 프로필 이름-tsa: 신뢰받는 서명 계정 이름*.exe: 파일을 서명하는 패턴-v: 장황함 수준 (추적, 정보, 경고, 오류)
기대 결과:
info: Signing WindowsEdgeLight.exe succeeded.
Completed in 2743 ms.
5단계: 서명 검증
PowerShell에서 이 작업을 할 수 있습니다:
# Check the signature
Get-AuthenticodeSignature ".\publish\MyApp.exe" | Format-List
# Look for:
# Status: Valid
# SignerCertificate: CN=Your Name, O=Your Name, ...
# TimeStamperCertificate: Should be present
EXE → Properties→ 디지털 서명 탭을 우클릭하세요:
- 서명 좀 봐야 해
- "이 디지털 서명은 괜찮아요."
지역 서명 문제의 흔한 점
이 모든 걸 다 쳤어요 ᄏᄏ
문제: "계정을 설정하려면 'az login'을 실행해 주세요"
- 원인: 올바른 스코프로 로그인하지 않음
- 수정: 그럼 도망치세요
az logoutaz login --use-device-code --scope "https://codesigning.azure.net/.default"
이슈: "403 금지"
- 원인: 잘못된 엔드포인트, 계정 이름, 권한 누락
- 수정:
- 엔드포인트가 귀하의 지역(wus2, eus 등)과 일치하는지 확인하세요.
- 계정 이름이 정확한지 확인하세요 (대소문자 구분 기준)
- "신뢰받는 서명 인증서 프로필 서명자" 역할이 있는지 확인하세요
문제: "사용자 계정이 테넌트에 존재하지 않습니다"
- 원인: Azure CLI가 Visual Studio 자격 증명을 사용하려고 합니다
- 해결: 장치 코드 흐름을 사용하세요 (2단계 참조)
3부: GitHub Actions를 이용한 자동 서명
여기서 마법이 일어납니다. 모든 동의서를 자동으로 서명하고 싶어요. 저는 GitVersion을 사용 중이라 커밋에 태그를 달기만 하면 GitHub Actions가 실행을 시작합니다. 실제 연재를 자세히 보실 수 있습니다 https://github.com/shanselman/WindowsEdgeLight/actions/runs/19775054123
1단계: 서비스 책임자 만들기
GitHub Actions는 코드를 서명하기 위해 자체 신원이 필요합니다. 우리는 서비스 주체(예: 로봇 계정)를 생성할 것입니다. 이것은 지역 서명 시스템과는 매우 다릅니다.
중요: 이를 위해서는 구독자에 소유자 또는 사용자 접근 관리자 역할이 필요합니다. 만약 없다면, Azure 관리자나 친구에게 물어보세요.
# Create service principal with signing permissions
az ad sp create-for-rbac \
--name "MyAppGitHubActions" \
--role "Trusted Signing Certificate Profile Signer" \
--scopes /subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/MyAppSigning/providers/Microsoft.CodeSigning/codeSigningAccounts/myapp-signing \
--json-auth
이 제품은 다음과 같은 JSON을 출력합니다:
{
"clientId": "12345678-1234-1234-1234-123456789abc",
"clientSecret": "super-secret-value-abc123",
"tenantId": "87654321-4321-4321-4321-cba987654321",
"subscriptionId": "abcdef12-3456-7890-abcd-ef1234567890"
}
이 값들을 즉시 저장하세요! 다시 회수할 수 없어. 이건 정말 중요해요. clientSecret
대안: Azure Portal Method
CLI가 작동하지 않으면:
- Azure Portal → App registrations → New registration
- 이름: "MyAppGitHubActions"
- 등록 클릭
- 애플리케이션(클라이언트) ID 복사하세요 - 이건
AZURE_CLIENT_ID - 디렉토리(세입자) ID 복사하세요 - 이건
AZURE_TENANT_ID - 인증서 및 비밀로 이동 → 새 클라이언트 비밀
- 설명: "GitHub Actions"
- 만료일: 최대 24개월
- 추가를 클릭하고 즉시 값을 복사하는데, 이건
AZURE_CLIENT_SECRET - 접근 제어(IAM)→ 신뢰받는 서명 계정으로 가세요
- 신뢰받는 서명 인증서 프로필 서명자에게 역할 할당→ 추가하세요
- 회원을 선택→ "MyAppGitHubActions"를 검색하세요
- 리뷰 + 할당
2단계: GitHub 비밀 추가
GitHub 저장소로 가세요:
- 설정 → 비밀과 변수 → 행동
- 각 항목별로 새 저장소 비밀을 클릭하세요:
AZURE_CLIENT_ID- 서비스 주체 출력 또는 앱 등록에서AZURE_CLIENT_SECRET -서비스 주체 출력 또는 인증서 및 비밀에서AZURE_TENANT_ID- 서비스 주체 출력 또는 앱 등록에서AZURE_SUBSCRIPTION_ID- Azure 포털 → 구독
보안 주의: 이 비밀들은 암호화되어 있으며 로그에 전혀 보이지 않습니다. 오직 당신의 워크플로우만이 접근할 수 있습니다. 다시는 못 볼 거야.
3단계: GitHub 워크플로우 업데이트
이건 약간 혼란스럽습니다. YAML은 사탄의 표시이지만, 우리 사회가 이미 그렇게 가라앉은 것입니다.
아래 닷넷 버전을 참고하세요. 당신 경우는 8점이나 9점 정도일 수도 있고요. 또한, 저는 x64와 ARM 버전 모두를 만들고 있고 GitVersion을 사용하고 있어서 더 완전한 build.yml을 원하시면 여기로 가 https://github.com/shanselman/WindowsEdgeLight/blob/master/.github/workflows/build.yml 저도 압축 파일을 압축하고 릴리스를 준비하고 있어서 느슨한 EXE가 ZIP 파일에 저장되도록 하고 있습니다.
서명 단계를 추가하여 다음을 추가하세요:.github/workflows/build.yml
name: Build and Sign
on:
push:
tags:
- 'v*'
workflow_dispatch:
permissions:
contents: write
jobs:
build:
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- name: Restore dependencies
run: dotnet restore MyApp/MyApp.csproj
- name: Build
run: |
dotnet publish MyApp/MyApp.csproj `
-c Release `
-r win-x64 `
--self-contained
# === SIGNING STEPS START HERE ===
- name: Azure Login
uses: azure/login@v2
with:
creds: '{"clientId":"${{ secrets.AZURE_CLIENT_ID }}","clientSecret":"${{ secrets.AZURE_CLIENT_SECRET }}","subscriptionId":"${{ secrets.AZURE_SUBSCRIPTION_ID }}","tenantId":"${{ secrets.AZURE_TENANT_ID }}"}'
- name: Sign executables with Trusted Signing
uses: azure/trusted-signing-action@v0
with:
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
endpoint: https://wus2.codesigning.azure.net/
trusted-signing-account-name: myapp-signing
certificate-profile-name: MyAppProfile
files-folder: ${{ github.workspace }}\MyApp\bin\Release\net10.0-windows\win-x64\publish
files-folder-filter: exe
files-folder-recurse: true
file-digest: SHA256
timestamp-rfc3161: http://timestamp.acs.microsoft.com
timestamp-digest: SHA256
# === SIGNING STEPS END HERE ===
- name: Create Release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v2
with:
files: MyApp/bin/Release/net10.0-windows/win-x64/publish/MyApp.exe
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
주요 요점:
endpoint: 본인의 지역 엔드포인트(wus2, eus 등)를 사용하세요.trusted-signing-account-name: 당신의 계정 이름 (정확한, 대문자 구분)certificate-profile-name: 당신의 인증서 프로필 이름 (정확하고 대문자 구분)files-folder: 컴파일된 실행 파일로 가는 경로files-folder-filter: 서명할 파일 형식(exe, dll 등)files-folder-recurse: 하위 폴더 내 서명 파일
4단계: 워크플로우 테스트
이제 워크플로우를 트리거하세요. 두 가지 선택지가 있습니다:
옵션 A: 수동 트리거 (테스트용으로 가장 안전함)
워크플로우에 가 포함되어 있으니, 태그를 만들지 않고도 수동으로 트리거할 수 있습니다:workflow_dispatch:
# Trigger manually via GitHub CLI
gh workflow run build.yml
# Or go to GitHub web UI:
# Actions tab → "Build and Sign" workflow → "Run workflow" button
이 방법은 다음과 같은 이유로 테스트에 이상적입니다:
- 태그는 필요 없어요
- 릴리스를 생성하지 않습니다
- 여러 번 테스트할 수 있습니다
- 디버깅하기 쉬운 문제들
옵션 B: 태그 생성 (실제 출시용)
# Make sure you're on your main branch with no uncommitted changes
git status
# Create and push a tag
git tag v1.0.0
git push origin v1.0.0
서명된 바이너리로 실제 릴리스를 만들 준비가 되었을 때 이 기능을 사용하세요. 이게 내가 내 쪽에서 하는 일이야.
5단계: 빌드 모니터링
GitHub CLI로 진행 상황을 확인해 보세요:
# See latest runs
gh run list --limit 5
# Watch a specific run
gh run watch
# View detailed status
gh run view --log
또는 방문할 수도 있습니다: https://github.com/YOUR_USERNAME/YOUR_REPO/actions
찾으세요:
- Azure 로그인 - ~5초 내에 완료됩니다
- Trusted Signing으로 실행 파일에 서명하세요 - 10~30초 내에 완료됩니다
- 릴리스 생성 - 서명된 실행 파일이 이제 GitHib 프로젝트의 /releases에서 제공됩니다
GitHub Actions 에서 흔히 발생하는 문제
당연히 몇 번 이런 걸 쳤어요.
문제: 서명 중 "403 금지"
- 원인: 서비스 주체가 권한이 없습니다
- 수정:
- Access Control (IAM) → 신뢰받는 서명 →계정 (IAM) Go to Azure Portal
- "MyAppGitHubActions"가 "신뢰받는 서명 인증서 프로필 서명자" 역할을 가지고 있는지 확인하세요
- 아니면 수동으로 추가하세요
문제: "패턴과 일치하는 파일이 없었습니다"
- 원인: 잘못된 경로 또는 잘못된 위치에 유물을 건설
files-folder - 수정:
- 서명하기 전에 디버그 단계를 추가하세요:
- run: Get-ChildItem -Recurse - EXE가 실제로 어디에 있는지 찾아보세요
- 매치 업데이트
files-folder
- 서명하기 전에 디버그 단계를 추가하세요:
문제: 비밀이 작동하지 않음
- 원인: 비밀 이름 또는 저장되지 않은 값의 오타
- 수정:
- 비밀 이름이 정확히 일치하는지 검증합니다 (대문자 구분)
- 확실하지 않으면 비밀을 다시 만들어 보세요
- 값에 여유 공백이 없는지 확인하세요
문제: "DefaultAzureCredential 인증 실패"
- 원인: 보통 세입자 ID나 고객 ID가 잘못 작성되어 있습니다
- 수정: 서비스 주체 출력에서 4개의 비밀이 모두 맞는지 확인하세요
4부: 증명서 이해하기
인증서 수명주기
Azure Trusted Signing은 보통 3일 정도의 단기 인증서를 사용합니다. 이 점이 저를 놀라게 했지만, 그들은 이게 사실 보안 기능이라고 합니다:
- 인증서가 해킹되면 빠르게 만료됩니다
- 인증서 파일이나 비밀번호는 절대 관리하지 않습니다
- 자동 갱신 - 아무것도 할 필요가 없습니다
그런데 제 서명이 3일 후에 끊기지 않나요?
아니요, 그게 타임스탬프가 쓰는 용도인 것 같아요. 파일에 서명할 때:
- Azure는 3일 인증서를 발급합니다
- 파일은 그 인증서로 서명됩니다
- 타임스탬프 서버는 "이 파일은 날짜에 서명되었습니다"를 기록합니다.
- 인증서가 만료된 후에도 서명은 유효한 상태로 유지됩니다. 타임스탬프가 인증서가 유효했던 시점에 서명되었음을 증명하기 때문입니다
그래서 로컬 및 GitHub Actions 서명 모두에 다음이 포함됩니다:
timestamp-rfc3161: http://timestamp.acs.microsoft.com
증명서에 포함된 내용
서명된 실행 파일이 다음과 같은 인증서를 가지고 있습니다:
- 제목: 당신의 이름 (예: "CN=존 도, O=존 도, L=시애틀, S=워싱턴, C=미국")
- 발행자: Microsoft ID Verified CS EOC CA 01
- 유효 날짜: 3일 창
- 키 크기: 3072비트 RSA (매우 안전함)
- 향상된 키 사용: 코드 서명
어떤 기기에서든 인증서를 검증하세요
# Using PowerShell
Get-AuthenticodeSignature "MyApp.exe" | Select-Object -ExpandProperty SignerCertificate | Format-List
# Using Windows UI
# Right-click EXE → Properties → Digital Signatures tab → Details → View Certificate
이 모든 과정이 한 시간에서 75분 정도 걸렸습니다. 상세했지만 깊게 어렵지는 않았다. 오타, 대소문자 민감, 그리고 역할 기반 접근 제어(Role-Based Access Control)와 관련된 몇 가지 계정 문제 때문에 저를 느리게 했습니다. 도움이 되었길 바랍니다!
사용 자료
- Azure Trusted Signing Documentation
- 닷넷/사인 도구
- azure/trusted-signing-action
- Windows 코드 서명 모범 사례
- 스마트스크린 평판 시스템
2025년 11월에 작성되었으며, 실제 WindowsEdgeLight 구현을 바탕으로 작성되었습니다. Azure 지역과 계정 유형에 따라 설정이 약간 다를 수 있습니다. 상황은 변하니 냉정하라.
댓글
댓글 쓰기