Hardening and Execution Restrictions in Containers
🌟 Objective
Strengthen the security of container execution through reduction of the attack surface, removal of unnecessary components and explicit restriction of runtime permissions, ensuring that each container runs only what is necessary, with the least privilege possible.
In the modern SSDLC, hardening cannot be treated as a declared intention.
It is necessary to ensure that the restrictions defined are effectively applied and verifiable at execution time.
These measures complement the choice of secure images and the validation of their provenance, reducing the impact of exploitable vulnerabilities, configuration errors and runtime abuse.
🧬 What container hardening means
Container hardening consists of the systematic application of measures that:
- Remove unnecessary binaries and packages (e.g.
curl,bash,ping); - Prevent execution as
root; - Restrict kernel
capabilitiesto what is strictly necessary; - Limit syscalls and interactions with the host (seccomp, AppArmor, SELinux);
- Apply immutability to the filesystem;
- Block dangerous interfaces such as
/proc,/sysor the Docker socket.
🧱 A container can only be considered hardened if the effective runtime state matches what was defined in the build and in the manifests.
⚠️ Configured hardening ≠ effective hardening
One of the most common errors in automated environments is to assume that:
- a well-written
Dockerfile, - a defined
securityContext, - or an applied policy,
automatically guarantee a secure runtime.
In practice, there are three distinct states:
- Declared hardening
What is defined in code or configuration. - Applied hardening
What the platform actually attempts to apply. - Effective hardening
What can be empirically observed in the running container.
This chapter explicitly treats hardening as a verifiable state, not as an assumed property.
📘 Examples of hardening practices
| Practice | Technique / Mechanism | Operational observations |
|---|---|---|
| Non-root user | USER in the Dockerfile | Must be validated at runtime |
| Read-only FS | readOnlyRootFilesystem: true (K8s) | Requires verification of mounts |
| Minimal capabilities | drop: ALL + explicit add | Avoid permissive defaults |
| Seccomp | runtime/default or custom profile | Confirm the active profile |
| AppArmor / SELinux | Restrictive profiles | Depends on host support |
| Unprivileged execution | No --privileged, no Docker socket | Must be blocked by policy |
🛠️ How to apply and verify at build and runtime
1️⃣ At build (image)
- Define a non-root user (
USER); - Avoid installing interactive tools;
- Minimise
ENTRYPOINTandCMD; - Add security and context labels;
- Validate the Dockerfile with linters (e.g. Hadolint).
The build defines intentions; it does not guarantee application.
2️⃣ At deploy (orchestration / CI/CD)
- Define an explicit
securityContext:runAsNonRoot: truereadOnlyRootFilesystem: trueallowPrivilegeEscalation: falsecapabilities: drop: ["ALL"]
- Apply Pod Security Standards / PSA;
- Enforce through OPA or Kyverno (see
05-policies-runtime-opa.md).
Technical enforcement blocks insecure configurations, but does not validate the real state.
3️⃣ At runtime (effective verification)
- Verify the effective user (
id,/proc/self/status); - Validate mounts and permissions;
- Confirm that the seccomp/AppArmor profile is active;
- Detect deviations (drift) from the expected configuration;
- Record results for audit.
Without this verification, hardening is merely assumed, not demonstrated.
📂 Where to configure and control
- Dockerfile: minimal and reproducible baseline;
- Manifests / Helm charts: declarative definition of restrictions;
- CI/CD: automatic validation of insecure configurations;
- Admission Controllers: centralised enforcement;
- Runtime monitoring: empirical confirmation of the state.
Each layer reduces the likelihood of error, but none is sufficient on its own.
✅ Good practices
- Define hardening profiles by workload type;
- Prohibit privileged containers by policy;
- Validate hardening after deploy, not only before;
- Treat exceptions as formal and temporary decisions;
- Review hardening after platform or kernel changes;
- Integrate continuous runtime verification in critical environments.
📎 Cross-references
| Document | Relation to hardening |
|---|---|
01-imagens-base.md | Minimisation of the surface in the image |
02-runners-isolamento.md | Isolation of the execution environment |
05-policies-runtime-opa.md | Technical enforcement of restrictions |
08-kubernetes-execucao.md | Practical application in clusters |
09-riscos-processo-imagens.md | Difference between intention and effective state |
🔐 Hardening only exists when it can be observed, reproduced and audited.
Configuration without verification is merely assumption.