Skip to content

Commit

Permalink
Merge pull request #100 from sebadob/generate-events
Browse files Browse the repository at this point in the history
Generate events
  • Loading branch information
sebadob committed Oct 26, 2023
2 parents d69845e + dced870 commit 797dad5
Show file tree
Hide file tree
Showing 40 changed files with 1,103 additions and 268 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ css-color = "0.2"
derive_more = "0.99"
dotenvy = "0.15"
flume = "0.11"
gethostname = "0.4"
jwt-simple = "0.11"
lazy_static = "1"
num_cpus = "1"
Expand Down
31 changes: 4 additions & 27 deletions dev_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,12 @@

## CURRENT WORK

- JWK auto-rotate scheduler

## TODO v0.17

The 0.17 release will be mostly about auditing and events, for instance things like "3 invalid login attempts from IP XY"

### events

task 'NATS events stream or maybe internal one' from the stage 2 todo

- implement base foundation for sending events internally and just log them to console in first version
- add the configurable option to persist events
- create a new events section in the admin ui to watch for new ones and
start with simple polling every few seconds first because of the HA_MODE problematic with SSE
- implement an SSE endpoint for listening to events in real time
- for SI deployments with SQLite, this is a no-brainer -> just copy each event to the corresponding tx
- for HA deployments:
- research sqlx + postgres + CDC to avoid additional deployment needs (or maybe just listen / notify? KISS?)
- if postgres does not work out nicely, think about using a NATS deployment for this task
- switch the UI component to the SSE stream
- add some way of configuring an email (or webhook, slack, ... ?) which gets messages depending on configured event level


### other features (some may come with v0.18 depending on amount of work)

- impl ApiKeyEntity in enc keys migrations
- add a way of detecting brute force or DoS attempts from certain IPs
- add an 'ip blacklist' feature
- add 'alg' in well-known jwks
- create an optional config to auto-blacklist IPs that have been detected doing brute force or DoS
think about the bigger picture here, maybe do this in 2 stages, like short block after 5 bad logins, 24h block after 10, ...
- add a mechanism to detect DoS attempts
- admin ui component for the new ApiKeys
- admin ui component to show blacklisted IPs
- maybe functionality to manually blacklist IPs?

Expand Down
77 changes: 77 additions & 0 deletions docs/config/config.html
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,78 @@ <h1 id="reference-config"><a class="header" href="#reference-config">Reference C
# if this happens more often. (default: 500)
#HASH_AWAIT_WARN_TIME=500

#####################################
######### EVENTS / AUDIT ############
#####################################

# The E-Mail address event notifications should be sent to
#EVENT_EMAIL=admin@localhost.de

# The notification level for events. Works the same way as a logging level. For instance:
# 'notice' means send out a notifications for all events with the info level or higher.
# Possible values:
# - info
# - notice
# - warning
# - critical
# default: 'notice'
EVENT_NOTIFY_LEVEL=notice

# Define the level from which on events should be persisted inside the database.
# All events with a lower level will be lost, if there is no active event subscriber.
# Possible values:
# - info
# - notice
# - warning
# - critical
# default: 'info'
EVENT_PERSIST_LEVEL=info

# Define the number of days when events should be cleaned up from the database.
# default: 31
EVENT_CLEANUP_DAYS=31

# The level for the generated Event after a new user has been registered.
# default: info
EVENT_LEVEL_NEW_USER=info
# The level for the generated Event after a user has changed his E-Mail
# default: notice
EVENT_LEVEL_USER_EMAIL_CHANGE=notice
# The level for the generated Event after a user has been given the 'rauthy_admin' role
# default: notice
EVENT_LEVEL_RAUTHY_ADMIN=notice
# The level for the generated Event after the JWKS has been rotated
# default: notice
EVENT_LEVEL_JWKS_ROTATE=notice
# The level for the generated Event after DB secrets have been migrated to a new key
# default: notice
EVENT_LEVEL_SECRETS_MIGRATED=notice
# The level for the generated Event after a Rauthy instance has been started
# default: info
EVENT_LEVEL_RAUTHY_START=info
# The level for the generated Event after a Rauthy entered a healthy state (again)
# default: notice
EVENT_LEVEL_RAUTHY_HEALTHY=notice
# The level for the generated Event after a Rauthy entered an unhealthy state
# default: critical
EVENT_LEVEL_RAUTHY_UNHEALTHY=critical
# The level for the generated Event after an IP has been blacklisted
# default: warning
EVENT_LEVEL_IP_BLACKLISTED=warning
# The level for the generated Event after certain amounts of false logins from an IP
# default: criticao
EVENT_LEVEL_FAILED_LOGINS_25=critical
# default: criticao
EVENT_LEVEL_FAILED_LOGINS_20=critical
# default: warning
EVENT_LEVEL_FAILED_LOGINS_15=warning
# default: warning
EVENT_LEVEL_FAILED_LOGINS_10=warning
# default: notice
EVENT_LEVEL_FAILED_LOGINS_7=notice
# default: info
EVENT_LEVEL_FAILED_LOGIN=info

