Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 50 additions & 42 deletions docs/articles/remoting/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,30 @@ title: Network Security

For many deployments, TLS is not strictly necessary:

* **Internal networks only** - If your cluster runs entirely within a trusted network boundary
* **Development/staging environments** - Where data sensitivity is low
* **Kubernetes with network policies** - Where the container network provides isolation
* Your cluster runs entirely within a trusted network boundary
* Development or staging environments where data sensitivity is low
* Kubernetes with network policies providing container-level isolation

### When TLS Is Recommended

You should enable TLS when:
Enable TLS when:

* **Crossing network boundaries** - Communication between data centers or cloud regions
* **Public internet transit** - Any traffic over public networks (even with VPN)
* **Compliance requirements** - PCI-DSS, HIPAA, or other regulatory needs
* **Defense-in-depth** - Additional security layer even on private networks
* **Multi-tenant environments** - Shared infrastructure with other applications
* Communicating between data centers or cloud regions
* Any traffic crosses public networks, even with a VPN underneath
* Compliance requirements apply (PCI-DSS, HIPAA, etc.)
* You want defense-in-depth on a private network
* Running on shared infrastructure alongside other applications

## Security Layers

Akka.Remote security operates on three complementary layers:
Akka.Remote security operates on four complementary layers:

1. **Network Isolation** - Using VPNs or private networks to restrict which machines can reach your actor systems
2. **Transport Encryption** - Using TLS to encrypt all communication between nodes
3. **Authentication** - Using mutual TLS to verify the identity of all connecting nodes
4. **Serialization Safety** - Restricting which types can be serialized/deserialized to prevent arbitrary type injection via remote messages

You should use **all three layers** in production for defense-in-depth security.
In production, you want all four. Skipping any of them leaves a gap the other three can't fully cover.

## TLS (Transport Layer Security) Overview

Expand All @@ -60,7 +61,7 @@ TLS encryption was introduced in Akka.NET v1.2 with the DotNetty transport. It p

## Certificate Validation: Independent Control

**New in Akka.NET v1.5.52+:** Certificate validation is now split into two independent settings for greater flexibility.
**New in Akka.NET v1.5.52+:** Certificate validation is split into two independent settings.

### Two Types of Validation

