Skip to content

Container hardening guides

Every guide below takes one popular Docker image, grades its default docker run on IronClaw's seven-dimension containment scale, and shows the exact ironctl scan --fix flags that close the gap. The grades are not hand-waved: each default grade comes from a read-only inspect of a running container started from the real image with plain docker run defaults, its entrypoint overridden with sleep purely to keep it alive. The scan itself executes nothing inside the container. It is the same data behind that image's isolation scorecard.

Two patterns show up across the set:

  • Datastores and sandboxes reach grade A. A database or a code sandbox that only its co-located services talk to can take --network=none and hit 100/100. Root, capabilities, and a read-only rootfs are the whole game.
  • Network services hit an honest ceiling at grade B. A broker, cache, proxy, or secrets server exists to be connected to, so --network=none would score the last points but break the service. The honest ceiling is 89/100, grade B, with the network dimension held at a WARN and contained with a scoped private network instead. We say so on every page rather than inflate the number.

Hardening once is the easy half. To keep the grade you just earned, put the same grader on every pull request with the GitHub Action: one uses: IronSecCo/ironclaw@v1 line, about 30 seconds, no account and no credentials.

Reach grade A (100/100)

Service Default Hardened The gap that closes
Postgres 48/100 D 100/100 A root, full caps, writable rootfs
MySQL 48/100 D 100/100 A root, full caps, writable rootfs
MariaDB 48/100 D 100/100 A root, full caps, writable rootfs
MongoDB 48/100 D 100/100 A root, full caps, writable rootfs
Redis 48/100 D 100/100 A root, full caps, writable rootfs
Cassandra 48/100 D 100/100 A root, full caps, writable rootfs (89/B multi-node)
ClickHouse 48/100 D 100/100 A root, full caps, writable rootfs
Elasticsearch 63/100 C 100/100 A full caps, writable rootfs (89/B multi-node)
InfluxDB 48/100 D 100/100 A root, full caps, writable rootfs (89/B if fleet pushes metrics)
Neo4j 48/100 D 100/100 A root, full caps, writable rootfs (89/B if clustered or remote clients)
CouchDB 48/100 D 100/100 A root, full caps, writable rootfs (89/B if clustered or remote clients)
QuestDB 48/100 D 100/100 A root, full caps, writable rootfs (89/B if a fleet pushes metrics)
CockroachDB 48/100 D 100/100 A root, full caps, writable rootfs (89/B if clustered or remote clients)
TimescaleDB 48/100 D 100/100 A root, full caps, writable rootfs (89/B with replicas or remote clients)
Valkey 48/100 D 100/100 A root, full caps, writable rootfs (89/B as a shared network cache)
Loki 63/100 C 100/100 A full caps, writable rootfs (89/B if a fleet pushes logs)
Tempo 63/100 C 100/100 A full caps, writable rootfs (89/B if a fleet pushes traces)
Meilisearch 48/100 D 100/100 A root, full caps, writable rootfs (89/B if remote clients)
YugabyteDB 48/100 D 100/100 A root, full caps, writable rootfs (89/B multi-node cluster)
Dragonfly 48/100 D 100/100 A root, full caps, writable rootfs (89/B as a shared network cache)
OpenSearch 63/100 C 100/100 A full caps, writable rootfs (89/B multi-node cluster)
Qdrant 48/100 D 100/100 A root, full caps, writable rootfs
ArangoDB 48/100 D 100/100 A root, full caps, writable rootfs (89/B if clustered or remote clients)
Solr 63/100 C 100/100 A full caps, writable rootfs (89/B multi-node cluster or remote clients)
VictoriaMetrics 48/100 D 100/100 A root, full caps, writable rootfs (89/B if a fleet pushes metrics)
ScyllaDB 48/100 D 100/100 A root, full caps, writable rootfs (89/B multi-node cluster)
Dgraph 48/100 D 100/100 A root, full caps, writable rootfs (89/B if clustered or remote clients)
Weaviate 48/100 D 100/100 A root, full caps, writable rootfs (89/B if remote clients)
RethinkDB 48/100 D 100/100 A root, full caps, writable rootfs (89/B if clustered or remote clients)
TiDB 48/100 D 100/100 A root, full caps, writable rootfs (89/B production cluster or remote clients)
Untrusted Node.js 48/100 D 100/100 A run untrusted code in a real sandbox

Honest ceiling: grade B (89/100)

These services must accept client connections, so the network dimension holds at a WARN by design.

Service Default Hardened Why 89 is the ceiling
Kafka 63/100 C 89/100 B broker: producers and consumers must connect
RabbitMQ 48/100 D 89/100 B broker: every service connects to the queue
Memcached 63/100 C 89/100 B cache: clients read and write over the network
nginx 48/100 D 89/100 B proxy: it exists to forward traffic
Vault 48/100 D 89/100 B secrets server: apps must reach the API
Consul 48/100 D 89/100 B service mesh: peers and clients must connect
ZooKeeper 48/100 D 89/100 B coordination server: peers and clients must connect
MinIO 48/100 D 89/100 B object store: S3 clients must reach the API
Grafana 63/100 C 89/100 B dashboard: browsers must reach the UI
Prometheus 63/100 C 89/100 B metrics: it scrapes targets and serves its API
Traefik 48/100 D 89/100 B proxy: it exists to accept and forward traffic
Jenkins 63/100 C 89/100 B CI server: agents and browsers must reach it
SonarQube 63/100 C 89/100 B code-quality server: scanners and browsers must reach it
Keycloak 63/100 C 89/100 B identity provider: every app must reach its endpoints
NATS 48/100 D 89/100 B broker: publishers and subscribers must connect
Gitea 48/100 D 89/100 B git server: developers and CI must reach it
HAProxy 63/100 C 89/100 B load balancer: it exists to accept and forward traffic
Typesense 48/100 D 89/100 B search server: your app must reach its query API
Immich 48/100 D 89/100 B photo server: browsers and mobile apps must reach it
pgAdmin 63/100 C 89/100 B admin console: your browser must reach the UI
Redpanda 63/100 C 89/100 B broker: producers and consumers must connect
EMQX 63/100 C 89/100 B MQTT broker: publishers and subscribers must connect
Kong 63/100 C 89/100 B API gateway: clients and upstreams connect through it
Envoy 48/100 D 89/100 B proxy: it exists to accept and forward traffic
Pulsar 63/100 C 89/100 B broker: producers and consumers must connect
NSQ 48/100 D 89/100 B broker: publishers and subscribers must connect

The pattern, one command

Every grade on this page comes from the same tool. Point it at any running container, a docker-compose.yml service, or a Kubernetes manifest, and it grades the real thing, then prints the fixes:

# install (Homebrew)
brew install ironsecco/ironclaw/ironclaw

# grade it, then print the exact hardening flags
ironctl scan my-container
ironctl scan my-container --fix

Want it in CI? The same engine ships as a GitHub Action on the Marketplace that scores every pull request and posts the grade as a sticky comment.

Keep going