{"id":18962886,"url":"https://github.com/mafrosis/step-ca-on-rpi","last_synced_at":"2025-09-05T17:31:26.767Z","repository":{"id":138921203,"uuid":"356420808","full_name":"mafrosis/step-ca-on-rpi","owner":"mafrosis","description":"Smallstep Certificate Authority on Rpi4 with Yubikey","archived":false,"fork":false,"pushed_at":"2025-04-26T03:46:15.000Z","size":26,"stargazers_count":13,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-26T04:42:31.928Z","etag":null,"topics":["certificate-authority","raspberrypi","smallstep"],"latest_commit_sha":null,"homepage":"","language":"Dockerfile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mafrosis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-04-09T23:21:58.000Z","updated_at":"2025-04-26T03:46:18.000Z","dependencies_parsed_at":"2025-04-26T04:29:04.853Z","dependency_job_id":"da86e99f-e609-4d68-a90f-f3b5f9205eff","html_url":"https://github.com/mafrosis/step-ca-on-rpi","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mafrosis/step-ca-on-rpi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mafrosis%2Fstep-ca-on-rpi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mafrosis%2Fstep-ca-on-rpi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mafrosis%2Fstep-ca-on-rpi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mafrosis%2Fstep-ca-on-rpi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mafrosis","download_url":"https://codeload.github.com/mafrosis/step-ca-on-rpi/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mafrosis%2Fstep-ca-on-rpi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273790554,"owners_count":25168674,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-05T02:00:09.113Z","response_time":402,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["certificate-authority","raspberrypi","smallstep"],"created_at":"2024-11-08T14:17:02.741Z","updated_at":"2025-09-05T17:31:26.750Z","avatar_url":"https://github.com/mafrosis.png","language":"Dockerfile","funding_links":[],"categories":[],"sub_categories":[],"readme":"Step CA with Yubikey on Rpi\n===========================\n\nInspired by this [blog post](https://smallstep.com/blog/build-a-tiny-ca-with-raspberry-pi-yubikey/)\nand the final run cost of my [Step CA on GCP](https://github.com/mafrosis/step-ca-on-gcp) project\n(30 AUD / month), I decided to simply run my CA on an existing rpi4.\n\nThe use of a Yubikey is not necessary, but does secure the key material in an offboard device isn't\neasily accessible from within the docker container. The `step-ca` process of course needs to be able\nto _use_ the keys to sign certificates etc, but a malicious user could not exfiltrate them as when\nthey're written to disk.\n\n\nInstall Yubikey-Manager\n-----------------------\n\nInstall the C libs required for the Python install:\n\n    sudo apt install libpcsclite-dev pcscd swig python3-dev\n\nThen install the latest via pip:\n\n    sudo pip install --user yubikey-manager\n\nCheck everything is working (as root!):\n\n```\n# ykman -v\nYubiKey Manager (ykman) version: 5.0.1\n# ykman info\nWARNING: Failed opening device\nDevice type: YubiKey 5 Nano\nSerial number: 12508380\nFirmware version: 5.2.7\nForm factor: Nano (USB-A)\nEnabled USB interfaces: OTP, FIDO, CCID\n\nApplications\nOTP             Enabled\nFIDO U2F        Enabled\nFIDO2           Enabled\nOATH            Enabled\nPIV             Enabled\nOpenPGP         Enabled\nYubiHSM Auth    Not available\n```\n\n\nSetup the Yubikey\n-----------------\n\nReset the PIV settings on the Yubikey to their defaults:\n\n```\n# ykman piv reset\nWARNING! This will delete all stored PIV data and restore factory settings. Proceed? [y/N]: y\nResetting PIV data...\nSuccess! All PIV data have been cleared from the YubiKey.\nYour YubiKey now has the default PIN, PUK and Management Key:\n    PIN:    123456\n    PUK:    12345678\n    Management Key: 010203040506070801020304050607080102030405060708\n```\n\n[Set the PIN and the PUK](https://developers.yubico.com/yubikey-piv-manager/PIN_and_Management_Key.html):\n\n    ykman piv access change-pin\n    ykman piv access change-puk\n    ykman piv access change-management-key --generate --protect\n\n\nConfigure Step-CA\n-----------------\n\nThe following is a working example of configuring `step-ca`. The generated password will be used for\nall certificate keys, and also for the \"admin\" provisioner.\n\n```\n\u003e export STEPPATH=/tmp/step \u0026\u0026 mkdir -p $STEPPATH\n\u003e step ca init --name=\"mafro.dev CA\" --provisioner=admin --dns=certs.mafro.dev --address=':443'\n✔ What do you want your password to be? [leave empty and we'll generate one]:\n✔ Password: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n\nGenerating root certificate...\nall done!\n\nGenerating intermediate certificate...\n\nGenerating user and host SSH certificate signing keys...\nall done!\n\n✔ Root certificate: /tmp/step/certs/root_ca.crt\n✔ Root private key: /tmp/step/secrets/root_ca_key\n✔ Root fingerprint: c7641ce4f91993dc3f00000000000000000000000f829c626d20fa02d89600e0\n✔ Intermediate certificate: /tmp/step/certs/intermediate_ca.crt\n✔ Intermediate private key: /tmp/step/secrets/intermediate_ca_key\n✔ Database folder: /tmp/step/db\n✔ Templates folder: /tmp/step/templates\n✔ Default configuration: /tmp/step/config/defaults.json\n✔ Certificate Authority configuration: /tmp/step/config/ca.json\n```\n\n\nAdd the Step-CA certs and keys to the Yubikey\n---------------------------------------------\n\nAdd both the root and intermediate into slots `82` and `83`, respectively:\n\n    \u003e ykman piv certificates import 82 certs/root_ca.crt\n    Enter a management key [blank to use default key]:\n    \u003e ykman piv keys import 82 secrets/root_ca_key\n    Enter a management key [blank to use default key]:\n    Enter password to decrypt key:\n    \u003e \n    \u003e ykman piv certificates import 83 certs/intermediate_ca.crt\n    Enter a management key [blank to use default key]:\n    \u003e ykman piv keys import 83 root/secrets/intermediate_ca_key\n    Enter a management key [blank to use default key]:\n    Enter password to decrypt key:\n\nThe following config sets up the CA to use the Yubikey intermediate certs/keys for signing:\n\n```\n\t\"key\": \"yubikey:slot-id=83\",\n\t\"kms\": {\n\t\t\"type\": \"yubikey\",\n\t\t\"pin\": \"YUBIPIN\"\n\t},\n```\n\n### Passing the Yubikey pin from an environment variable\n\nAll this config is committed to Github, so I certainly don't want to also include my Yubikey pin.\nA solution is passing via environment variables. Step CA doesn't natively support this, so a small\nbit of [jq surgery](./docker-entrypoint.sh#L6) is necessary.\n\n\nUse the Yubikey to generate SSH user and host keypairs\n------------------------------------------------------\n\nNormally the `--ssh` parameter to `step ca init` is used to configure the CA server to be able to\ngenerate SSH certs. In this case, we will instead use the Yubikey to generate the keypairs,\nretaining the private component only on the Yubikey.\n\n    \u003e ykman piv keys generate -a ECCP256 84 certs/ssh_host_ca_key.pub\n    \u003e Enter a management key [blank to use default key]:\n    \u003e \n    \u003e ykman piv keys generate -a ECCP256 85 certs/ssh_user_ca_key.pub\n    \u003e Enter a management key [blank to use default key]:\n\nThe following stanza is added to the CA config at `$STEPPATH/config/ca.json`:\n\n```\n  \"ssh\": {\n    \"hostKey\": \"yubikey:slot-id=84\",\n    \"userKey\": \"yubikey:slot-id=85\"\n  },\n```\n\nReference: [Enable SSH After Init](https://github.com/smallstep/certificates/discussions/400)\n\n\nSSO for SSH\n-----------\n\nThis section is essentially short-form instructions derived from\n[smallstep.com/blog/diy-single-sign-on-for-ssh](https://smallstep.com/blog/diy-single-sign-on-for-ssh/).\n\nSmallstep CA can issue certs for use with SSH. By configuring Google oAuth as the identity provider,\nGoogle does the authentication for us, and `step-ca` issues the cert.\n\n\n```\n┌──────────┐            ┌──────────┐           ┌─ ── ── ── ── ─┐\n│          │            │          │\n│  Client  │────SSH────▶│  Server  │           │    Google     │\n│  (macOS) │            │  (locke) │               oAuth app\n│          │            │          │           │               │\n└──────────┘            └──────────┘\n      │                                        └─ ── ── ── ── ─┘\n      │                                                ▲\n      │                 ┌──────────┐                   │\n    request             │          │                   │\n      cert─────────────▶│    CA    │────authenticate───┘\n                        │ (ringil) │\n                        │          │\n                        └──────────┘\n```\n\nNote: The naming convention here is to SSH from the _client_ into the _host_ server.\n\n\n#### Setup the Google oAuth app\n\n 1. Configure oAuth consent at https://console.developers.google.com/apis/credentials/consent\n 2. Create an oAuth app at https://console.cloud.google.com/apis/credentials\n   a. Click `Create credentials`, choosing `OAuth client ID`\n   b. Select `Desktop app` as application type\n   c. Retain your client ID and client secret\n\n\n#### Configure the CA to support this OIDC app\n\nNext, we must configure the CA with a new OIDC provisioner (named \"Google\") using above secrets. The\n`--domain` parameter is your Google SSO domain name.\n\n```\n\u003e step ca provisioner add Google --type=OIDC --ssh \\\n    --client-id \"$OIDC_CLIENT_ID\" \\\n    --client-secret \"$OIDC_CLIENT_SECRET\" \\\n    --configuration-endpoint 'https://accounts.google.com/.well-known/openid-configuration' \\\n    --domain mafro.net\nSuccess! Your `step-ca` config has been updated. To pick up the new configuration SIGHUP (kill -1 \u003cpid\u003e) or restart the step-ca process.\n```\n\n\n#### Create trust relationship between host server and our CA\n\nNext our CA needs to trust an identity document provided by the host system. In the blog post,\nthe host is an AWS EC2 instance which provides its instance identity to the CA server, and is trusted\nvia the Amazon signature of the AWS account ID (see [script here](https://gist.github.com/tashian/fde43668cbf6e3227fb13ef51db650b8)).\n\nOn the host server, install the [Smallstep CLI tools](#install-smallstep-cli). Next, bootstrap the\n`step` client as usual:\n\n```\n\u003e FINGERPRINT=$(step certificate fingerprint root_ca.crt)\n\u003e step ca bootstrap --ca-url https://ringil --fingerprint $FINGERPRINT\nThe root certificate has been saved in $HOME/.step/certs/root_ca.crt.\nYour configuration has been saved in $HOME/.step/config/defaults.json.\n```\n\nGenerate a certificate and configure `sshd` to use it. Run the following as root, so it's possible\nto write `/etc/ssh`.\n\nIn the following example, the host server is named `locke`. The steps are:\n\n1. Generate a token with the `admin` provisioner\n2. Inspect the token for your amusement\n\n```\n\u003e TOKEN=$(step ca token $(hostname) --ssh --host --provisioner admin)\n✔ Provisioner: admin (JWK) [kid: ydABxIT07b0000000000000000000000nGYFRfEGmNA]\n✔ Please enter the password to decrypt the provisioner key:\n\u003e echo $TOKEN | step crypto jwt inspect --insecure\n{\n  \"header\": {\n    \"alg\": \"ES256\",\n    \"kid\": \"ydABxIT07bl-G9jSxfCB45pxNylrKitsnGYFRfEGmNA\",\n    \"typ\": \"JWT\"\n  },\n  \"payload\": {\n    \"aud\": \"https://ringil:8443/1.0/ssh/sign\",\n    \"exp\": 1618046362,\n    \"iat\": 1618046062,\n    \"iss\": \"admin\",\n    \"jti\": \"776b2fce13c90b675f0a1f55712eee80f2504f5f6d4723e0a4fd80e5d35fde40\",\n    \"nbf\": 1618046062,\n    \"sha\": \"b07c800d7bf36422bd7da01fc2db11efebaafdd5b83092ff82136e75a6d033f9\",\n    \"step\": {\n      \"ssh\": {\n        \"certType\": \"host\",\n        \"keyID\": \"locke\",\n        \"principals\": [],\n        \"validAfter\": \"\",\n        \"validBefore\": \"\"\n      }\n    },\n    \"sub\": \"locke\"\n  },\n  \"signature\": \"E-b6SIaN9atMMo-ICdnoUCjQWMLYuJxkVuB5dBDGjxtzKpPyC-ydnLH5qYV9TTss7MgA2tciMNi9ka-PJ0LNqg\"\n}\n\u003e step ssh certificate $(hostname) /etc/ssh/ssh_host_ecdsa_key.pub --host --sign --provisioner admin --principal $(hostname) --token $TOKEN\n✔ CA: https://ringil:8443\n✔ Would you like to overwrite /etc/ssh/ssh_host_ecdsa_key-cert.pub [y/n]: y\n✔ Certificate: /etc/ssh/ssh_host_ecdsa_key-cert.pub\n\u003e step ssh config --host --set Certificate=ssh_host_ecdsa_key-cert.pub --set Key=ssh_host_ecdsa_key\n✔ /etc/ssh/sshd_config\n✔ /etc/ssh/ca.pub\n\u003e systemctl restart sshd\n```\n\n### Setup the client to use SSH via OIDC\n\nThe following steps are run on the _client_ system, which is connecting to the host configured above.\n\n```\n\u003e FINGERPRINT=$(step certificate fingerprint root_ca.crt)\n\u003e step ca bootstrap --ca-url https://ringil --fingerprint $FINGERPRINT\nThe root certificate has been saved in /Users/blackm/.step/certs/root_ca.crt.\nYour configuration has been saved in /Users/blackm/.step/config/defaults.json.\n\u003e step ssh config\n✔ /Users/mafro/.ssh/config\n✔ /Users/mafro/.step/ssh/config\n✔ /Users/mafro/.step/ssh/known_hosts\n```\n\nConfigure your SSH client config such that step is used to generate the SSH certificate on demand:\n\n```\n\u003e cat ~/.ssh/config\nHost locke\n    User pi\n    UserKnownHostsFile /Users/blackm/.step/ssh/known_hosts\n    ProxyCommand step ssh proxycommand %r %h %p --provisioner Google\n```\n\nThe `Google` provisioner is the OIDC one created at the beginning.\n\nNow, using this configuration is as simple as `ssh locke`, and the OIDC flow is triggered:\n\n```\n\u003e ssh locke\n✔ Provisioner: Google (OIDC) [client: 824164598483-frmggjqidnm16kjob9ud8a6a6ahvub1v.apps.googleusercontent.com]\nYour default web browser has been opened to visit:\n\nhttps://accounts.google.com/o/oauth2/v2/auth?\u003csnip\u003e\n\n✔ CA: https://ringil:8443\nLinux locke 5.10.17-v7l+ #1414 SMP Fri Apr 30 13:20:47 BST 2021 armv7l\n\nThe programs included with the Debian GNU/Linux system are free software;\nthe exact distribution terms for each program are described in the\nindividual files in /usr/share/doc/*/copyright.\n\nDebian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent\npermitted by applicable law.\nLast login: Thu Jun 17 06:07:51 2021 from 192.168.1.139\npi@locke:~ \u003e\n```\n\nIf you wanted to have a peek at your SSH certificate, as provisioned by your CA:\n\n```\n\u003e step ssh list --raw | step ssh inspect\n-:\n    Type: ecdsa-sha2-nistp256-cert-v01@openssh.com user certificate\n    Public key: ECDSA-CERT SHA256:1p9Ux0LVclOe3wFH9ISo+eUiqoAi/CoK7bE/VSdf2r0\n    Signing CA: ECDSA SHA256:WoobT5Uoi8cddLhcxILd5eLoPiq27iEaVCDV/oL/B6I\n    Key ID: \"m@mafro.net\"\n    Serial: 8826815887645788865\n    Valid: from 2021-06-17T05:44:17 to 2021-06-17T21:44:17\n    Principals:\n        m\n        m@mafro.net\n        mafro\n        pi\n    Critical Options: (none)\n    Extensions:\n        permit-agent-forwarding\n        permit-port-forwarding\n        permit-pty\n        permit-user-rc\n        permit-X11-forwarding\n```\n\n\n#### References for oAuth\n\n- https://smallstep.com/blog/diy-single-sign-on-for-ssh/\n- https://github.com/smallstep/certificates/blob/master/docs/provisioners.md#oidc\n\n\nConfigure an SSH template with custom principals\n------------------------------------------------\n\nWhen using the [OIDC provisioner](https://github.com/smallstep/certificates/blob/master/docs/provisioners.md#oidc)\nto issue SSH certs, you are limited to only issuing certs with a principal which matches the email\nof the OIDC identity - eg. if your email is `bob@example.com`, then the principals on your cert will\nbe `bob` and `bob@example.com`.\n\nThis is fine if you're logging into a server as `bob`, using an OIDC identity of `bob@example.com`.\nIt doesn't work if you're, say, logging in as user `pi`, using an OIDC identity of `mafro@example.com`.\n\nThis can be solved using [templated SSH certs](https://smallstep.com/blog/clever-uses-of-ssh-certificate-templates)!\n\nModify the `principals` field of an [SSH user template](./step-config/templates/ssh/mafro.tpl), and\nupdate the CA config at `$STEPPATH/config/ca.json` to include the following to the `OIDC`\nprovisioner:\n\n```\n\t\"options\": {\n\t\t\"ssh\": {\n\t\t\t\"templateFile\": \"templates/ssh/mafro.tpl\"\n\t\t}\n\t}\n```\n\n\nCross-compile for armv6\n-----------------------\n\nSmallstep doesn't distribute a binary for Raspberry Pi Zero armv6 architecture. Use the following\ncommands to build on macOS. You could build on Raspbian, but the golang version in apt was 1.11, and\ntoo old to build `step` at time of writing.\n\n```\ngit clone --branch=v0.15.14 https://github.com/smallstep/cli.git /tmp/step-cli\ncd /tmp/step-cli\nGOOS=linux GOARCH=arm GOARM=6 make build\ntar czf step-0.15.14-armv6.tar.gz -C bin step\nmv step-0.15.14-armv6.tar.gz ~\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmafrosis%2Fstep-ca-on-rpi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmafrosis%2Fstep-ca-on-rpi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmafrosis%2Fstep-ca-on-rpi/lists"}