Skip to content

refactor: run the webserver unprivileged#3666

Open
sgaist wants to merge 9 commits into
masterfrom
3485_webserver_with_own_uid_gid
Open

refactor: run the webserver unprivileged#3666
sgaist wants to merge 9 commits into
masterfrom
3485_webserver_with_own_uid_gid

Conversation

@sgaist

@sgaist sgaist commented Aug 31, 2025

Copy link
Copy Markdown
Contributor

What type of PR is this?

Uncomment one (or more) /kind <> lines:

/kind bug

/kind cleanup

/kind design

/kind documentation

/kind failing-test

/kind feature

/kind release

Any specific area of the project related to this PR?

Uncomment one (or more) /area <> lines:

/area build

/area engine

/area tests

/area proposals

/area CI

What this PR does / why we need it:

The webserver is running in a thread with the same privileges as the falco process. In order to make running it more secure, use fork rather than thread and then change the user and group id to unprivileged values.

Which issue(s) this PR fixes:

Fixes #3485

Special notes for your reviewer:

Does this PR introduce a user-facing change?:

webserver: the webserver component now runs in an unprivileged fork. The user id and group id used to run the fork can be configured through the webserver configuration block.

@poiana

poiana commented Aug 31, 2025

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: sgaist

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@poiana
poiana requested a review from Kaizhe August 31, 2025 08:56
@poiana
poiana requested a review from mstemm August 31, 2025 08:56
@poiana poiana added the size/M label Aug 31, 2025
@sgaist

sgaist commented Aug 31, 2025

Copy link
Copy Markdown
Contributor Author

Note for reviewers: it's the first time I am taking a shot at fork so I might have implemented things in a wrong fashion.
I will welcome hints to documentation/best practice for it.

@sgaist
sgaist force-pushed the 3485_webserver_with_own_uid_gid branch 2 times, most recently from 0699b71 to c052012 Compare September 1, 2025 13:45
@leogr

leogr commented Sep 4, 2025

Copy link
Copy Markdown
Member

Hey @sgaist

I'm unsure if we have enough time to put this into the upcoming release, but it seems really interesting!

So tentatively for
/milestone 0.42.0

Also, I have a side question. While investigating #3664, I had the feeling that when the Prometheus metrics and web server are enabled, the memory consumption slightly increases by simply repeatedly refreshing the metrics web page. However, I can't reliably repro this. So, it would be great if, along with this initiative, we can also investigate more about possible issues with the web server (and the dependent metrics) feature(s).

@poiana poiana added this to the 0.42.0 milestone Sep 4, 2025
@leogr

leogr commented Sep 24, 2025

Copy link
Copy Markdown
Member

Since we are likely too late for the upcoming release, moving to
/milestone 0.43.0

@poiana poiana modified the milestones: 0.42.0, 0.43.0 Sep 24, 2025
Comment thread userspace/falco/webserver.cpp Outdated
Comment thread userspace/falco/webserver.cpp Outdated
@ekoops

ekoops commented Jan 7, 2026

Copy link
Copy Markdown
Contributor

Hey @sgaist , any update on this?

@sgaist

sgaist commented Jan 7, 2026

Copy link
Copy Markdown
Contributor Author

@ekoops sorry, I just realized that your review got lost in my mail box. I'll check that ASAP.

@ekoops ekoops modified the milestones: 0.43.0, 0.44.0 Jan 14, 2026
@leogr

leogr commented Feb 2, 2026

Copy link
Copy Markdown
Member

@sgaist any update on this?

@sgaist

sgaist commented Feb 2, 2026

Copy link
Copy Markdown
Contributor Author

I have done some exploration on the IPC side with pipes however I realized that there's no way to send back the information that the webserver was started through this mechanism as by design it enters a blocking loop and there's no callback that could be used to state "started".
Next thing I am thinking about is to simply start a small loop from the parent that tries to talk to the webserver to know that it is started.
What do you guys think ?

The webserver was running in a thread with the same
privileges as the falco process. In order to make running
it more secure, use fork rather than thread and then change
the user and group id to unprivileged values.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
@sgaist
sgaist force-pushed the 3485_webserver_with_own_uid_gid branch from c052012 to 6eaed3f Compare February 9, 2026 21:44
Using a local variable won't work since the server and the
main application don't share the same memory space anymore.

To check that the server is running, a call to the health
endpoint is used.

While the start of the server should be pretty fast, a
simple exponential backoff has been implemented to allow
for room in case the start is slowed for some reason.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
@sgaist
sgaist force-pushed the 3485_webserver_with_own_uid_gid branch from 6eaed3f to 23ba06d Compare February 9, 2026 21:48
@sgaist

sgaist commented Feb 9, 2026

Copy link
Copy Markdown
Contributor Author

Also, I have a side question. While investigating #3664, I had the feeling that when the Prometheus metrics and web server are enabled, the memory consumption slightly increases by simply repeatedly refreshing the metrics web page. However, I can't reliably repro this. So, it would be great if, along with this initiative, we can also investigate more about possible issues with the web server (and the dependent metrics) feature(s).

I am wondering whether this is the result of calling the metrics collector snapshot function.

Comment thread userspace/falco/webserver.cpp Outdated
Comment thread userspace/falco/webserver.cpp Outdated
Comment thread userspace/falco/webserver.cpp Outdated
Comment thread userspace/falco/webserver.cpp Outdated
}
if(m_server_thread.joinable()) {
m_server_thread.join();
falco_logger::log(falco_logger::level::INFO, "Webserver: killing fork\n");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about using "webserver process" instead of "fork"? I mean, both here and in the other places... WDYT?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reworded some of the other texts as well to make things nicer.

@github-project-automation github-project-automation Bot moved this from Todo to In progress in Falco Roadmap Feb 10, 2026
They were inverted.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
Improve readability

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
@sgaist
sgaist requested a review from ekoops February 10, 2026 10:56
Comment thread userspace/falco/webserver.cpp Outdated
} catch(std::exception &e) {
falco_logger::log(falco_logger::level::ERR,
"falco_webserver: " + std::string(e.what()) + "\n");
"Webserver: " + std::string(e.what()) + "\n");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concern is what happens if the m_server->listen(...) call fail. Here, we are catching the exception, and after we print a log line, we just return from the function. Even if the main falco process will recognize that the son is not running, I guess we should avoid letting the web server process to proceed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, if the server does not start for some reason, it will be detected by the loop below that tries to connect to the server. However, it's not a nice way to detect that.
I have refactored that part.

Comment thread userspace/falco/configuration.cpp Outdated
Comment on lines +492 to +493
m_webserver_config.m_uid = m_config.get_scalar<uint32_t>("webserver.uid", 1000);
m_webserver_config.m_gid = m_config.get_scalar<uint32_t>("webserver.gid", 1000);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if 1000 is the right choice here. Maybe we should provide IDs that are not connected to any user... After all, it's not always the case that 1000 is the uid of an user in the system. What do you think?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I have currently changed them for the nobody uid/pid.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
If starting the server throws for some reason,
the result will be instantly shown.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
@sgaist
sgaist force-pushed the 3485_webserver_with_own_uid_gid branch from cdf6b93 to fd13688 Compare February 11, 2026 23:20
@ekoops

ekoops commented Feb 12, 2026

Copy link
Copy Markdown
Contributor

Hey @sgaist , I guess we broke prometheus metrics: https://github.com/falcosecurity/falco/actions/runs/21926985793?pr=3666

@sgaist

sgaist commented Feb 23, 2026

Copy link
Copy Markdown
Contributor Author

Oh damn, it seems that my answer got lost in the process.

I dug a bit on that part only to realize that the metrics end point activation will happen in the parent process hence the breakage you spotted.

@ekoops ekoops modified the milestones: 0.44.0, 0.45.0 May 21, 2026
@sgaist

sgaist commented May 24, 2026

Copy link
Copy Markdown
Contributor Author

I was able to come back to this and I think it needs a bit more design brainstorming (I was I bit tired when starting this and there are several details that escaped me at that time).

I think that the webserver, as a forked process, should not have anything to do with directly accessing the state object to retrieve the stats. We should rather have a proper IPC in place that decouples both.

What do you think ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

No longer run webserver as root under main falco process

4 participants