What are the security benefits and pitfalls of running Actuator on a separate management port?
answer
- management.server.port + management.server.address=127.0.0.1
- network segmentation = defense in depth
- separate child ManagementContext = separate security
- probes/LB health checks must be repointed
- management.server.ssl is independent of server.ssl
basics
~20 sSetting management.server.port to a different port than the app moves /actuator off the public port. Bind it to an internal address (management.server.address=127.0.0.1 or a private interface) so only ops/monitoring on the internal network can reach it, adding network-level isolation on top of Spring Security.
solid answer
~40 smanagement.server.port runs actuator on its own HTTP listener, separate from the application's server.port. The security value is network segmentation: you firewall or bind the management port to a private interface (management.server.address) so the internet-facing load balancer never routes to /actuator at all. This is defense in depth on top of the SecurityFilterChain. Pitfalls: the separate port spins up a distinct child management context with its own security auto-configuration, so your app's SecurityFilterChain may not apply there the way you expect — you must verify auth still guards it. EndpointRequest matchers are scoped per port. Also mind that health probes now hit the management port, load balancer health checks must be repointed, and TLS/cert config for the two ports is independent.
code
yaml · 14 linesserver:
port: 8080 # public application port
management:
server:
port: 8081 # actuator on its own listener
address: 127.0.0.1 # bind to loopback / private NIC only
ssl:
enabled: false # independent from server.ssl — set intentionally
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
# Still add a SecurityFilterChain — the internal port is NOT a substitute for auth.go deeper
Should know you can put actuator on a different port for isolation.
Should bind it to an internal address and know probes move with it.
Should explain separate-context security implications and treat it as layered, not a replacement for auth.
Should weigh network segmentation vs operational cost and design the port/TLS/probe/NetworkPolicy story end to end.
**The mechanism.** `server.port` is the application's listener; `management.server.port` (when set and different) makes Actuator serve from a **separate** embedded server on that port. Setting it to `-1` disables the web actuator entirely; setting it equal to `server.port` (or leaving it unset) keeps everything on one port. **Security benefits:** - **Network isolation.** The public load balancer / ingress only forwards to the app port. The management port can be bound to a private interface via `management.server.address=127.0.0.1` (or a VPC-internal NIC) so `/actuator` is physically unreachable from the internet — an attacker can't even attempt requests. This is a network control layered under the Spring Security control (defense in depth): a misconfigured filter chain no longer means public exposure. - **Independent hardening.** You can apply different firewall rules, mTLS, or a separate TLS cert on the management port, and expose it only to the monitoring subnet / Prometheus scraper / k8s node. - **Different base path / server config** without touching the app. **Pitfalls and gotchas:** - **Separate context = separate security.** A distinct management port creates a separate `ManagementContext` (a child web server). Spring Boot auto-configures security for it, but the app's custom `SecurityFilterChain` beans are wired into the **main** context and may not govern the management port the way you assume. You must explicitly verify that authentication still protects the endpoints on that port (test it). Never assume 'it's on an internal port so auth doesn't matter' — internal networks get breached (SSRF, compromised pod). - **`EndpointRequest` scoping.** The matcher matches within the context/port where the chain runs; mixing app-chain rules and a separate management port needs care. - **Probes move.** Kubernetes liveness/readiness and cloud LB health checks target `/actuator/health` — when it moves to the management port, those checks and NetworkPolicies must be repointed, or the pod appears unhealthy. - **TLS duplication.** `server.ssl.*` applies to the app port; the management port has its own `management.server.ssl.*`. Forgetting it can leave the management port plaintext. - **Context path differences.** `server.servlet.context-path` does not apply to the management port unless configured; base paths differ. **When to use:** valuable in production behind an orchestrator where you can bind the port to an internal interface and scrape it from an in-cluster monitoring stack. For simple single-port deployments the same-port + Spring Security + minimal exposure approach is often sufficient; the separate port is an added isolation layer, not a replacement for authentication.
- Does moving actuator to a separate internal port remove the need for Spring Security on it?No. Internal networks are breachable (SSRF, a compromised sibling pod, a misrouted proxy). The separate port is a network isolation layer; you still authenticate and authorize the endpoints. Defense in depth means both controls stay.
- What operational thing commonly breaks when you introduce a management port?Health checks. Kubernetes probes and load balancer health checks point at /actuator/health on the old port; they must be repointed to the management port (and NetworkPolicies/firewall updated) or the instance is marked unhealthy.
saying these in an interview costs you the question
- Treating an internal management port as a reason to skip authentication
- Assuming the app's SecurityFilterChain automatically governs the separate management context
- Forgetting management.server.ssl is separate from server.ssl
- Not repointing probes/LB health checks after the port change