Problem
Exposing port 22 encourages SSH-in-container operations and increases attack surface. This conflicts with immutable infrastructure and controlled release workflows. Action: expose only application ports and use orchestrator-native access paths for operations.
Description
Containers should be rebuilt and redeployed, not patched interactively over SSH. Shell-based hot fixes bypass code review and are difficult to audit. Action: remove SSH daemons and SSH-related runbook steps from application images.
EXPOSE is metadata, but metadata influences docs, compose defaults, and internal tooling. Declaring port 22 normalizes an insecure operations model and increases accidental exposure risk in lower environments. Action: add a policy check that blocks EXPOSE 22 unless a documented exception exists.
Operational access should use logs, metrics, debug sidecars, and controlled kubectl exec with RBAC. These paths preserve audit trails and align with platform controls. Action: document approved debugging workflows so engineers do not fall back to SSH during incidents.
Use this rollout checklist to retire SSH patterns:
- Block
EXPOSE 22in Dockerfile linting and CI. - Remove SSH server packages from runtime images.
- Provide incident debugging runbooks that use platform-native access.
- Track migration deadlines for any legacy workload exceptions.
Treat verification as part of the rule, not optional cleanup. Action: automate a static check, a build check, and a runtime smoke check in the default CI pipeline so regressions are caught before review.
- Static check: fail when the disallowed pattern appears in Dockerfile or manifest.
- Build check: run a minimal image build to confirm the secure pattern is valid.
- Runtime check: start the workload and assert expected behavior with one deterministic probe.
Examples of code
Problematic code
FROM ubuntu:24.04
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]Verified code
FROM ubuntu:24.04
EXPOSE 8080
CMD ["./app-server"]