From 1476314bf5eb6ed27644bfb5f0aa9bd22cf5b513 Mon Sep 17 00:00:00 2001 From: Vitaly Potyarkin Date: Thu, 21 Sep 2023 11:20:50 +0000 Subject: [PATCH] Separate searching for ssh-agent identity into a function --- secrets/access/acl.go | 34 ++++++++++++++++++++++++++++++++++ secrets/cmd/secretctl/cert.go | 31 +++++-------------------------- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/secrets/access/acl.go b/secrets/access/acl.go index 5980f3a..e5df4d4 100644 --- a/secrets/access/acl.go +++ b/secrets/access/acl.go @@ -8,6 +8,7 @@ import ( _ "github.com/mattn/go-sqlite3" "golang.org/x/crypto/ssh" + "github.com/sio/pond/secrets/agent" "github.com/sio/pond/secrets/master" "github.com/sio/pond/secrets/util" ) @@ -154,3 +155,36 @@ func (acl *ACL) Check(key ssh.PublicKey, c Capability, dir string) error { } var ErrPermissionDenied = errors.New("permission denied") + +// Connect to ssh-agent and find an identity that has sufficient permissions +func (acl *ACL) FindAgent(caps []Capability, paths []string) (*agent.Conn, error) { + signer, err := agent.New(nil) + if err != nil { + return nil, err + } + fail := func(err error) (*agent.Conn, error) { + _ = signer.Close() + return nil, err + } + identities := signer.ListKeys() + if len(identities) == 0 { + return fail(fmt.Errorf("no identities available in ssh-agent")) + } +loop_id: + for _, id := range identities { + for _, capability := range caps { + for _, path := range paths { + err = acl.Check(id, Required[capability], path) + if err != nil { + continue loop_id + } + } + } + err = signer.SetIdentity(id) + if err != nil { + return fail(err) + } + return signer, nil + } + return fail(fmt.Errorf("ssh-agent: no matching identity out of %d tried", len(identities))) +} diff --git a/secrets/cmd/secretctl/cert.go b/secrets/cmd/secretctl/cert.go index cb065cf..1ee9001 100644 --- a/secrets/cmd/secretctl/cert.go +++ b/secrets/cmd/secretctl/cert.go @@ -7,7 +7,6 @@ import ( "golang.org/x/crypto/ssh" "github.com/sio/pond/secrets/access" - "github.com/sio/pond/secrets/agent" "github.com/sio/pond/secrets/master" "github.com/sio/pond/secrets/repo" "github.com/sio/pond/secrets/util" @@ -82,36 +81,16 @@ func (c *CertCmd) delegateUser(r *repo.Repository, to ssh.PublicKey, lifetime ti if err != nil { return "", err } - signer, err := agent.New(nil) + signer, err := acl.FindAgent(caps, c.Path) if err != nil { return "", err } defer func() { _ = signer.Close() }() - identities := signer.ListKeys() - if len(identities) == 0 { - return "", fmt.Errorf("no identities available in ssh-agent") - } -loop_id: - for _, id := range identities { - for _, capability := range caps { - for _, p := range c.Path { - err = acl.Check(id, access.Required[capability], p) - if err != nil { - continue loop_id - } - } - } - err = signer.SetIdentity(id) - if err != nil { - return "", err - } - cert, err := access.DelegateUser(signer, to, caps, c.Path, c.User, lifetime) - if err != nil { - return "", err - } - return r.Save(cert) + cert, err := access.DelegateUser(signer, to, caps, c.Path, c.User, lifetime) + if err != nil { + return "", err } - return "", fmt.Errorf("ssh-agent: not enough permissions to issue this certificate (tried %d identities)", len(identities)) + return r.Save(cert) } func (c *CertCmd) delegateAdmin(r *repo.Repository, to ssh.PublicKey, lifetime time.Duration) (path string, err error) {