fix(signer): let a confined AppContainer signer read its sealed key on Windows#417
Open
ion-alpha-dev wants to merge 3 commits into
Open
fix(signer): let a confined AppContainer signer read its sealed key on Windows#417ion-alpha-dev wants to merge 3 commits into
ion-alpha-dev wants to merge 3 commits into
Conversation
…n Windows A signer extension runs confined, and on Windows that is an AppContainer with a default-deny filesystem. The host names a sealed key at <data-dir>/signers/<name>.key and hands the path to the signer at unlock, but nothing granted the container read on that file, so the signer failed at unlock with "read sealed key: Access is denied" and the mint never reached signing. The container's package SID is also minted fresh from the scratch working directory on every launch, so granting the per-launch SID would leave a dead entry by the next run. Grant the sealed key to ALL APPLICATION PACKAGES before the signer launches: read on the key file and traverse on the two directories above it, non-inheritable so nothing else under the data directory is exposed. The key is an encrypted box whose passphrase lives only in the vault and reaches the signer over the private unlock channel, never on disk, so a package-read entry on the ciphertext discloses nothing to a container that does not already hold the passphrase. Off Windows the grant is a no-op: a signer there reads the key through ordinary POSIX permissions. Verified end to end on devnet: a stock-path signed mint through the released solana-signer now unlocks, signs, and lands a fixed-supply token (authority revoked).
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
The sealed-key grant test asserted the entry landed by string-matching the security descriptor's SDDL, but a well-known SID renders as its alias there (ALL APPLICATION PACKAGES prints as "AC", not "S-1-15-2-1"), so the match failed on some Windows builds. Walk the access list and compare the trustee SID by value instead. Also range over the integer bounds so the loops satisfy the intrange linter.
…me seam The grant that makes a signer's sealed key reachable by its confined process can only fail on Windows, so the mount's error branch for it had no coverage on the platforms CI measures. Route the grant through a field on the extension runtime, defaulted to the real grant, so a test can inject a failure and assert the mount aborts naming that reason. No behaviour change: production still calls the platform grant.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Grant a signer extension's sealed key to ALL APPLICATION PACKAGES before the signer process launches, so the confined signer can open the key the host named for it. The grant is read on the key file and traverse on the two directories above it, non-inheritable, and it is a no-op off Windows. Adds
sandbox.GrantSealedKeyReadable, called frommountSignerright after the key is located and before the launch, plus tests that assert the entry lands on the file and its parents and that repeated grants are idempotent.Why
A signer runs confined, and on Windows that is an AppContainer with a default-deny filesystem. The host seals a key at
<data-dir>/signers/<name>.keyand hands the path to the signer over the private unlock channel, but nothing granted the container read on that file, so the signer failed at unlock withread sealed key: Access is deniedand a mint never reached signing. The container's package SID is minted fresh from the scratch working directory on every launch, so granting the per-launch SID would leave a dead entry by the next run; the well-known ALL APPLICATION PACKAGES SID is stable and carried by every AppContainer. Granting it here is safe because the file is an encrypted box whose passphrase lives only in the vault and never touches disk, so a package-read entry on the ciphertext discloses nothing to a container that does not already hold the passphrase. The grants are scoped tightly (read on the one key file, traverse-only on the parents) so no other file under the data directory is exposed.How to verify
On Windows, seal a Solana key and run a signed mint through the released signer:
flynn auth set signer/solana-signer, seal a raw key to%APPDATA%\flynn\signers\solana-signer.key, thenflynn extensions call token token_mint '{"name":"T","symbol":"T","metadataUri":"https://example.com/t.json","supply":1000000}' --signer solana-signer --endpoint https://api.devnet.solana.com. Before this change the call fails at unlock with Access is denied; after it, the signer unlocks, signs, and the mint lands a fixed-supply token with its mint authority revoked.go test ./sandbox/ -run GrantSealedKeycovers the ACL entry and idempotency on Windows and the no-op off Windows.