Skip to content

🚀 [Feature]: Adding functionality to sign JWTs via Key Vault Keys #481

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

Merged
merged 15 commits into from
Jul 18, 2025

Conversation

MariusStorhaug
Copy link
Member

@MariusStorhaug MariusStorhaug commented Jul 17, 2025

Description

This pull request introduces support for signing GitHub App JSON Web Tokens (JWTs) using Azure Key Vault in addition to local RSA private keys. It also refactors and enhances existing JWT-related functionality to improve maintainability and clarity. The most significant changes include the addition of Azure Key Vault integration, refactoring of JWT signing methods, and updates to related utility functions.

Improvements to Authentication Logic

  • Enhanced Connect-GitHubAccount to support both private key and Azure Key Vault-based authentication for GitHub Apps, introducing new parameter sets and validation for KeyVaultKeyReference.

Azure Key Vault Integration

  • Added a new KeyVaultKeyReference property to the GitHubAppContext class for specifying Azure Key Vault keys as an alternative to local private keys.
  • Introduced the Add-GitHubKeyVaultJWTSignature function to sign JWTs using Azure Key Vault keys, supporting both Azure CLI and Az PowerShell authentication.
  • Added utility functions Test-GitHubAzureCLI and Test-GitHubAzPowerShell to check for Azure CLI and Az PowerShell module installation and authentication.

Refactoring of JWT Signing

  • Renamed Add-GitHubJWTSignature to Add-GitHubLocalJWTSignature for clarity and updated it to use the new GitHubJWTComponent helper for base64 URL encoding.
  • Updated Update-GitHubAppJWT to conditionally use either Add-GitHubLocalJWTSignature or Add-GitHubKeyVaultJWTSignature based on the presence of PrivateKey or KeyVaultKeyReference in the context.

Enhancements to JWT Utility Functions

  • Added GitHubJWTComponent class to centralize base64 URL encoding logic and simplify JWT creation.
  • Updated New-GitHubUnsignedJWT to use GitHubJWTComponent for encoding JWT headers and payloads.

See it in action

https://github.com/PSModule/GitHub-Script/actions/runs/16364842244/job/46239654619

Type of change

  • 📖 [Docs]
  • 🪲 [Fix]
  • 🩹 [Patch]
  • ⚠️ [Security fix]
  • 🚀 [Feature]
  • 🌟 [Breaking change]

Checklist

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas

…WTSignature` functions; update `Update-GitHubAppJWT` to use local signing method
…r JWT signing functions and update authentication methods in `Connect-GitHubAccount`
@MariusStorhaug MariusStorhaug self-assigned this Jul 17, 2025
@Copilot Copilot AI review requested due to automatic review settings July 17, 2025 15:58
@MariusStorhaug MariusStorhaug requested a review from a team as a code owner July 17, 2025 15:58
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This pull request introduces Azure Key Vault integration for GitHub App JWT signing, enabling secure storage and usage of private keys through Azure Key Vault as an alternative to local private key files. The changes enhance security by eliminating the need to store sensitive private keys locally while maintaining backward compatibility with existing private key authentication.

  • Adds support for Azure Key Vault key references in GitHub App authentication flows
  • Refactors JWT signing functionality to support both local private keys and Key Vault-based signing
  • Introduces new utility functions to validate Azure CLI and Azure PowerShell authentication states

Reviewed Changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
Connect-GitHubAccount.ps1 Enhanced to support Key Vault key references with new parameter sets and validation
Test-GitHubAzureCLI.ps1 New utility function to verify Azure CLI installation and authentication status
Test-GitHubAzPowerShell.ps1 New utility function to verify Azure PowerShell module availability and authentication
Update-GitHubAppJWT.ps1 Modified to conditionally use either local or Key Vault JWT signing based on context
New-GitHubUnsignedJWT.ps1 Refactored to use new GitHubJWTComponent class for base64 URL encoding
Add-GitHubLocalJWTSignature.ps1 Renamed from Add-GitHubJWTSignature and updated to return secure string
Add-GitHubKeyVaultJWTSignature.ps1 New function implementing Key Vault-based JWT signing with Azure authentication
GitHubJWTComponent.ps1 New utility class centralizing base64 URL encoding logic for JWT operations
GitHubAppContext.ps1 Extended to include KeyVaultKeyReference property for Key Vault authentication
README.md Updated documentation with Key Vault authentication examples and prerequisites

… in `Update-GitHubAppJWT` and adding `Test-GitHubJWTRefreshRequired` function for refresh validation
…T` and `Update-GitHubUserAccessToken` to use hyphens instead of slashes for improved compatibility
…ired` to use `JwtTimeTolerance` instead of `JwtRefreshThreshold` for improved accuracy
- Created TEMPLATE.ps1 for Pester tests with default configurations.
- Added Teams.Tests.ps1 to test GitHub Teams API functionalities including team creation, retrieval, updating, and deletion.
- Introduced Users.Tests.ps1 to validate user-related API calls such as user retrieval and updates.
- Implemented Variables.Tests.ps1 to cover GitHub variable management including setting, updating, and removing variables for users, organizations, and repositories.
…matting context display for better readability
…ed` and improve error handling in `Test-GitHubAccessTokenRefreshRequired`
- Created TEMPLATE.ps1 for structuring Pester tests with authentication cases.
- Added Teams.Tests.ps1 to test GitHub Teams API functionalities, including team creation, retrieval, updating, and deletion.
- Introduced Users.Tests.ps1 to validate user-related API calls, including user retrieval and updates.
- Implemented Variables.Tests.ps1 to test GitHub variable management, covering organization and repository scopes, variable creation, updates, and deletions.
Copy link
Contributor

