Skip to content

Commit dd64a27

Browse files
committed
feat: added ability to configure TTL index for audit documents
1 parent 3c0b6a7 commit dd64a27

File tree

7 files changed

+138
-56
lines changed

7 files changed

+138
-56
lines changed

Diff for: .env.example

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ DB_USER_COLLECTION=users
1212
DB_AUDIT_COLLECTION=audits
1313
DB_CREATE_INDEXES=true
1414
DB_AUDIT_ENABLED=false
15+
DB_AUDIT_TTL=0
1516

1617
# JWT
1718
JWT_SECRET=topSecretSecret

Diff for: Cargo.lock

+32-32
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: Dockerfile

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ ENV [email protected]
3737
ENV DEFAULT_USER_PASSWORD=123456
3838
ENV DEFAULT_USER_ENABLED=true
3939
ENV MAX_FETCH_LIMIT=100
40+
ENV DB_AUDIT_TTL=0
4041

4142
# Set the working directory
4243
WORKDIR /usr/src/auth-rs

Diff for: docs/CONFIGURATION.md

+27-24
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,34 @@
1212

1313
The following environment variables can be used to configure `auth-rs`:
1414

15-
| Variable | Default | Required | Type | Description |
16-
|--------------------------|---------------|----------------------------------------------|-------------|------------------------------------------------------------------------|
17-
| SERVER_ADDR | `0.0.0.0` | `false` | `IPAddress` | The server address |
18-
| SERVER_PORT | `8080` | `false` | `u16` | The port that the server will use |
19-
| MAX_FETCH_LIMIT | `100` | `false` | `i64` | The maximum amount of entity records that can be retrieved in one call |
20-
| DB_CONNECTION_STRING | N/A | `true` | `String` | The MongoDB connection string |
21-
| DB_DATABASE | N/A | `true` | `String` | The MongoDB Database that will be used by `auth-rs` |
22-
| DB_PERMISSION_COLLECTION | `permissions` | `false` | `String` | The collection that holds the `Permission` entities |
23-
| DB_ROLE_COLLECTION | `roles` | `false` | `String` | The collection that holds the `Role` entities |
24-
| DB_USER_COLLECTION | `users` | `false` | `String` | The collection that holds the `User` entities |
25-
| DB_AUDIT_COLLECTION | `audits` | `false` | `String` | The collection that holds the `Audit` entities |
26-
| DB_CREATE_INDEXES | `true` | `false` | `bool` | Automatically create collection indexes |
27-
| DB_AUDIT_ENABLED | `false` | `false` | `bool` | Enable or disable audit trails |
28-
| JWT_SECRET | N/A | `true` | `String` | The JWT secret |
29-
| JWT_EXPIRATION | `3600` | `false` | `usize` | The JWT expiration time in seconds |
30-
| RUST_LOG | N/A | `false` | `String` | The default log level |
31-
| RUST_BACKTRACE | N/A | `false` | `String` | Controls whether or not backtraces are displayed when a panic occurs |
32-
| GENERATE_DEFAULT_USER | `true` | `false` | `bool` | Sets whether a default administrator `User` should be generated |
33-
| DEFAULT_USER_USERNAME | N/A | `true` if `GENERATE_DEFAULT_USER` is enabled | `String` | The default `User`'s username |
34-
| DEFAULT_USER_EMAIL | N/A | `false` | `String` | The default `User`'s email address |
35-
| DEFAULT_USER_PASSWORD | N/A | `true` if `GENERATE_DEFAULT_USER` is enabled | `String` | The default `User`'s password |
36-
| DEFAULT_USER_ENABLED | N/A | `true` if `GENERATE_DEFAULT_USER` is enabled | `bool` | Sets whether the default user is enabled or not |
37-
| ENABLE_OPENAPI | `true` | `false` | `bool` | Enables or disables the OpenAPI endpoint |
15+
| Variable | Default | Required | Type | Description |
16+
|--------------------------|---------------|----------------------------------------------|-------------|-------------------------------------------------------------------------|
17+
| SERVER_ADDR | `0.0.0.0` | `false` | `IPAddress` | The server address |
18+
| SERVER_PORT | `8080` | `false` | `u16` | The port that the server will use |
19+
| MAX_FETCH_LIMIT | `100` | `false` | `i64` | The maximum amount of entity records that can be retrieved in one call |
20+
| DB_CONNECTION_STRING | N/A | `true` | `String` | The MongoDB connection string |
21+
| DB_DATABASE | N/A | `true` | `String` | The MongoDB Database that will be used by `auth-rs` |
22+
| DB_PERMISSION_COLLECTION | `permissions` | `false` | `String` | The collection that holds the `Permission` entities |
23+
| DB_ROLE_COLLECTION | `roles` | `false` | `String` | The collection that holds the `Role` entities |
24+
| DB_USER_COLLECTION | `users` | `false` | `String` | The collection that holds the `User` entities |
25+
| DB_AUDIT_COLLECTION | `audits` | `false` | `String` | The collection that holds the `Audit` entities |
26+
| DB_CREATE_INDEXES | `true` | `false` | `bool` | Automatically create collection indexes |
27+
| DB_AUDIT_ENABLED | `false` | `false` | `bool` | Enable or disable audit trails |
28+
| DB_AUDIT_TTL | `0` | `false` | `u64` | Automatically remove `Audit` entities after a set amount of seconds |
29+
| JWT_SECRET | N/A | `true` | `String` | The JWT secret |
30+
| JWT_EXPIRATION | `3600` | `false` | `usize` | The JWT expiration time in seconds |
31+
| RUST_LOG | N/A | `false` | `String` | The default log level |
32+
| RUST_BACKTRACE | N/A | `false` | `String` | Controls whether or not backtraces are displayed when a panic occurs |
33+
| GENERATE_DEFAULT_USER | `true` | `false` | `bool` | Sets whether a default administrator `User` should be generated |
34+
| DEFAULT_USER_USERNAME | N/A | `true` if `GENERATE_DEFAULT_USER` is enabled | `String` | The default `User`'s username |
35+
| DEFAULT_USER_EMAIL | N/A | `false` | `String` | The default `User`'s email address |
36+
| DEFAULT_USER_PASSWORD | N/A | `true` if `GENERATE_DEFAULT_USER` is enabled | `String` | The default `User`'s password |
37+
| DEFAULT_USER_ENABLED | N/A | `true` if `GENERATE_DEFAULT_USER` is enabled | `bool` | Sets whether the default user is enabled or not |
38+
| ENABLE_OPENAPI | `true` | `false` | `bool` | Enables or disables the OpenAPI endpoint |
3839

