Skip to content

[Filebeat/Journald] allow to use a chroot when calling journalctl#48008

Merged
belimawr merged 37 commits intoelastic:mainfrom
belimawr:journald-chroot
Dec 19, 2025
Merged

[Filebeat/Journald] allow to use a chroot when calling journalctl#48008
belimawr merged 37 commits intoelastic:mainfrom
belimawr:journald-chroot

Conversation

@belimawr
Copy link
Contributor

@belimawr belimawr commented Dec 9, 2025

Proposed commit message

Add support in the journald inpur for using chroot when calling
`journalctl`. In a container environment this allows to mount the host
file system into the container and use its `journalctl`, which
prevents any sort of incompatibility between the `journalctl` in the
container image and the host Journald.

Checklist

  • My code follows the style guidelines of this project
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have made corresponding change to the default configuration files
  • I have added tests that prove my fix is effective or that my feature works. Where relevant, I have used the stresstest.sh script to run them under stress conditions and race detector to verify their stability.
  • I have added an entry in ./changelog/fragments using the changelog tool.

## Disruptive User Impact

Author's Checklist

  • Finish manual testing steps

How to test this PR locally

Run the tests

cd filebeat
go test -v -count=1 -run=TestConfigureJournalctlPath ./input/journald/
go test -v -count=1 -tags=integration -run=TestNewFactoryChroot ./input/journald/pkg/journalctl
go test -tags=integration -v -count=1 -run=TestJournaldChroot ./tests/integration

Manual testing

1. Create a filebeat.yml

filebeat.yml

filebeat.inputs:
  - type: journald
    id: journald-input-id
    chroot: /host
    journalctl_path: /usr/bin/journalctl

output.discard:
  enabled: true

# output.console:
#   enabled: true
#   pretty: false

logging:
  to_stderr: true
  metrics.period: 5s

2. Build a staicaly linked Filebeat binary

CGO_ENABLED=0 go build -ldflags '-extldflags "-static" -s' -tags timetzdata .

3. Create a Dockerfile and build a test image

Dockerfile

FROM alpine:latest AS prep

FROM scratch

COPY --from=prep /etc/alpine-release /etc/alpine-release
COPY filebeat /
COPY filebeat.yml /
ENTRYPOINT ["/filebeat"]
CMD ["-c", "/filebeat.yml", "--strict.perms=false"]

docker build -t filebeat-chroot-test .

4. Run the container

docker run --rm -v /:/host filebeat-chroot-test

You should see in the logs the journalctl starting:

{
  "@timestamp": "2025-12-17T17:14:29.446Z",
  "ecs.version": "1.6.0",
  "id": "journald-input-id",
  "input_id": "journald-input-id",
  "input_source": "LOCAL_SYSTEM_JOURNAL",
  "log.level": "info",
  "log.logger": "input.journald.reader.journalctl-runner",
  "log.origin": {
    "file.line": 153,
    "file.name": "journalctl/journalctl.go",
    "function": "github.com/elastic/beats/v7/filebeat/input/journald.(*journald).Run.NewFactory.func1"
  },
  "message": "Journalctl command. Paths relative to chroot (if set)",
  "path": "LOCAL_SYSTEM_JOURNAL",
  "process.chroot": "/host",
  "process.command_line": "/usr/bin/journalctl --utc --output=json --no-pager --all --follow --no-tail --boot all",
  "service.name": "filebeat"
}
{
  "@timestamp": "2025-12-17T17:14:29.447Z",
  "ecs.version": "1.6.0",
  "id": "journald-input-id",
  "input_id": "journald-input-id",
  "input_source": "LOCAL_SYSTEM_JOURNAL",
  "log.level": "info",
  "log.logger": "input.journald.reader.journalctl-runner",
  "log.origin": {
    "file.line": 163,
    "file.name": "journalctl/journalctl.go",
    "function": "github.com/elastic/beats/v7/filebeat/input/journald.(*journald).Run.NewFactory.func1"
  },
  "message": "journalctl started",
  "path": "LOCAL_SYSTEM_JOURNAL",
  "process.pid": 23,
  "service.name": "filebeat"
}

You can also see the number events published in the metrics that are logged every 5s.

If you want to see the events, remove the discard output and uncomment
the console output in filebeat.yml, then rebuild the docker image
and run it again.

Related issues

## Use cases
## Screenshots
## Logs