#####################################
####### LIFETIMES / TIMEOUTS ########
#####################################
Expand Down Expand Up @@ -409,6 +481,11 @@ <h1 id="reference-config"><a class="header" href="#reference-config">Reference C
# setting the initial password. (default: 86400)
#ML_LT_PWD_FIRST=86400

# The interval in seconds in which keep-alives should be sent to SSE clients.
# Depending on your network setup, proxy timeouts, ..., you may adjust this value to fit your needs.
# default: 30
#SSE_KEEP_ALIVE=30

#####################################
############# LOGGING ###############
#####################################
Expand Down
77 changes: 77 additions & 0 deletions docs/print.html
Original file line number Diff line number Diff line change
Expand Up @@ -1515,6 +1515,78 @@ <h4 id="config-adjustements---rest-api"><a class="header" href="#config-adjustem
# if this happens more often. (default: 500)
#HASH_AWAIT_WARN_TIME=500

#####################################
######### EVENTS / AUDIT ############
#####################################

# The E-Mail address event notifications should be sent to
#EVENT_EMAIL=admin@localhost.de

# The notification level for events. Works the same way as a logging level. For instance:
# 'notice' means send out a notifications for all events with the info level or higher.
# Possible values:
# - info
# - notice
# - warning
# - critical
# default: 'notice'
EVENT_NOTIFY_LEVEL=notice

# Define the level from which on events should be persisted inside the database.
# All events with a lower level will be lost, if there is no active event subscriber.
# Possible values:
# - info
# - notice
# - warning
# - critical
# default: 'info'
EVENT_PERSIST_LEVEL=info

# Define the number of days when events should be cleaned up from the database.
# default: 31
EVENT_CLEANUP_DAYS=31

# The level for the generated Event after a new user has been registered.
# default: info
EVENT_LEVEL_NEW_USER=info
# The level for the generated Event after a user has changed his E-Mail
# default: notice
EVENT_LEVEL_USER_EMAIL_CHANGE=notice
# The level for the generated Event after a user has been given the 'rauthy_admin' role
# default: notice
EVENT_LEVEL_RAUTHY_ADMIN=notice
# The level for the generated Event after the JWKS has been rotated
# default: notice
EVENT_LEVEL_JWKS_ROTATE=notice
# The level for the generated Event after DB secrets have been migrated to a new key
# default: notice
EVENT_LEVEL_SECRETS_MIGRATED=notice
# The level for the generated Event after a Rauthy instance has been started
# default: info
EVENT_LEVEL_RAUTHY_START=info
# The level for the generated Event after a Rauthy entered a healthy state (again)
# default: notice
EVENT_LEVEL_RAUTHY_HEALTHY=notice
# The level for the generated Event after a Rauthy entered an unhealthy state
# default: critical
EVENT_LEVEL_RAUTHY_UNHEALTHY=critical
# The level for the generated Event after an IP has been blacklisted
# default: warning
EVENT_LEVEL_IP_BLACKLISTED=warning
# The level for the generated Event after certain amounts of false logins from an IP
# default: criticao
EVENT_LEVEL_FAILED_LOGINS_25=critical
# default: criticao
EVENT_LEVEL_FAILED_LOGINS_20=critical
# default: warning
EVENT_LEVEL_FAILED_LOGINS_15=warning
# default: warning
EVENT_LEVEL_FAILED_LOGINS_10=warning
# default: notice
EVENT_LEVEL_FAILED_LOGINS_7=notice
# default: info
EVENT_LEVEL_FAILED_LOGIN=info

#####################################
####### LIFETIMES / TIMEOUTS ########
#####################################
Expand Down Expand Up @@ -1568,6 +1640,11 @@ <h4 id="config-adjustements---rest-api"><a class="header" href="#config-adjustem
# setting the initial password. (default: 86400)
#ML_LT_PWD_FIRST=86400

