Separate identity proof from permission decisions, then design AtlasMart human/service roles that keep application data access distinct from cluster administration, backup, and monitoring.

Authentication, Authorization, Roles, Service Identities, and Least Privilege

AtlasMart begins security engineering by separating identity proof from permission and by giving each workload only the data-plane or control-plane authority it actually needs.

Advanced120–155 minutesLeast-privilege policy labPython 3.13+ · standard libraryVendor-neutral · free/local mandatory pathLast reviewed: August 2026
01

Separate authentication, authorization, and accounting/audit responsibilities before assigning permissions.

02

Distinguish human identities from workload/service identities and avoid shared database superusers.

03

Design roles for application read/write, monitoring, backup, and cluster administration using least privilege.

04

Use bounded credential lifetimes and observable denied/allowed actions without assuming short-lived credentials are available in every product.

1. A service account should not be a cluster administrator

AtlasMart's catalog API needs to read products. Its order service needs to mutate orders. A backup job needs snapshot/backup access. An operator occasionally needs to change cluster membership. These are different security subjects with different duties. Authentication establishes who or what is connecting; authorization decides what that authenticated identity may do. Combining them into one shared superuser credential destroys the boundary that makes compromise containable.

A human identity represents a person and should usually flow through an organization identity provider with accountable elevation. A service identity represents a workload and should be bound to one service or automation purpose. Both require revocation, rotation, and audit, but their lifecycle and interaction patterns differ.

2. Role design starts from duties, not product defaults

Least privilege means granting the minimum operations and resource scope needed for the current duty. It is not merely “read-only vs read-write.” Distributed databases expose data-plane operations, topology/configuration control, backup/restore, metrics, repair, user/role management, and sometimes cloud-project administration. A role that can read catalog rows should not automatically be able to add nodes, alter replication, read backups, or create new privileged users.

Identity Needed permissions Should not have
catalog-api Catalog read on its namespace Cluster admin, backup, role management
orders-api Order read/write inside owned boundary Unrelated tenant/catalog admin
monitor-service Metrics/health metadata Business-data mutation
backup-service Backup create/read and required key access Normal application writes
on-call operator Time-bounded approved admin scope Permanent shared superuser

3. Observable request path

A useful security trace records identity, credential type, requested resource/action, authorization decision, policy/role version, and correlation ID—without logging reusable secrets. The decision “authenticated but denied cluster:write” is valuable evidence: it proves identity validation succeeded but the role boundary stopped privilege escalation. Conversely, a successful request only proves the evaluated policy allowed it; it does not prove the caller's host is uncompromised or the action was business-appropriate.

Security boundary

Application permissions and cluster-management permissions are separate attack surfaces. Treating database access as one broad privilege domain turns an application vulnerability into a topology, backup, and identity-management incident.

4. Deliberately wrong approach: a shared superuser in every service

Teams sometimes start development with one powerful credential and then carry it into production. If AtlasMart's catalog service is compromised, the attacker can then mutate orders, alter roles, or reconfigure the cluster even though the catalog workload never needed those operations. Shared credentials also make attribution weak: audit records tell you which credential acted, not which workload/person actually controlled it.

The repair is role separation plus individual workload identities, explicit resource scopes, credential rotation/revocation, and audited emergency elevation. Where the platform supports short-lived credentials, prefer them; otherwise simulate the same lifecycle with frequent rotation and narrow secrets rather than claiming every product has identical token semantics.

5. AtlasMart lab: authenticate, authorize, expire, deny

Mandatory lab environment

Python 3.13+ standard library only; verified with Python 3.13.5. This is a policy simulator, not a real identity provider or database ACL engine. No database server, directory service, cloud IAM, password, token, or privileged OS access is required.

python · AtlasMart deterministic simulation
from dataclasses import dataclass

PERMISSIONS = {
    "catalog_reader": {"catalog:read"},
    "order_writer": {"orders:read", "orders:write"},
    "backup_service": {"backup:create", "backup:read"},
    "monitor_service": {"metrics:read"},
    "cluster_admin": {"cluster:read", "cluster:write", "roles:write"},
}

