Chapter 06Lesson 03~60 minutes

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.

BeginnerOwnershipDeployment identities

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, and getent.
  • Use chgrp and chown with 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.

From inode IDs to displayed account names
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.

CommandResultPrivilege expectation
chgrp GROUP FILEChange group onlyOwner may select a group they belong to
chown USER FILEChange owner onlyNormally privileged
chown USER:GROUP FILEChange bothNormally privileged
chown :GROUP FILEChange group onlySame group restrictions apply
file="$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.

01Application content

Owned by the deployment authority; the runtime identity normally reads but does not modify it.

02Secrets

Owned by a tightly controlled identity with the narrowest readable group or ACL.

03Logs and state

Writable by the runtime account or a dedicated service group.

04Shared maintenance

A group can encode a team role more safely than world-writable modes.

05CI workspaces

Owned consistently by the runner identity to prevent cleanup and cache failures.

Do not solve identity design with broad permissions

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 sort

On 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.

Next lesson

umask, Special Bits, and Shared Directories

The next lesson explains how default modes are derived and how setgid, sticky, and setuid semantics affect shared and privileged objects.

10. Further reading

  • Linux man-pages: chown(2), chown(1), credentials(7), and user_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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.