From 14a8df7bf44173a88c971c056e59729369079287 Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Thu, 28 Sep 2023 14:24:29 -0700 Subject: [PATCH 1/5] enable agent confirmation from config --- cmd/keymaster/main.go | 34 ++++++++++++++++++++++++++++++++-- lib/client/config/api.go | 11 ++++++----- lib/client/sshagent/agent.go | 30 ++++++++++++++++++++---------- lib/client/sshagent/api.go | 8 +++++++- 4 files changed, 65 insertions(+), 18 deletions(-) diff --git a/cmd/keymaster/main.go b/cmd/keymaster/main.go index 3183ed62..8ae5c401 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,30 @@ 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.UpsertCertIntoAgent(certText, signer, filePrefix+"-"+userName, uint32((*twofa.Duration).Seconds()), logger) + err = sshagent.WithAddedKeyUpserCertIntoAgent(keyToAdd, logger) if err == nil { return nil } @@ -282,7 +306,9 @@ 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 + //err = sshagent.UpsertCertIntoAgent(certText, signer, filePrefix+"-"+userName, 0, logger) + err = sshagent.WithAddedKeyUpserCertIntoAgent(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/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..f18a2992 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 withAddedKeyUpserCertIntoAgent(keyToAdd, logger) +} + +func withAddedKeyUpserCertIntoAgent(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..844e9af1 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 WithAddedKeyUpserCertIntoAgent(certToAdd agent.AddedKey, logger log.Logger) error { + return withAddedKeyUpserCertIntoAgent(certToAdd, logger) } From 9562b3fcef5ed12e3f7ce46964e51ae5b549adbc Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Thu, 28 Sep 2023 14:31:35 -0700 Subject: [PATCH 2/5] cleanup --- cmd/keymaster/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/keymaster/main.go b/cmd/keymaster/main.go index 8ae5c401..e520f568 100644 --- a/cmd/keymaster/main.go +++ b/cmd/keymaster/main.go @@ -296,7 +296,6 @@ func insertSSHCertIntoAgentORWriteToFilesystem(certText []byte, } //comment should be based on key type? - //err = sshagent.UpsertCertIntoAgent(certText, signer, filePrefix+"-"+userName, uint32((*twofa.Duration).Seconds()), logger) err = sshagent.WithAddedKeyUpserCertIntoAgent(keyToAdd, logger) if err == nil { return nil @@ -307,7 +306,8 @@ func insertSSHCertIntoAgentORWriteToFilesystem(certText []byte, // we are on windows OR we have an agent running on windows thar is forwarded // to us. keyToAdd.LifetimeSecs = 0 - //err = sshagent.UpsertCertIntoAgent(certText, signer, filePrefix+"-"+userName, 0, logger) + // confirmation is also broken on windows, but since it is an opt-in security + // feature we never change the user preference err = sshagent.WithAddedKeyUpserCertIntoAgent(keyToAdd, logger) if err == nil { return nil From 3f4925aec3e4e2519d5b20b4bf32e9cb97b2f551 Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Thu, 28 Sep 2023 14:35:24 -0700 Subject: [PATCH 3/5] update versions --- Makefile | 2 +- keymaster.spec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/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 From 0009f76558ffe86bdeb84f9ee7b56b2d462d0c48 Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Thu, 28 Sep 2023 14:47:39 -0700 Subject: [PATCH 4/5] fixing tests --- cmd/keymaster/main_test.go | 1 + 1 file changed, 1 insertion(+) 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) From fac951afee7ee383c0d61c3f05ebf8a03fed3252 Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Tue, 3 Oct 2023 09:39:54 -0700 Subject: [PATCH 5/5] fixing typo --- cmd/keymaster/main.go | 4 ++-- lib/client/sshagent/agent.go | 4 ++-- lib/client/sshagent/api.go | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/keymaster/main.go b/cmd/keymaster/main.go index e520f568..0ab5a1e4 100644 --- a/cmd/keymaster/main.go +++ b/cmd/keymaster/main.go @@ -296,7 +296,7 @@ func insertSSHCertIntoAgentORWriteToFilesystem(certText []byte, } //comment should be based on key type? - err = sshagent.WithAddedKeyUpserCertIntoAgent(keyToAdd, logger) + err = sshagent.WithAddedKeyUpsertCertIntoAgent(keyToAdd, logger) if err == nil { return nil } @@ -308,7 +308,7 @@ func insertSSHCertIntoAgentORWriteToFilesystem(certText []byte, 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.WithAddedKeyUpserCertIntoAgent(keyToAdd, logger) + err = sshagent.WithAddedKeyUpsertCertIntoAgent(keyToAdd, logger) if err == nil { return nil } diff --git a/lib/client/sshagent/agent.go b/lib/client/sshagent/agent.go index f18a2992..ea87a8ed 100644 --- a/lib/client/sshagent/agent.go +++ b/lib/client/sshagent/agent.go @@ -72,10 +72,10 @@ func upsertCertIntoAgent( Comment: comment, ConfirmBeforeUse: confirmBeforeUse, } - return withAddedKeyUpserCertIntoAgent(keyToAdd, logger) + return withAddedKeyUpsertCertIntoAgent(keyToAdd, logger) } -func withAddedKeyUpserCertIntoAgent(certToAdd agent.AddedKey, logger log.Logger) error { +func withAddedKeyUpsertCertIntoAgent(certToAdd agent.AddedKey, logger log.Logger) error { if certToAdd.Certificate == nil { return fmt.Errorf("Needs a certificate to be added") } diff --git a/lib/client/sshagent/api.go b/lib/client/sshagent/api.go index 844e9af1..c17586a4 100644 --- a/lib/client/sshagent/api.go +++ b/lib/client/sshagent/api.go @@ -15,6 +15,6 @@ func UpsertCertIntoAgent( return upsertCertIntoAgent(certText, privateKey, comment, lifeTimeSecs, false, logger) } -func WithAddedKeyUpserCertIntoAgent(certToAdd agent.AddedKey, logger log.Logger) error { - return withAddedKeyUpserCertIntoAgent(certToAdd, logger) +func WithAddedKeyUpsertCertIntoAgent(certToAdd agent.AddedKey, logger log.Logger) error { + return withAddedKeyUpsertCertIntoAgent(certToAdd, logger) }