@@ -33,23 +33,25 @@ const sshEndToken = "# ------------END-CODER-ENTERPRISE------------"
33
33
34
34
func configSSHCmd ()* cobra.Command {
35
35
var (
36
- configpath string
37
- remove = false
36
+ configpath string
37
+ remove = false
38
+ additionalOptions []string
38
39
)
39
40
40
41
cmd := & cobra.Command {
41
42
Use :"config-ssh" ,
42
43
Short :"Configure SSH to access Coder workspaces" ,
43
44
Long :"Inject the proper OpenSSH configuration into your local SSH config file." ,
44
- RunE :configSSH (& configpath ,& remove ),
45
+ RunE :configSSH (& configpath ,& remove , & additionalOptions ),
45
46
}
46
47
cmd .Flags ().StringVar (& configpath ,"filepath" ,filepath .Join ("~" ,".ssh" ,"config" ),"override the default path of your ssh config file" )
48
+ cmd .Flags ().StringSliceVarP (& additionalOptions ,"option" ,"o" , []string {},"additional options injected in the ssh config (ex. disable caching with\" -o ControlPath=none\" )" )
47
49
cmd .Flags ().BoolVar (& remove ,"remove" ,false ,"remove the auto-generated Coder ssh config" )
48
50
49
51
return cmd
50
52
}
51
53
52
- func configSSH (configpath * string ,remove * bool )func (cmd * cobra.Command ,_ []string )error {
54
+ func configSSH (configpath * string ,remove * bool , additionalOptions * [] string )func (cmd * cobra.Command ,_ []string )error {
53
55
return func (cmd * cobra.Command ,_ []string )error {
54
56
ctx := cmd .Context ()
55
57
usr ,err := user .Current ()
@@ -118,7 +120,7 @@ func configSSH(configpath *string, remove *bool) func(cmd *cobra.Command, _ []st
118
120
return xerrors .Errorf ("Failed to get executable path: %w" ,err )
119
121
}
120
122
121
- newConfig := makeNewConfigs (binPath ,workspacesWithProviders ,privateKeyFilepath )
123
+ newConfig := makeNewConfigs (binPath ,workspacesWithProviders ,privateKeyFilepath , * additionalOptions )
122
124
123
125
err = os .MkdirAll (filepath .Dir (* configpath ),os .ModePerm )
124
126
if err != nil {
@@ -226,7 +228,7 @@ func writeSSHKey(ctx context.Context, client coder.Client, privateKeyPath string
226
228
return ioutil .WriteFile (privateKeyPath , []byte (key .PrivateKey ),0600 )
227
229
}
228
230
229
- func makeNewConfigs (binPath string ,workspaces []coderutil.WorkspaceWithWorkspaceProvider ,privateKeyFilepath string )string {
231
+ func makeNewConfigs (binPath string ,workspaces []coderutil.WorkspaceWithWorkspaceProvider ,privateKeyFilepath string , additionalOptions [] string )string {
230
232
newConfig := fmt .Sprintf ("\n %s\n %s\n \n " ,sshStartToken ,sshStartMessage )
231
233
232
234
sort .Slice (workspaces ,func (i ,j int )bool {return workspaces [i ].Workspace .Name < workspaces [j ].Workspace .Name })
@@ -240,32 +242,41 @@ func makeNewConfigs(binPath string, workspaces []coderutil.WorkspaceWithWorkspac
240
242
continue
241
243
}
242
244
243
- newConfig += makeSSHConfig (binPath ,workspace .Workspace .Name ,privateKeyFilepath )
245
+ newConfig += makeSSHConfig (binPath ,workspace .Workspace .Name ,privateKeyFilepath , additionalOptions )
244
246
}
245
247
newConfig += fmt .Sprintf ("\n %s\n " ,sshEndToken )
246
248
247
249
return newConfig
248
250
}
249
251
250
- func makeSSHConfig (binPath ,workspaceName ,privateKeyFilepath string )string {
251
- entry := fmt .Sprintf (
252
- `Host coder.%s
253
- HostName coder.%s
254
- ProxyCommand "%s" tunnel %s 12213 stdio
255
- StrictHostKeyChecking no
256
- ConnectTimeout=0
257
- IdentitiesOnly yes
258
- IdentityFile="%s"
259
- ` ,workspaceName ,workspaceName ,binPath ,workspaceName ,privateKeyFilepath )
252
+ func makeSSHConfig (binPath ,workspaceName ,privateKeyFilepath string ,additionalOptions []string )string {
253
+ // Custom user options come first to maximizessh customization.
254
+ options := []string {}
255
+ if len (additionalOptions )> 0 {
256
+ options = []string {
257
+ "# Custom options. Duplicated values will always prefer the first!" ,
258
+ }
259
+ options = append (options ,additionalOptions ... )
260
+ options = append (options ,"# End custom options." )
261
+ }
262
+ options = append (options ,
263
+ fmt .Sprintf ("HostName coder.%s" ,workspaceName ),
264
+ fmt .Sprintf ("ProxyCommand %q tunnel %s 12213 stdio" ,binPath ,workspaceName ),
265
+ "StrictHostKeyChecking no" ,
266
+ "ConnectTimeout=0" ,
267
+ "IdentitiesOnly yes" ,
268
+ fmt .Sprintf ("IdentityFile=%q" ,privateKeyFilepath ),
269
+ )
260
270
261
271
if runtime .GOOS == "linux" || runtime .GOOS == "darwin" {
262
- entry += ` ControlMaster auto
263
- ControlPath ~/.ssh/.connection-%r@%h:%p
264
- ControlPersist 600
265
- `
272
+ options = append (options ,
273
+ "ControlMaster auto" ,
274
+ "ControlPath ~/.ssh/.connection-%r@%h:%p" ,
275
+ "ControlPersist 600" ,
276
+ )
266
277
}
267
278
268
- return entry
279
+ return fmt . Sprintf ( "Host coder.%s \n \t %s \n \n " , workspaceName , strings . Join ( options , " \n \t " ))
269
280
}
270
281
271
282
func writeStr (filename ,data string )error {