Create AuthorizedKeysCommand (#5236)
This commit is contained in:
		
							parent
							
								
									00533d3870
								
							
						
					
					
						commit
						7d9a191a3c
					
				
					 7 changed files with 136 additions and 19 deletions
				
			
		|  | @ -27,10 +27,14 @@ func argsSet(c *cli.Context, args ...string) error { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func initDB() error { | func initDB() error { | ||||||
|  | 	return initDBDisableConsole(false) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func initDBDisableConsole(disableConsole bool) error { | ||||||
| 	setting.NewContext() | 	setting.NewContext() | ||||||
| 	models.LoadConfigs() | 	models.LoadConfigs() | ||||||
| 
 | 
 | ||||||
| 	setting.NewXORMLogService(false) | 	setting.NewXORMLogService(disableConsole) | ||||||
| 	if err := models.SetEngine(); err != nil { | 	if err := models.SetEngine(); err != nil { | ||||||
| 		return fmt.Errorf("models.SetEngine: %v", err) | 		return fmt.Errorf("models.SetEngine: %v", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
							
								
								
									
										85
									
								
								cmd/keys.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								cmd/keys.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,85 @@ | ||||||
|  | // Copyright 2018 The Gitea Authors. All rights reserved.
 | ||||||
|  | // Use of this source code is governed by a MIT-style
 | ||||||
|  | // license that can be found in the LICENSE file.
 | ||||||
|  | 
 | ||||||
|  | package cmd | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  | 
 | ||||||
|  | 	"code.gitea.io/gitea/models" | ||||||
|  | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  | 
 | ||||||
|  | 	"github.com/urfave/cli" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // CmdKeys represents the available keys sub-command
 | ||||||
|  | var CmdKeys = cli.Command{ | ||||||
|  | 	Name:   "keys", | ||||||
|  | 	Usage:  "This command queries the Gitea database to get the authorized command for a given ssh key fingerprint", | ||||||
|  | 	Action: runKeys, | ||||||
|  | 	Flags: []cli.Flag{ | ||||||
|  | 		cli.StringFlag{ | ||||||
|  | 			Name:  "expected, e", | ||||||
|  | 			Value: "git", | ||||||
|  | 			Usage: "Expected user for whom provide key commands", | ||||||
|  | 		}, | ||||||
|  | 		cli.StringFlag{ | ||||||
|  | 			Name:  "username, u", | ||||||
|  | 			Value: "", | ||||||
|  | 			Usage: "Username trying to log in by SSH", | ||||||
|  | 		}, | ||||||
|  | 		cli.StringFlag{ | ||||||
|  | 			Name:  "type, t", | ||||||
|  | 			Value: "", | ||||||
|  | 			Usage: "Type of the SSH key provided to the SSH Server (requires content to be provided too)", | ||||||
|  | 		}, | ||||||
|  | 		cli.StringFlag{ | ||||||
|  | 			Name:  "content, k", | ||||||
|  | 			Value: "", | ||||||
|  | 			Usage: "Base64 encoded content of the SSH key provided to the SSH Server (requires type to be provided too)", | ||||||
|  | 		}, | ||||||
|  | 		cli.StringFlag{ | ||||||
|  | 			Name:  "config, c", | ||||||
|  | 			Value: "custom/conf/app.ini", | ||||||
|  | 			Usage: "Custom configuration file path", | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func runKeys(c *cli.Context) error { | ||||||
|  | 	if c.IsSet("config") { | ||||||
|  | 		setting.CustomConf = c.String("config") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !c.IsSet("username") { | ||||||
|  | 		return errors.New("No username provided") | ||||||
|  | 	} | ||||||
|  | 	// Check username matches the expected username
 | ||||||
|  | 	if strings.TrimSpace(c.String("username")) != strings.TrimSpace(c.String("expected")) { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	content := "" | ||||||
|  | 
 | ||||||
|  | 	if c.IsSet("type") && c.IsSet("content") { | ||||||
|  | 		content = fmt.Sprintf("%s %s", strings.TrimSpace(c.String("type")), strings.TrimSpace(c.String("content"))) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if content == "" { | ||||||
|  | 		return errors.New("No key type and content provided") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := initDBDisableConsole(true); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	publicKey, err := models.SearchPublicKeyByContent(content) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	fmt.Println(publicKey.AuthorizedString()) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | @ -154,6 +154,9 @@ SSH_PORT = 22 | ||||||
| SSH_LISTEN_PORT = %(SSH_PORT)s | SSH_LISTEN_PORT = %(SSH_PORT)s | ||||||
| ; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'. | ; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'. | ||||||
| SSH_ROOT_PATH = | SSH_ROOT_PATH = | ||||||
|  | ; Gitea will create a authorized_keys file by default when it is not using the internal ssh server | ||||||
|  | ; If you intend to use the AuthorizedKeysCommand functionality then you should turn this off. | ||||||
|  | SSH_CREATE_AUTHORIZED_KEYS_FILE = true | ||||||
| ; For the built-in SSH server, choose the ciphers to support for SSH connections, | ; For the built-in SSH server, choose the ciphers to support for SSH connections, | ||||||
| ; for system SSH this setting has no effect | ; for system SSH this setting has no effect | ||||||
| SSH_SERVER_CIPHERS = aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, arcfour256, arcfour128 | SSH_SERVER_CIPHERS = aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, arcfour256, arcfour128 | ||||||
|  |  | ||||||
|  | @ -163,3 +163,24 @@ for automatic deployments. | ||||||
|             - `gitea generate secret INTERNAL_TOKEN` |             - `gitea generate secret INTERNAL_TOKEN` | ||||||
|             - `gitea generate secret LFS_JWT_SECRET` |             - `gitea generate secret LFS_JWT_SECRET` | ||||||
|             - `gitea generate secret SECRET_KEY` |             - `gitea generate secret SECRET_KEY` | ||||||
|  | 
 | ||||||
|  | #### keys | ||||||
|  | 
 | ||||||
|  | Provides an SSHD AuthorizedKeysCommand. Needs to be configured in the sshd config file: | ||||||
|  | 
 | ||||||
|  | ```ini | ||||||
|  | ... | ||||||
|  | # The value of -e and the AuthorizedKeysCommandUser should match the | ||||||
|  | # username running gitea | ||||||
|  | AuthorizedKeysCommandUser git | ||||||
|  | AuthorizedKeysCommand /path/to/gitea keys -e git -u %u -t %t -k %k | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The command will return the appropriate authorized_keys line for the | ||||||
|  | provided key. You should also set the value | ||||||
|  | `SSH_CREATE_AUTHORIZED_KEYS_FILE=false` in the `[server]` section of | ||||||
|  | `app.ini`. | ||||||
|  | 
 | ||||||
|  | NB: opensshd requires the gitea program to be owned by root and not | ||||||
|  | writable by group or others. The program must be specified by an absolute | ||||||
|  | path. | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								main.go
									
									
									
									
									
								
							|  | @ -13,6 +13,7 @@ import ( | ||||||
| 	"code.gitea.io/gitea/cmd" | 	"code.gitea.io/gitea/cmd" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  | 
 | ||||||
| 	// register supported doc types
 | 	// register supported doc types
 | ||||||
| 	_ "code.gitea.io/gitea/modules/markup/csv" | 	_ "code.gitea.io/gitea/modules/markup/csv" | ||||||
| 	_ "code.gitea.io/gitea/modules/markup/markdown" | 	_ "code.gitea.io/gitea/modules/markup/markdown" | ||||||
|  | @ -48,6 +49,7 @@ arguments - which can alternatively be run by running the subcommand web.` | ||||||
| 		cmd.CmdAdmin, | 		cmd.CmdAdmin, | ||||||
| 		cmd.CmdGenerate, | 		cmd.CmdGenerate, | ||||||
| 		cmd.CmdMigrate, | 		cmd.CmdMigrate, | ||||||
|  | 		cmd.CmdKeys, | ||||||
| 	} | 	} | ||||||
| 	app.Flags = append(app.Flags, cmd.CmdWeb.Flags...) | 	app.Flags = append(app.Flags, cmd.CmdWeb.Flags...) | ||||||
| 	app.Action = cmd.CmdWeb.Action | 	app.Action = cmd.CmdWeb.Action | ||||||
|  |  | ||||||
|  | @ -558,7 +558,7 @@ func DeletePublicKey(doer *User, id int64) (err error) { | ||||||
| // outside any session scope independently.
 | // outside any session scope independently.
 | ||||||
| func RewriteAllPublicKeys() error { | func RewriteAllPublicKeys() error { | ||||||
| 	//Don't rewrite key if internal server
 | 	//Don't rewrite key if internal server
 | ||||||
| 	if setting.SSH.StartBuiltinServer { | 	if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedKeysFile { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -118,23 +118,24 @@ var ( | ||||||
| 	LetsEncryptEmail     string | 	LetsEncryptEmail     string | ||||||
| 
 | 
 | ||||||
| 	SSH = struct { | 	SSH = struct { | ||||||
| 		Disabled             bool           `ini:"DISABLE_SSH"` | 		Disabled                 bool           `ini:"DISABLE_SSH"` | ||||||
| 		StartBuiltinServer   bool           `ini:"START_SSH_SERVER"` | 		StartBuiltinServer       bool           `ini:"START_SSH_SERVER"` | ||||||
| 		BuiltinServerUser    string         `ini:"BUILTIN_SSH_SERVER_USER"` | 		BuiltinServerUser        string         `ini:"BUILTIN_SSH_SERVER_USER"` | ||||||
| 		Domain               string         `ini:"SSH_DOMAIN"` | 		Domain                   string         `ini:"SSH_DOMAIN"` | ||||||
| 		Port                 int            `ini:"SSH_PORT"` | 		Port                     int            `ini:"SSH_PORT"` | ||||||
| 		ListenHost           string         `ini:"SSH_LISTEN_HOST"` | 		ListenHost               string         `ini:"SSH_LISTEN_HOST"` | ||||||
| 		ListenPort           int            `ini:"SSH_LISTEN_PORT"` | 		ListenPort               int            `ini:"SSH_LISTEN_PORT"` | ||||||
| 		RootPath             string         `ini:"SSH_ROOT_PATH"` | 		RootPath                 string         `ini:"SSH_ROOT_PATH"` | ||||||
| 		ServerCiphers        []string       `ini:"SSH_SERVER_CIPHERS"` | 		ServerCiphers            []string       `ini:"SSH_SERVER_CIPHERS"` | ||||||
| 		ServerKeyExchanges   []string       `ini:"SSH_SERVER_KEY_EXCHANGES"` | 		ServerKeyExchanges       []string       `ini:"SSH_SERVER_KEY_EXCHANGES"` | ||||||
| 		ServerMACs           []string       `ini:"SSH_SERVER_MACS"` | 		ServerMACs               []string       `ini:"SSH_SERVER_MACS"` | ||||||
| 		KeyTestPath          string         `ini:"SSH_KEY_TEST_PATH"` | 		KeyTestPath              string         `ini:"SSH_KEY_TEST_PATH"` | ||||||
| 		KeygenPath           string         `ini:"SSH_KEYGEN_PATH"` | 		KeygenPath               string         `ini:"SSH_KEYGEN_PATH"` | ||||||
| 		AuthorizedKeysBackup bool           `ini:"SSH_AUTHORIZED_KEYS_BACKUP"` | 		AuthorizedKeysBackup     bool           `ini:"SSH_AUTHORIZED_KEYS_BACKUP"` | ||||||
| 		MinimumKeySizeCheck  bool           `ini:"-"` | 		MinimumKeySizeCheck      bool           `ini:"-"` | ||||||
| 		MinimumKeySizes      map[string]int `ini:"-"` | 		MinimumKeySizes          map[string]int `ini:"-"` | ||||||
| 		ExposeAnonymous      bool           `ini:"SSH_EXPOSE_ANONYMOUS"` | 		CreateAuthorizedKeysFile bool           `ini:"SSH_CREATE_AUTHORIZED_KEYS_FILE"` | ||||||
|  | 		ExposeAnonymous          bool           `ini:"SSH_EXPOSE_ANONYMOUS"` | ||||||
| 	}{ | 	}{ | ||||||
| 		Disabled:           false, | 		Disabled:           false, | ||||||
| 		StartBuiltinServer: false, | 		StartBuiltinServer: false, | ||||||
|  | @ -863,6 +864,7 @@ func NewContext() { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	SSH.AuthorizedKeysBackup = sec.Key("SSH_AUTHORIZED_KEYS_BACKUP").MustBool(true) | 	SSH.AuthorizedKeysBackup = sec.Key("SSH_AUTHORIZED_KEYS_BACKUP").MustBool(true) | ||||||
|  | 	SSH.CreateAuthorizedKeysFile = sec.Key("SSH_CREATE_AUTHORIZED_KEYS_FILE").MustBool(true) | ||||||
| 	SSH.ExposeAnonymous = sec.Key("SSH_EXPOSE_ANONYMOUS").MustBool(false) | 	SSH.ExposeAnonymous = sec.Key("SSH_EXPOSE_ANONYMOUS").MustBool(false) | ||||||
| 
 | 
 | ||||||
| 	sec = Cfg.Section("server") | 	sec = Cfg.Section("server") | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue