19 Commits

Author SHA1 Message Date
9a0cf7bd8a Merge pull request 'v0.5.0' (#5) from develop into main
Reviewed-on: #5
2026-01-17 20:25:14 +05:00
b938b73cfd Update CHANGELOG.md with 0.5.0 release date 2026-01-17 20:15:43 +05:00
ce031be060 Update CHANGELOG.md with sudo login tracking and notification details 2026-01-15 00:31:44 +05:00
5e50bc179f Add sudo command login tracking and notification support 2026-01-15 00:28:11 +05:00
279f58b644 Update CHANGELOG.md with su login tracking and notification details 2026-01-14 23:27:52 +05:00
26365a519b Add su command login tracking and notification support 2026-01-14 23:25:16 +05:00
d1f307d2ad Update CHANGELOG.md with 0.5.0 changes: add local login tracking and notifications 2026-01-14 21:51:55 +05:00
ccf228242d Add TTY login tracking with notification support 2026-01-14 21:51:20 +05:00
5e12b1f6ab Refactor: Rename SSH alert keys for clarity and update relevant usages 2026-01-13 22:09:42 +05:00
67abcc0ef2 Refactor: Rename processLogin to process in SSH analyzer for consistency 2026-01-13 00:27:11 +05:00
5ad40cdf9b Refactor: Rename process to processLogin in SSH analyzer for clarity 2026-01-13 00:24:07 +05:00
374abcea80 Refactor: Consolidate sshProcessReturn into generic processReturn for improved reusability 2026-01-13 00:18:55 +05:00
4748630b04 Merge pull request 'v0.4.0' (#4) from develop into main
Reviewed-on: #4
2026-01-11 17:01:42 +05:00
a75df70922 Update CHANGELOG.md with release date for version 0.4.0 2026-01-11 16:50:56 +05:00
a84f1ccde6 Update CHANGELOG.md to document IP blocking fix during Docker container redirection 2026-01-11 16:49:58 +05:00
0d13f851dd Fixed a bug where IP blocking for containers did not work when Docker was enabled 2026-01-11 16:44:33 +05:00
bbaf0304c3 Merge pull request 'v0.3.0' (#3) from develop into main
Reviewed-on: #3
2026-01-04 17:09:39 +05:00
69157c90cb Merge pull request 'v0.2.0' (#2) from develop into main
Reviewed-on: #2
2025-11-29 16:12:03 +05:00
e76d2ae398 Merge pull request 'v0.1.0' (#1) from develop into main
Reviewed-on: #1
2025-11-08 17:34:06 +05:00
19 changed files with 616 additions and 44 deletions

View File

@@ -1,4 +1,28 @@
## 0.4.0 (soon)
## 0.5.0 (17.1.2026)
***
#### Русский
* В настройках analyzer.toml добавил параметры local_enable и local_notify.
* local_enable = Включает отслеживание локальных авторизаций (TTY, физический доступ). По умолчанию включён.
* local_notify = Включает уведомления о локальных авторизациях. По умолчанию включён.
* В настройках analyzer.toml добавил параметры su_enable и su_notify.
* su_enable = Включает отслеживание авторизаций через su. По умолчанию включён.
* su_notify = Включает уведомления об авторизациях через su. По умолчанию включён.
* В настройках analyzer.toml добавил параметры sudo_enable и sudo_notify.
* sudo_enable = Включает отслеживание авторизаций через sudo. По умолчанию выключен.
* sudo_notify = Включает уведомления об авторизациях через sudo. По умолчанию включён.
***
#### English
* Added local_enable and local_notify parameters to analyzer.toml settings.
* local_enable = Enables tracking of local logins (TTY, physical access). Enabled by default.
* local_notify = Enables notifications about local logins. Enabled by default.
* Added su_enable and su_notify parameters to analyzer.toml settings.
* su_enable = Enables tracking of logins via su. Enabled by default.
* su_notify = Enables notifications about logins via su. Enabled by default.
* Added sudo_enable and sudo_notify parameters to analyzer.toml settings.
* sudo_enable = Enables tracking of logins via sudo. Off by default.
* sudo_notify = Enables notifications about logins via sudo. Enabled by default.
***
## 0.4.0 (11.1.2026)
***
#### Русский
* Удалён параметр options.docker_support из файла firewall.toml. Настройки от Docker перенесены в файл docker.toml.
@@ -8,6 +32,7 @@
* Исправлена ошибка:
* Настройка binaryLocations.docker не работала.
* Программа аварийно завершалась после остановки Docker'а.
* Указанные в настройках IP-адреса не блокировались во время перенаправления в контейнер Docker.
***
#### English
* Removed the options.docker_support parameter from firewall.toml. Docker settings have been moved to the docker.toml file.
@@ -17,6 +42,7 @@
* Fixed error:
* The binaryLocations.docker setting did not work.
* The program crashed after Docker was stopped.
* The IP addresses specified in the settings were not blocked during redirection to the Docker container.
***
## 0.3.0 (4.1.2026)
***

View File

@@ -45,3 +45,66 @@ ssh_enable = true
# Default: true
###
ssh_notify = true
###
# Включает отслеживание локальных авторизаций (TTY, физический доступ).
# По умолчанию: true
# ***
# Enables tracking of local authorizations (TTY, physical access).
# Default: true
###
local_enable = true
###
# Включает уведомления о локальных авторизациях.
# По умолчанию: true
# ***
# Enables local authorization notifications.
# Default: true
###
local_notify = true
###
# Включает отслеживание, если кто-либо использует команду `su` для доступа к другой учетной записи.
# По умолчанию: true
# ***
# Enables tracking if someone uses the `su` command to access another account.
# Default: true
###
su_enable = true
###
# Включает уведомления, если кто-либо использует команду `su` для доступа к другой учетной записи.
# По умолчанию: true
# ***
# Enables notifications if someone uses the `su` command to access another account.
# Default: true
###
su_notify = true
###
# Включает отслеживание, если кто-либо использует команду `sudo` для доступа к другой учетной записи.
#
# ПРИМЕЧАНИЕ: Эта опция может стать обременительной, если команда sudo широко используется
# для получения root-доступа администраторами или панелями управления.
#
# По умолчанию: false
# ***
# Enables tracking if someone uses the `sudo` command to access another account.
#
# NOTE: This option could become onerous if sudo is used extensively for root
# access by administrators or control panels.
#
# Default: false
###
sudo_enable = false
###
# Включает уведомления, если кто-либо использует команду `sudo` для доступа к другой учетной записи.
# По умолчанию: true
# ***
# Enables notifications if someone uses the `sudo` command to access another account.
# Default: true
###
sudo_notify = true

View File

@@ -28,8 +28,23 @@ type analyzer struct {
func New(config config2.Config, logger log.Logger, notify notifications.Notifications) Analyzer {
var units []string
if config.Login.Enabled && config.Login.SSH.Enabled {
units = append(units, "ssh")
if config.Login.Enabled {
if config.Login.SSH.Enabled {
units = append(units, "_SYSTEMD_UNIT=ssh.service")
}
if config.Login.Local.Enabled {
units = append(units, "SYSLOG_IDENTIFIER=login")
}
if config.Login.Su.Enabled {
units = append(units, "SYSLOG_IDENTIFIER=su")
}
if config.Login.Sudo.Enabled {
units = append(units, "SYSLOG_IDENTIFIER=sudo")
}
}
systemdService := analyzerLog.NewSystemd(config.BinPath.Journalctl, units, logger)
@@ -63,14 +78,26 @@ func (a *analyzer) processLogs(ctx context.Context) {
return
}
a.logger.Debug(fmt.Sprintf("Received log entry: %s", entry))
switch entry.Unit {
case "ssh.service":
switch {
case entry.Unit == "ssh.service":
if err := a.analysis.SSH(&entry); err != nil {
a.logger.Error(fmt.Sprintf("Failed to analyze SSH logs: %s", err))
}
break
case entry.SyslogIdentifier == "login":
if err := a.analysis.Locale(&entry); err != nil {
a.logger.Error(fmt.Sprintf("Failed to analyze locale logs: %s", err))
}
case entry.SyslogIdentifier == "sudo":
if err := a.analysis.Sudo(&entry); err != nil {
a.logger.Error(fmt.Sprintf("Failed to analyze sudo logs: %s", err))
}
case entry.SyslogIdentifier == "su":
if err := a.analysis.Su(&entry); err != nil {
a.logger.Error(fmt.Sprintf("Failed to analyze su logs: %s", err))
}
default:
a.logger.Warn(fmt.Sprintf("Unknown unit: %s", entry.Unit))
a.logger.Debug(fmt.Sprintf("Unknown unit or SyslogIdentifier: %s", entry.Unit))
}
}
}

View File

@@ -4,9 +4,27 @@ type Login struct {
Enabled bool
Notify bool
SSH LoginSSH
Local LoginLocal
Su LoginSu
Sudo LoginSudo
}
type LoginSSH struct {
Enabled bool
Notify bool
}
type LoginLocal struct {
Enabled bool
Notify bool
}
type LoginSu struct {
Enabled bool
Notify bool
}
type LoginSudo struct {
Enabled bool
Notify bool
}

View File

@@ -9,10 +9,16 @@ import (
type Analysis interface {
SSH(entry *analysisServices.Entry) error
Locale(entry *analysisServices.Entry) error
Su(entry *analysisServices.Entry) error
Sudo(entry *analysisServices.Entry) error
}
type analysis struct {
sshService analysisServices.Analysis
sshService analysisServices.Analysis
localeService analysisServices.Analysis
suService analysisServices.Analysis
sudoService analysisServices.Analysis
logger log.Logger
notify notifications.Notifications
@@ -20,12 +26,27 @@ type analysis struct {
func NewAnalysis(config *config.Config, logger log.Logger, notify notifications.Notifications) Analysis {
return &analysis{
sshService: analysisServices.NewSSH(config, logger, notify),
logger: logger,
notify: notify,
sshService: analysisServices.NewSSH(config, logger, notify),
localeService: analysisServices.NewLocale(config, logger, notify),
suService: analysisServices.NewSu(config, logger, notify),
sudoService: analysisServices.NewSudo(config, logger, notify),
logger: logger,
notify: notify,
}
}
func (a *analysis) SSH(entry *analysisServices.Entry) error {
return a.sshService.Process(entry)
}
func (a *analysis) Locale(entry *analysisServices.Entry) error {
return a.localeService.Process(entry)
}
func (a *analysis) Su(entry *analysisServices.Entry) error {
return a.suService.Process(entry)
}
func (a *analysis) Sudo(entry *analysisServices.Entry) error {
return a.sudoService.Process(entry)
}

View File

@@ -9,10 +9,17 @@ type Analysis interface {
}
type Entry struct {
Message string
Unit string
PID string
Time time.Time
Message string
Unit string
PID string
SyslogIdentifier string
Time time.Time
}
type processReturn struct {
found bool
subject string
body string
}
type EmptyAnalysis struct{}

View File

@@ -0,0 +1,78 @@
package analysis
import (
"fmt"
"regexp"
"git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/daemon/analyzer/config"
"git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/daemon/notifications"
"git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/i18n"
"git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/log"
)
type locale struct {
login localeLogin
logger log.Logger
notify notifications.Notifications
}
type localeLogin struct {
enabled bool
notify bool
}
func NewLocale(config *config.Config, logger log.Logger, notify notifications.Notifications) Analysis {
if !config.Login.Enabled || !config.Login.Local.Enabled {
return &EmptyAnalysis{}
}
return &locale{
login: localeLogin{
enabled: config.Login.Enabled && config.Login.SSH.Enabled,
notify: config.Login.Notify && config.Login.SSH.Notify,
},
logger: logger,
notify: notify,
}
}
func (l *locale) Process(entry *Entry) error {
if l.login.enabled {
result, err := l.login.process(entry)
if err != nil {
l.logger.Error(fmt.Sprintf("Failed to process TTY login: %s", err))
} else if result.found {
if l.login.notify {
l.notify.SendAsync(notifications.Message{Subject: result.subject, Body: result.body})
}
l.logger.Info(fmt.Sprintf("TTY login detected: %s", entry.Message))
}
}
return nil
}
func (l *localeLogin) process(entry *Entry) (processReturn, error) {
re := regexp.MustCompile(`^pam_unix\(login:session\): session opened for user (\S+)\(\S+\) by \S+`)
matches := re.FindStringSubmatch(entry.Message)
if matches != nil {
user := matches[1]
return processReturn{
found: true,
subject: i18n.Lang.T("alert.login.locale.subject", map[string]any{
"User": user,
}),
body: i18n.Lang.T("alert.login.locale.body", map[string]any{
"User": user,
"Log": entry.Message,
"Time": entry.Time,
}),
}, nil
}
return processReturn{found: false}, nil
}

View File

@@ -22,12 +22,6 @@ type sshLogin struct {
notify bool
}
type sshProcessReturn struct {
found bool
subject string
body string
}
func NewSSH(config *config.Config, logger log.Logger, notify notifications.Notifications) Analysis {
if !config.Login.Enabled || !config.Login.SSH.Enabled {
return &EmptyAnalysis{}
@@ -60,7 +54,7 @@ func (s *ssh) Process(entry *Entry) error {
return nil
}
func (l *sshLogin) process(entry *Entry) (sshProcessReturn, error) {
func (l *sshLogin) process(entry *Entry) (processReturn, error) {
re := regexp.MustCompile(`^Accepted (\S+) for (\S+) from (\S+) port \S+`)
matches := re.FindStringSubmatch(entry.Message)
@@ -68,13 +62,13 @@ func (l *sshLogin) process(entry *Entry) (sshProcessReturn, error) {
user := matches[2]
ip := matches[3]
return sshProcessReturn{
return processReturn{
found: true,
subject: i18n.Lang.T("alert.login.subject", map[string]any{
subject: i18n.Lang.T("alert.login.ssh.subject", map[string]any{
"User": user,
"IP": ip,
}),
body: i18n.Lang.T("alert.login.body", map[string]any{
body: i18n.Lang.T("alert.login.ssh.body", map[string]any{
"User": user,
"IP": ip,
"Log": entry.Message,
@@ -83,5 +77,5 @@ func (l *sshLogin) process(entry *Entry) (sshProcessReturn, error) {
}, nil
}
return sshProcessReturn{found: false}, nil
return processReturn{found: false}, nil
}

View File

@@ -0,0 +1,81 @@
package analysis
import (
"fmt"
"regexp"
"git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/daemon/analyzer/config"
"git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/daemon/notifications"
"git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/i18n"
"git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/log"
)
type su struct {
login suLogin
logger log.Logger
notify notifications.Notifications
}
type suLogin struct {
enabled bool
notify bool
}
func NewSu(config *config.Config, logger log.Logger, notify notifications.Notifications) Analysis {
if !config.Login.Enabled || !config.Login.Su.Enabled {
return &EmptyAnalysis{}
}
return &su{
login: suLogin{
enabled: config.Login.Enabled && config.Login.Su.Enabled,
notify: config.Login.Notify && config.Login.Su.Notify,
},
logger: logger,
notify: notify,
}
}
func (l *su) Process(entry *Entry) error {
if l.login.enabled {
result, err := l.login.process(entry)
if err != nil {
l.logger.Error(fmt.Sprintf("Failed to process Su login: %s", err))
} else if result.found {
if l.login.notify {
l.notify.SendAsync(notifications.Message{Subject: result.subject, Body: result.body})
}
l.logger.Info(fmt.Sprintf("Su login detected: %s", entry.Message))
}
}
return nil
}
func (l *suLogin) process(entry *Entry) (processReturn, error) {
re := regexp.MustCompile(`^pam_unix\(su:session\): session opened for user (\S+)\(\S+\) by (\S+)\(\S+\)`)
matches := re.FindStringSubmatch(entry.Message)
if matches != nil {
user := matches[1]
byUser := matches[2]
return processReturn{
found: true,
subject: i18n.Lang.T("alert.login.su.subject", map[string]any{
"User": user,
"ByUser": byUser,
}),
body: i18n.Lang.T("alert.login.su.body", map[string]any{
"User": user,
"ByUser": byUser,
"Log": entry.Message,
"Time": entry.Time,
}),
}, nil
}
return processReturn{found: false}, nil
}

View File

@@ -0,0 +1,81 @@
package analysis
import (
"fmt"
"regexp"
"git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/daemon/analyzer/config"
"git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/daemon/notifications"
"git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/i18n"
"git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/log"
)
type sudo struct {
login sudoLogin
logger log.Logger
notify notifications.Notifications
}
type sudoLogin struct {
enabled bool
notify bool
}
func NewSudo(config *config.Config, logger log.Logger, notify notifications.Notifications) Analysis {
if !config.Login.Enabled || !config.Login.Su.Enabled {
return &EmptyAnalysis{}
}
return &sudo{
login: sudoLogin{
enabled: config.Login.Enabled && config.Login.Sudo.Enabled,
notify: config.Login.Notify && config.Login.Sudo.Notify,
},
logger: logger,
notify: notify,
}
}
func (s *sudo) Process(entry *Entry) error {
if s.login.enabled {
result, err := s.login.process(entry)
if err != nil {
s.logger.Error(fmt.Sprintf("Failed to process Sudo login: %s", err))
} else if result.found {
if s.login.notify {
s.notify.SendAsync(notifications.Message{Subject: result.subject, Body: result.body})
}
s.logger.Info(fmt.Sprintf("Sudo login detected: %s", entry.Message))
}
}
return nil
}
func (s *sudoLogin) process(entry *Entry) (processReturn, error) {
re := regexp.MustCompile(`^pam_unix\(sudo:session\): session opened for user (\S+)\(\S+\) by (\S+)\(\S+\)`)
matches := re.FindStringSubmatch(entry.Message)
if matches != nil {
user := matches[1]
byUser := matches[2]
return processReturn{
found: true,
subject: i18n.Lang.T("alert.login.sudo.subject", map[string]any{
"User": user,
"ByUser": byUser,
}),
body: i18n.Lang.T("alert.login.sudo.body", map[string]any{
"User": user,
"ByUser": byUser,
"Log": entry.Message,
"Time": entry.Time,
}),
}, nil
}
return processReturn{found: false}, nil
}

View File

@@ -32,6 +32,7 @@ type journalRawEntry struct {
Message string `json:"MESSAGE"`
Unit string `json:"_SYSTEMD_UNIT"`
PID string `json:"_PID"`
SyslogIdentifier string `json:"SYSLOG_IDENTIFIER"`
SourceTimestamp string `json:"_SOURCE_REALTIME_TIMESTAMP"`
RealtimeTimestamp string `json:"__REALTIME_TIMESTAMP"`
}
@@ -74,8 +75,11 @@ func (s *systemd) Run(ctx context.Context, logChan chan<- analysisServices.Entry
func (s *systemd) watch(ctx context.Context, logChan chan<- analysisServices.Entry) error {
args := []string{"-f", "-n", "0", "-o", "json"}
for _, unit := range s.units {
args = append(args, "-u", unit)
for index, unit := range s.units {
if index > 0 {
args = append(args, "+")
}
args = append(args, unit)
}
cmd := exec.CommandContext(ctx, s.path, args...)
@@ -115,10 +119,11 @@ func (s *systemd) watch(ctx context.Context, logChan chan<- analysisServices.Ent
}
logChan <- analysisServices.Entry{
Message: raw.Message,
Unit: raw.Unit,
PID: raw.PID,
Time: entryTime,
Message: raw.Message,
Unit: raw.Unit,
PID: raw.PID,
SyslogIdentifier: raw.SyslogIdentifier,
Time: entryTime,
}
}

View File

@@ -27,6 +27,9 @@ type Chains interface {
NewLocalOutput() error
LocalOutput() LocalOutput
NewLocalForward() error
LocalForward() LocalForward
ClearRules() error
NewNoneChain(chain string) (Chain, error)
@@ -39,8 +42,9 @@ type chains struct {
forward Forward
packetFilter PacketFilter
localInput LocalInput
localOutput LocalOutput
localInput LocalInput
localOutput LocalOutput
localForward LocalForward
family nftFamily.Type
table string
@@ -147,6 +151,19 @@ func (c *chains) LocalOutput() LocalOutput {
return c.localOutput
}
func (c *chains) NewLocalForward() error {
localForward, err := newLocalForward(c.nft, c.family, c.table)
if err != nil {
return err
}
c.localForward = localForward
return nil
}
func (c *chains) LocalForward() LocalForward {
return c.localForward
}
func (c *chains) ClearRules() error {
return clearRules(c.nft, c.family, c.table)
}

View File

@@ -0,0 +1,41 @@
package chain
import (
nft "git.kor-elf.net/kor-elf-shield/go-nftables-client"
nftChain "git.kor-elf.net/kor-elf-shield/go-nftables-client/chain"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/family"
)
type LocalForward interface {
AddRule(expr ...string) error
AddRuleIn(AddRuleFunc func(expr ...string) error) error
}
type localForward struct {
nft nft.NFT
family family.Type
table string
chain string
}
func newLocalForward(nft nft.NFT, family family.Type, table string) (LocalForward, error) {
chain := "local-forward"
if err := nft.Chain().Add(family, table, chain, nftChain.TypeNone); err != nil {
return nil, err
}
return &localForward{
nft: nft,
family: family,
table: table,
chain: chain,
}, nil
}
func (l *localForward) AddRule(expr ...string) error {
return l.nft.Rule().Add(l.family, l.table, l.chain, expr...)
}
func (l *localForward) AddRuleIn(AddRuleFunc func(expr ...string) error) error {
return AddRuleFunc("iifname != \"lo\" counter jump " + l.chain)
}

View File

@@ -8,6 +8,10 @@ func (f *firewall) reloadForward() error {
}
chain := f.chains.Forward()
if err := f.reloadForwardAddIPs(); err != nil {
return err
}
if f.config.Options.DockerSupport {
if err := f.docker.NftChains().ForwardFilterJump(chain.AddRule); err != nil {
return err
@@ -23,3 +27,53 @@ func (f *firewall) reloadForward() error {
return nil
}
func (f *firewall) reloadForwardAddIPs() error {
if err := f.chains.NewLocalForward(); err != nil {
return err
}
chain := f.chains.LocalForward()
if err := chain.AddRuleIn(f.chains.Forward().AddRule); err != nil {
return err
}
for _, ipConfig := range f.config.IP4.InIPs {
if ipConfig.Action != ActionDrop && ipConfig.Action != ActionReject {
continue
}
if err := forwardAddIP(chain.AddRule, ipConfig, "ip"); err != nil {
return err
}
}
if !f.config.IP6.Enable {
return nil
}
for _, ipConfig := range f.config.IP6.InIPs {
if ipConfig.Action != ActionDrop && ipConfig.Action != ActionReject {
continue
}
if err := forwardAddIP(chain.AddRule, ipConfig, "ip6"); err != nil {
return err
}
}
return nil
}
func forwardAddIP(addRuleFunc func(expr ...string) error, config ConfigIP, ipMatch string) error {
rule := ipMatch + " saddr " + config.IP + " iifname != \"lo\""
// There, during routing, the port changes and then the IP blocking rule will not work.
//if !config.OnlyIP {
// rule += " " + config.Protocol.String() + " dport " + strconv.Itoa(int(config.Port))
//}
rule += " counter " + config.Action.String()
if err := addRuleFunc(rule); err != nil {
return err
}
return nil
}

View File

@@ -27,6 +27,15 @@
"daemon is not running": "Daemon is not running",
"daemon is not reopening logger": "The daemon did not reopen the log",
"alert.login.subject": "SSH login alert for user {{.User}} from {{.IP}}",
"alert.login.body": "Logged into the OS via ssh:\n Time: {{.Time}}\n IP: {{.IP}}\n User: {{.User}}\n Log: {{.Log}}"
"alert.login.ssh.subject": "SSH login alert for user {{.User}} from {{.IP}}",
"alert.login.ssh.body": "Logged into the OS via ssh:\n Time: {{.Time}}\n IP: {{.IP}}\n User: {{.User}}\n Log: {{.Log}}",
"alert.login.locale.subject": "Login message for user {{.User}} (TTY)",
"alert.login.locale.body": "Logged into the OS via TTY:\n Time: {{.Time}}\n User: {{.User}}\n Log: {{.Log}}",
"alert.login.su.subject": "User {{.ByUser}} has accessed user {{.User}} via su",
"alert.login.su.body": "User {{.ByUser}} accessed user {{.User}} via su.\nTime: {{.Time}}\nLog: {{.Log}}",
"alert.login.sudo.subject": "User {{.ByUser}} has accessed user {{.User}} via sudo",
"alert.login.sudo.body": "User {{.ByUser}} accessed user {{.User}} via sudo.\nTime: {{.Time}}\nLog: {{.Log}}"
}

View File

@@ -27,6 +27,15 @@
"daemon is not running": "Демон жұмыс істемейді",
"daemon is not reopening logger": "Жын журналды қайта ашпады",
"alert.login.subject": "{{.IP}} IP мекенжайынан {{.User}} пайдаланушысына арналған SSH кіру хабарламасы",
"alert.login.body": "ОС-қа ssh арқылы кірді:\n Уақыт: {{.Time}}\n IP: {{.IP}}\n Пайдаланушы: {{.User}}\n Лог: {{.Log}}"
"alert.login.ssh.subject": "{{.IP}} IP мекенжайынан {{.User}} пайдаланушысына арналған SSH кіру хабарламасы",
"alert.login.ssh.body": "ОС-қа ssh арқылы кірді:\n Уақыт: {{.Time}}\n IP: {{.IP}}\n Пайдаланушы: {{.User}}\n Лог: {{.Log}}",
"alert.login.locale.subject": "{{.User}} пайдаланушысына арналған кіру хабарламасы (TTY)",
"alert.login.locale.body": "ОЖ-ға TTY арқылы кірдіңіз:\n Уақыт: {{.Time}}\n Пайдаланушы: {{.User}}\n Лог: {{.Log}}",
"alert.login.su.subject": "{{.ByUser}} пайдаланушысы {{.User}} пайдаланушысына su арқылы кіру мүмкіндігін алды",
"alert.login.su.body": "{{.ByUser}} пайдаланушысы {{.User}} пайдаланушысына su арқылы кірді.\nУақыты: {{.Time}}\nЛог: {{.Log}}",
"alert.login.sudo.subject": "{{.ByUser}} пайдаланушысы {{.User}} пайдаланушысына sudo арқылы кіру мүмкіндігін алды",
"alert.login.sudo.body": "{{.ByUser}} пайдаланушысы {{.User}} пайдаланушысына sudo арқылы кірді.\nУақыты: {{.Time}}\nЛог: {{.Log}}"
}

View File

@@ -27,6 +27,15 @@
"daemon is not running": "Демон не запущен",
"daemon is not reopening logger": "Демон не открыл журнал повторно",
"alert.login.subject": "SSH-сообщение о входе пользователя {{.User}} с IP-адреса {{.IP}}",
"alert.login.body": "Вошли в ОС через ssh:\n Время: {{.Time}}\n IP: {{.IP}}\n Пользователь: {{.User}}\n Лог: {{.Log}}"
"alert.login.ssh.subject": "SSH-сообщение о входе пользователя {{.User}} с IP-адреса {{.IP}}",
"alert.login.ssh.body": "Вошли в ОС через ssh:\n Время: {{.Time}}\n IP: {{.IP}}\n Пользователь: {{.User}}\n Лог: {{.Log}}",
"alert.login.locale.subject": "Сообщение о входе пользователя {{.User}} (TTY)",
"alert.login.locale.body": "Вошли в ОС через TTY:\n Время: {{.Time}}\n Пользователь: {{.User}}\n Лог: {{.Log}}",
"alert.login.su.subject": "Пользователь {{.ByUser}} получил доступ к пользователю {{.User}} через su",
"alert.login.su.body": "Пользователь {{.ByUser}} получил доступ к пользователю {{.User}} через su.\nВремя: {{.Time}}\nЛог: {{.Log}}",
"alert.login.sudo.subject": "Пользователь {{.ByUser}} получил доступ к пользователю {{.User}} через sudo",
"alert.login.sudo.body": "Пользователь {{.ByUser}} получил доступ к пользователю {{.User}} через sudo.\nВремя: {{.Time}}\nЛог: {{.Log}}"
}

View File

@@ -1,18 +1,38 @@
package analyzer
type Login struct {
Enabled bool `mapstructure:"enabled"`
Notify bool `mapstructure:"notify"`
Enabled bool `mapstructure:"enabled"`
Notify bool `mapstructure:"notify"`
SSHEnable bool `mapstructure:"ssh_enable"`
SSHNotify bool `mapstructure:"ssh_notify"`
LocalEnable bool `mapstructure:"local_enable"`
LocalNotify bool `mapstructure:"local_notify"`
SuEnable bool `mapstructure:"su_enable"`
SuNotify bool `mapstructure:"su_notify"`
SudoEnable bool `mapstructure:"sudo_enable"`
SudoNotify bool `mapstructure:"sudo_notify"`
}
func defaultLogin() Login {
return Login{
Enabled: true,
Notify: true,
Enabled: true,
Notify: true,
SSHEnable: true,
SSHNotify: true,
LocalEnable: true,
LocalNotify: true,
SuEnable: true,
SuNotify: true,
SudoEnable: false,
SudoNotify: true,
}
}

View File

@@ -157,6 +157,18 @@ func (o *otherSettingsPath) ToAnalyzerConfig(binaryLocations *binaryLocations) (
Enabled: setting.Login.SSHEnable,
Notify: setting.Login.SSHNotify,
},
Local: config.LoginLocal{
Enabled: setting.Login.LocalEnable,
Notify: setting.Login.LocalNotify,
},
Su: config.LoginSu{
Enabled: setting.Login.SuEnable,
Notify: setting.Login.SuNotify,
},
Sudo: config.LoginSudo{
Enabled: setting.Login.SudoEnable,
Notify: setting.Login.SudoNotify,
},
}
return config.Config{