Module GitHub - 0.36.0-kvSigning001 published to the PowerShell Gallery.

Copy link
Contributor

GitHub release for GitHub v0.36.0-kvSigning001 has been created.

@MariusStorhaug
Copy link
Member Author

MariusStorhaug commented Jul 18, 2025

Tests seem fine on function app too:

Details from Flex Consumption plan AFA

Connected! You are now viewing logs of Function runs in the current Code + Test panel. To see all the logs for this Function, please go to 'Logs' from the Function menu.
2025-07-18T11:43:24Z   [Verbose]   AuthenticationScheme: WebJobsAuthLevel was successfully authenticated.
2025-07-18T11:43:24Z   [Verbose]   Authorization was successful.
2025-07-18T11:43:24Z   [Information]   Executing 'Functions.info' (Reason='This function was programmatically called via the host APIs.', Id=c766bee2-4221-4b04-8344-b80303ce7867)
2025-07-18T11:43:24Z   [Verbose]   Sending invocation id: 'c766bee2-4221-4b04-8344-b80303ce7867
2025-07-18T11:43:24Z   [Verbose]   Posting invocation id:c766bee2-4221-4b04-8344-b80303ce7867 on workerId:dd2dbc28-1a9a-4fad-8cde-153fb9671c1a
2025-07-18T11:43:24Z   [Information]   INFORMATION: PSVersionTable
2025-07-18T11:43:24Z   [Information]   INFORMATION: 
Name                           Value
----                           -----
PSVersion                      7.4.7
PSEdition                      Core
GitCommitId                    7.4.7
OS                             Debian GNU/Linux 12 (bookworm)
Platform                       Unix
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

2025-07-18T11:43:24Z   [Information]   INFORMATION: Environment variables
2025-07-18T11:43:24Z   [Information]   INFORMATION: 
Name                                                 Value
----                                                 -----
_                                                    /usr/bin/setsid
APP_UID                                              1654
APPLICATIONINSIGHTS_AUTHENTICATION_STRING            ClientId=20c2f9e9-c56b-40c…
APPLICATIONINSIGHTS_CONNECTION_STRING                InstrumentationKey=c5c8a29…
APPSETTING_APPLICATIONINSIGHTS_AUTHENTICATION_STRING ClientId=20c2f9e9-c56b-40c…
APPSETTING_APPLICATIONINSIGHTS_CONNECTION_STRING     InstrumentationKey=c5c8a29…
APPSETTING_AZURE_CLIENT_ID                           20c2f9e9-c56b-40c5-a272-e8…
APPSETTING_AzureWebJobsStorage__blobServiceUri       https://githubapp90db.blob…
APPSETTING_AzureWebJobsStorage__clientId             20c2f9e9-c56b-40c5-a272-e8…
APPSETTING_AzureWebJobsStorage__credential           managedidentity
APPSETTING_AzureWebJobsStorage__queueServiceUri      https://githubapp90db.queu…
APPSETTING_AzureWebJobsStorage__tableServiceUri      https://githubapp90db.tabl…
APPSETTING_ScmType                                   GitHubAction
APPSETTING_WEBSITE_AUTH_ENABLED                      False
APPSETTING_WEBSITE_DEFAULT_HOSTNAME                  githubapp-hpccaed2acckbpew…
APPSETTING_WEBSITE_SITE_NAME                         githubapp
APPSETTING_WEBSITE_SLOT_NAME                         Production
ASPNET_VERSION                                       8.0.17
ASPNETCORE_CONTENTROOT                               /azure-functions-host
ASPNETCORE_HTTP_PORTS                                8080
ASPNETCORE_URLS                                      http://localhost:9091
AZURE_CLIENT_ID                                      20c2f9e9-c56b-40c5-a272-e8…
AZUREPS_CHECK_FOR_UPGRADE                            False
AZUREPS_HOST_ENVIRONMENT                             AzureFunctions/4.1040.300.0
AZUREPS_OUTPUT_PLAINTEXT_AZACCESSTOKEN               true
AzureWebEncryptionKey                                F36DCA3CD22ADA487A62874A64…
AzureWebJobsFeatureFlags                             EnableWorkerIndexing
AzureWebJobsScriptRoot                               /home/site/wwwroot
AzureWebJobsStorage__blobServiceUri                  https://githubapp90db.blob…
AzureWebJobsStorage__clientId                        20c2f9e9-c56b-40c5-a272-e8…
AzureWebJobsStorage__credential                      managedidentity
AzureWebJobsStorage__queueServiceUri                 https://githubapp90db.queu…
AzureWebJobsStorage__tableServiceUri                 https://githubapp90db.tabl…
CONTAINER_ENCRYPTION_KEY                             xfLOjzY2NB2qUDFQnnXDqojtUS…
CONTAINER_IMAGE_URL                                  NotSet
CONTAINER_NAME                                       a1a838dc-833b-4cbc-a56d-2a…
CONTAINER_SPECIALIZATION_CONTEXT_MOUNT_PATH          /container-specialization-…
CORS_ALLOWED_ORIGINS                                 ["https://portal.azure.com…
CORS_SUPPORT_CREDENTIALS                             False
DOTNET_RUNNING_IN_CONTAINER                          true
DOTNET_USE_POLLING_FILE_WATCHER                      true
DOTNET_VERSION                                       8.0.17
FUNCTIONS_APPLICATION_DIRECTORY                      /home/site/wwwroot
FUNCTIONS_EXTENSION_VERSION                          ~4
FUNCTIONS_METRICS_PUBLISH_PATH                       /tmp/metrics
FUNCTIONS_PLATFORM_CONFIG_FILE_PATH                  /local/platformconfig
FUNCTIONS_ROLLOUT_STAGE                              5
FUNCTIONS_TARGET_GROUP                               http
FUNCTIONS_WORKER_DIRECTORY                           /azure-functions-host/work…
FUNCTIONS_WORKER_RUNTIME                             powershell
FUNCTIONS_WORKER_RUNTIME_VERSION                     7.4
HOME                                                 /home
HOST_VERSION                                         4.1040.300.0
IDENTITY_ENDPOINT                                    http://169.254.255.2:8081/…
IDENTITY_HEADER                                      564B002633F94B9BA52BA073C2…
INITIALIZED_FROM_PLACEHOLDER                         True
LANG                                                 C.UTF-8
LEGION_SERVICE_HOST                                  1
LocalSitePackagesPath                                /local/sitepackages
LOGNAME                                              app
MESH_INIT_URI                                        http://localhost:6060/
MSI_ENDPOINT                                         http://169.254.255.2:8081/…
MSI_SECRET                                           564B002633F94B9BA52BA073C2…
PATH                                                 /usr/local/sbin:/usr/local…
POWERSHELL_DISTRIBUTION_CHANNEL                      Azure-Functions:4.1040.300…
PSModulePath                                         /home/site/wwwroot/Modules…
PSWorkerInProcConcurrencyUpperBound                  1000
PWD                                                  /
REGION_NAME                                          West Europe
ScmType                                              GitHubAction
SHELL                                                /bin/bash
SHLVL                                                0
SUDO_COMMAND                                         /azure-functions-host/Micr…
SUDO_GID                                             0
SUDO_UID                                             0
SUDO_USER                                            root
TERM                                                 xterm
USER                                                 app
WEBSITE_AUTH_ENABLED                                 False
WEBSITE_AUTH_ENCRYPTION_KEY                          F36DCA3CD22ADA487A62874A64…
WEBSITE_AUTH_SIGNING_KEY                             4ACEA9AFEF019B6546A42F03DF…
WEBSITE_CLOUD_NAME                                   Azure
WEBSITE_CONTAINER_READY                              1
WEBSITE_DEFAULT_HOSTNAME                             githubapp-hpccaed2acckbpew…
WEBSITE_DEPLOYMENT_ID                                githubapp
WEBSITE_FUNCTIONS_AZUREMONITOR_CATEGORIES            None
WEBSITE_HOME_STAMPNAME                               waws-prod-am2-795
WEBSITE_HOSTNAME                                     githubapp-hpccaed2acckbpew…
WEBSITE_OWNER_NAME                                   0724c827-ca8a-48c0-8b6e-4c…
WEBSITE_PLACEHOLDER_MODE                             0
WEBSITE_POD_NAME                                     a1a838dc-833b-4cbc-a56d-2a…
WEBSITE_SITE_NAME                                    githubapp
WEBSITE_SKU                                          FlexConsumption
WEBSITE_SLOT_NAME                                    Production

2025-07-18T11:43:24Z   [Information]   INFORMATION: AzContext
2025-07-18T11:43:24Z   [Information]   INFORMATION: 
Name               : Azure subscription 1 (0724c827-ca8a-48c0-8b6e-4c43b3dcfe01) - 195ee85d-2f10-4764-8352-a3c99aa772fb - 20c2f9e9-c56b-40c5-a272-e8ddb9a3b8e4
Subscription       : 0724c827-ca8a-48c0-8b6e-4c43b3dcfe01
Account            : 20c2f9e9-c56b-40c5-a272-e8ddb9a3b8e4
Environment        : AzureCloud
Tenant             : 195ee85d-2f10-4764-8352-a3c99aa772fb
TokenCache         : 
VersionProfile     : 
ExtendedProperties : {}

2025-07-18T11:43:24Z   [Information]   INFORMATION: GitHubContext
2025-07-18T11:43:24Z   [Information]   INFORMATION: 
Name        : github.com/psmodule-org-app
Type        : App
AuthType    : APP
TokenType   : JWT
HostName    : github.com
UserName    : psmodule-org-app
ClientID    : Iv23liYDnEbKlS9IVzHf
OwnerName   : PSModule
OwnerType   : Organization
Permissions : @{keys=write; organization_actions_variables=write; organization_self_hosted_runners=write; organization_custom_properties=admin; starring=write; user_events=read; repository_hooks=write; organization_personal_access_token_requests=write; codespaces_secrets=write; organization_api_insights=read; gpg_keys=write; pages=write; administration=write; organization_knowledge_bases=write; watching=write; statuses=write; organization_projects=admin; dependabot_secrets=write; merge_queues=write; interaction_limits=write; blocking=write; organization_events=read; repository_projects=admin; copilot_messages=read; organization_codespaces_secrets=write; checks=write; organization_administration=write; organization_user_blocking=write; organization_announcement_banners=write; plan=read; environments=write; gists=write; git_signing_ssh_public_keys=write; followers=write; codespaces_metadata=read; organization_custom_roles=write; repository_advisories=write; profile=write; deployments=write; metadata=read; organization_codespaces=write; organization_plan=read; issues=write; organization_hooks=write; codespaces=write; organization_network_configurations=write; organization_codespaces_settings=write; members=write; codespaces_user_secrets=write; organization_dependabot_secrets=write; actions_variables=write; contents=write; organization_copilot_seat_management=write; secret_scanning_alerts=write; packages=write; pull_requests=write; security_events=write; vulnerability_alerts=write; actions=write; discussions=write; codespaces_lifecycle_admin=write; attestations=write; emails=write; copilot_editor_context=read; workflows=write; secrets=write; team_discussions=write; organization_custom_org_roles=write; single_file=write; organization_secrets=write; organization_personal_access_tokens=write; organization_private_registries=write; organization_models=read; repository_custom_properties=write}
Events      : {push}
ApiBaseUri  : https://api.github.com
Enterprise  : 
Owner       : 
Repository  : 
HttpVersion : 2.0
PerPage     : 100

2025-07-18T11:43:24Z   [Information]   INFORMATION: GitHubConfig
2025-07-18T11:43:24Z   [Information]   INFORMATION: 
HostName                      : github.com
ApiBaseUri                    : https://api.github.com
GitHubAppClientID             : Iv1.f26b61bc99e69405
OAuthAppClientID              : 7204ae9b0580f2cb8288
EnvironmentType               : AFA
DefaultContext                : github.com/psmodule-org-app
AccessTokenGracePeriodInHours : 4
JwtTimeTolerance              : 300
ApiVersion                    : 2022-11-28
HttpVersion                   : 2.0
PerPage                       : 100
RetryCount                    : 0
RetryInterval                 : 1

2025-07-18T11:43:24Z   [Information]   Executed 'Functions.info' (Succeeded, Id=c766bee2-4221-4b04-8344-b80303ce7867, Duration=63ms)

@MariusStorhaug MariusStorhaug merged commit 465671b into main Jul 18, 2025
22 of 25 checks passed
@MariusStorhaug MariusStorhaug deleted the kvSigning branch July 18, 2025 13:12
Copy link
Contributor

Module GitHub - 0.36.0 published to the PowerShell Gallery.

Copy link
Contributor

GitHub release for GitHub v0.36.0 has been created.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

🚀[Feature]: Support KeyVault-based signing for GitHub App JWTs
1 participant