Skip to content

build(sentry): Prepare for a non-root sentry image - #4535

Merged
oioki merged 4 commits into
masterfrom
alextarasov/sentry-non-root-prep
Sep 29, 2026
Merged

oioki merged 4 commits into
masterfrom
alextarasov/sentry-non-root-prep

Conversation

@oioki

@oioki oioki commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

Make self-hosted work with both the current root sentry image and the upcoming non-root one (getsentry/sentry#125848, which has to wait for this PR).

  • sentry/Dockerfile: run customizations as root, then switch to USER sentry. Make /etc/ssl/certs writable by sentry so the entrypoint's update-ca-certificates keeps working for custom CAs.
  • install/ensure-sentry-data-ownership.sh: chown sentry-data to 999 once during install instead of on every container start (the old entrypoint did this as root).
  • cron/Dockerfile: install gosu itself, since the upstream image will drop it.

Follow-up for distroless: build the custom CA trust store at install time instead of in the entrypoint.

The upstream sentry image is moving to run as the non-root sentry user and will drop gosu (getsentry/sentry#125848). Make self-hosted work with both the current root image and the upcoming non-root one:

- Run build customizations (nodestore-s3, enhance-image.sh, requirements.txt) as root, then switch to the sentry user.
- Trust custom CAs without update-ca-certificates, which needs root: build a combined bundle in /tmp and point the TLS env vars at it.
- Fix sentry-data ownership once during install instead of at every container start.
- Install gosu in the cleanup image instead of relying on the sentry image.
@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Coverage Results 📊

✅ 22 passed | Total: 22 | Pass Rate: 100% | Execution Time: 11m 18s

📊 Comparison with Base Branch

Metric Change
Total Tests —
Passed Tests —
Failed Tests —
Skipped Tests —

✨ Test counts unchanged from base.

All tests are passing successfully.

✅ Patch coverage is 100.00% (no changed executable lines found; target 50%).
Project statement coverage is 95.54% (unchanged from base (838b998) to head (a61a82a)).

Coverage diff
@@            Coverage Diff             @@
##        master     #4535       +/-##
==========================================
  Coverage    95.54%    95.54%        —%
==========================================
  Files            5         5         —
  Tracked lines       336       336         —
  Branches         0         0         —
==========================================
  Hits           321       321         —
  Misses          15        15         —
  Partials         0         0         —

Generated by Coverage Action

Replace the /tmp CA bundle with making /etc/ssl/certs writable by the sentry user, so the existing entrypoint can run update-ca-certificates unchanged. The bundle approach left the standard bundle path and the hashed certs directory without the custom CAs, and did not apply to docker compose exec, so clients that don't read the TLS env vars (e.g. librdkafka, capath lookups, paths set in sentry.conf.py) would stop trusting them.
@oioki
oioki marked this pull request as ready for review September 29, 2026 09:07

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 582885b. Configure here.

for root, dirs, files in os.walk("/data"):
for path in (root, *(os.path.join(root, name) for name in dirs + files)):
if os.lstat(path).st_uid != SENTRY_UID:
os.lchown(path, SENTRY_UID, -1)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ownership check skips nested files

Medium Severity

The install-time chown only walks /data when /data or /data/files themselves are not uid 999. Those two directories are the first paths updated, so an interrupted run, a volume whose root is already 999, or leftover root-owned trees such as custom-packages make the next ./install.sh skip the walk. Nested files then stay root-owned, and the non-root sentry process cannot write them. The old entrypoint repaired ! -user sentry files on every start; this path cannot recover.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 582885b. Configure here.

@oioki oioki Sep 29, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good bot. Now walks bottom-up so interrupted runs resume. Nested-files case matches the old entrypoint's guard, so leaving that.

Chown /data last, so if the walk is interrupted the ownership guard still triggers a full walk on the next install.
Comment thread install/ensure-sentry-data-ownership.sh Outdated

os.makedirs("/data/files", exist_ok=True)
if any(os.stat(p).st_uid != SENTRY_UID for p in ("/data", "/data/files")):
for root, dirs, files in os.walk("/data", topdown=False):

@aminvakil aminvakil Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Current os.walk does not fail if something cannot be read for whatever reason (I/O errors mainly is what crosses mind).

Previous find command would have fail.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Added onerror=fail option to be on par with find /data behavior (we are going to delete it in getsentry/sentry#125848)

os.walk skips directories it cannot list by default, which would leave them root-owned without any error. Raise instead so install.sh stops, like the old entrypoint's find under set -e.
@oioki
oioki merged commit 85ef848 into master Sep 29, 2026
24 checks passed
@oioki
oioki deleted the alextarasov/sentry-non-root-prep branch September 29, 2026 10:26
oioki added a commit to getsentry/sentry that referenced this pull request Sep 29, 2026
Run the self-hosted `sentry` image as the `sentry` user (uid 999)
instead of starting as root and stepping down with `gosu`, like
getsentry/snuba#2777. `/data` is created with the right owner at build
time, so the entrypoint no longer needs to `chown` it. Production
already runs getsentry as 999 via `runAsUser`.

Prep for moving the image to a distroless base.

**Depends on getsentry/self-hosted#4535 being on self-hosted `master`.**
Self-hosted master and relocation validation use `:nightly`, so they'd
pick this up within a day of merging.
@aldy505 aldy505 mentioned this pull request Oct 4, 2026
17 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

4 participants