Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

Commit 52b3a1e

Browse files
authored
Merge pull request #21 from keybase/david/specify-key-in-ssh-config
Specify key in ssh config and add kssh debug logs
2 parents 835c208 + a6989bc commit 52b3a1e

10 files changed

Lines changed: 88 additions & 18 deletions

File tree

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,18 @@ VERSION:
152152
0.0.1
153153
154154
GLOBAL OPTIONS:
155-
--help, Show help
155+
--help Show help
156+
-v Enable kssh and ssh debug logs
156157
--provision Provision a new SSH key and add it to the ssh-agent. Useful if you need to run another
157158
program that uses SSH auth (eg scp, rsync, etc)
158159
--set-default-bot Set the default bot to be used for kssh. Not necessary if you are only in one team that
159160
is using Keybase SSH CA
160161
--clear-default-bot Clear the default bot
161162
--bot Specify a specific bot to be used for kssh. Not necessary if you are only in one team that
162-
is using Keybase SSH CA`)
163+
is using Keybase SSH CA
164+
--set-default-user Set the default SSH user to be used for kssh. Useful if you use ssh configs that do not set
165+
a default SSH user
166+
--clear-default-user Clear the default SSH user
163167
```
164168

165169
## Architecture

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.12
55
require (
66
github.com/google/uuid v1.1.1
77
github.com/keybase/go-keybase-chat-bot v0.0.0-20190812134859-bc54fd9cf83b
8+
github.com/sirupsen/logrus v1.4.2
89
github.com/stretchr/testify v1.3.0
910
github.com/urfave/cli v1.21.0
1011
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4

go.sum

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
22
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
33
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
5+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
46
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
57
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
68
github.com/keybase/go-keybase-chat-bot v0.0.0-20190812134859-bc54fd9cf83b h1:7Te2f9LQ/rd6XSzpntz6BaCBgglZ0uiCdv3/GdhX9VA=
79
github.com/keybase/go-keybase-chat-bot v0.0.0-20190812134859-bc54fd9cf83b/go.mod h1:vNc28YFzigVJod0j5EbuTtRIe7swx8vodh2yA4jZ2s8=
10+
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
11+
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
812
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
913
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
14+
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
15+
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
1016
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
17+
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
18+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
1119
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
1220
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
1321
github.com/urfave/cli v1.21.0 h1:wYSSj06510qPIzGSua9ZqsncMmWE3Zr55KBERygyrxE=
@@ -19,6 +27,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
1927
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
2028
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
2129
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
30+
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
2231
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e h1:D5TXcfTk7xF7hvieo4QErS3qqCB4teTffacDWr7CI+0=
2332
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
2433
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

src/cmd/kssh/kssh.go

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ import (
1313
"github.com/google/uuid"
1414
"github.com/keybase/bot-ssh-ca/src/kssh"
1515
"github.com/keybase/bot-ssh-ca/src/shared"
16+
log "github.com/sirupsen/logrus"
1617

1718
"golang.org/x/crypto/ssh"
1819
)
1920

2021
func main() {
22+
kssh.InitLogging()
2123
team, remainingArgs, action, err := handleArgs(os.Args[1:])
2224
if err != nil {
2325
fmt.Printf("Failed to parse arguments: %v\n", err)
@@ -29,7 +31,9 @@ func main() {
2931
os.Exit(1)
3032
}
3133
if isValidCert(keyPath) {
34+
log.WithField("keyPath", keyPath).Debug("Reusing unexpired certificate")
3235
doAction(action, keyPath, remainingArgs)
36+
os.Exit(0)
3337
}
3438
config, err := getConfig(team)
3539
if err != nil {
@@ -80,6 +84,7 @@ var cliArguments = []kssh.CLIArgument{
8084
{Name: "--set-default-user", HasArgument: true},
8185
{Name: "--clear-default-user", HasArgument: false},
8286
{Name: "--help", HasArgument: false},
87+
{Name: "-v", HasArgument: false, Preserve: true},
8388
}
8489

8590
func generateHelpPage() string {
@@ -93,7 +98,8 @@ VERSION:
9398
0.0.1
9499
95100
GLOBAL OPTIONS:
96-
--help, Show help
101+
--help Show help
102+
-v Enable kssh and ssh debug logs
97103
--provision Provision a new SSH key and add it to the ssh-agent. Useful if you need to run another
98104
program that uses SSH auth (eg scp, rsync, etc)
99105
--set-default-bot Set the default bot to be used for kssh. Not necessary if you are only in one team that
@@ -171,6 +177,9 @@ func handleArgs(args []string) (string, []string, Action, error) {
171177
fmt.Println(generateHelpPage())
172178
os.Exit(0)
173179
}
180+
if arg.Argument.Name == "-v" {
181+
log.SetLevel(log.DebugLevel)
182+
}
174183
}
175184
return team, remaining, action, nil
176185
}
@@ -249,7 +258,7 @@ func isValidCert(keyPath string) bool {
249258

250259
// Provision a new signed SSH key with the given config
251260
func provisionNewKey(config kssh.ConfigFile, keyPath string) error {
252-
fmt.Println("Generating a new SSH key...")
261+
log.Debug("Generating a new SSH key...")
253262
err := sshutils.GenerateNewSSHKey(keyPath, true, false)
254263
if err != nil {
255264
return fmt.Errorf("Failed to generate a new SSH key: %v", err)
@@ -264,13 +273,15 @@ func provisionNewKey(config kssh.ConfigFile, keyPath string) error {
264273
return fmt.Errorf("Failed to generate a new UUID for the SignatureRequest: %v", err)
265274
}
266275

276+
log.Debug("Requesting signature from the CA....")
267277
resp, err := kssh.GetSignedKey(config, shared.SignatureRequest{
268278
UUID: randomUUID.String(),
269279
SSHPublicKey: string(pubKey),
270280
})
271281
if err != nil {
272282
return fmt.Errorf("Failed to get a signed key from the CA: %v", err)
273283
}
284+
log.Debug("Received signature from the CA!")
274285

275286
err = ioutil.WriteFile(shared.KeyPathToCert(keyPath), []byte(resp.SignedKey), 0600)
276287
if err != nil {
@@ -291,7 +302,7 @@ func runSSHWithKey(keyPath string, remainingArgs []string) {
291302
}
292303
if user != "" {
293304
useConfig = true
294-
err = kssh.CreateDefaultUserConfigFile()
305+
err = kssh.CreateDefaultUserConfigFile(keyPath)
295306
if err != nil {
296307
fmt.Printf("Failed to set default user: %v\n", err)
297308
os.Exit(1)
@@ -305,13 +316,11 @@ func runSSHWithKey(keyPath string, remainingArgs []string) {
305316
os.Exit(1)
306317
}
307318

308-
// A new line to separate kssh output from ssh output
309-
fmt.Printf("\n")
310-
311319
argumentList := []string{"-i", keyPath, "-o", "IdentitiesOnly=yes"}
312320
checkAndWarnOnUnspecifiedBehavior(useConfig, remainingArgs)
313321
if useConfig {
314322
argumentList = append(argumentList, "-F", kssh.AlternateSSHConfigFile)
323+
log.WithField("user", user).Debug("Using default ssh user")
315324
}
316325

317326
argumentList = append(argumentList, remainingArgs...)
@@ -333,7 +342,7 @@ func checkAndWarnOnUnspecifiedBehavior(useConfig bool, arguments []string) {
333342
if useConfig {
334343
for _, arg := range arguments {
335344
if arg == "-F" {
336-
fmt.Println("Warning: You passed a -F flag, but kssh also uses this argument in " +
345+
log.Warn("Warning: You passed a -F flag, but kssh also uses this argument in " +
337346
"order to implement support for a default SSH username, which you're also using. " +
338347
"Either do not use the -F flag or run `kssh --clear-default-user` to reset the " +
339348
"default SSH user and delegate this to the running CA bot.")

src/cmd/kssh/kssh_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ func copyKeyFromTestFixture(t *testing.T, name, destination string) {
2323
require.NoError(t, err)
2424
err = ioutil.WriteFile(shared.KeyPathToCert(destination), cert, 0600)
2525
require.NoError(t, err)
26-
2726
}
2827

2928
func TestIsValidCert(t *testing.T) {

src/kssh/bot.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ func GetSignedKey(config ConfigFile, request shared.SignatureRequest) (shared.Si
5151
}
5252
}()
5353

54-
fmt.Println("Requesting signature from the CA....")
5554
hasBeenAcked := false
5655
startTime := time.Now()
5756
for {
@@ -97,7 +96,6 @@ func GetSignedKey(config ConfigFile, request shared.SignatureRequest) (shared.Si
9796
// someone else's signature request
9897
continue
9998
}
100-
fmt.Println("Received signature from the CA!")
10199
return resp, nil
102100
}
103101
}

src/kssh/flags.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,24 @@ package kssh
33
import "fmt"
44

55
type CLIArgument struct {
6-
Name string // eg "--foo"
7-
HasArgument bool // true if an argument comes after it (eg "--foo bar") false if it is a boolean flag (eg "--help")
6+
// The name of the flag eg "--foo"
7+
Name string
8+
9+
// HasArgument:true if an argument comes after it (eg "--foo bar") false if it is a boolean flag (eg "--help")
10+
HasArgument bool
11+
12+
// Preserve:true if you wish to preserve this argument into the list of remaining arguments even if found
13+
// eg if your command takes in a `-v` flag and the subcommand also takes in a `-v` flag
14+
// incompatible with HasArgument: true but only because that has not been built
15+
Preserve bool
816
}
917

1018
type ParsedCLIArgument struct {
19+
// The CLIArgument that was found and parsed
1120
Argument CLIArgument
12-
Value string
21+
22+
// The value associated with it if HasArgument:true. Otherwise an empty string.
23+
Value string
1324
}
1425

1526
// ParseArgs parses os.Args for use with kssh. This is handwritten rather than using go's flag library (or
@@ -19,6 +30,12 @@ type ParsedCLIArgument struct {
1930
//
2031
// Returns: a list of the remaining unparsed arguments, a list of the parsed arguments, error
2132
func ParseArgs(args []string, cliArguments []CLIArgument) ([]string, []ParsedCLIArgument, error) {
33+
for _, cliArg := range cliArguments {
34+
if cliArg.Preserve && cliArg.HasArgument {
35+
return nil, nil, fmt.Errorf("cannot specify Preserve and HasArgument for argument %s", cliArg.Name)
36+
}
37+
}
38+
2239
remainingArguments := []string{}
2340
found := []ParsedCLIArgument{}
2441
OUTER:
@@ -36,6 +53,9 @@ OUTER:
3653
i++
3754
}
3855
found = append(found, parsed)
56+
if cliArg.Preserve {
57+
remainingArguments = append(remainingArguments, arg)
58+
}
3959
continue OUTER
4060
}
4161
}

src/kssh/flags_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ func TestParseArgs(t *testing.T) {
1919
{Name: "--arg-with-value", HasArgument: true},
2020
{Name: "--arg2-with-value", HasArgument: true},
2121
{Name: "--arg-without-value", HasArgument: false},
22+
{Name: "--preserved-flag", Preserve: true},
2223
}
2324
testCases := []testCase{
2425
// No arguments
@@ -71,6 +72,16 @@ func TestParseArgs(t *testing.T) {
7172
remaining: nil,
7273
found: nil,
7374
},
75+
// Preserve:true
76+
{
77+
args: []string{"--preserved-flag", "--arg-without-value", "unused"},
78+
err: nil,
79+
remaining: []string{"--preserved-flag", "unused"},
80+
found: []ParsedCLIArgument{
81+
{Argument: CLIArgument{Name: "--preserved-flag", HasArgument: false, Preserve: true}, Value: ""},
82+
{Argument: CLIArgument{Name: "--arg-without-value", HasArgument: false}, Value: ""},
83+
},
84+
},
7485
}
7586

7687
for i, testCase := range testCases {

src/kssh/log.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package kssh
2+
3+
import log "github.com/sirupsen/logrus"
4+
5+
// Prefix formatter adds a prefix of "kssh: " to log messages before delegating to the default text formatter
6+
type prefixFormatter struct{}
7+
8+
func (pf *prefixFormatter) Format(entry *log.Entry) ([]byte, error) {
9+
entry.Message = "kssh: " + entry.Message
10+
textFormatter := &log.TextFormatter{}
11+
return textFormatter.Format(entry)
12+
}
13+
14+
func InitLogging() {
15+
log.SetLevel(log.WarnLevel)
16+
log.SetFormatter(&prefixFormatter{})
17+
}

src/kssh/ssh.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func AddKeyToSSHAgent(keyPath string) error {
2222
var AlternateSSHConfigFile = shared.ExpandPathWithTilde("~/.ssh/kssh-config")
2323

2424
// Create an SSH config file that inherits from the default SSH config file but sets a default SSH user
25-
func CreateDefaultUserConfigFile() error {
25+
func CreateDefaultUserConfigFile(keyPath string) error {
2626
user, err := GetDefaultSSHUser()
2727
if err != nil {
2828
return err
@@ -44,10 +44,13 @@ func CreateDefaultUserConfigFile() error {
4444
f.Close()
4545
}
4646

47+
// This config file sets a default ssh user and a default ssh key. This ensures that kssh's signed key will be used.
4748
config := fmt.Sprintf("# kssh config file to set a default SSH user\n"+
4849
"Include config\n"+
4950
"Host *\n"+
50-
" User %s\n", user)
51+
" User %s\n"+
52+
" IdentityFile %s\n"+
53+
" IdentitiesOnly yes\n", user, keyPath)
5154

5255
f, err := os.OpenFile(AlternateSSHConfigFile, os.O_CREATE|os.O_WRONLY, 0644)
5356
if err != nil {
@@ -58,7 +61,6 @@ func CreateDefaultUserConfigFile() error {
5861
if err != nil {
5962
return err
6063
}
61-
fmt.Printf("Using default ssh user %s\n", user)
6264
return nil
6365
}
6466

0 commit comments

Comments
 (0)