3940
> *Note*: The audit trail feature is disabled by default and will have a noticeable performance impact when enabled.
41+
> Audit trails can be set to expire automatically after a set amount of seconds by changing the `DB_AUDIT_TTL` environment variable
42+
> to the desired amount of seconds (greater than zero), if the `DB_CREATE_INDEXES` variable is also enabled.
4043
4144
## Changing the default configuration
4245

@@ -54,7 +57,7 @@ You can add environment variables when running the container using the `-e` flag
5457
An example of running the container using Docker:
5558

5659
```bash
57-
docker run -d -p 8080:8080 -e DB_CONNECTION_STRING=mongodb://localhost:27017 -e DB_DATABASE=auth-rs -e HASH_SALT=mysalt -e JWT_SECRET=mysecret -e DEFAULT_USER_USERNAME=admin -e DEFAULT_USER_PASSWORD=secret -e DEFAULT_USER_ENABLED=true opserva/auth-rs
60+
docker run -d -p 8080:8080 -e DB_CONNECTION_STRING=mongodb://localhost:27017 -e DB_DATABASE=auth-rs -e -e JWT_SECRET=mysecret -e DEFAULT_USER_USERNAME=admin -e DEFAULT_USER_PASSWORD=secret -e DEFAULT_USER_ENABLED=true opserva/auth-rs
5861
```
5962