Expand Down Expand Up @@ -335,17 +336,17 @@ akka.remote.dot-netty.tcp {

## Programmatic Certificate Validation (v1.5.55+)

**New in Akka.NET v1.5.55:** Certificate validation can now be configured programmatically using `DotNettySslSetup` with custom validators. This provides fine-grained control over validation logic while maintaining full backward compatibility with HOCON configuration.
**New in Akka.NET v1.5.55:** Certificate validation can be configured programmatically via `DotNettySslSetup` and custom validators. HOCON config still works — programmatic setup just takes precedence when both are present.

### When to Use Programmatic Configuration

Use programmatic setup when you need:

* **Custom validation logic** - Implement domain-specific validation rules
* **Certificate pinning** - Accept only specific certificates by thumbprint
* **Subject/Issuer validation** - Verify certificate attributes
* **Dynamic configuration** - Load validation rules from runtime sources
* **Composable validators** - Combine multiple validation strategies
* Domain-specific certificate validation rules
* Certificate pinning by thumbprint
* Subject or issuer attribute checks
* Validation rules loaded at runtime
* Multiple validators composed together

### CertificateValidation Helper Factory

Expand Down Expand Up @@ -405,7 +406,7 @@ var sslSetup = new DotNettySslSetup(
);
```

This ensures programmatic validation logic always takes priority for explicit security requirements.
If a custom validator is set, it wins regardless of what `suppress-validation` says in HOCON.

## Startup Certificate Validation (v1.5.52+)

Expand All @@ -420,7 +421,7 @@ The startup validation verifies:
* Application has permissions to access the private key
* Private key is accessible for both RSA and ECDSA algorithms

This fail-fast validation prevents runtime TLS handshake failures by detecting certificate configuration problems during system initialization.
Better to catch a bad certificate at startup than mid-handshake on a live connection.

### Common Private Key Permission Issues

Expand Down Expand Up @@ -484,41 +485,33 @@ sequenceDiagram

### When to Enable Mutual TLS

**Enable mutual TLS (`require-mutual-authentication = true`) when:**
Enable it (`require-mutual-authentication = true`) when:

* All nodes are under your control (typical Akka.NET cluster) ✓ **Recommended**
* You need defense-in-depth security
* All nodes are under your control — this is the typical Akka.NET cluster setup, and the recommendation
* Compliance requires bidirectional authentication (PCI-DSS, HIPAA, etc.)
* You want to prevent misconfigured nodes from joining
* You want to prevent misconfigured nodes from joining the cluster

**Disable mutual TLS (`require-mutual-authentication = false`) when:**
Disable it (`require-mutual-authentication = false`) when:

* Clients cannot provide certificates (rare in Akka.NET)
* You're using client-server architecture where clients are untrusted
* Backward compatibility with older clients required
* Clients can't provide certificates (rare in Akka.NET)
* You're running a client-server architecture where clients are untrusted
* Backward compatibility with older clients is required

**Default is TRUE for security-by-default posture** (since v1.5.52).
The default is `true` since v1.5.52.

### Security Benefits of Mutual TLS

1. **Prevents Asymmetric Connectivity Issues**
* Without mTLS: A node with broken certificate can connect OUT to cluster (client TLS succeeds)
* With mTLS: Node cannot connect without working certificate (enforced both ways)
**Asymmetric connectivity protection.** Without mTLS, a node with a broken certificate can still connect *out* to the cluster (client TLS succeeds even if the server cert is bad). With mTLS, it can't connect at all.

2. **Defense-in-Depth**
* Startup validation prevents broken servers
* Mutual TLS prevents broken clients
* Both together provide complete protection
**Defense-in-depth.** Startup validation catches broken server configs; mTLS catches broken clients. Together they cover both directions.

3. **Identity Verification**
* Every node must prove it owns the certificate
* Prevents certificate theft attacks (attacker needs private key)
**Real identity verification.** Every node must prove it holds the private key — not just that it has a copy of the certificate. An attacker who steals a cert file but not the private key gets nothing.

For configuration examples in both HOCON and programmatic styles, see [Validation Strategies](#validation-strategies-hocon-vs-programmatic-v1552) and [Programmatic Certificate Validation](#programmatic-certificate-validation-v1555) sections above.

## Configuration Examples and Security Analysis

This section provides concrete examples of different security configurations and their tradeoffs.
Concrete examples with security tradeoffs for each configuration level.

### HOCON Configuration Security Levels

Expand Down Expand Up @@ -592,9 +585,24 @@ akka.remote {

**Note:** This does NOT replace TLS encryption. Use both together.

## Serialization Security

Every message Akka.Remote sends goes through serialization. When a type has no explicit serializer binding, Akka.NET silently falls back to the `System.Object` serializer (Newtonsoft.Json). On an open network that's a problem: an attacker who can reach your endpoint can send messages that cause arbitrary types to be deserialized.

Disable the fallback in v1.5.66+:

```hocon
akka.actor.serialization-settings.allow-unregistered-types = false
```

With this set, Akka.NET throws a `SerializationException` for any unregistered type instead of silently falling back to JSON. Turn it on in production.

> [!NOTE]
> Full details — including Hyperion's built-in dangerous-type blacklist and schema-based serialization recommendations — are covered in [Serialization Security](xref:serialization#serialization-security).

## Virtual Private Networks (VPNs)

The best practice for network security is to make the network itself secure. Run Akka.Remote on private networks that require VPN access.
The most reliable security measure is a network that attackers can't reach in the first place. Run Akka.Remote on private networks that require VPN access.

**Why VPNs matter:**

Expand Down Expand Up @@ -796,4 +804,4 @@ Recommendations:

* [Akka.Remote Configuration](xref:akka-remote-configuration)
* [DotNetty Transport](https://github.com/Azure/DotNetty)
* [Serialization Security](xref:serialization#serialization-security) - Disable the default serializer fallback to prevent arbitrary type deserialization (v1.5.66+)
* [Serialization Security](xref:serialization#serialization-security) - Controlling which types can be serialized/deserialized over the wire
22 changes: 7 additions & 15 deletions docs/articles/serialization/serialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -365,25 +365,18 @@ For security-sensitive applications, we recommend disabling this fallback:
akka.actor.serialization-settings.allow-unregistered-types = false
```

When disabled, `FindSerializerForType` will throw a `SerializationException` if no explicit serializer binding exists for a type. This ensures:
When disabled, `FindSerializerForType` throws a `SerializationException` for any type with no explicit binding. Only registered types can be serialized, missing bindings blow up at development time rather than silently in production, and all your persisted/remoted messages go through the serializers you actually configured.

1. **Security**: Only explicitly registered types can be serialized/deserialized
2. **Schema safety**: Missing serializer registrations are caught at development time rather than silently falling back to JSON
3. **Explicit contracts**: All persisted/remoted messages go through intentionally configured serializers

When you enable this setting and attempt to serialize an unregistered type, you'll receive a helpful error message guiding you to either add a serialization binding or re-enable the fallback.
When you hit this exception, the error message tells you exactly which type is unregistered and what to do about it.

### Danger of Polymorphic Serializer

One of the danger of polymorphic serializers is the danger of unsafe object type injection into
the serialization/de-serialization chain. This issue applies to any type of polymorphic serializer,
including JSON, BinaryFormatter, etc. In Akka, this issue primarily affects developers who allow third parties to pass messages directly
to unsecured Akka.Remote endpoints, a [practice that we do not encourage](https://getakka.net/articles/remoting/security.html#akkaremote-with-virtual-private-networks).
Polymorphic serializers — JSON, BinaryFormatter, Hyperion, and others — are vulnerable to object type injection through the deserialization chain. In Akka, this mainly bites developers who allow third parties to pass messages directly to an unsecured Akka.Remote endpoint, a [practice that we do not encourage](xref:network-security#serialization-security).

Generally, there are two approaches you can take to alleviate this problem:
There are two ways to address this:

1. Implement a schema-based serialization that are contract bound, which is more expensive to setup at first but fundamentally faster and more secure.
2. Implement a filtering or blacklist to block dangerous types.
1. Use schema-based serialization (contract-bound) — more setup upfront, but faster and fundamentally more secure.
2. Maintain a blocklist of dangerous types.

An example of using a schema-based serialization in Akka can be read under the title "Using Google
Protocol Buffers to Version State and Messages" in [this documentation](https://petabridge.com/cluster/lesson3)
Expand Down Expand Up @@ -412,8 +405,7 @@ from being deserialized:
* `System.Diagnostics.Process`
* `System.Management.IWbemClassObjectFreeThreaded`

Be warned that these class can be used as a man in the middle and arbitrary code injection attack vector, but if you need
to serialize one of these class, you can turn off this feature using this inside your HOCON settings:
Each of these is a known code execution vector. If you genuinely need to serialize one of them, you can disable the block in HOCON:

```hocon
akka.actor.serialization-settings.hyperion.disallow-unsafe-type = false
Expand Down
Loading