Skip to content

Commit 1357924

Browse files
committed
添加使用说明
1 parent 66dabb1 commit 1357924

File tree

6 files changed

+227
-174
lines changed

6 files changed

+227
-174
lines changed

.github/workflows/build.yml

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
name: Build macOS Binaries
2+
3+
on:
4+
push:
5+
branches: [ main, master ]
6+
pull_request:
7+
branches: [ main, master ]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
13+
strategy:
14+
matrix:
15+
goos: [darwin]
16+
goarch: [amd64, arm64]
17+
18+
steps:
19+
- name: Checkout code
20+
uses: actions/checkout@v4
21+
22+
- name: Set up Go
23+
uses: actions/setup-go@v5
24+
with:
25+
go-version: '1.21'
26+
27+
- name: Verify Go version
28+
run: go version
29+
30+
- name: Cache Go modules
31+
uses: actions/cache@v4
32+
with:
33+
path: |
34+
~/.cache/go-build
35+
~/go/pkg/mod
36+
key: ${{ runner.os }}-go-${{ matrix.goos }}-${{ matrix.goarch }}-${{ hashFiles('**/go.sum') }}
37+
restore-keys: |
38+
${{ runner.os }}-go-${{ matrix.goos }}-${{ matrix.goarch }}-
39+
${{ runner.os }}-go-${{ matrix.goos }}-
40+
${{ runner.os }}-go-
41+
42+
- name: Build
43+
env:
44+
CGO_ENABLED: 0
45+
run: |
46+
mkdir -p dist
47+
GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build \
48+
-ldflags="-s -w" \
49+
-trimpath \
50+
-o dist/fssh-${{ matrix.goos }}-${{ matrix.goarch }} \
51+
./cmd/fssh
52+
53+
- name: Upload artifacts
54+
uses: actions/upload-artifact@v4
55+
with:
56+
name: fssh-${{ matrix.goos }}-${{ matrix.goarch }}
57+
path: dist/fssh-${{ matrix.goos }}-${{ matrix.goarch }}
58+
retention-days: 30
59+
60+
create-release:
61+
needs: build
62+
runs-on: ubuntu-latest
63+
if: startsWith(github.ref, 'refs/tags/')
64+
65+
steps:
66+
- name: Checkout code
67+
uses: actions/checkout@v4
68+
69+
- name: Download all artifacts
70+
uses: actions/download-artifact@v4
71+
72+
- name: Display structure of downloaded files
73+
run: find . -type f -name "fssh-*" | sort
74+
75+
- name: Create tarball
76+
run: |
77+
mkdir -p release
78+
cp fssh-darwin-amd64/fssh-darwin-amd64 release/fssh-amd64
79+
cp fssh-darwin-arm64/fssh-darwin-arm64 release/fssh-arm64
80+
tar -czf release/fssh-macos.tar.gz -C release fssh-amd64 fssh-arm64
81+
shasum -a 256 release/fssh-macos.tar.gz > release/fssh-macos.tar.gz.sha256
82+
cat release/fssh-macos.tar.gz.sha256
83+
84+
- name: Create Release
85+
uses: softprops/action-gh-release@v1
86+
with:
87+
files: release/*
88+
body: |
89+
## Binaries
90+
- `fssh-amd64` - Intel Macs (x86_64)
91+
- `fssh-arm64` - Apple Silicon Macs (M1, M2, M3)
92+
- `fssh-macos.tar.gz` - Both binaries packed
93+
- `fssh-macos.tar.gz.sha256` - SHA256 checksums
94+
env:
95+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

README.md

Lines changed: 82 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,107 @@
1-
# fssh — Touch ID–Protected SSH Agent and CLI
1+
# fssh
2+
3+
![Touch ID Fingerprint](images/finger.png)
4+
5+
A solution for macOS that eliminates the need to manually unlock private keys with passphrases every time you use public key authentication, and helps you quickly view and connect to SSH hosts configured in `~/.ssh/config` without having to open the config file each time.
6+
7+
When SSH connects to a remote host, it prompts for fingerprint authentication, which decrypts and imports the private key upon successful verification. Additionally, fssh provides an interactive shell where you can quickly view and connect to hosts defined in `~/.ssh/config`.
28

39
## Use Cases
4-
- Plaintext SSH keys on disk are risky and easy to exfiltrate
5-
- Encrypted keys require entering passphrases for every SSH login, which is inconvenient
6-
- With many hosts in `~/.ssh/config`, aliases are easy to forget; you often need to open the file before every connection
7-
8-
## Solution (fssh — finger‑ssh)
9-
- On macOS, unlock a Touch ID–protected master key to decrypt local encrypted SSH keys for authentication
10-
- Provide an OpenSSH‑compatible ssh‑agent
11-
- An interactive shell that parses hosts from `~/.ssh/config`, supports search and direct connect
12-
13-
## Overview
14-
- Securely store and use SSH private keys on macOS with Touch ID (or equivalent local authentication)
15-
- Provide an SSH agent that can operate in two modes:
16-
- Secure per‑sign unlock: prompts for Touch ID on each signature (or within a configurable TTL window)
17-
- Convenience preload: decrypts keys once and keeps them in memory for subsequent signatures
18-
- Interactive shell to discover hosts from `~/.ssh/config` and connect fast with tab completion
19-
- macOS login auto‑start via `launchd` and a generic LaunchAgent plist
20-
21-
## Key Features
22-
- Touch ID‑protected master key, stored in macOS Keychain
23-
- Encrypted key store at `~/.fssh/keys/<alias>.enc` using PKCS#8 + AES‑GCM
24-
- RSA‑SHA2 signatures (`rsa‑sha2‑256/512`) supported by the agent
25-
- Multiple keys import with unique `alias`
26-
- Configurable agent socket and logging via `~/.fssh/config.json`
27-
- Optional Touch ID TTL (`unlock_ttl_seconds`) to avoid repeated prompts in secure mode
28-
- `config-gen` to generate local `~/.ssh/config` entries with `IdentityAgent`
29-
- `sshd-align` to align server‑side `sshd_config` for RSA‑SHA2 algorithms
30-
31-
## Install (macOS)
32-
- Build: `go build ./cmd/fssh`
33-
- Place binary: `mv fssh /usr/local/bin/`
34-
- Initialize: `fssh init`
35-
- Import keys: `fssh import --alias work --file ~/.ssh/id_ed25519 --ask-passphrase`
36-
- Config ssh agent,File: `~/.ssh/config`
37-
- Example:
10+
- Plaintext SSH keys stored locally on disk pose security risks
11+
- Encrypted keys require entering passphrases every time you connect, which is inconvenient
12+
- When multiple hosts are configured in `~/.ssh/config`, their aliases are easy to forget over time, requiring you to check the config file before each connection
13+
14+
## Solutions
15+
- Automatically prompts for Touch ID fingerprint verification when using SSH commands to connect to hosts on macOS, then uses the master key to decrypt SSH private keys for authentication
16+
- Compatible with OpenSSH's ssh-agent
17+
- Running `fssh` directly launches an interactive shell where you can use commands like `list` and `connect` to view host information from `~/.ssh/config`. In this shell, you can enter a host's ID, host name, or IP directly to connect via SSH
18+
19+
## Screenshots
20+
SSH connection with fingerprint unlock:
21+
![Touch ID authentication](images/finger.png)
22+
23+
Viewing hosts from `~/.ssh/config` in the interactive shell:
24+
![Interactive shell](images/shell.png)
25+
26+
Connecting to a host from the interactive shell:
27+
![SSH connection](images/login.png)
28+
29+
## Features
30+
- Touch ID/Local authentication to read master key (stored in Keychain)
31+
- AES-256-GCM + HKDF encryption for private keys (independent `salt`/`nonce` per file)
32+
- Private key import/export (PKCS#8 PEM backup), listing and status checking
33+
- ssh-agent:
34+
- Supports fingerprint verification per signature, or configure TTL for repeat access within a short time window
35+
- Compatible with RSA-SHA2 (rsa-sha2-256/512)
36+
- Interactive Shell: parses `~/.ssh/config` hosts, Tab completion, default connection behavior
37+
- Configuration generator: automatically generates local `~/.ssh/config` entries with `IdentityAgent`
38+
39+
## Installation & Configuration
40+
1. Build: `go build ./cmd/fssh`; install to `/usr/local/bin/fssh`
41+
2. Run `fssh init` to initialize the master key
42+
3. Run `fssh import -alias <string> -file <path/to/private> --ask-passphrase` to import private keys
43+
4. Start the SSH authentication agent: `fssh agent --unlock-ttl-seconds 600`
44+
5. Modify the `~/.ssh/config` file so all SSH connections go through the fssh agent (you can also use `export SSH_AUTH_SOCK=~/.fssh/agent.sock` to set the variable for specific use cases)
45+
46+
Configure the OpenSSH agent by adding the following at the beginning of `~/.ssh/config`:
3847
```
3948
host *
4049
ServerAliveInterval 30
4150
AddKeysToAgent yes
4251
ControlPersist 60
4352
ControlMaster auto
44-
ControlPath ~/.ssh/shareconn/master-%r@%h:%p
45-
Ciphers +aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc
46-
HostKeyAlgorithms +ssh-rsa
47-
KexAlgorithms +diffie-hellman-group1-sha1
48-
IdentityAgent /Users/leo/.fssh/agent.sock
53+
IdentityAgent ~/.fssh/agent.sock
4954
```
5055

51-
## Configuration
52-
- File: `~/.fssh/config.json`
53-
- Example:
56+
6. If needed, create and modify the configuration file: `~/.fssh/config.json`, example:
5457
```
5558
{
56-
"socket": "~/.fssh/agent.sock",
57-
"require_touch_id_per_sign": true,
58-
"unlock_ttl_seconds": 600,
59-
"log_out": "/var/tmp/fssh-agent.out.log",
60-
"log_err": "/var/tmp/fssh-agent.err.log",
61-
"log_level": "info",
62-
"log_format": "plain",
63-
"log_time_format": "2006-01-02T15:04:05Z07:00"
59+
"socket":"~/.fssh/agent.sock",
60+
"require_touch_id_per_sign":true,
61+
"unlock_ttl_seconds":600,
62+
"log_level":"info",
63+
"log_format":"plain"
6464
}
6565
```
66-
- Precedence: CLI flags > config file > defaults
6766

68-
## Start Agent
69-
- Foreground: `fssh agent`
70-
- With TTL: `fssh agent --unlock-ttl-seconds 600`
71-
- Use in shell: `export SSH_AUTH_SOCK=~/.fssh/agent.sock`
72-
73-
## Auto‑Start on Login (LaunchAgents)
74-
- Copy plist: `cp contrib/com.fssh.agent.plist ~/Library/LaunchAgents/com.fssh.agent.plist`
75-
- Load: `launchctl load -w ~/Library/LaunchAgents/com.fssh.agent.plist`
76-
- Reload after config changes:
77-
- Preferred: `launchctl kickstart -k gui/$(id -u)/com.fssh.agent`
78-
- Legacy: `launchctl unload -w ~/Library/LaunchAgents/com.fssh.agent.plist && launchctl load -w ~/Library/LaunchAgents/com.fssh.agent.plist`
67+
- socket: SSH agent socket location
68+
- require_touch_id_per_sign: Whether to require Touch ID verification on every SSH signature
69+
- true: Security mode enabled, requires Touch ID on each signature (or after TTL expires)
70+
- false: Convenience mode, decrypts all keys once during startup and keeps them in memory
71+
- unlock_ttl_seconds: Cache time window after Touch ID unlock
72+
- log_level: Controls log output level
73+
- debug: Shows all logs (including cache hit information)
74+
- info: Shows general information (default)
75+
- warn: Shows warnings and errors only
76+
- error: Shows only errors
77+
- log_format: Controls log output format
78+
- plain: Human-readable plain format
79+
- json: Structured JSON format
80+
81+
## Auto-start on Login
82+
- Start agent: `fssh agent --unlock-ttl-seconds 600`
83+
- Auto-start: Copy `contrib/com.fssh.agent.plist` to `~/Library/LaunchAgents/` and run `launchctl load -w`; after modifying configuration, use `launchctl kickstart -k gui/$(id -u)/com.fssh.agent` to reload
7984

8085
## Interactive Shell
81-
- Start: `fssh` or `fssh shell`
86+
- Launch: `fssh` or `fssh shell`
8287
- Commands:
83-
- `list` — show `id\thost(ip)`
84-
- `search <term>` — filter by id/host/ip
85-
- `connect <id|host|ip>` — connect via OpenSSH
86-
- Tab completion for commands and host/id/ip
87-
- Non‑command input defaults to `connect`
88-
89-
## Config Generator
90-
- Print block: `fssh config-gen --host backuphost --user root`
91-
- Write to file: `fssh config-gen --host backuphost --user root --write`
92-
- Overwrite existing: `fssh config-gen --host backuphost --overwrite --write`
93-
- Global algorithms (optional): `fssh config-gen --global-algos --write` adds RSA‑SHA2 once to `Host *`
94-
- Generated host block contains `IdentityAgent` and optional `User/Port`; per‑host algorithm lines are not added by default
95-
96-
## Server Alignment (Optional)
97-
- Align RSA‑SHA2 on server: `fssh sshd-align --host backuphost --sudo`
98-
- Changes on remote `/etc/ssh/sshd_config`:
99-
- `PubkeyAuthentication yes`
100-
- `PubkeyAcceptedAlgorithms +rsa-sha2-512,rsa-sha2-256`
101-
- `PubkeyAcceptedKeyTypes +rsa-sha2-512,rsa-sha2-256` (compat)
88+
- `list` displays `id\thost(ip)`
89+
- `search <term>` filters by id/host/ip
90+
- `connect <id|host|ip>` initiates connection; non-command input defaults to connection
91+
- Tab completion covers commands and id/host/ip
10292

10393
## Troubleshooting
104-
- “incorrect signature type / no mutual signature supported”
105-
- Ensure agent is running and environment: `export SSH_AUTH_SOCK=~/.fssh/agent.sock`
106-
- Client config for host uses agent: `IdentityAgent ~/.fssh/agent.sock`
107-
- Server accepts RSA‑SHA2 (use `sshd-align` or edit `sshd_config`)
108-
- Input not visible after connect
109-
- Agent shell uses `ssh -tt` and suspends line editor during remote session
110-
- Logging
111-
- Configure `log_out/log_err`, `log_level`, `log_format`; restart agent after changes
94+
- "incorrect signature type / no mutual signature supported"
95+
- Confirm agent is running and set `SSH_AUTH_SOCK=~/.fssh/agent.sock`
96+
- Local entries should include `IdentityAgent ~/.fssh/agent.sock`
97+
- Server accepts RSA-SHA2 (use `sshd-align` or manually edit)
98+
- Input invisible after connection: use `ssh -tt` and suspend line editing during remote session
99+
- Logging: configure `log_out/log_err`, `log_level`, `log_format`; restart agent after changes
112100

113101
## Security Notes
114-
- Secure mode: per‑sign unlock (or TTL cache) reduces risk by avoiding long‑lived decrypted keys
115-
- Convenience mode: preload all keys into memory; prefer only when prompts are impractical
116-
- Never store plaintext secrets in the repo or logs; use Keychain and config paths
117-
118-
## Comparison to Secretive
119-
- Storage model
120-
- Secretive: keys in Secure Enclave, non‑exportable by design
121-
- fssh: PKCS#8 encrypted files in `~/.fssh/keys` with Touch ID‑protected master key in Keychain; optional password‑protected PEM export for recovery
122-
- Access control
123-
- Secretive: Touch ID/Apple Watch gate before key access; access notifications
124-
- fssh: LocalAuthentication on each signature or within a configurable TTL window; no notifications yet
125-
- Hardware support
126-
- Secretive: Smart Card/YubiKey supported for Macs without SE
127-
- fssh: no smart card support yet (roadmap)
128-
- Agent and algorithms
129-
- Secretive: signs with SE‑backed keys (non‑exportable)
130-
- fssh: OpenSSH‑compatible agent with RSA‑SHA2 (`rsa‑sha2‑256/512`) extended signatures; includes `sshd-align` to align server algorithms
131-
- Developer and ops tools
132-
- Secretive: native app experience and Homebrew install
133-
- fssh: CLI and interactive shell (host parsing, tab completion, default connect), `config-gen` to write `IdentityAgent` entries, generic `launchd` auto‑start, unified logging
134-
- Platform
135-
- Secretive: macOS with Secure Enclave
136-
- fssh: macOS today; planned cross‑platform support
102+
- Security mode: per-signature unlock (or TTL cache) avoids long-term decrypted private keys in memory
103+
- Convenience mode: decrypts and keeps in memory on startup; only use this when prompted too frequently
104+
- Avoid plaintext leakage: don't store plaintext keys/passwords in repositories or logs
137105

138106
## Credits
139107
- This project is assisted by TRAE AI software
140-
141-
## License
142-
- Proprietary project (example). Adjust this section as appropriate for your distribution.

0 commit comments

Comments
 (0)