updates
This commit is contained in:
@@ -11,6 +11,9 @@ import (
|
||||
)
|
||||
|
||||
const authorizedKeysPath = "/root/.ssh/authorized_keys"
|
||||
const sshConfigPath = "/root/.ssh/config"
|
||||
const managedConfigPath = "/root/.ssh/keymanager.conf"
|
||||
const includeDirective = "Include /root/.ssh/keymanager.conf"
|
||||
|
||||
func ReadAuthorizedKeys() ([]string, error) {
|
||||
data, err := os.ReadFile(authorizedKeysPath)
|
||||
@@ -135,3 +138,91 @@ func GenerateKeyPair(keyPath string, opts KeyGenOptions) (string, error) {
|
||||
}
|
||||
return strings.TrimSpace(string(pubData)), nil
|
||||
}
|
||||
|
||||
// AddSSHIdentity writes an IdentityFile entry for keyPath into the managed
|
||||
// keymanager.conf include file, and ensures ~/.ssh/config includes it.
|
||||
func AddSSHIdentity(keyPath string) error {
|
||||
if err := os.MkdirAll(filepath.Dir(sshConfigPath), 0700); err != nil {
|
||||
return fmt.Errorf("mkdir .ssh: %w", err)
|
||||
}
|
||||
|
||||
if err := ensureIncludeDirective(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read existing managed config (it may not exist yet).
|
||||
var existing string
|
||||
data, err := os.ReadFile(managedConfigPath)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("read %s: %w", managedConfigPath, err)
|
||||
}
|
||||
existing = string(data)
|
||||
|
||||
line := "IdentityFile " + keyPath
|
||||
for _, l := range strings.Split(existing, "\n") {
|
||||
if strings.TrimSpace(l) == line {
|
||||
return nil // already present
|
||||
}
|
||||
}
|
||||
|
||||
if existing != "" && !strings.HasSuffix(existing, "\n") {
|
||||
existing += "\n"
|
||||
}
|
||||
updated := existing + line + "\n"
|
||||
|
||||
if err := os.WriteFile(managedConfigPath, []byte(updated), 0600); err != nil {
|
||||
return fmt.Errorf("write %s: %w", managedConfigPath, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveSSHIdentity removes the IdentityFile entry for keyPath from the managed config.
|
||||
func RemoveSSHIdentity(keyPath string) error {
|
||||
data, err := os.ReadFile(managedConfigPath)
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("read %s: %w", managedConfigPath, err)
|
||||
}
|
||||
|
||||
line := "IdentityFile " + keyPath
|
||||
var kept []string
|
||||
for _, l := range strings.Split(strings.TrimRight(string(data), "\n"), "\n") {
|
||||
if strings.TrimSpace(l) != line {
|
||||
kept = append(kept, l)
|
||||
}
|
||||
}
|
||||
|
||||
content := strings.Join(kept, "\n")
|
||||
if len(kept) > 0 {
|
||||
content += "\n"
|
||||
}
|
||||
if err := os.WriteFile(managedConfigPath, []byte(content), 0600); err != nil {
|
||||
return fmt.Errorf("write %s: %w", managedConfigPath, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ensureIncludeDirective adds "Include /root/.ssh/keymanager.conf" to the top
|
||||
// of ~/.ssh/config if it is not already present. The Include must appear before
|
||||
// any Host stanzas to be effective for all connections.
|
||||
func ensureIncludeDirective() error {
|
||||
data, err := os.ReadFile(sshConfigPath)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("read %s: %w", sshConfigPath, err)
|
||||
}
|
||||
|
||||
for _, l := range strings.Split(string(data), "\n") {
|
||||
if strings.TrimSpace(l) == includeDirective {
|
||||
return nil // already present
|
||||
}
|
||||
}
|
||||
|
||||
// Prepend the Include directive so it takes effect before any Host blocks.
|
||||
updated := includeDirective + "\n" + string(data)
|
||||
if err := os.WriteFile(sshConfigPath, []byte(updated), 0600); err != nil {
|
||||
return fmt.Errorf("write %s: %w", sshConfigPath, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user