{"id":9324,"date":"2025-12-02T09:42:36","date_gmt":"2025-12-02T09:42:36","guid":{"rendered":"https:\/\/techtrendfeed.com\/?p=9324"},"modified":"2025-12-02T09:42:37","modified_gmt":"2025-12-02T09:42:37","slug":"routinely-signing-a-home-windows-exe-with-azure-trusted-signing-dotnet-signal-and-github-actions","status":"publish","type":"post","link":"https:\/\/techtrendfeed.com\/?p=9324","title":{"rendered":"Routinely Signing a Home windows EXE with Azure Trusted Signing, dotnet signal, and GitHub Actions"},"content":{"rendered":"<p> <br \/>\n<\/p>\n<div id=\"\">&#13;<br \/>\n            &#13;<\/p>\n<p><a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/images.hanselman.com\/blog\/Windows-Live-Writer\/Automatically-Signing-a-Windows-EXE-with_D0BE\/image_2.png\"><img loading=\"lazy\" decoding=\"async\" title=\"WindowsEdgeLight on a Surface\" style=\"float: right; padding-top: 0px; padding-left: 0px; margin: 0px 0px 0px 5px; display: inline; padding-right: 0px\" alt=\"WindowsEdgeLight on a Surface\" src=\"https:\/\/images.hanselman.com\/blog\/Windows-Live-Writer\/Automatically-Signing-a-Windows-EXE-with_D0BE\/image_thumb%5B1%5D.png\" width=\"400\" align=\"right\" height=\"344\"\/><\/a>Mac Tahoe (in Beta as of the time of this writing) has this new characteristic known as Edge Mild that principally places a shiny image of an Edge Mild round your display and principally makes use of the facility of OLED to present you a digital ring mild. So I used to be like, why cannot we even have good issues? I wrote (<a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/www.youtube.com\/watch?v=WMbHVu4lAGA\">vibed, with GitHub Copilot and Claude Sonnet 4.5<\/a>) a Home windows Edge Mild App (supply code at <a rel=\"nofollow\" target=\"_blank\" title=\"https:\/\/github.com\/shanselman\/WindowsEdgeLight\" href=\"https:\/\/github.com\/shanselman\/WindowsEdgeLight\">https:\/\/github.com\/shanselman\/WindowsEdgeLight<\/a> and you may get the most recent launch right here <a rel=\"nofollow\" target=\"_blank\" title=\"https:\/\/github.com\/shanselman\/WindowsEdgeLight\/releases\" href=\"https:\/\/github.com\/shanselman\/WindowsEdgeLight\/releases\">https:\/\/github.com\/shanselman\/WindowsEdgeLight\/releases<\/a> or the app will test for brand new releases and autoupdate with Updatum).<\/p>\n<p>Nevertheless, as is with all suss free executables on the web, whenever you run random stuff you may usually get the Window Defender &#8216;new cellphone, who dis&#8217; warning which is frightening. After a number of downloads and no viruses or complaints, my executable will finally achieve popularity with the Home windows Defender Sensible Display service, however having a Code Signing Certificates is claimed to assist with that. Nevertheless, code signing certs are costly and a problem to handle and renew.<\/p>\n<p>Somebody informed me that <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/azure.microsoft.com\/en-us\/products\/trusted-signing\">Azure Trusted Signing<\/a> was considerably much less of a problem &#8211; it is much less, however it&#8217;s nonetheless non-trivial. I learn <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/weblog.west-wind.com\/posts\/2025\/Jul\/20\/Fighting-through-Setting-up-Microsoft-Trusted-Signing\">this put up from Rick (his weblog is gold and has been for years) earlier within the yr<\/a> and a few of it was tremendous helpful and different stuff has been made less complicated over time.<\/p>\n<p>I wrote 80% of this weblog put up, however since I simply spent an hour getting code signing to work and GitHub Copilot was going via and logging the whole lot I did, I did use Claude 4.5 to assist manage a few of this. I&#8217;ve reviewed all of it and re-written components I did not like, so any errors are mine.<\/p>\n<p>Azure Trusted Signing is Microsoft&#8217;s cloud-based code signing service that:<\/p>\n<ul>\n<li><strong>No {hardware} tokens<\/strong> &#8211; The whole lot occurs within the cloud  <\/li>\n<li><strong>Computerized certificates administration<\/strong> &#8211; Certificates are issued and renewed routinely  <\/li>\n<li><strong>GitHub Actions integration<\/strong> &#8211; Signal throughout your CI\/CD pipeline. I used GH Actions.  <\/li>\n<li><strong>Kinda Affortable<\/strong> &#8211; About $10\/month for small initiatives. I would love it if this had been $10 a yr. That is cheaper than a yearly cert, however it&#8217;ll add up after some time so I am at all times in search of cheaper\/simpler choices.  <\/li>\n<li><strong>Trusted by Home windows<\/strong> &#8211; Makes use of the identical certificates authority as Microsoft&#8217;s personal apps, so it&#8217;s best to get your EXE trusted sooner<\/li>\n<\/ul>\n<h2>Conditions<\/h2>\n<p>Earlier than beginning, you may want:  <\/p>\n<ol>\n<li><strong>Azure subscription<\/strong>  <\/li>\n<li><strong>Azure CLI<\/strong> &#8211; <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/aka.ms\/installazurecliwindows\">Set up from right here<\/a>  <\/li>\n<li><strong>Identification validation paperwork<\/strong> &#8211; Driver&#8217;s license or passport for particular person builders. Observe that I am within the US, so your mileage could fluctuate however I principally arrange the account, scanned a QR code, took an image of my license, then did a selfie, then waited.  <\/li>\n<li><strong>Home windows PC<\/strong> &#8211; For native signing (elective) however I ended up utilizing the dotnet signal device. There are  <\/li>\n<li><strong>GitHub repository<\/strong> &#8211; For automated signing (elective)<\/li>\n<\/ol>\n<h3>Half 1: Setting Up Azure Trusted Signing<\/h3>\n<h4>Step 1: Register the Useful resource Supplier<\/h4>\n<p>First, I have to allow the Azure Trusted Signing service in my subscription. This may be achieved within the Portal, or on the CLI. <\/p>\n<pre><code># Login to Azure\naz login\n\n# Register the Microsoft.CodeSigning useful resource supplier\naz supplier register --namespace Microsoft.CodeSigning\n\n# Look forward to registration to finish (takes 2-3 minutes)\naz supplier present --namespace Microsoft.CodeSigning --query \"registrationState\"\n<\/code><\/pre>\n<p>Wait till the output reveals <code>\"Registered\"<\/code>.\n<\/p>\n<h3>Step 2: Create a Trusted Signing Account<\/h3>\n<p>Now create the precise signing account. You are able to do this by way of Azure Portal or CLI.\n<\/p>\n<p><strong>Choice A: Azure Portal (Simpler for first-timers)<\/strong>\n<\/p>\n<ol>\n<li>Go to <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/portal.azure.com\/\">Azure Portal<\/a>\n<\/li>\n<li>Seek for &#8220;Trusted Signing Accounts&#8221;\n<\/li>\n<li>Click on <strong>Create<\/strong>\n<\/li>\n<li>Fill in:\n<ul>\n<li><strong>Subscription<\/strong>: Your subscription\n<\/li>\n<li><strong>Useful resource Group<\/strong>: Create new or use present (e.g., &#8220;MyAppSigning&#8221;)\n<\/li>\n<li><strong>Account Identify<\/strong>: A singular title (e.g., &#8220;myapp-signing&#8221;)\n<\/li>\n<li><strong>Area<\/strong>: Select closest to you (e.g., &#8220;West US 2&#8221;)\n<\/li>\n<li><strong>SKU<\/strong>: Fundamental (ample for many apps)<\/li>\n<\/ul>\n<\/li>\n<li>Click on <strong>Assessment + Create<\/strong>, then <strong>Create<\/strong><\/li>\n<\/ol>\n<p><strong>Choice B: Azure CLI (Quicker in case you are a CLI individual or wish to drive stick shift)<\/strong><\/p>\n<pre><code># Create a useful resource group\naz group create --name MyAppSigning --location westus2\n\n# Create the Trusted Signing account\naz trustedsigning create \n  --resource-group MyAppSigning \n  --account-name myapp-signing \n  --location westus2 \n  --sku-name Fundamental\n<\/code><\/pre>\n<p><strong>Essential<\/strong>: Observe your area endpoint. Widespread ones are:\n<\/p>\n<ul>\n<li>East US: <code>https:\/\/eus.codesigning.azure.web\/<\/code>\n<\/li>\n<li>West US 2: <code>https:\/\/wus2.codesigning.azure.web\/<\/code>\n<\/li>\n<li>Your particular area: Test in Azure Portal underneath your account&#8217;s Overview web page<\/li>\n<\/ul>\n<p>I completely flaked on this and messed round for 10 min earlier than I noticed that this URL issues and is particular to your account. Keep in mind this endpoint.<\/p>\n<h3>Step 3: Full Identification Validation<\/h3>\n<p>That is crucial step. Microsoft must confirm you are an actual individual\/group.\n<\/p>\n<ol>\n<li>In Azure Portal, go to your Trusted Signing Account\n<\/li>\n<li>Click on <strong>Identification validation<\/strong> within the left menu\n<\/li>\n<li>Click on <strong>Add id validation<\/strong>\n<\/li>\n<li>Select validation kind:\n<ul>\n<li><strong>Particular person<\/strong>: For solo builders (makes use of driver&#8217;s license\/passport)\n<\/li>\n<li><strong>Group<\/strong>: For firms (makes use of enterprise registration paperwork)<\/li>\n<\/ul>\n<\/li>\n<li>For <strong>Particular person validation<\/strong>:\n<ul>\n<li>Add a transparent photograph of your government-issued ID\n<\/li>\n<li>Present your full authorized title (should match ID precisely)\n<\/li>\n<li>Present your electronic mail deal with<\/li>\n<\/ul>\n<\/li>\n<li>Submit and look forward to approval<\/li>\n<\/ol>\n<p><strong>Approval Time<\/strong>:\n<\/p>\n<ul>\n<li>Particular person: Often 1-3 enterprise days\n<\/li>\n<li>Group: 3-5 enterprise days\n<\/li>\n<li>Me: This took about 4 hours, so once more, YMMV. I used my private account and my private Azure (do not belief MSFT of us with limitless Azure credit, I pay for my very own) in order that they did not comprehend it was me. I went via the common line, not the Pre-check line LOL.<\/li>\n<\/ul>\n<p>You may obtain an electronic mail when authorised. <strong>You can&#8217;t signal any code till that is authorised.<\/strong>\n<\/p>\n<h3>Step 4: Create a Certificates Profile<\/h3>\n<p>As soon as your id is validated, create a certificates profile. That is what really points the signing certificates.\n<\/p>\n<ol>\n<li>In your Trusted Signing Account, click on <strong>Certificates profiles<\/strong>\n<\/li>\n<li>Click on <strong>Add certificates profile<\/strong>\n<\/li>\n<li>Fill in:\n<ul>\n<li><strong>Profile title<\/strong>: Descriptive title (e.g., &#8220;MyAppProfile&#8221;)\n<\/li>\n<li><strong>Profile kind<\/strong>: Select <strong>Public Belief<\/strong> (required to stop SmartScreen)\n<\/li>\n<li><strong>Identification validation<\/strong>: Choose your authorised id\n<\/li>\n<li><strong>Certificates kind<\/strong>: Code Signing<\/li>\n<\/ul>\n<\/li>\n<li>Click on <strong>Add<\/strong><\/li>\n<\/ol>\n<p><strong>Essential<\/strong>: Solely &#8220;Public Belief&#8221; profiles forestall SmartScreen warnings. &#8220;Personal Belief&#8221; is for inner apps solely. This took me a second to appreciate additionally as it is not an intuitive title.\n<\/p>\n<h3>Step 5: Confirm Your Setup<\/h3>\n<pre><code># Listing your Trusted Signing accounts\naz trustedsigning present \n  --resource-group MyAppSigning \n  --account-name myapp-signing\n\n# Ought to present standing: \"Succeeded\"\n<\/code><\/pre>\n<p><strong>Write down these values<\/strong> &#8211; you may want them later:\n<\/p>\n<ul>\n<li><strong>Account Identify<\/strong>: <code>myapp-signing<\/code>\n<\/li>\n<li><strong>Certificates Profile Identify<\/strong>: <code>MyAppProfile<\/code>\n<\/li>\n<li><strong>Endpoint URL<\/strong>: <code>https:\/\/wus2.codesigning.azure.web\/<\/code> (or your area)\n<\/li>\n<li><strong>Subscription ID<\/strong>: Present in Azure Portal\n<\/li>\n<li><strong>Useful resource Group<\/strong>: <code>MyAppSigning<\/code><\/li>\n<\/ul>\n<h2>Half 2: Native Code Signing<\/h2>\n<p>Now let&#8217;s signal an executable in your my machine. You do not NEED to do that, however I wished to attempt it domestically to keep away from a bunch of CI\/CD runs, and I wished to right-click the EXE and see the cert in Properties earlier than I took all of it to the cloud. The good half about this was that I did not have to mess with any certificates.\n<\/p>\n<h3>Step 1: Assign Your self the Signing Position<\/h3>\n<p>You want permission to really use the signing service.\n<\/p>\n<p><strong>Choice A: Azure Portal<\/strong>\n<\/p>\n<ol>\n<li>Go to your Trusted Signing Account\n<\/li>\n<li>Click on <strong>Entry management (IAM)<\/strong>\n<\/li>\n<li>Click on <strong>Add<\/strong> \u2192 <strong>Add function task<\/strong>\n<\/li>\n<li>Seek for and choose <strong>Trusted Signing Certificates Profile Signer. <\/strong>That is necessary. I looked for &#8220;code&#8221; and located nothing. Seek for &#8220;Trusted&#8221;\n<\/li>\n<li>Click on <strong>Subsequent<\/strong>\n<\/li>\n<li>Click on <strong>Choose members<\/strong> and discover your person account\n<\/li>\n<li>Click on <strong>Choose<\/strong>, then <strong>Assessment + assign<\/strong><\/li>\n<\/ol>\n<p><strong>Choice B: Azure CLI<\/strong><\/p>\n<pre><code># Get your person object ID\n$userId = az advert signed-in-user present --query id -o tsv\n\n# Assign the function\naz function task create \n  --role \"Trusted Signing Certificates Profile Signer\" \n  --assignee-object-id $userId \n  --scope \/subscriptions\/YOUR_SUBSCRIPTION_ID\/resourceGroups\/MyAppSigning\/suppliers\/Microsoft.CodeSigning\/codeSigningAccounts\/myapp-signing\n<\/code><\/pre>\n<p>Substitute <code>YOUR_SUBSCRIPTION_ID<\/code> together with your precise subscription ID.\n<\/p>\n<h3>Step 2: Login with the Appropriate Scope<\/h3>\n<p>That is essential &#8211; it is advisable login with the particular codesigning scope.<\/p>\n<pre><code># Logout first to clear previous tokens\naz logout\n\n# Login with codesigning scope\naz login --use-device-code --scope \"https:\/\/codesigning.azure.web\/.default\"\n<\/code><\/pre>\n<p>This offers you a code to enter at <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/microsoft.com\/devicelogin\">https:\/\/microsoft.com\/devicelogin<\/a>. Observe the prompts.\n<\/p>\n<p><strong>Why gadget code movement?<\/strong> As a result of Azure CLI&#8217;s default authentication can battle with Visible Studio credentials in my expertise. System code movement is extra dependable for code signing.\n<\/p>\n<h3>Step 3: Obtain the Signal Instrument<\/h3>\n<p><strong>Choice A: Set up Globally (Really useful for normal use)<\/strong><\/p>\n<pre><code># Set up as a world device (accessible in every single place)\ndotnet device set up --global --prerelease signal\n\n# Confirm set up\nsignal --version\n<\/code><\/pre>\n<p><strong>Choice B: Set up Domestically (Undertaking-specific)<\/strong><\/p>\n<pre><code># Set up to present listing\ndotnet device set up --tool-path . --prerelease signal\n\n# Use with .signal.exe\n<\/code><\/pre>\n<p><strong>Which ought to I exploit?<\/strong>\n<\/p>\n<ul>\n<li><strong>International<\/strong>: When you&#8217;ll signal a number of initiatives or signal continuously\n<\/li>\n<li><strong>Native<\/strong>: If you wish to preserve the device with a particular mission or don&#8217;t need it in your PATH<\/li>\n<\/ul>\n<h3>Step 4: Signal Your Executable<\/h3>\n<p>Observe once more that code signing URL is particular to you. The tscp is your Trusted Signing Certificates Profile title and the tsa is your Trusted Signing Account title. I set *.exe to signal all of the EXEs within the folder and be aware that the -b base listing is an absolute path, not a relative one. For me it was d:githubWindowsEdgeLightpublish, and your mileage will fluctuate.<\/p>\n<pre><code># Navigate to your mission folder\ncd C:MyProject\n\n# Signal the executable\n.signal.exe code trusted-signing `\n  -b \"C:MyProjectpublish\" `\n  -tse \"https:\/\/wus2.codesigning.azure.web\" `\n  -tscp \"MyAppProfile\" `\n  -tsa \"myapp-signing\" `\n  *.exe `\n  -v Info\n<\/code><\/pre>\n<p><strong>Parameters defined:<\/strong>\n<\/p>\n<ul>\n<li><code>-b<\/code>: Base listing containing information to signal\n<\/li>\n<li><code>-tse<\/code>: Trusted Signing endpoint (your area)\n<\/li>\n<li><code>-tscp<\/code>: Certificates profile title\n<\/li>\n<li><code>-tsa<\/code>: Trusted Signing account title\n<\/li>\n<li><code>*.exe<\/code>: Sample to match information to signal\n<\/li>\n<li><code>-v<\/code>: Verbosity stage (Hint, Info, Warning, Error)<\/li>\n<\/ul>\n<p><strong>Anticipated output:<\/strong><\/p>\n<pre><code>data: Signing WindowsEdgeLight.exe succeeded.\nAccomplished in 2743 ms.\n<\/code><\/pre>\n<h3>Step 5: Confirm the Signature<\/h3>\n<p>You are able to do this in PowerShell:<\/p>\n<pre><code># Test the signature\nGet-AuthenticodeSignature \".publishMyApp.exe\" | Format-Listing\n\n# Search for:\n# Standing: Legitimate\n# SignerCertificate: CN=Your Identify, O=Your Identify, ...\n# TimeStamperCertificate: Ought to be current\n<\/code><\/pre>\n<p><strong>Proper-click the EXE<\/strong> \u2192 <strong>Properties<\/strong> \u2192 <strong>Digital Signatures<\/strong> tab:\n<\/p>\n<ul>\n<li>You need to see your signature\n<\/li>\n<li>&#8220;This digital signature is OK&#8221;<\/li>\n<\/ul>\n<h3>Widespread Native Signing Points<\/h3>\n<p>I hit all of those lol<\/p>\n<p><strong>Subject: &#8220;Please run &#8216;az login&#8217; to arrange account&#8221;<\/strong>\n<\/p>\n<ul>\n<li><strong>Trigger<\/strong>: Not logged in with the best scope\n<\/li>\n<li><strong>Repair<\/strong>: Run <code>az logout<\/code> then <code>az login --use-device-code --scope \"https:\/\/codesigning.azure.web\/.default\"<\/code><\/li>\n<\/ul>\n<p><strong>Subject: &#8220;403 Forbidden&#8221;<\/strong>\n<\/p>\n<ul>\n<li><strong>Trigger<\/strong>: Mistaken endpoint, account title, or lacking permissions\n<\/li>\n<li><strong>Repair<\/strong>:\n<ul>\n<li>Confirm endpoint matches your area (wus2, eus, and so on.)\n<\/li>\n<li>Confirm account title is actual (case-sensitive)\n<\/li>\n<li>Confirm you may have &#8220;Trusted Signing Certificates Profile Signer&#8221; function<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><strong>Subject: &#8220;Person account doesn&#8217;t exist in tenant&#8221;<\/strong>\n<\/p>\n<ul>\n<li><strong>Trigger<\/strong>: Azure CLI making an attempt to make use of Visible Studio credentials\n<\/li>\n<li><strong>Repair<\/strong>: Use gadget code movement (see Step 2)<\/li>\n<\/ul>\n<h2>Half 3: Automated Signing with GitHub Actions<\/h2>\n<p>That is the place the magic occurs. I wish to routinely signal each launch. I am utilizing GitVersion so I simply have to tag a commit and GitHub Actions will kick off a run. You possibly can go take a look at an actual run intimately at <a rel=\"nofollow\" target=\"_blank\" title=\"https:\/\/github.com\/shanselman\/WindowsEdgeLight\/actions\/runs\/19775054123\" href=\"https:\/\/github.com\/shanselman\/WindowsEdgeLight\/actions\/runs\/19775054123\">https:\/\/github.com\/shanselman\/WindowsEdgeLight\/actions\/runs\/19775054123<\/a>\n<\/p>\n<h3>Step 1: Create a Service Principal<\/h3>\n<p>GitHub Actions wants its personal id to signal code. We&#8217;ll create a service principal (like a robotic account). That is VERY completely different than your native signing setup.\n<\/p>\n<p><strong>Essential<\/strong>: You want <strong>Proprietor<\/strong> or <strong>Person Entry Administrator<\/strong> function in your subscription to do that. If you do not have it, ask your Azure admin or a buddy.<\/p>\n<pre><code># Create service principal with signing permissions\naz advert sp create-for-rbac \n  --name \"MyAppGitHubActions\" \n  --role \"Trusted Signing Certificates Profile Signer\" \n  --scopes \/subscriptions\/YOUR_SUBSCRIPTION_ID\/resourceGroups\/MyAppSigning\/suppliers\/Microsoft.CodeSigning\/codeSigningAccounts\/myapp-signing \n  --json-auth\n<\/code><\/pre>\n<p>This outputs JSON like this:<\/p>\n<pre><code>{\n  \"clientId\": \"12345678-1234-1234-1234-123456789abc\",\n  \"clientSecret\": \"super-secret-value-abc123\",\n  \"tenantId\": \"87654321-4321-4321-4321-cba987654321\",\n  \"subscriptionId\": \"abcdef12-3456-7890-abcd-ef1234567890\"\n}\n<\/code><\/pre>\n<p><strong>SAVE THESE VALUES IMMEDIATELY!<\/strong> You possibly can&#8217;t retrieve the <code>clientSecret<\/code> once more. That is tremendous necessary.\n<\/p>\n<p><strong>Various: Azure Portal Technique<\/strong>\n<\/p>\n<p>If CLI would not work:\n<\/p>\n<ol>\n<li><strong>Azure Portal<\/strong> \u2192 <strong>App registrations<\/strong> \u2192 <strong>New registration<\/strong>\n<\/li>\n<li>Identify: &#8220;MyAppGitHubActions&#8221;\n<\/li>\n<li>Click on <strong>Register<\/strong>\n<\/li>\n<li><strong>Copy the Utility (consumer) ID<\/strong> &#8211; that is <code>AZURE_CLIENT_ID<\/code>\n<\/li>\n<li><strong>Copy the Listing (tenant) ID<\/strong> &#8211; that is <code>AZURE_TENANT_ID<\/code>\n<\/li>\n<li>Go to <strong>Certificates &amp; secrets and techniques<\/strong> \u2192 <strong>New consumer secret<\/strong>\n<\/li>\n<li>Description: &#8220;GitHub Actions&#8221;\n<\/li>\n<li>Expiration: 24 months (max)\n<\/li>\n<li>Click on <strong>Add<\/strong> and <strong>instantly copy the Worth<\/strong> &#8211; that is <code>AZURE_CLIENT_SECRET<\/code>\n<\/li>\n<li>Go to your Trusted Signing Account \u2192 <strong>Entry management (IAM)<\/strong>\n<\/li>\n<li><strong>Add function task<\/strong> \u2192 <strong>Trusted Signing Certificates Profile Signer<\/strong>\n<\/li>\n<li><strong>Choose members<\/strong> \u2192 Seek for &#8220;MyAppGitHubActions&#8221;\n<\/li>\n<li><strong>Assessment + assign<\/strong><\/li>\n<\/ol>\n<h3>Step 2: Add GitHub Secrets and techniques<\/h3>\n<p>Go to your GitHub repository:\n<\/p>\n<ol>\n<li><strong>Settings<\/strong> \u2192 <strong>Secrets and techniques and variables<\/strong> \u2192 <strong>Actions<\/strong>\n<\/li>\n<li>Click on <strong>New repository secret<\/strong> for every:<\/li>\n<\/ol>\n<ul>\n<li><code>AZURE_CLIENT_ID <\/code>&#8211; From service principal output or App registration <\/li>\n<li><code>AZURE_CLIENT_SECRET <span>- <\/span><\/code>From service principal output or Certificates &amp; secrets and techniques <\/li>\n<li><code>AZURE_TENANT_ID <\/code>&#8211; From service principal output or App registration <\/li>\n<li><code>AZURE_SUBSCRIPTION_ID <\/code>&#8211; Azure Portal \u2192 Subscriptions <\/li>\n<\/ul>\n<p><strong>Safety Observe<\/strong>: These secrets and techniques are encrypted and by no means seen in logs. Solely your workflow can entry them. You may by no means see them once more.\n<\/p>\n<h3>Step 3: Replace Your GitHub Workflow<\/h3>\n<p>It is a little complicated because it&#8217;s YAML, which is Devil&#8217;s markup, however it&#8217;s what we have now sunk to as a society.\n<\/p>\n<p>Observe the dotnet-version under. Yours is likely to be 8 or 9, and so on. Additionally, I&#8217;m constructing each x64 and ARM variations and I&#8217;m utilizing GitVersion so if you would like a extra full construct.yml, you possibly can go right here <a rel=\"nofollow\" target=\"_blank\" title=\"https:\/\/github.com\/shanselman\/WindowsEdgeLight\/blob\/master\/.github\/workflows\/build.yml\" href=\"https:\/\/github.com\/shanselman\/WindowsEdgeLight\/blob\/master\/.github\/workflows\/build.yml\">https:\/\/github.com\/shanselman\/WindowsEdgeLight\/blob\/grasp\/.github\/workflows\/construct.yml<\/a> I&#8217;m additionally zipping mine up and prepping my releases so my free EXE lives in a ZIP file.\n<\/p>\n<p>Add signing steps to your <code>.github\/workflows\/construct.yml<\/code>:<\/p>\n<pre><code>title: Construct and Signal\n\non:\n  push:\n    tags:\n      - 'v*'\n  workflow_dispatch:\n\npermissions:\n  contents: write\n\njobs:\n  construct:\n    runs-on: windows-latest\n    \n    steps:\n    - title: Checkout code\n      makes use of: actions\/checkout@v4\n      with:\n        fetch-depth: 0\n      \n    - title: Setup .NET\n      makes use of: actions\/setup-dotnet@v4\n      with:\n        dotnet-version: '10.0.x'\n        \n    - title: Restore dependencies\n      run: dotnet restore MyApp\/MyApp.csproj\n\n    - title: Construct\n      run: |\n        dotnet publish MyApp\/MyApp.csproj `\n          -c Launch `\n          -r win-x64 `\n          --self-contained\n\n    # === SIGNING STEPS START HERE ===\n    \n    - title: Azure Login\n      makes use of: azure\/login@v2\n      with:\n        creds: '{\"clientId\":\"${{ secrets and techniques.AZURE_CLIENT_ID }}\",\"clientSecret\":\"${{ secrets and techniques.AZURE_CLIENT_SECRET }}\",\"subscriptionId\":\"${{ secrets and techniques.AZURE_SUBSCRIPTION_ID }}\",\"tenantId\":\"${{ secrets and techniques.AZURE_TENANT_ID }}\"}'\n\n    - title: Signal executables with Trusted Signing\n      makes use of: azure\/trusted-signing-action@v0\n      with:\n        azure-tenant-id: ${{ secrets and techniques.AZURE_TENANT_ID }}\n        azure-client-id: ${{ secrets and techniques.AZURE_CLIENT_ID }}\n        azure-client-secret: ${{ secrets and techniques.AZURE_CLIENT_SECRET }}\n        endpoint: https:\/\/wus2.codesigning.azure.web\/\n        trusted-signing-account-name: myapp-signing\n        certificate-profile-name: MyAppProfile\n        files-folder: ${{ github.workspace }}MyAppbinReleasenet10.0-windowswin-x64publish\n        files-folder-filter: exe\n        files-folder-recurse: true\n        file-digest: SHA256\n        timestamp-rfc3161: http:\/\/timestamp.acs.microsoft.com\n        timestamp-digest: SHA256\n    \n    # === SIGNING STEPS END HERE ===\n        \n    - title: Create Launch\n      if: startsWith(github.ref, 'refs\/tags\/')\n      makes use of: softprops\/action-gh-release@v2\n      with:\n        information: MyApp\/bin\/Launch\/net10.0-windows\/win-x64\/publish\/MyApp.exe\n      env:\n        GITHUB_TOKEN: ${{ secrets and techniques.GITHUB_TOKEN }}\n<\/code><\/pre>\n<p><strong>Key factors:<\/strong>\n<\/p>\n<ul>\n<li><code>endpoint<\/code>: Use YOUR area&#8217;s endpoint (wus2, eus, and so on.)\n<\/li>\n<li><code>trusted-signing-account-name<\/code>: Your account title (actual, case-sensitive)\n<\/li>\n<li><code>certificate-profile-name<\/code>: Your certificates profile title (actual, case-sensitive)\n<\/li>\n<li><code>files-folder<\/code>: Path to your compiled executables\n<\/li>\n<li><code>files-folder-filter<\/code>: File sorts to signal (exe, dll, and so on.)\n<\/li>\n<li><code>files-folder-recurse<\/code>: Signal information in subfolders<\/li>\n<\/ul>\n<h3>Step 4: Check the Workflow<\/h3>\n<p>Now set off the workflow. You&#8217;ve gotten two choices:<\/p>\n<p><strong>Choice A: Guide Set off (Most secure for testing)<\/strong>\n<\/p>\n<p>Because the workflow consists of <code>workflow_dispatch:<\/code>, you possibly can set off it manually with out making a tag:<\/p>\n<pre><code># Set off manually by way of GitHub CLI\ngh workflow run construct.yml\n\n# Or go to GitHub net UI:\n# Actions tab \u2192 \"Construct and Signal\" workflow \u2192 \"Run workflow\" button\n<\/code><\/pre>\n<p>That is best for testing as a result of:\n<\/p>\n<ul>\n<li>No tag required\n<\/li>\n<li>Will not create a launch\n<\/li>\n<li>Can check a number of instances\n<\/li>\n<li>Simple to debug points<\/li>\n<\/ul>\n<p><strong>Choice B: Create a Tag (For precise releases)<\/strong><\/p>\n<pre><code># Ensure you're in your fundamental department with no uncommitted modifications\ngit standing\n\n# Create and push a tag\ngit tag v1.0.0\ngit push origin v1.0.0\n<\/code><\/pre>\n<p>Use this whenever you&#8217;re able to create an precise launch with signed binaries. That is what I&#8217;m doing on my facet.\n<\/p>\n<h3>Step 5: Monitor the Construct<\/h3>\n<p>Watch the progress with GitHub CLI:<\/p>\n<pre><code># See newest runs\ngh run record --limit 5\n\n# Watch a particular run\ngh run watch\n\n# View detailed standing\ngh run view --log\n<\/code><\/pre>\n<p>Or go to: <code>https:\/\/github.com\/YOUR_USERNAME\/YOUR_REPO\/actions<\/code>\n<\/p>\n<p><strong>Search for:<\/strong>\n<\/p>\n<ul>\n<li>Azure Login &#8211; Ought to full in ~5 seconds\n<\/li>\n<li>Signal executables with Trusted Signing &#8211; Ought to full in ~10-30 seconds\n<\/li>\n<li>Create Launch &#8211; Your signed executable is now accessible in \/releases in your GitHib mission<\/li>\n<\/ul>\n<h3>Widespread GitHub Actions Points<\/h3>\n<p>I hit a number of of those, natch.<\/p>\n<p><strong>Subject: &#8220;403 Forbidden&#8221; throughout signing<\/strong>\n<\/p>\n<ul>\n<li><strong>Trigger<\/strong>: Service principal would not have permissions\n<\/li>\n<li><strong>Repair<\/strong>:\n<ol>\n<li>Go to Azure Portal \u2192 Trusted Signing Account \u2192 Entry management (IAM)\n<\/li>\n<li>Confirm &#8220;MyAppGitHubActions&#8221; has &#8220;Trusted Signing Certificates Profile Signer&#8221; function\n<\/li>\n<li>If not, add it manually<\/li>\n<\/ol>\n<\/li>\n<\/ul>\n<p><strong>Subject: &#8220;No information matched the sample&#8221;<\/strong>\n<\/p>\n<ul>\n<li><strong>Trigger<\/strong>: Mistaken <code>files-folder<\/code> path or construct artifacts in incorrect location\n<\/li>\n<li><strong>Repair<\/strong>:\n<ol>\n<li>Add a debug step earlier than signing: <code>- run: Get-ChildItem -Recurse<\/code>\n<\/li>\n<li>Discover the place your EXE is definitely situated\n<\/li>\n<li>Replace <code>files-folder<\/code> to match<\/li>\n<\/ol>\n<\/li>\n<\/ul>\n<p><strong>Subject: Secrets and techniques not working<\/strong>\n<\/p>\n<ul>\n<li><strong>Trigger<\/strong>: Typo in secret title or worth not saved\n<\/li>\n<li><strong>Repair<\/strong>:\n<ol>\n<li>Confirm secret names EXACTLY match (case-sensitive)\n<\/li>\n<li>Re-create secrets and techniques if uncertain\n<\/li>\n<li>Be certain no additional areas in values<\/li>\n<\/ol>\n<\/li>\n<\/ul>\n<p><strong>Subject: &#8220;DefaultAzureCredential authentication failed&#8221;<\/strong>\n<\/p>\n<ul>\n<li><strong>Trigger<\/strong>: Often incorrect tenant ID or consumer ID\n<\/li>\n<li><strong>Repair<\/strong>: Confirm all 4 secrets and techniques are right from service principal output<\/li>\n<\/ul>\n<h2>Half 4: Understanding the Certificates<\/h2>\n<h3>Certificates Lifecycle<\/h3>\n<p>Azure Trusted Signing makes use of <strong>short-lived certificates<\/strong> (usually 3 days). This freaked me out however they are saying that is really a safety characteristic: <\/p>\n<ul>\n<li>If a certificates is compromised, it expires shortly\n<\/li>\n<li>You by no means handle certificates information or passwords\n<\/li>\n<li>Computerized renewal &#8211; you do not have to do something<\/li>\n<\/ul>\n<p><strong>However will not my signature break after 3 days?<\/strong>\n<\/p>\n<p>No, plainly&#8217;s what <strong>timestamping<\/strong> is for. Whenever you signal a file:\n<\/p>\n<ol>\n<li>Azure points a 3-day certificates\n<\/li>\n<li>The file is signed with that certificates\n<\/li>\n<li>A timestamp server information &#8220;this file was signed on DATE&#8221;\n<\/li>\n<li>Even after the certificates expires, the signature stays legitimate as a result of the timestamp proves it was signed when the certificates was legitimate<\/li>\n<\/ol>\n<p>That is why each native and GitHub Actions signing embrace:<\/p>\n<pre><code>timestamp-rfc3161: http:\/\/timestamp.acs.microsoft.com\n<\/code><\/pre>\n<h3>What the Certificates Comprises<\/h3>\n<p>Your signed executable has a certificates with:\n<\/p>\n<ul>\n<li><strong>Topic<\/strong>: Your title (e.g., &#8220;CN=John Doe, O=John Doe, L=Seattle, S=Washington, C=US&#8221;)\n<\/li>\n<li><strong>Issuer<\/strong>: Microsoft ID Verified CS EOC CA 01\n<\/li>\n<li><strong>Legitimate Dates<\/strong>: 3-day window\n<\/li>\n<li><strong>Key Dimension<\/strong>: 3072-bit RSA (very safe)\n<\/li>\n<li><strong>Enhanced Key Utilization<\/strong>: Code Signing<\/li>\n<\/ul>\n<h3>Confirm Certificates on Any Machine<\/h3>\n<pre><code># Utilizing PowerShell\nGet-AuthenticodeSignature \"MyApp.exe\" | Choose-Object -ExpandProperty SignerCertificate | Format-Listing\n\n# Utilizing Home windows UI\n# Proper-click EXE \u2192 Properties \u2192 Digital Signatures tab \u2192 Particulars \u2192 View Certificates\n<\/code><\/pre>\n<p>This entire factor took me about an hour to 75 minutes. It was detailed, however not deeply tough. Misspellings, case-sensitivity, and some account points with Position-Primarily based Entry Management did gradual me down. Hope this helps!<\/p>\n<h3>Used Sources<\/h3>\n<p><em>Written in November 2025 primarily based on real-world implementation for WindowsEdgeLight. Your setup may fluctuate barely relying on Azure area and account kind. Issues change, be stoic.<\/em><\/p>\n<p>&#13;<br \/>\n&#13;<br \/>\n&#13;<br \/>\n&#13;<\/p>\n<div class=\"about-scott\">\n<div class=\"bioBox\">\n<h4>About Scott<\/h4>\n<div class=\"bioBoxInner\">\n<p>Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, advisor, father, diabetic, and Microsoft worker. He&#8217;s a failed stand-up comedian, a cornrower, and a e book creator.<\/p>\n<p>                        <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/facebook.com\/shanselman\" class=\"sm-link\"><img decoding=\"async\" src=\"http:\/\/images.hanselman.com\/main\/icon-fb.png\" alt=\"facebook\"\/><\/a><br \/>\n                        <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/bsky.app\/profile\/scott.hanselman.com\" class=\"sm-link\"><img decoding=\"async\" src=\"http:\/\/images.hanselman.com\/main\/icon-bluesky.png\" alt=\"bluesky\"\/><\/a><br \/>\n                        <a rel=\"nofollow\" target=\"_blank\" href=\"http:\/\/feeds.hanselman.com\/ScottHanselman\" class=\"sm-link\"><img decoding=\"async\" src=\"http:\/\/images.hanselman.com\/main\/icon-rss.png\" alt=\"subscribe\"\/><\/a><br \/>\n                        <a rel=\"nofollow\" target=\"_blank\" href=\"http:\/\/hanselman.com\/about\">About<\/a> \u00a0 <a rel=\"nofollow\" target=\"_blank\" href=\"http:\/\/www.hanselman.com\/newsletter\">Publication<\/a>\n                    <\/div><\/div>\n<div class=\"ads-box\">\n<div class=\"ad-item\">\n                        <strong>Internet hosting By<\/strong><br \/>\n                        <a rel=\"nofollow\" target=\"_blank\" rel=\"nofollow\" href=\"https:\/\/azure.microsoft.com\/free\"><img loading=\"lazy\" decoding=\"async\" alt=\"Hosted on Linux using .NET in an Azure App Service\" class=\"ad\" border=\"0\" valign=\"top\" vspace=\"4\" width=\"125\" height=\"125\" src=\"http:\/\/images.hanselman.com\/main\/azure-250x250.png\"\/><\/a>\n                    <\/div><\/div><\/div>\n<p>&#13;<br \/>\n&#13;<br \/>\n            &#13;<br \/>\n&#13;<br \/>\n&#13;<br \/>\n            &#13;<br \/>\n&#13;<br \/>\n            &#13;\n        <\/p><\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>&#13; &#13; Mac Tahoe (in Beta as of the time of this writing) has this new characteristic known as Edge Mild that principally places a shiny image of an Edge Mild round your display and principally makes use of the facility of OLED to present you a digital ring mild. So I used to be [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":9326,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[56],"tags":[2469,6714,1126,6716,6715,933,633,3822,4828,1059],"class_list":["post-9324","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-software","tag-actions","tag-automatically","tag-azure","tag-dotnet","tag-exe","tag-github","tag-sign","tag-signing","tag-trusted","tag-windows"],"_links":{"self":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts\/9324","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=9324"}],"version-history":[{"count":1,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts\/9324\/revisions"}],"predecessor-version":[{"id":9325,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts\/9324\/revisions\/9325"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/media\/9326"}],"wp:attachment":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=9324"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=9324"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=9324"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}<!-- This website is optimized by Airlift. Learn more: https://airlift.net. Template:. Learn more: https://airlift.net. Template: 69d9690a190636c2e0989534. Config Timestamp: 2026-04-10 21:18:02 UTC, Cached Timestamp: 2026-05-07 20:10:21 UTC -->