6063
Alternatively, you can provide an `.env` file to the container using the `--env-file` flag:

Diff for: src/components/env_reader.rs

+9
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,14 @@ impl EnvReader {
147147
Err(_) => false,
148148
};
149149

150+
let audit_ttl = match env::var("DB_AUDIT_TTL") {
151+
Ok(d) => {
152+
let res: u64 = d.trim().parse().expect("DB_AUDIT_TTL must be a number");
153+
res
154+
}
155+
Err(_) => 0,
156+
};
157+
150158
let create_indexes = match env::var("DB_CREATE_INDEXES") {
151159
Ok(d) => {
152160
let res: bool = d
@@ -182,6 +190,7 @@ impl EnvReader {
182190
audit_collection,
183191
create_indexes,
184192
audit_enabled,
193+
audit_ttl,
185194
);
186195

187196
let server_config = ServerConfig::new(addr, port, max_limit);

Diff for: src/configuration/config.rs

+64
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::services::Services;
2020
use log::{error, info};
2121
use mongodb::bson::doc;
2222
use mongodb::bson::oid::ObjectId;
23+
use mongodb::error::ErrorKind;
2324
use mongodb::options::{ClientOptions, IndexOptions, ServerApi, ServerApiVersion};
2425
use mongodb::{Client, Database, IndexModel};
2526
use regex::Regex;
@@ -127,6 +128,8 @@ impl Config {
127128
cfg.create_role_indexes(&db_config.role_collection).await;
128129
cfg.create_user_indexes(&db_config.user_collection).await;
129130
cfg.create_audit_indexes(&db_config.audit_collection).await;
131+
cfg.create_or_delete_audit_ttl_index(db_config.audit_ttl, &db_config.audit_collection)
132+
.await;
130133
}
131134

132135
cfg
@@ -507,6 +510,67 @@ impl Config {
507510
.expect("Creating an index should succeed");
508511
}
509512

513+
/// # Summary
514+
///
515+
/// Create or delete a TTL index for the Audit collection.
516+
///
517+
/// # Arguments
518+
///
519+
/// * `expire_after` - A u64 that holds the TTL in seconds.
520+
/// * `audit_collection` - A string slice that holds the name of the Audit collection.
521+
///
522+
/// # Panics
523+
///
524+
/// This method will panic if the index could not be created or deleted (unless Error Command code 27 applies).
525+
pub async fn create_or_delete_audit_ttl_index(
526+
&self,
527+
expire_after: u64,
528+
audit_collection: &str,
529+
) {
530+
if expire_after > 0 {
531+
info!("Creating TTL index for the Audit collection");
532+
533+
let duration = std::time::Duration::from_secs(expire_after);
534+
535+
// Define the TTL index model
536+
let model = IndexModel::builder()
537+
.keys(doc! {
538+
"createdAt": 1
539+
})
540+
.options(IndexOptions::builder().expire_after(Some(duration)).build())
541+
.build();
542+
543+
self.database
544+
.collection::<Audit>(audit_collection)
545+
.create_index(model, None)
546+
.await
547+
.expect("Creating an index should succeed");
548+
} else {
549+
info!("Deleting TTL index for the Audit collection");
550+
551+
match self
552+
.database
553+
.collection::<Audit>(audit_collection)
554+
.drop_index("createdAt_1", None)
555+
.await
556+
{
557+
Ok(_) => {}
558+
Err(e) => match e.kind.as_ref() {
559+
ErrorKind::Command(e) => {
560+
if e.code == 27 {
561+
info!("TTL index for the Audit collection does not exist");
562+
} else {
563+
panic!("Failed to delete TTL index: {:?}", e);
564+
}
565+
}
566+
_ => {
567+
panic!("Failed to delete TTL index: {:?}", e);
568+
}
569+
},
570+
}
571+
}
572+
}
573+
510574
/// # Summary
511575
///
512576
/// Initialize the database.

0 commit comments

Comments
 (0)