Ownership with chown and chgrp
Permission bits are interpreted relative to an object’s owner and group. That makes ownership part of the authorization policy, not merely descriptive metadata. This lesson explains numeric UID/GID identity, what ordinary users may change, how service accounts and shared groups use ownership, and how to audit drift without damaging a filesystem tree.
Learning objectives
By the end of this lesson
- Explain why files store numeric UID and GID values rather than account names.
- Inspect owner/group mappings with
stat,id, andgetent. - Use
chgrpandchownwith explicit targets and verification. - Recognize recursive ownership, symlink, archive, container, and network-filesystem hazards.
- Build an ownership audit for a deployment tree.
1. Files store numeric identities
An inode records a numeric user ID and group ID. Tools resolve those numbers through local or network identity databases to display names. If the mapping is absent, ls -n and stat still reveal the authoritative numbers.
flowchart LR I["Inode metadata
UID 1001 / GID 2001"] --> N["Name-service lookup
local files, LDAP, SSSD, etc."] N -->|mapping exists| D["Display deploy:appteam"] N -->|mapping missing| X["Display numeric 1001:2001"] P["Process effective UID
and supplementary GIDs"] --> A["Permission-class selection"] I --> A
target="$HOME/devops-academy/linux/chapter06/lesson03"
mkdir -p -- "$target"
printf 'artifact=true
' > "$target/artifact.conf"
id
ls -ln -- "$target/artifact.conf"
stat -c 'uid=%u user=%U gid=%g group=%G mode=%a name=%n' -- "$target/artifact.conf"
getent passwd "$(id -u)"
getent group "$(id -g)"Names are administrative labels. Numeric consistency matters when extracting archives, mounting shared storage, running rootless containers, or moving files between systems with different account databases.
2. Ownership changes have privilege boundaries
An ordinary user generally cannot transfer a file to another user. Otherwise, users could evade quotas or cause another identity to own hostile content. The owner may usually change a file’s group to one of the owner’s supplementary groups. Root or an appropriately privileged process can assign arbitrary owners and groups.
chgrp GROUP FILEChange group onlyOwner may select a group they belong tochown USER FILEChange owner onlyNormally privilegedchown USER:GROUP FILEChange bothNormally privilegedchown :GROUP FILEChange group onlySame group restrictions applyfile="$HOME/devops-academy/linux/chapter06/lesson03/artifact.conf"
primary_group=$(id -gn)
# Safe for a file you own: assign your primary group explicitly.
chgrp -- "$primary_group" "$file"
# Equivalent group-only chown form.
chown -- ":$primary_group" "$file"
stat -c '%U:%G %u:%g %a %n' -- "$file"3. Service ownership should follow responsibility
A typical deployment separates the identity that owns immutable application content from the identity that runs the service. For example, root or a deployment account may own binaries and configuration, while a service account receives write access only to runtime directories through group ownership or ACLs.
Owned by the deployment authority; the runtime identity normally reads but does not modify it.
Owned by a tightly controlled identity with the narrowest readable group or ACL.
Writable by the runtime account or a dedicated service group.
A group can encode a team role more safely than world-writable modes.
Owned consistently by the runner identity to prevent cleanup and cache failures.
If a service cannot write because the tree belongs to the wrong account, chmod 777 obscures the ownership error and expands access to every local user.
4. Recursive ownership changes can cross boundaries
chown -R can alter thousands of objects and may interact with symlinks or mount points in surprising ways. Use a precise root, preview with find, stay on one filesystem when appropriate, and avoid following untrusted links.
root="$HOME/devops-academy/linux/chapter06/lesson03/release"
mkdir -p -- "$root/bin" "$root/config" "$root/state"
# Preview owner/group state without changing it.
find "$root" -xdev -printf '%u:%g %m %y %p
' | LC_ALL=C sort
# Find objects that do not match the expected current owner/group.
expected_user=$(id -un)
expected_group=$(id -gn)
find "$root" -xdev \( ! -user "$expected_user" -o ! -group "$expected_group" \) -print
# Bounded repair for a tree you own.
chown -R -- "$expected_user:$expected_group" "$root"
find "$root" -xdev -printf '%u:%g %p
' | LC_ALL=C sortOn production paths, snapshot or inventory before repair. Package managers may expect specific ownership, and changing system paths recursively can make services unbootable or weaken security.
5. Numeric ownership explains container and archive surprises
Container processes and host processes may use different names for the same numeric IDs—or the same names for different IDs. Bind-mounted files are authorized by numeric identity. Archives can preserve numeric ownership, and privileged extraction may recreate it. Network filesystems may remap root or rely on centralized identity.
# Archive without requiring privileged owner restoration in the lab.
lab="$HOME/devops-academy/linux/chapter06/lesson03"
tar -czf "$lab/release.tar.gz" -C "$lab" release
# Inspect archive owner/group fields before extraction.
tar -tvzf "$lab/release.tar.gz"
# On extraction as an ordinary user, explicitly avoid restoring ownership.
mkdir -p -- "$lab/restored"
tar --no-same-owner -xzf "$lab/release.tar.gz" -C "$lab/restored"6. Hands-on lab: audit deployment ownership
set -eu
lab="$HOME/devops-academy/linux/chapter06/lesson03"
root="$lab/deployment"
rm -rf -- "$root"
mkdir -p -- "$root/bin" "$root/config" "$root/state"
printf '#!/usr/bin/env bash
echo ready
' > "$root/bin/check"
printf 'port=8080
' > "$root/config/app.conf"
printf 'counter=0
' > "$root/state/runtime.db"
chmod 750 -- "$root/bin" "$root/bin/check"
chmod 640 -- "$root/config/app.conf"
chmod 700 -- "$root/state"
user=$(id -un)
group=$(id -gn)
chown -R -- "$user:$group" "$root"
{
printf 'expected=%s:%s
' "$user" "$group"
printf '=== numeric and named ownership ===
'
find "$root" -xdev -printf '%U:%G %u:%g %m %p
' | LC_ALL=C sort
printf '=== unexpected owners ===
'
find "$root" -xdev \( ! -user "$user" -o ! -group "$group" \) -print
printf '=== unresolved identities ===
'
find "$root" -xdev \( -nouser -o -nogroup \) -print
} > "$lab/ownership-audit.txt"
cat -- "$lab/ownership-audit.txt"
test ! -s <(find "$root" -xdev \( ! -user "$user" -o ! -group "$group" \) -print)Verification checklist
7. Common ownership mistakes
Assuming names are stored in the file
Inodes store numeric IDs; names are resolved through identity databases.
Recursively chowning a broad system path
This can break package ownership, services, and security assumptions.
Ignoring container UID mappings
Bind mounts use numeric IDs, so matching names do not guarantee matching access.
Using ownership to replace team policy
A single owner is not a role model. Groups and ACLs express shared access more directly.
8. Knowledge check
Question 1. What does an inode store for owner and group: names or numbers?
Question 2. Why can an ordinary owner usually change a file to one of their groups but not to another user?
Question 3. Why can a bind-mounted file show an unexpected owner inside a container?
9. Summary
Ownership gives permission bits their identity context. Linux stores numeric UID/GID values, resolves them to names for display, restricts ownership transfer, and uses groups to represent shared roles. Safe ownership work is bounded, previewed, numerically audited, and conscious of archives, containers, network identity, and mount boundaries.
10. Further reading
- Linux man-pages:
chown(2),chown(1),credentials(7), anduser_namespaces(7). - GNU Coreutils manuals for
chown,chgrp, and ownership options. - GNU Tar manual for ownership preservation and extraction controls.
- Name Service Switch documentation for account and group resolution.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this address.