skip to content

A service that runs fine on an Ubuntu host fails with permission denied after being deployed onto a Red Hat Enterprise Linux host, even though file ownership and mode bits are identical on both machines. What about RHEL's default configuration explains this, and how do you confirm it before changing anything?

level: seniorimportance: should knowfreq 52%

answer

  1. two checks must both pass
  2. the other host was not enforcing anything
  3. identical mode bits, different outcome
  4. confirm the mode before touching anything
  5. permissive briefly, then straight back

basics

~20 s

RHEL ships SELinux in enforcing mode with its targeted policy by default, so access is checked against policy as well as against ownership and mode bits. Ubuntu leaves most custom services unconfined, which is why the same file permissions behave differently on the two hosts.

solid answer

~50 s

The difference is mandatory access control. RHEL enables SELinux in enforcing mode with the targeted policy out of the box, which means a permission check the traditional user/group/mode bits allow can still be refused by policy. Ubuntu ships AppArmor with profiles for a handful of programs, so a service you wrote yourself is effectively unconfined there — the migration surprise is not that RHEL is broken, it is that the Ubuntu host was never enforcing anything on your process. Confirm before you touch anything: check the mode with `getenforce`, and look for denial records in the audit log at the moment of the failure. If you need certainty, `setenforce 0` temporarily and see whether the symptom disappears — then put it straight back. The fix is a policy correction, never `chmod 777` and never leaving enforcement off.

go deeper

for a junior

Know that on RHEL a permission check involves more than owner, group and mode bits, and that identical file permissions can therefore behave differently than on an Ubuntu host.

for a middle

Explain that the platform applies a second, mandatory check the file owner cannot waive, and describe the confirmation sequence: check the mode, find the denial record, and only then form a hypothesis.

for a senior

Show the migration judgment — predict which parts of a move will trip enforcement, keep the diagnostic toggle to seconds, and treat policy work as a planned workstream rather than an incident.

for a principal

Own the position that the enforcing default is an asset the organisation bought deliberately, and set the standard that no team ships by weakening it — with a supported path for legitimate exceptions.

## Two access checks, not one On a traditional Unix system, an access decision comes from discretionary access control: the file's owner, group and mode bits, evaluated against the process's credentials. Discretionary means the owner of the object decides — if you own a file, you may open its permissions to everyone. Mandatory access control adds a second, independent check that the object's owner cannot waive. The kernel consults a system-wide policy, and the operation proceeds only if *both* checks pass. SELinux is the mandatory access control implementation RHEL ships, and the important fact for this question is the default: enforcing mode with the targeted policy, from a stock installation, with no action from the administrator. That is why identical ownership and identical mode bits produce different outcomes on the two hosts. The mode bits are not the whole decision on RHEL. ## Why Ubuntu did not warn you Debian and Ubuntu also ship a mandatory access control system — AppArmor — enabled by default. The difference is coverage and philosophy. AppArmor's shipped profiles confine a specific set of packaged programs; a service you built and installed yourself typically has no profile and runs unconfined. RHEL's targeted policy also aims at a set of confined domains rather than every process, but the surrounding policy governs far more of the system, and the labelling applied to files and ports means an unpackaged service can still find itself denied by policy that was written about the *resources* rather than about the program. The honest framing in an interview is: the platform did not become stricter by accident. RHEL is frequently chosen *because* of this posture — it is the reason a security team signed off on the platform, and often the reason a compliance profile is satisfiable at all. Treating it as an obstacle to switch off is the answer that ends the interview. ## Confirming the diagnosis Work in this order, and change nothing until the first two steps are done. 1. **Establish the mode.** `getenforce` reports `Enforcing`, `Permissive` or `Disabled`. If it says Enforcing, mandatory access control is a live suspect. If it says Permissive, denials are logged but not applied — so it is *not* your cause, and you should look elsewhere. 2. **Look for the denial.** Enforcement decisions that refuse an operation are logged as denial records by the audit subsystem. Reproduce the failure and look at the audit log for entries written at that instant; the record names the process, the operation and the target, and its presence is direct evidence rather than inference. 3. **Prove causation if you still need to.** Temporarily switch to permissive with `setenforce 0`, retry the operation, and switch back with `setenforce 1` immediately. If the operation succeeds in permissive and fails in enforcing, you have your answer. This is a diagnostic step measured in seconds, not a configuration change — a host left permissive is a host that quietly lost the property it was chosen for. Note that `setenforce` is a runtime toggle only; it does not survive a reboot, which is a useful safety property when you are experimenting on someone else's server. ## The patterns that trigger it during a migration Without going into how policy is written, these are the shapes of change that reliably produce a denial on RHEL and nothing at all on a stock Ubuntu box: - Application data placed under a non-standard directory — an application root somewhere convenient rather than where the policy expects that kind of content to live. - Files moved into place rather than created there, or unpacked from an archive built on another system, so they arrive carrying the wrong classification. - A daemon listening on an unusual port number. - A service reaching outside its expected footprint — writing where it normally only reads, or opening a network connection when nothing it normally does requires one. Recognising the *shape* is the senior skill here: you can predict during planning which parts of a migration will need policy attention, rather than discovering them one production incident at a time. ## The fixes, ranked The correct resolution is to bring the deployment into line with policy, or to extend policy deliberately for this workload. Both are ordinary, supported operations with their own tooling. What is not acceptable, in an interview or in production: - Widening file permissions until the error goes away. It does not address a policy denial at all, and it leaves a genuine permissions defect behind — you have weakened one control while the other still refuses. - Disabling enforcement globally so the deployment can proceed. On a platform picked for its security posture, this converts a fixable packaging problem into an audit finding, and it will be discovered by someone other than you. - Assuming the RHEL host is misconfigured. It is at its defaults; the Ubuntu host was the permissive one. Build the policy work into the migration plan as a known workstream, and the surprise stops being a surprise.

  • If getenforce reports Permissive, can mandatory access control still be your cause?
    No — in permissive mode the decision is logged but never applied, so nothing is actually refused on that basis. Those logged denials are still useful, because they are a preview of what would break in enforcing mode, but for a live permission-denied failure you should look at ownership, mode bits, the process's effective user, mount options and any container or namespace boundary instead.
  • Why is disabling enforcement to unblock a deployment a poor answer even when it works?
    Because it removes the property the platform was chosen for. In most shops RHEL's default posture is what a compliance profile or a security sign-off depends on, so turning it off converts a solvable packaging problem into an audit finding — and it is a change nobody remembers making six months later when someone asks why this host differs from the rest of the fleet.
  • How would you make this class of surprise less likely on the next migration?
    Test on the target platform early rather than at cutover, with enforcement on, so denials surface during development. Standardise where application data lives instead of improvising per service, create files in place rather than relocating them from elsewhere, and treat any non-standard port or unusual access pattern as a flagged item in the migration plan needing policy work.

saying these in an interview costs you the question

  • Concludes the RHEL host is misconfigured out of the box.
  • Fixes a policy denial by widening file permissions.
  • Recommends disabling enforcement permanently to ship.
  • Assumes Ubuntu enforced the same controls on a custom service.
  • Blames the application without checking for denial records.

context