@dataclass
class Identity:
    name: str
    kind: str
    roles: tuple
    expires_at: int

identities = {
    "catalog-api": Identity("catalog-api", "service", ("catalog_reader",), 120),
    "orders-api": Identity("orders-api", "service", ("order_writer",), 120),
    "backup-job": Identity("backup-job", "service", ("backup_service",), 105),
    "oncall-alice": Identity("oncall-alice", "human", ("cluster_admin",), 103),
}

def authenticate(name, now):
    ident = identities.get(name)
    if ident is None:
        return None, "unknown identity"
    if now >= ident.expires_at:
        return None, "credential expired"
    return ident, "authenticated"

def authorize(ident, permission):
    granted=set()
    for role in ident.roles:
        granted |= PERMISSIONS[role]
    return permission in granted

def attempt(name, permission, now):
    ident, reason = authenticate(name, now)
    if not ident:
        return (name, permission, "DENY", reason)
    return (name, permission, "ALLOW" if authorize(ident, permission) else "DENY",
            "role policy")

print("SEPARATE AUTHENTICATION FROM AUTHORIZATION")
for req in [
    ("catalog-api", "catalog:read", 100),
    ("catalog-api", "cluster:write", 100),
    ("backup-job", "backup:create", 100),
    ("backup-job", "orders:write", 100),
    ("oncall-alice", "cluster:write", 100),
    ("oncall-alice", "cluster:write", 104),
]:
    print(attempt(*req))

print("\nBROKEN SHARED SUPERUSER")
shared_permissions={"catalog:read","orders:read","orders:write","backup:create","backup:read","metrics:read","cluster:read","cluster:write","roles:write"}
print("compromised catalog process can cluster:write:", "cluster:write" in shared_permissions)

print("\nREPAIRED LEAST PRIVILEGE")
print("catalog-api cluster:write:", attempt("catalog-api","cluster:write",100))
print("orders-api orders:write:", attempt("orders-api","orders:write",100))
print("monitor-service modeled role permissions:", sorted(PERMISSIONS["monitor_service"]))
print("short-lived on-call credential expires at t=103; use a fresh audited grant for later emergencies")
Expected evidence

The catalog identity can read catalog data but is denied cluster:write; the backup identity cannot mutate orders; and the on-call credential stops authenticating after its simulated expiry. The broken shared-superuser model demonstrates why credential compromise must not imply control-plane compromise.

6. Production judgment

Measure denied-operation rate, authentication failures, stale/unused privileged roles, credential age, break-glass usage, role-change events, and unexpected data-plane identities calling admin endpoints. Keep service identities unique enough to attribute actions. Protect the identity store itself, and ensure backup/monitoring roles do not become hidden read-all pathways to regulated data.

PostgreSQL 18 explicitly separates connection authentication from role-based privileges. Its current documentation also supports certificate-based client authentication over TLS. These are implementation anchors, not a requirement to use PostgreSQL in the chapter.

The next lesson asks what happens after identity is correct but sensitive bytes cross networks, memory, storage, snapshots, and backups.

Check your understanding

  1. What is the difference between authentication and authorization?
  2. Why are service identities preferable to one shared application login?
  3. Why should monitoring and backup use distinct roles?
  4. What does a denied admin request from an authenticated application identity prove?
  5. Why is permanent superuser access a poor break-glass mechanism?
Review the answers

1. Authentication establishes the identity of a caller; authorization evaluates whether that authenticated identity may perform an action on a resource.

2. They constrain privilege and improve attribution, rotation, revocation, and blast-radius control per workload.

3. They need different operations and data scopes; combining them creates unnecessary access paths and weakens incident containment.

4. The identity was recognized but policy prevented that action; it does not prove the caller itself is trustworthy.

5. It creates standing privilege. Emergency access should be time-bounded, approved, scoped, audited, and reviewed.

References

Foundational claims use standards, specifications, primary research, or current official documentation where practical. Product references are optional implementation anchors; the mandatory labs are vendor-neutral.

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.