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 { | ||||
| 	return initDBDisableConsole(false) | ||||
| } | ||||
| 
 | ||||
| func initDBDisableConsole(disableConsole bool) error { | ||||
| 	setting.NewContext() | ||||
| 	models.LoadConfigs() | ||||
| 
 | ||||
| 	setting.NewXORMLogService(false) | ||||
| 	setting.NewXORMLogService(disableConsole) | ||||
| 	if err := models.SetEngine(); err != nil { | ||||
| 		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 | ||||
| ; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'. | ||||
| 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 system SSH this setting has no effect | ||||
| 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 LFS_JWT_SECRET` | ||||
|             - `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/modules/log" | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 
 | ||||
| 	// register supported doc types
 | ||||
| 	_ "code.gitea.io/gitea/modules/markup/csv" | ||||
| 	_ "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.CmdGenerate, | ||||
| 		cmd.CmdMigrate, | ||||
| 		cmd.CmdKeys, | ||||
| 	} | ||||
| 	app.Flags = append(app.Flags, cmd.CmdWeb.Flags...) | ||||
| 	app.Action = cmd.CmdWeb.Action | ||||
|  |  | |||
|  | @ -558,7 +558,7 @@ func DeletePublicKey(doer *User, id int64) (err error) { | |||
| // outside any session scope independently.
 | ||||
| func RewriteAllPublicKeys() error { | ||||
| 	//Don't rewrite key if internal server
 | ||||
| 	if setting.SSH.StartBuiltinServer { | ||||
| 	if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedKeysFile { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -118,23 +118,24 @@ var ( | |||
| 	LetsEncryptEmail     string | ||||
| 
 | ||||
| 	SSH = struct { | ||||
| 		Disabled             bool           `ini:"DISABLE_SSH"` | ||||
| 		StartBuiltinServer   bool           `ini:"START_SSH_SERVER"` | ||||
| 		BuiltinServerUser    string         `ini:"BUILTIN_SSH_SERVER_USER"` | ||||
| 		Domain               string         `ini:"SSH_DOMAIN"` | ||||
| 		Port                 int            `ini:"SSH_PORT"` | ||||
| 		ListenHost           string         `ini:"SSH_LISTEN_HOST"` | ||||
| 		ListenPort           int            `ini:"SSH_LISTEN_PORT"` | ||||
| 		RootPath             string         `ini:"SSH_ROOT_PATH"` | ||||
| 		ServerCiphers        []string       `ini:"SSH_SERVER_CIPHERS"` | ||||
| 		ServerKeyExchanges   []string       `ini:"SSH_SERVER_KEY_EXCHANGES"` | ||||
| 		ServerMACs           []string       `ini:"SSH_SERVER_MACS"` | ||||
| 		KeyTestPath          string         `ini:"SSH_KEY_TEST_PATH"` | ||||
| 		KeygenPath           string         `ini:"SSH_KEYGEN_PATH"` | ||||
| 		AuthorizedKeysBackup bool           `ini:"SSH_AUTHORIZED_KEYS_BACKUP"` | ||||
| 		MinimumKeySizeCheck  bool           `ini:"-"` | ||||
| 		MinimumKeySizes      map[string]int `ini:"-"` | ||||
| 		ExposeAnonymous      bool           `ini:"SSH_EXPOSE_ANONYMOUS"` | ||||
| 		Disabled                 bool           `ini:"DISABLE_SSH"` | ||||
| 		StartBuiltinServer       bool           `ini:"START_SSH_SERVER"` | ||||
| 		BuiltinServerUser        string         `ini:"BUILTIN_SSH_SERVER_USER"` | ||||
| 		Domain                   string         `ini:"SSH_DOMAIN"` | ||||
| 		Port                     int            `ini:"SSH_PORT"` | ||||
| 		ListenHost               string         `ini:"SSH_LISTEN_HOST"` | ||||
| 		ListenPort               int            `ini:"SSH_LISTEN_PORT"` | ||||
| 		RootPath                 string         `ini:"SSH_ROOT_PATH"` | ||||
| 		ServerCiphers            []string       `ini:"SSH_SERVER_CIPHERS"` | ||||
| 		ServerKeyExchanges       []string       `ini:"SSH_SERVER_KEY_EXCHANGES"` | ||||
| 		ServerMACs               []string       `ini:"SSH_SERVER_MACS"` | ||||
| 		KeyTestPath              string         `ini:"SSH_KEY_TEST_PATH"` | ||||
| 		KeygenPath               string         `ini:"SSH_KEYGEN_PATH"` | ||||
| 		AuthorizedKeysBackup     bool           `ini:"SSH_AUTHORIZED_KEYS_BACKUP"` | ||||
| 		MinimumKeySizeCheck      bool           `ini:"-"` | ||||
| 		MinimumKeySizes          map[string]int `ini:"-"` | ||||
| 		CreateAuthorizedKeysFile bool           `ini:"SSH_CREATE_AUTHORIZED_KEYS_FILE"` | ||||
| 		ExposeAnonymous          bool           `ini:"SSH_EXPOSE_ANONYMOUS"` | ||||
| 	}{ | ||||
| 		Disabled:           false, | ||||
| 		StartBuiltinServer: false, | ||||
|  | @ -863,6 +864,7 @@ func NewContext() { | |||
| 		} | ||||
| 	} | ||||
| 	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) | ||||
| 
 | ||||
| 	sec = Cfg.Section("server") | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue