From 3a74155e23e6bceeb2fdeb7778e22ebeb24d677e Mon Sep 17 00:00:00 2001 From: Hunter Hawke Date: Tue, 13 Oct 2026 13:42:46 -0400 Subject: [PATCH] Protect GitHub tutorial: correct the credential request and username mapping Create the SSH credential with the Create Endpoint Configuration request, and leave the authority out so certificates come from the team's SSH authority, the one Smallstep SSH uses. Say that the GitHub username reaches the certificate in the login@github.com extension, not in the principals, and describe what SSH.Principals holds. Add the key:: prefix to the user.signingkey command, so Git reads the value as a public key and not as a file path. Drop the dashboard check from the troubleshooting list; ssh-add -l already covers it. Refs PRO-606 Co-Authored-By: Claude Opus 5.5 --- tutorials/protect-github-ssh.mdx | 54 +++++++++++++++++--------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/tutorials/protect-github-ssh.mdx b/tutorials/protect-github-ssh.mdx index ebd18ba3..abc39a3e 100644 --- a/tutorials/protect-github-ssh.mdx +++ b/tutorials/protect-github-ssh.mdx @@ -1,5 +1,5 @@ --- -updated_at: October 05, 2026 +updated_at: October 13, 2026 title: Protect GitHub with SSH Certificates html_title: Protect GitHub Repositories with Hardware-Bound SSH Certificates description: Authenticate to GitHub with short-lived SSH certificates backed by your device's TPM or Secure Enclave, issued and managed by the Smallstep Agent. @@ -22,7 +22,7 @@ sequenceDiagram participant Git as git client participant GH as GitHub Agent->>CA: Request SSH user certificate (hardware-bound key) - CA->>Agent: Certificate with GitHub username principal + CA->>Agent: Certificate with GitHub username extension Git->>GH: git push (certificate via SSH agent socket) GH->>GH: Verify certificate against trusted CA GH->>Git: Access granted @@ -46,7 +46,7 @@ You will need: ## Sync users and their GitHub usernames -Smallstep issues each user an SSH certificate whose *principals* must include the user's GitHub username—that's how GitHub maps a certificate to a GitHub account. +Smallstep issues each user an SSH certificate that carries the user's GitHub username in the `login@github.com` extension—that's how GitHub maps a certificate to a GitHub account. To make the username available, configure your identity provider to sync users to Smallstep with a custom `githubUsername` attribute. @@ -117,25 +117,21 @@ echo "Authorization: Bearer [your API token]" > api_headers set -o history ``` -Next, choose the SSH authority that should issue your SSH certificates. -In the Smallstep dashboard, go to **Certificate Manager → Authorities**, open the authority, -and copy its **Authority ID** from the **Authority Settings** panel. - -Then create the credential with the [Create Credential](https://gateway.smallstep.com/v2025-01-01/operations/PostCredentials) endpoint: +Then create the credential with the [Create Endpoint Configuration](https://gateway.smallstep.com/v2025-01-01/operations/PostEndpointConfigurations) endpoint: ```bash curl -sH @api_headers --request POST \ - --url https://gateway.smallstep.com/api/credentials \ + --url https://gateway.smallstep.com/api/endpoint-configurations \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header 'x-smallstep-api-version: 2025-01-01' \ --data @- <<'EOF' | jq { - "slug": "github", - "certificate": { + "kind": "account", + "name": "GitHub", + "certificateInfo": { "type": "SSH_USER", - "authorityID": "[your authority ID]", - "fields": { + "details": { "keyId": { "deviceMetadata": "smallstep:identity", "static": "github" @@ -145,10 +141,9 @@ curl -sH @api_headers --request POST \ } } }, - "key": { + "keyInfo": { "protection": "HARDWARE_ATTESTED" }, - "managementMode": "agent", "policy": { "assurance": ["high"], "operatingSystem": ["macOS", "Windows", "Linux"] @@ -159,17 +154,26 @@ EOF Here's what the fields mean: -- **`certificate.type: "SSH_USER"`** issues SSH user certificates instead of X.509 certificates. -- **`fields.keyId`** sets the certificate's key ID, used for identification and audit logging. -- **`fields.principals`** populates the certificate's principals from device metadata. - `SSH.Principals` includes the user's SSH principals synced from your identity provider—including the `githubUsername` attribute you configured above—and `smallstep:identity` adds the email address of the user assigned to the device. -- **`key.protection: "HARDWARE_ATTESTED"`** generates the private key in the device's +- **`kind: "account"`** marks this as a credential that a person uses to access a protected resource—here, GitHub. +- **`certificateInfo.type: "SSH_USER"`** issues SSH user certificates instead of X.509 certificates. +- **`details.keyId`** sets the certificate's key ID, used for identification and audit logging. +- **`details.principals`** populates the certificate's principals from device metadata. + `SSH.Principals` adds the user's POSIX usernames and SSH group principals synced from your identity provider, + and `smallstep:identity` adds the email address of the user assigned to the device. +- **`keyInfo.protection: "HARDWARE_ATTESTED"`** generates the private key in the device's secure hardware (TPM or Secure Enclave), where it can never be exported. - **`policy`** selects the devices that receive this credential; here, high-assurance macOS, Windows, and Linux devices. +The request doesn't name an authority. +Smallstep issues these certificates from your team's SSH authority—the same authority [Smallstep SSH](../ssh/README.mdx) uses—so this credential works alongside Smallstep SSH. + +The GitHub username isn't one of the principals. +Smallstep adds it to each certificate automatically, in the `login@github.com` extension, +from the `githubUsername` attribute you configured above. + Once this credential is created, the Smallstep Agent on matching devices automatically requests -and renews hardware-bound SSH certificates with the appropriate GitHub username as a principal. +and renews hardware-bound SSH certificates that carry each user's GitHub username. # Step 2: Configure the enforcement point @@ -203,7 +207,7 @@ ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBK... 5. Click **Add CA** The CA now appears in your list of SSH certificate authorities, -and any SSH certificate signed by your Smallstep CA with a valid GitHub username principal +and any SSH certificate signed by your Smallstep CA that carries a valid GitHub username will be accepted for authentication to your organization's repositories. For more information, @@ -347,12 +351,13 @@ git config --global url."org-[your org ID]@github.com:[your org]/".insteadOf "gi You can configure `git` to sign commits with the same hardware-protected SSH credential, providing cryptographic proof of commit authorship. -1. Tell Git to use SSH for signing, and set your signing key: +1. Tell Git to use SSH for signing, and set your signing key. + The `key::` prefix tells Git that the value is a public key, not a file path: ```bash git config --global gpg.format ssh step ssh list --raw | head -1 | step crypto key format --ssh - git config --global user.signingkey "[your SSH public key]" + git config --global user.signingkey "key::[your SSH public key]" ``` 2. Configure allowed signers, so `git` can verify signatures locally: @@ -393,4 +398,3 @@ For more, see [GitHub's documentation on commit signature verification](https:// If nothing is listed, confirm the device matches the credential's policy (assurance level, operating system, and tags), and see the [agent troubleshooting guide](../platform/troubleshooting-agent.mdx). -- In the Smallstep dashboard, confirm the user's device shows an issued SSH certificate.