09 · Cloud identity and container boundaries
Depth: developed lesson · Prerequisites: foundations, Linux and networking, identity models · Time: three 90-minute sessions.
Cloud and container investigations often fail at the same point: a visible label is mistaken for effective authority. An identity policy is one input to a cloud decision. A container's configured user is one input to its host boundary. In both cases, trace the actor through the relevant controls to the resource and operation being assessed.
This chapter uses original policy and configuration worksheets, plus optional inspection of an existing disposable container. It provisions no cloud resources. Provider-specific AWS/Azure/GCP labs and Kubernetes remain deeper material to develop.
Outcomes
- Distinguish management-plane actions from actions on application data.
- Evaluate a small explicit policy and preserve the limits of that model.
- Explain why an image, container, host and workload identity are separate objects.
- Review mounts, user, privileges and network exposure as a connected boundary.
- Separate declared configuration, inspected runtime configuration and demonstrated behavior.
Session 1: reason about policy combinations
A cloud action has an identity, an API operation, a resource and request context. Reading stored data and changing the policy that governs that data are different operations. The second may change what future requests can do, so a data-access review must also examine who can modify the controlling policy.
AWS documents policy evaluation as a combination of applicable policy types, including identity/resource policies and limiting controls such as permission boundaries and organization policies. Explicit deny can override allow, but the exact combination depends on the scenario. Do not treat a single visible allow statement as a complete effective-permission result. AWS policy evaluation logic.
The following fictional teaching policy is not an AWS policy interpreter. It has no conditions, wildcards, cross-account rules, nested roles or service-specific exceptions. Its contract is: deny if an exact request appears in the deny set; otherwise allow only exact requests in the allow set; otherwise deny by default.
allow = {
('reader', 'read', 'training-report'),
('editor', 'read', 'training-report'),
('editor', 'write', 'training-report'),
('deployer', 'change-policy', 'training-report'),
}
deny = {('editor', 'write', 'training-report')}
cases = [
('reader', 'read', 'training-report'),
('reader', 'write', 'training-report'),
('editor', 'read', 'training-report'),
('editor', 'write', 'training-report'),
('deployer', 'change-policy', 'training-report'),
('deployer', 'read', 'training-report'),
]
for request in cases:
decision = 'deny' if request in deny else 'allow' if request in allow else 'deny'
print(request, decision)
Save and run this block as a private Python exercise. Predict the decisions first.
Worked results
Allow, deny, allow, deny, allow, deny. The editor's exact deny defeats its exact allow. The deployer has no current read grant in this model, but its policy-change permission is a separate control-plane authority worth investigating. Whether it could grant itself read access depends on the policy-change constraints, which this static evaluator does not implement.
Draw the missing policy-change edge and label it unresolved, rather than announcing that the deployer already read the report. This is the same prerequisite discipline used in Windows path reasoning.
Session 2: inspect the container boundary on paper
An image identifies packaged filesystem content and configuration. A container is an instance with runtime settings and possible writable state. The host and its container engine control another boundary. A workload may also hold an external cloud identity; local process permissions and cloud API permissions must be assessed separately.
Docker's security model involves kernel isolation, resource controls, daemon access and configuration. Granting a container powerful host access can weaken isolation regardless of its application label. A reduced user or capability set is useful evidence, but it is not proof that every host boundary holds. Docker Engine security.
Compare these fictional inspection summaries, not runnable Compose files:
| Setting | Workload A | Workload B |
|---|---|---|
| User | Explicit non-root UID 10001 | UID 0 |
| Privileged mode | false | true |
| Root filesystem | read-only | writable |
| Mounts | One read-only synthetic input directory | Host root directory read-write; Docker control socket |
| Published listener | Loopback only | All host interfaces |
| Cloud role | Read one training object | Change role policy and read broad data scope |
For each row, write the resource exposed and an observation needed to verify the claimed boundary. Prioritize B's host/control access rather than arguing only about image names. A read-only root filesystem does not automatically make every mounted path read-only; examine mounts individually. Docker bind mounts connect host paths to container paths and can be configured read-only or writable. Docker bind-mount documentation.
Now change one fact: A retains a read-only filesystem but receives a cloud role that can rewrite access policy. Which earlier conclusion changes? Local filesystem restrictions cannot establish least privilege for an external API. Keep both kinds of authority on the diagram.
Session 3: optional runtime configuration inspection
Use only an existing disposable container that you own, identified in your lab scope. This exercise does not start, pull, restart or alter containers. Record the Docker context before inspecting so you do not accidentally treat a remote engine as your local lab.
docker context show
docker version
After confirming the context and substituting the exact lab container name, inspect selected fields:
DeadwireLabContainer='your-owned-lab-container'
docker container inspect --format '{{.Name}} user={{.Config.User}} image_id={{.Image}}' "$DeadwireLabContainer"
docker container inspect --format 'privileged={{.HostConfig.Privileged}} readonly_root={{.HostConfig.ReadonlyRootfs}} network={{.HostConfig.NetworkMode}}' "$DeadwireLabContainer"
docker container inspect --format '{{json .Mounts}}' "$DeadwireLabContainer"
docker container inspect --format '{{json .NetworkSettings.Ports}}' "$DeadwireLabContainer"
Docker's inspection command supports formatted field output. These commands read configuration; they do not test an escape or cloud permission. Keep mount paths and identifiers private. Docker inspect reference.
An empty configured user is an unresolved effective-identity question, not proof of a particular UID throughout runtime. The reported image ID identifies the local image object; it is not automatically evidence of a trusted publisher or a verified registry signature. Ports describe the engine's reported mapping, not an end-to-end firewall test.
If no disposable container exists, complete the two worksheets and mark runtime inspection pending. Do not inspect Deadwire's operational containers merely to produce a student transcript, and do not claim a reference-checked command was executed in your lab.
Turn observations into a least-privilege review
Write one paragraph for each boundary: identity to API, workload to filesystem, workload to network, and workload to engine. For each, state required access, observed access and unexplained excess. A useful remediation proposal preserves the required operation and removes a specific unnecessary authority.
Plan both a positive and negative retest: the workload still reads the permitted training object, but an unrelated object request is denied; the application still consumes its input, but cannot modify that read-only mount. These are proposed tests until performed in an authorized lab.
Evidence and acceptance
Save the six policy decisions, the container comparison and an authority diagram that includes policy modification. Add redacted runtime inspection only if performed. Acceptance requires explaining why neither a single allow statement nor a non-root user label establishes the entire security boundary.
Safety and scope
No cloud account, credentials or paid resources are needed for the worksheets. The optional Docker commands inspect one owned lab container. Do not mount the host root or control socket to recreate fictional workload B; its deliberately excessive configuration is a paper exercise.
Teach-back
- Why is changing a resource policy different from reading the resource?
- Which real-provider rules are absent from the six-case evaluator?
- Why can a read-only container still have excessive cloud authority?
- What separates an image identifier from trusted image provenance?
Continue: 10 · Code and byte analysis, then 14 · Cryptography and secure engineering.