Jeremy Stott 6b8e6fc2c2 Initial commit of sshrimp.
* sshrimp-agent and sshrimp-ca building and deploying.
* mage build system working.
* successful deploy and SSH to host.
* need to tidy up and add tests.
2020-02-18 23:45:55 +13:00

93 lines
2.3 KiB
Go

package main
import (
"crypto/rand"
"crypto/rsa"
"fmt"
"net"
"os"
"os/signal"
"strings"
"syscall"
"github.com/alecthomas/kong"
"github.com/stoggi/sshrimp/internal/config"
"github.com/stoggi/sshrimp/internal/sshrimpagent"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
var cli struct {
Config string `kong:"arg,type='string',help='sshrimp config file (default: ${config_file} or ${env_var_name} environment variable)',default='${config_file}',env='SSHRIMP_CONFIG'"`
}
func main() {
ctx := kong.Parse(&cli,
kong.Name("sshrimp-agent"),
kong.Description("An SSH Agent that renews SSH certificates automatically from a SSHrimp Certificate Authority."),
kong.Vars{
"config_file": config.DefaultPath,
"env_var_name": config.EnvVarName,
},
)
c := config.NewSSHrimpWithDefaults()
ctx.FatalIfErrorf(c.Read(cli.Config))
ctx.FatalIfErrorf(launchAgent(c, ctx))
}
func launchAgent(c *config.SSHrimp, ctx *kong.Context) error {
if _, err := os.Stat(c.Agent.Socket); err == nil {
return fmt.Errorf("socket %s already exists", c.Agent.Socket)
}
// This affects all files created for the process. Since this is a sensitive
// socket, only allow the current user to write to the socket.
syscall.Umask(0077)
listener, err := net.Listen("unix", c.Agent.Socket)
if err != nil {
return err
}
defer listener.Close()
ctx.Printf("listening on %s", c.Agent.Socket)
// Generate a new SSH private/public key pair
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return err
}
signer, err := ssh.NewSignerFromKey(privateKey)
if err != nil {
return err
}
// Create the sshrimp agent with our configuration and the private key signer
sshrimpAgent := sshrimpagent.NewSSHrimpAgent(c, signer)
// Listen for signals so that we can close the listener and exit nicely
osSignals := make(chan os.Signal)
signal.Notify(osSignals, os.Interrupt, os.Kill)
go func() {
_ = <-osSignals
listener.Close()
}()
// Accept connections and serve the agent
for {
conn, err := listener.Accept()
if err != nil {
if strings.Contains(err.Error(), "use of closed network connection") {
// Occurs if the user interrupts the agent with a ctrl-c signal
return nil
}
return err
}
if err := agent.ServeAgent(sshrimpAgent, conn); err != nil {
return err
}
}
}