# The interval in seconds in which keep-alives should be sent to SSE clients.
# Depending on your network setup, proxy timeouts, ..., you may adjust this value to fit your needs.
# default: 30
#SSE_KEEP_ALIVE=30

#####################################
############# LOGGING ###############
#####################################
Expand Down
2 changes: 1 addition & 1 deletion docs/searchindex.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/searchindex.json

Large diffs are not rendered by default.

46 changes: 38 additions & 8 deletions frontend/src/components/admin/events/Event.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,39 @@
<div class="row">
<div class="col-ts">{ts()}</div>

{#if event.typ === 'NewRauthyAdmin'}
{#if event.typ === 'Test'}
<div class="col-typ">{event.typ}</div>
<div class="col-ip">{event.ip}</div>
<div class="col-text">{event.text}</div>

{:else if event.typ === 'InvalidLogins'}
<div class="col-typ">{`${event.typ}: ${event.data}`}</div>
<div class="col-ip">{event.ip}</div>

{:else}
{:else if event.typ === 'SecretsMigrated'}
<div class="col-typ">{event.typ}</div>
<div class="col-ip">{event.ip || ''}</div>

{:else if event.typ === 'NewRauthyAdmin' || event.typ === 'NewUserRegistered'}
<div class="col-typ">{event.typ}</div>
<div class="col-ip">{event.ip || ''}</div>
<div class="col-text">{@html event.text.replace('@', '<wbr/>@')}</div>

{:else if event.typ === 'IpBlacklisted'}
<div class="col-typ">{event.typ}</div>
<div class="col-ip">{event.ip}</div>
<div class="col-text">{`Expires: ${formatDateFromTs(event.data)}`}</div>

{:else if event.typ === 'RauthyStarted'
|| event.typ === 'RauthyHealthy'
|| event.typ === 'RauthyUnhealthy'
}
<div class="col-typ">{event.typ}</div>
<div class="col-ip"></div>
<div class="col-text">{event.text}</div>

{:else}
<div class="col-typ">{event.typ}</div>

{/if}
</div>
Expand All @@ -96,21 +118,29 @@
{`: ${event.data}`}<br/>
{event.ip}

{:else if event.typ === 'NewRauthyAdmin'}
{:else if event.typ === 'SecretsMigrated'}
{event.ip}

{:else if event.typ === 'NewRauthyAdmin'
|| event.typ === 'NewUserRegistered'
}
<br/>
{event.ip || ''}
<br/>
{@html event.text.replace('@', '<wbr/>@')}

{:else if event.typ === 'IpBlacklisted'}
<br/>
{event.ip}

{:else if event.typ === 'PossibleBruteForce'}
<br/>
{event.ip}
{formatDateFromTs(event.data)}

{:else if event.typ === 'PossibleDoS'}
{:else if event.typ === 'RauthyStarted'
|| event.typ === 'RauthyHealthy'
|| event.typ === 'RauthyUnhealthy'
}
<br/>
{event.ip}
{event.text}

{/if}
{:else}
Expand Down
47 changes: 26 additions & 21 deletions frontend/src/components/admin/events/Events.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -47,31 +47,14 @@
$: if (eventLevel) {
saveEventLevel(eventLevel);
if (es && es.readyState !== 2) {
es.close();
}
stream();
}
onMount(async () => {
eventLevel = await readSavedEventLevel();
if (!es || es.closed) {
es = new EventSource(`/auth/v1/events?latest=${latest}`);
es.onopen = () => {
console.log('SSE Events Stream opened');
events = [];
};
es.onerror = () => {
console.error('SSE Events Stream closed');
};
es.onmessage = ev => {
if (ev.data) {
let event = JSON.parse(ev.data);
// keep max 500 events in the UI to not consume endless amounts of memory
events = [event, ...events.slice(-499)];
}
};
}
});
function eventColor(level) {
Expand Down Expand Up @@ -101,6 +84,28 @@
await postTestEvent();
}
function stream() {
console.log('opening SSE stream');
es = new EventSource(`/auth/v1/events?latest=${latest}&level=${eventLevel?.toLowerCase() || 'info'}`);
es.onopen = () => {
console.log('SSE Events Stream opened');
events = [];
};
es.onerror = () => {
console.error('SSE Events Stream closed');
};
es.onmessage = ev => {
if (ev.data) {
let event = JSON.parse(ev.data);
// keep max 500 events in the UI to not consume endless amounts of memory
events = [event, ...events.slice(-499)];
}
};
}
</script>
<div
Expand Down
Loading

0 comments on commit 797dad5

Please sign in to comment.