From abb9cffe4a9b36c124b1ef8fad4a00eff4ba36de Mon Sep 17 00:00:00 2001 From: Eric Lesiuta Date: Tue, 8 Dec 2020 12:54:33 -0500 Subject: [PATCH] Log IP on SSH authentication failure for Built-in SSH server (#13150) * Log IP on SSH authentication failure fixes https://github.com/go-gitea/gitea/issues/13094 * include string 'Failed authentication attempt' in error * update fail2ban docs also match failed authentication over command line * better logging of authentication errors with IP addresses * format ... Co-authored-by: techknowlogick Co-authored-by: 6543 <6543@obermui.de> --- docs/content/doc/usage/fail2ban-setup.en-us.md | 10 ++++++++-- modules/ssh/ssh.go | 2 +- routers/private/serv.go | 2 ++ routers/repo/http.go | 1 + 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/content/doc/usage/fail2ban-setup.en-us.md b/docs/content/doc/usage/fail2ban-setup.en-us.md index ad99ca9e288..42b61416be5 100644 --- a/docs/content/doc/usage/fail2ban-setup.en-us.md +++ b/docs/content/doc/usage/fail2ban-setup.en-us.md @@ -20,18 +20,24 @@ sure to test this before relying on it so you don't lock yourself out.** Gitea returns an HTTP 200 for bad logins in the web logs, but if you have logging options on in `app.ini`, then you should be able to go off of `log/gitea.log`, which gives you something like this -on a bad authentication: +on a bad authentication from the web or CLI using SSH or HTTP respectively: ```log 2018/04/26 18:15:54 [I] Failed authentication attempt for user from xxx.xxx.xxx.xxx ``` +```log +2020/10/15 16:05:09 modules/ssh/ssh.go:188:publicKeyHandler() [E] SearchPublicKeyByContent: public key does not exist [id: 0] Failed authentication attempt from xxx.xxx.xxx.xxx +``` +```log +2020/10/15 16:08:44 ...s/context/context.go:204:HandleText() [E] invalid credentials from xxx.xxx.xxx.xxx +``` Add our filter in `/etc/fail2ban/filter.d/gitea.conf`: ```ini # gitea.conf [Definition] -failregex = .*Failed authentication attempt for .* from +failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from ignoreregex = ``` diff --git a/modules/ssh/ssh.go b/modules/ssh/ssh.go index 761164caa01..9bfa39ef42d 100644 --- a/modules/ssh/ssh.go +++ b/modules/ssh/ssh.go @@ -186,7 +186,7 @@ func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool { pkey, err := models.SearchPublicKeyByContent(strings.TrimSpace(string(gossh.MarshalAuthorizedKey(key)))) if err != nil { - log.Error("SearchPublicKeyByContent: %v", err) + log.Error("SearchPublicKeyByContent: %v Failed authentication attempt from %s", err, ctx.RemoteAddr()) return false } diff --git a/routers/private/serv.go b/routers/private/serv.go index 182fe272451..90e1d30b013 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -132,6 +132,7 @@ func ServCommand(ctx *macaron.Context) { for _, verb := range ctx.QueryStrings("verb") { if "git-upload-pack" == verb { // User is fetching/cloning a non-existent repository + log.Error("Failed authentication attempt (cannot find repository: %s/%s) from %s", results.OwnerName, results.RepoName, ctx.RemoteAddr()) ctx.JSON(http.StatusNotFound, map[string]interface{}{ "results": results, "type": "ErrRepoNotExist", @@ -317,6 +318,7 @@ func ServCommand(ctx *macaron.Context) { userMode := perm.UnitAccessMode(unitType) if userMode < mode { + log.Error("Failed authentication attempt for %s with key %s (not authorized to %s %s/%s) from %s", user.Name, key.Name, modeString, ownerName, repoName, ctx.RemoteAddr()) ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ "results": results, "type": "ErrUnauthorized", diff --git a/routers/repo/http.go b/routers/repo/http.go index 40c1f36bc33..d4464ec62e4 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -102,6 +102,7 @@ func HTTP(ctx *context.Context) { owner, err := models.GetUserByName(username) if err != nil { + log.Error("Attempted access of unknown user from %s", ctx.RemoteAddr()) ctx.NotFoundOrServerError("GetUserByName", models.IsErrUserNotExist, err) return }