@belimawr belimawr self-assigned this Dec 9, 2025
@belimawr belimawr added backport-skip Skip notification from the automated backport with mergify Team:Elastic-Agent-Data-Plane Label for the Agent Data Plane team labels Dec 9, 2025
@botelastic botelastic bot added needs_team Indicates that the issue/PR needs a Team:* label and removed needs_team Indicates that the issue/PR needs a Team:* label labels Dec 9, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Dec 9, 2025

🤖 GitHub comments

Just comment with:

  • run docs-build : Re-trigger the docs validation. (use unformatted text in the comment!)
@belimawr
Copy link
Contributor Author

belimawr commented Dec 9, 2025

The failing test on Windows is unrelated to this PR. The flaky test issue: #48009

@belimawr belimawr changed the title [WIP] Journald chroot Dec 9, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Dec 10, 2025

🔍 Preview links for changed docs

@belimawr belimawr marked this pull request as ready for review December 11, 2025 13:01
@belimawr belimawr requested review from a team as code owners December 11, 2025 13:01
@mergify
Copy link
Contributor

mergify bot commented Dec 16, 2025

This pull request is now in conflicts. Could you fix it? 🙏
To fixup this pull request, you can check out it locally. See documentation: https://help.github.com/articles/checking-out-pull-requests-locally/

git fetch upstream
git checkout -b journald-chroot upstream/journald-chroot
git merge upstream/main
git push upstream journald-chroot
@cmacknz cmacknz added backport-9.3 Automated backport to the 9.3 branch and removed backport-skip Skip notification from the automated backport with mergify labels Dec 17, 2025
@cmacknz
Copy link
Member

cmacknz commented Dec 17, 2025

This looks like it will work if you are root, have you found what the least privilege way to execute journalctl is yet? Can you for example be a non-root user with CAP_SYS_CHROOT (you might need more than just this) and execute journalctl?

The wolfi images do not have root as the running container user for example, so ideally we can keep that and add the minimum capabilities rather than being root if possible.

@belimawr
Copy link
Contributor Author

This looks like it will work if you are root, have you found what the least privilege way to execute journalctl is yet? Can you for example be a non-root user with CAP_SYS_CHROOT (you might need more than just this) and execute journalctl?

The wolfi images do not have root as the running container user for example, so ideally we can keep that and add the minimum capabilities rather than being root if possible.

I've been trying different variations of privileges and doing some research, the only way I can get the chroot to work is when setting the user to root. Even without adding --cap-add CAP_SYS_CHROOT it works if I ran Filebeat as root (--user 0). Everything I found also states that using chroot requires root.

--cap-drop CAP_SYS_CHROOT prevents even root from running the chroot. So CAP_SYS_CHROOT is definitely required, but it seems to be enabled by default on my machine 🤷‍♂️.

I'll update the docs to reflect it.

@belimawr
Copy link
Contributor Author

The CI failure is unrelated to this PR, here is the flaky test isuse: #48187

Copy link
Member

@cmacknz cmacknz left a comment

Choose a reason for hiding this comment

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

Thanks, I'm fine with this (and backport to 9.3).

We can work out the minimum privileges separately.

Copy link
Contributor

@colleenmcginnis colleenmcginnis left a comment

Choose a reason for hiding this comment

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

I left a couple minor non-blocking suggestions below.

@belimawr belimawr merged commit b5e52fa into elastic:main Dec 19, 2025
208 of 211 checks passed
mergify bot pushed a commit that referenced this pull request Dec 19, 2025
…48008)

Add support in the journald inpur for using chroot when calling
`journalctl`. In a container environment this allows to mount the host
file system into the container and use its `journalctl`, which
prevents any sort of incompatibility between the `journalctl` in the
container image and the host Journald.

---------

Co-authored-by: Craig MacKenzie <craig.mackenzie@elastic.co>
(cherry picked from commit b5e52fa)
belimawr added a commit that referenced this pull request Dec 19, 2025
…48008) (#48197)

Add support in the journald inpur for using chroot when calling
`journalctl`. In a container environment this allows to mount the host
file system into the container and use its `journalctl`, which
prevents any sort of incompatibility between the `journalctl` in the
container image and the host Journald.

---------


(cherry picked from commit b5e52fa)

Co-authored-by: Tiago Queiroz <tiago.queiroz@elastic.co>
Co-authored-by: Craig MacKenzie <craig.mackenzie@elastic.co>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-9.3 Automated backport to the 9.3 branch Team:Elastic-Agent-Data-Plane Label for the Agent Data Plane team

5 participants