This commit is contained in:
redlineo committed 2026-07-22 15:14:44 +03:00
1 parent 23c7133fa9
commit 8c1b93c14e
16 files changed
+1187 -295

No files matched your search

+14 -11
View File
@@ -19,20 +19,23 @@ const managedMarker = "# ssh-access-tui managed key — do not edit by hand, use
// actual security boundary for a jump/forward-only account:
// - restrict disables pty, X11, agent-forwarding, user-rc, etc.
// - port-forwarding re-enables (only) local/dynamic forwarding
// - permitopen=... whitelists exactly the host:port pairs this key
// may forward to — this is what makes "only these hosts" a protocol-level
// guarantee rather than a client-side convention.
// - permitopen=... whitelists exactly the address:port pairs this key
// may forward to — this is what makes "only these destinations" a
// protocol-level guarantee rather than a client-side convention. Every
// service on every host the user's groups grant becomes one
// permitopen= entry here, independent of how many services share a
// host or how many hosts share a port number.
//
// Reverse forwarding (-R) is intentionally never granted here.
func BuildKeyOptions(hosts []model.Host) string {
if len(hosts) == 0 {
// No hosts assigned yet: restrict everything, permit nothing, so the
// key authenticates but cannot open forwarding channels anywhere.
func BuildKeyOptions(forwards []model.Forward) string {
if len(forwards) == 0 {
// No forwards assigned yet: restrict everything, permit nothing, so
// the key authenticates but cannot open forwarding channels anywhere.
return "restrict"
}
opts := []string{"restrict", "port-forwarding"}
for _, h := range hosts {
opts = append(opts, fmt.Sprintf(`permitopen="%s:%s"`, h.Address, strconv.Itoa(h.Port)))
for _, f := range forwards {
opts = append(opts, fmt.Sprintf(`permitopen="%s:%s"`, f.Address, strconv.Itoa(f.Port)))
}
return strings.Join(opts, ",")
}
@@ -40,7 +43,7 @@ func BuildKeyOptions(hosts []model.Host) string {
// WriteAuthorizedKeys writes the single managed key line (with its
// permitopen restrictions) into ~<username>/.ssh/authorized_keys, replacing
// any previous ssh-access-tui-managed line for that user.
func WriteAuthorizedKeys(username, pubKeyLine string, hosts []model.Host) error {
func WriteAuthorizedKeys(username, pubKeyLine string, forwards []model.Forward) error {
u, err := user.Lookup(username)
if err != nil {
return fmt.Errorf("lookup user %s: %w", username, err)
@@ -49,7 +52,7 @@ func WriteAuthorizedKeys(username, pubKeyLine string, hosts []model.Host) error
if err := os.MkdirAll(sshDir, 0o700); err != nil {
return fmt.Errorf("create .ssh dir: %w", err)
}
line := fmt.Sprintf("%s %s", BuildKeyOptions(hosts), strings.TrimSpace(pubKeyLine))
line := fmt.Sprintf("%s %s", BuildKeyOptions(forwards), strings.TrimSpace(pubKeyLine))
content := managedMarker + "\n" + line + "\n"
akPath := filepath.Join(sshDir, "authorized_keys")