diff --git a/Makefile b/Makefile index de409cca..054b34b6 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ endif BINARY=keymaster # These are the values we want to pass for Version and BuildTime -VERSION=1.13.5 +VERSION=1.14.0 #BUILD_TIME=`date +%FT%T%z` # Setup the -ldflags option for go build here, interpolate the variable values diff --git a/cmd/keymaster/main.go b/cmd/keymaster/main.go index 3183ed62..0ab5a1e4 100644 --- a/cmd/keymaster/main.go +++ b/cmd/keymaster/main.go @@ -17,6 +17,9 @@ import ( "strings" "time" + "golang.org/x/crypto/ssh" + "golang.org/x/crypto/ssh/agent" + "github.com/Cloud-Foundations/Dominator/lib/log/cmdlogger" "github.com/Cloud-Foundations/Dominator/lib/net/rrdialer" "github.com/Cloud-Foundations/golib/pkg/log" @@ -271,9 +274,29 @@ func insertSSHCertIntoAgentORWriteToFilesystem(certText []byte, filePrefix string, userName string, privateKeyPath string, + confirmBeforeUse bool, logger log.DebugLogger) (err error) { + + pubKey, _, _, _, err := ssh.ParseAuthorizedKey(certText) + if err != nil { + logger.Println(err) + return err + } + sshCert, ok := pubKey.(*ssh.Certificate) + if !ok { + return fmt.Errorf("It is not a certificate") + } + comment := filePrefix + "-" + userName + keyToAdd := agent.AddedKey{ + PrivateKey: signer, + Certificate: sshCert, + Comment: comment, + LifetimeSecs: uint32((*twofa.Duration).Seconds()), + ConfirmBeforeUse: confirmBeforeUse, + } + //comment should be based on key type? - err = sshagent.UpsertCertIntoAgent(certText, signer, filePrefix+"-"+userName, uint32((*twofa.Duration).Seconds()), logger) + err = sshagent.WithAddedKeyUpsertCertIntoAgent(keyToAdd, logger) if err == nil { return nil } @@ -282,7 +305,10 @@ func insertSSHCertIntoAgentORWriteToFilesystem(certText []byte, // barfs on timeouts missing, so we rety without a timeout in case // we are on windows OR we have an agent running on windows thar is forwarded // to us. - err = sshagent.UpsertCertIntoAgent(certText, signer, filePrefix+"-"+userName, 0, logger) + keyToAdd.LifetimeSecs = 0 + // confirmation is also broken on windows, but since it is an opt-in security + // feature we never change the user preference + err = sshagent.WithAddedKeyUpsertCertIntoAgent(keyToAdd, logger) if err == nil { return nil } @@ -390,6 +416,7 @@ func setupCerts( } logger.Debugf(0, "certificates successfully generated") + confirmKeyUse := configContents.Base.AgentConfirmUse // Time to write certs and keys // old agents do not understand sha2 certs, so we inject Ed25519 first // if present @@ -399,6 +426,7 @@ func setupCerts( FilePrefix+"-ed25519", userName, sshKeyPath+"-ed25519", + confirmKeyUse, logger) if err != nil { return err @@ -409,6 +437,7 @@ func setupCerts( FilePrefix+"-rsa", userName, sshKeyPath+"-rsa", + confirmKeyUse, logger) if err != nil { return err @@ -502,6 +531,7 @@ func main() { logger.Fatal(err) } config := loadConfigFile(client, logger) + logger.Debugf(3, "loaded Config=%+v", config) // Adjust user name if len(config.Base.Username) > 0 { userName = config.Base.Username diff --git a/cmd/keymaster/main_test.go b/cmd/keymaster/main_test.go index cfc2656d..df2ce501 100644 --- a/cmd/keymaster/main_test.go +++ b/cmd/keymaster/main_test.go @@ -267,6 +267,7 @@ func TestInsertSSHCertIntoAgentORWriteToFilesystem(t *testing.T) { "someprefix", "username", privateKeyPath, + false, testlogger.New(t)) if err != nil { t.Fatal(err) diff --git a/keymaster.spec b/keymaster.spec index eacd7af1..54374947 100644 --- a/keymaster.spec +++ b/keymaster.spec @@ -1,5 +1,5 @@ Name: keymaster -Version: 1.13.5 +Version: 1.14.0 Release: 1%{?dist} Summary: Short term access certificate generator and client diff --git a/lib/client/config/api.go b/lib/client/config/api.go index 806ed727..4c039364 100644 --- a/lib/client/config/api.go +++ b/lib/client/config/api.go @@ -7,11 +7,12 @@ import ( ) type BaseConfig struct { - Gen_Cert_URLS string `yaml:"gen_cert_urls"` - Username string `yaml:"username"` - FilePrefix string `yaml:"file_prefix"` - AddGroups bool `yaml:"add_groups"` - WebauthBrowser string `yaml:"webauth_browser"` + Gen_Cert_URLS string `yaml:"gen_cert_urls"` + Username string `yaml:"username"` + FilePrefix string `yaml:"file_prefix"` + AddGroups bool `yaml:"add_groups"` + WebauthBrowser string `yaml:"webauth_browser"` + AgentConfirmUse bool `yaml:"agent_confirm_use"` } // AppConfigFile represents a keymaster client configuration file diff --git a/lib/client/sshagent/agent.go b/lib/client/sshagent/agent.go index a76287a5..ea87a8ed 100644 --- a/lib/client/sshagent/agent.go +++ b/lib/client/sshagent/agent.go @@ -55,6 +55,7 @@ func upsertCertIntoAgent( privateKey interface{}, comment string, lifeTimeSecs uint32, + confirmBeforeUse bool, logger log.Logger) error { pubKey, _, _, _, err := ssh.ParseAuthorizedKey(certText) if err != nil { @@ -65,6 +66,20 @@ func upsertCertIntoAgent( if !ok { return fmt.Errorf("It is not a certificate") } + keyToAdd := agent.AddedKey{ + PrivateKey: privateKey, + Certificate: sshCert, + Comment: comment, + ConfirmBeforeUse: confirmBeforeUse, + } + return withAddedKeyUpsertCertIntoAgent(keyToAdd, logger) +} + +func withAddedKeyUpsertCertIntoAgent(certToAdd agent.AddedKey, logger log.Logger) error { + if certToAdd.Certificate == nil { + return fmt.Errorf("Needs a certificate to be added") + } + conn, err := connectToDefaultSSHAgentLocation() if err != nil { return err @@ -73,22 +88,17 @@ func upsertCertIntoAgent( agentClient := agent.NewClient(conn) //delete certs in agent with the same comment - _, err = deleteDuplicateEntries(comment, agentClient, logger) + _, err = deleteDuplicateEntries(certToAdd.Comment, agentClient, logger) if err != nil { logger.Printf("failed during deletion err=%s", err) return err } - - keyToAdd := agent.AddedKey{ - PrivateKey: privateKey, - Certificate: sshCert, - Comment: comment, - } // NOTE: Current Windows ssh (OpenSSH_for_Windows_7.7p1, LibreSSL 2.6.5) // barfs when encountering a lifetime so we only add it for non-windows - if runtime.GOOS != "windows" { - keyToAdd.LifetimeSecs = lifeTimeSecs + if runtime.GOOS == "windows" { + certToAdd.LifetimeSecs = 0 + certToAdd.ConfirmBeforeUse = false } - return agentClient.Add(keyToAdd) + return agentClient.Add(certToAdd) } diff --git a/lib/client/sshagent/api.go b/lib/client/sshagent/api.go index 600b220b..c17586a4 100644 --- a/lib/client/sshagent/api.go +++ b/lib/client/sshagent/api.go @@ -1,6 +1,8 @@ package sshagent import ( + "golang.org/x/crypto/ssh/agent" + "github.com/Cloud-Foundations/golib/pkg/log" ) @@ -10,5 +12,9 @@ func UpsertCertIntoAgent( comment string, lifeTimeSecs uint32, logger log.Logger) error { - return upsertCertIntoAgent(certText, privateKey, comment, lifeTimeSecs, logger) + return upsertCertIntoAgent(certText, privateKey, comment, lifeTimeSecs, false, logger) +} + +func WithAddedKeyUpsertCertIntoAgent(certToAdd agent.AddedKey, logger log.Logger) error { + return withAddedKeyUpsertCertIntoAgent(certToAdd, logger) }