Production readiness¶
The MCP Lifecycle Operator ships with defaults tuned for a fast getting-started experience: permissive network access, an allow-all egress posture for managed pods, and simple examples that skip external dependencies such as cert-manager. Those defaults are deliberately not what you want in production.
This page is aimed at platform and cluster operators. It is a hub that gathers the hardening and day-2 topics the operator supports, grouped by category. Each category links out to the detailed page where one already exists, and covers the configuration inline where it does not.
Note
These settings are independent - adopt them incrementally. Nothing here changes the operator's default behaviour; you opt in per concern.
Readiness checklist¶
| Area | Default | Production recommendation | Details |
|---|---|---|---|
| Managed-pod network isolation | Ingress open to any pod; egress allow-all | Restrict spec.network.ingressFrom / egressTo |
Network isolation |
| Gateway exposure | ClusterIP Service per server | Shared gateway via httproute or kuadrant |
Gateway integration |
| TLS posture | Go defaults | Pin TLS_MIN_VERSION / groups to policy |
TLS & transport security |
| Metrics endpoint | Served over HTTPS on 8443 |
Scrape over TLS; avoid insecureSkipVerify |
Metrics & monitoring security |
| Operator hardening | Non-root, read-only rootfs, all caps dropped | Keep the shipped securityContext; scope RBAC |
Operator hardening |
| Availability & resources | 1 replica, modest requests/limits | Size for load; plan storage migrations | Availability & operations |
Network isolation¶
The operator creates a NetworkPolicy for every managed MCP server pod. Out of the box that policy allows any pod in the cluster to reach the server port and lets the server pod egress anywhere. For production, and to align with the NSA CSI MCP Security guidance on designing for boundaries, restrict both directions through spec.network.
apiVersion: mcp.x-k8s.io/v1beta1
kind: MCPServer
metadata:
name: my-mcp-server
namespace: default
spec:
# ...
network:
# Only pods in the server's namespace carrying this label may reach it.
# Add a namespaceSelector to admit clients from other namespaces.
ingressFrom:
- podSelector:
matchLabels:
role: mcp-client
# The server pod may only egress to this CIDR on 443/TCP.
egressTo:
- ipBlock:
cidr: 10.0.0.0/8
egressPorts:
- port: 443
protocol: TCP
| Field | Effect when set | Effect when empty (default) |
|---|---|---|
network.ingressFrom |
Only the listed NetworkPolicyPeers can reach the server port |
Any pod in the cluster can connect |
network.egressTo |
Server pod may only reach the listed destinations | Egress to all destinations allowed |
network.egressPorts |
Restricts egress to the listed ports | All ports allowed to whatever egressTo permits |
network.dnsEgressPeer |
Scopes the automatic DNS rule to a specific destination | DNS (port 53) allowed to any destination |
NetworkPolicies are additive
These rows describe only the policy the operator manages. Kubernetes unions every NetworkPolicy that selects a pod, so another policy in the namespace can still admit broader ingress or egress than what you configure here. Audit the other policies that select the server pod when you rely on these restrictions.
DNS is always permitted when egress is restricted
As soon as egressTo or egressPorts is set, the operator prepends an egress rule allowing UDP and TCP port 53 so pods can still resolve names. Use dnsEgressPeer to narrow that rule to your cluster's DNS service. dnsEgressPeer on its own does not activate egress restrictions.
Peers use the standard Kubernetes NetworkPolicyPeer shape (podSelector, namespaceSelector, ipBlock); ipBlock cannot be combined with the selector fields. These constraints are checked during reconciliation, not by an admission webhook: an MCPServer with an invalid CIDR is still admitted by the API server and then reports a ValidationError status condition, so validate config before applying rather than relying on kubectl apply to reject it.
Gateway integration¶
Each MCP server is backed by a ClusterIP Service, reachable only from inside the cluster. To let clients outside the cluster reach servers through a shared ingress point - instead of wiring up external exposure per server - route them through a gateway. The operator ships two providers:
httproute- the Kubernetes Gateway API.kuadrant- the Kuadrant MCP Gateway. The provider creates theHTTPRouteandMCPServerRegistrationthat route MCP traffic through the gateway; it does not createAuthPolicyorRateLimitPolicyresources (configure those separately - see the tip below).
Set spec.gateway.provider and the operator manages an MCPGatewayBinding for you. Both providers require spec.gateway.configRef pointing at a ConfigMap with the gateway details; reconciliation fails without it. See the full Gateway Integration guide for provider configuration and examples.
Tip
For internet-facing deployments prefer the kuadrant provider, but expose an MCP server only after the applicable AuthPolicy and RateLimitPolicy resources are configured and verified at the gateway. Remember to supply its required configRef.
TLS & transport security¶
The controller manager serves its webhook and metrics endpoints over TLS, and opens an outbound TLS connection to each managed server to verify the MCP handshake. Both surfaces read the same profile from TLS_MIN_VERSION, TLS_CIPHER_SUITES, and TLS_GROUPS.
In production, pin these to your organization's crypto policy (or let a platform TLS profile such as an OpenShift TLSSecurityProfile supply them) instead of relying on Go defaults. The outbound client path enforces a TLS 1.2 floor that a permissive profile cannot lower.
See the TLS configuration page for the full variable reference, TLS 1.3 named groups, and post-quantum (X25519MLKEM768) availability.
Metrics & monitoring security¶
The operator exposes Prometheus metrics over HTTPS on port 8443. In production:
- Scrape the endpoint over TLS and provision the scraper with the CA so you can drop
insecureSkipVerify: truefrom anyServiceMonitor/PodMonitor. cert-manager is the usual way to issue the serving certificate. - Restrict who can reach
8443(RBAC on the metrics reader, and/or a NetworkPolicy on the operator namespace).
See the Metrics page for the full list of exposed metrics and their labels.
Operator hardening¶
The shipped controller Deployment already runs the manager container with a locked-down container-level securityContext (under spec.template.spec.containers[]) - keep it:
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
Additional hardening for production:
- RBAC - the operator installs with the ClusterRole it needs to manage MCP servers cluster-wide. If you run it scoped to specific namespaces, tighten the role bindings accordingly and review the granted verbs against your least-privilege baseline.
- Namespace isolation - apply a NetworkPolicy to the operator's own namespace so only your monitoring stack can reach the metrics port.
- Image provenance - pin the operator image by digest and verify signatures where your supply-chain policy requires it.
Availability & operations¶
- Replicas & resources - the operator ships with a single replica and modest requests/limits (
cpu: 10m/memory: 128Mirequests,cpu: 500m/memory: 512Milimits). Size these for the number of managed servers in your cluster and load-test before committing to limits; see Performance testing. - Storage-version migrations - when upgrading across API storage versions, drive the migration deliberately rather than relying on lazy conversion. See the Storage Version Migration page.
Performance testing¶
Sizing and scaling recommendations should be backed by load and stress testing (operator under many managed servers, CPU/memory under load). This is tracked upstream and is not yet part of this guide.
Further reading¶
- NSA/CISA Cybersecurity Information Sheet on MCP security - the boundary and hardening recommendations this guide draws on.
- Gateway Integration guide
- TLS configuration · Metrics · Storage Version Migration