> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tensor9.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Connection Security

Every appliance maintains a single secure channel back to your [control plane](/fundamentals/control-plane). Deployments and operations ride this channel, and the appliance reports its status back over it. This page explains the mechanics of that channel and the mutual TLS (mTLS) trust model that secures both ends of it.

## The connection at a glance

* **One channel per appliance**, between the appliance's [controller](/fundamentals/appliances#controller) and your control plane.
* **Outbound-only**: the appliance always dials out. It never opens inbound ports.
* **Mutually authenticated**: both ends present and verify certificates before any data flows.
* **Long-lived**: established once during appliance setup and re-handshaked as needed.

The channel carries control traffic in both directions:

| Direction                 | Carries                                                                                |
| ------------------------- | -------------------------------------------------------------------------------------- |
| Control plane → appliance | Deployment instructions, operations commands (remote shell, one-off scripts, restarts) |
| Appliance → control plane | Responses to those commands, deployment and health status, and connection liveness     |

Telemetry (logs, metrics, traces) does not ride this channel - observability data is handled separately. See [Observability](/fundamentals/observability).

## Outbound-only by design

The appliance controller initiates the connection to your control plane over outbound HTTPS. It does **not** open inbound network ports, assign public IPs, or create ingress rules for itself. Your control plane never reaches into the customer's network unsolicited; it can only send instructions back down a connection the appliance already opened.

This matters for two reasons:

* **It's easy for customers to allow.** Most networks already permit outbound HTTPS, so customers don't have to open ingress ports - a request that is often logistically difficult and a security concern in regulated environments.
* **It shrinks the attack surface.** There is no listening socket on the appliance for an attacker to reach, and no inbound path from your control plane into customer infrastructure.

The connectivity behavior is part of the appliance's [form factor](/fundamentals/key-concepts#form-factor). See [connectivity modes](/fundamentals/appliances#connectivity-modes) for how `Connected` and `Disconnected` appliances differ.

## Mutual TLS: both sides prove who they are

Ordinary (one-way) TLS only proves the *server's* identity to the client. mTLS adds the reverse: the client must also present a certificate the server verifies. On the appliance-to-control-plane channel, **both ends authenticate each other** on every handshake:

* Your control plane verifies that the connecting appliance is one it actually provisioned.
* The appliance verifies that it is talking to *your* control plane, not an impostor endpoint.

During appliance [setup](/fundamentals/appliances#customer-signup-flow), Tensor9 provisions each end with the certificates it needs to recognize the other. Neither side will complete a handshake with a party it cannot verify.

### The two identities

| Identity                       | Belongs to                                                | Verified by                                                                                                                           |
| ------------------------------ | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| **Control plane certificate**  | Your control plane, running in your own AWS account       | The appliance, which is provisioned at setup to trust only your control plane                                                         |
| **Appliance leaf certificate** | The individual appliance's controller (one per appliance) | Your control plane, which validates it against the CA chain it issued and against the leaf fingerprint it recorded for that appliance |

### The handshake

<Steps>
  <Step title="Appliance dials out">
    The appliance controller opens an outbound connection to your control plane's endpoint.
  </Step>

  <Step title="Appliance verifies the control plane">
    Your control plane presents its certificate. The appliance validates that it chains to your control plane's CA - the root it pinned when it enrolled (see [Bootstrapping trust with cloud identity](#bootstrapping-trust-with-cloud-identity)). If it doesn't validate, the appliance refuses to proceed - so a spoofed or man-in-the-middle endpoint cannot impersonate your control plane.
  </Step>

  <Step title="Control plane verifies the appliance">
    The appliance presents its leaf certificate. Your control plane validates that the certificate chains to its CA and matches the leaf fingerprint it recorded for that appliance at enrollment. If the certificate doesn't chain, doesn't match the recorded fingerprint (for example, after the appliance was revoked), or has expired, the control plane drops the handshake.
  </Step>

  <Step title="Channel established">
    With both ends authenticated, an encrypted channel is established and deployments, operations, and status updates can flow over it.
  </Step>
</Steps>

## Bootstrapping trust with cloud identity

The handshake above assumes each side already holds a certificate. But a brand-new appliance has none - and handing it a pre-shared secret to start with would just move the problem. Tensor9 closes this gap by bootstrapping the appliance's first certificate off the **platform's own identity system** - AWS, GCP, or Kubernetes - so there is no long-lived shared secret to distribute or leak.

Enrollment follows the same four steps on every platform; only the proof of identity differs:

<Steps>
  <Step title="Appliance opens a bootstrap connection">
    The appliance opens a provisional connection to your control plane. Your control plane accepts it to carry the enrollment exchange, but treats it as unauthenticated - the appliance hasn't proven its identity yet.
  </Step>

  <Step title="Appliance attests its platform identity">
    Over that connection the appliance sends an enrollment request containing a certificate signing request (CSR) for the certificate it wants, plus a **platform-signed proof of identity** (see the table below). The proof is bound to this enrollment, so a captured proof cannot be replayed on a different connection.
  </Step>

  <Step title="Control plane verifies the identity with the platform">
    Your control plane validates the proof against the platform's own authority - AWS STS, Google's token-signing keys, or the cluster's OIDC keys - and confirms the identity it resolves to matches the one recorded for this appliance at provisioning time, set by the customer's own infrastructure.
  </Step>

  <Step title="Control plane issues the real certificate">
    On a match, your control plane signs the CSR with its KMS-backed CA and returns the leaf certificate, the CA chain, and the root. The appliance pins that root and authenticates with its real, chain-validated certificate from then on.
  </Step>
</Steps>

The proof of identity is each platform's native primitive:

| Platform       | What the appliance presents                                                                 | What your control plane checks it against                                                                                                  |
| -------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| **AWS**        | A presigned STS `GetCallerIdentity` request, signed with the IAM role the appliance runs as | Forwards it to AWS STS, which returns the caller's role ARN; matches that against the role recorded for the appliance                      |
| **GCP**        | A Google-signed instance-identity token (JWT) fetched from the instance metadata server     | Verifies the signature against Google's public keys; matches the project and service account against those recorded for the appliance      |
| **Kubernetes** | A projected ServiceAccount token (JWT) mounted into the appliance's pod                     | Verifies the signature against the cluster's OIDC keys; matches the namespace and service account against those recorded for the appliance |

The key property is the same across all three: the appliance proves *"I am this workload, running under this identity"* using credentials the platform already issued it. Nothing secret is transmitted or stored, and the proof is bound to the customer's registered identity and to the specific enrollment. The root of trust is the customer's own cloud or cluster IAM.

## Per-appliance identity

Each appliance has its **own** leaf certificate, not a shared secret reused across the fleet. When your control plane issues that certificate, it records the leaf's fingerprint against that appliance. On every handshake it checks both that the presented certificate chains to its CA and that the fingerprint matches the one on record - so an appliance can only ever authenticate as itself, and that recorded fingerprint is the lever for revoking it.

The practical consequences:

* **No shared bearer secret.** There is no API key or token that, if leaked, authenticates as any appliance. An appliance's credential only authenticates *that* appliance.
* **Blast radius is contained.** Compromising one appliance's certificate does not let an attacker present as a different appliance.
* **No reaching into customer infrastructure.** Cutting an appliance off is decided on your side - you don't need access to the customer's environment, which is outbound-only and may be unreachable on demand. See [Cutting off an appliance](#cutting-off-an-appliance).

## Certificate lifecycle

Every certificate on this channel is issued from a two-tier certificate authority that your control plane operates **inside your own AWS account** - the same dedicated account your control plane runs in. The CA signing keys are held in [KMS](https://docs.aws.amazon.com/kms/) in that account: the private keys never leave KMS, and issuance happens through KMS signing operations. There is no exportable CA key to leak, and the CA stays under your control - Tensor9 never holds it on your behalf.

| Certificate          | Validity | Role                                                                                                  |
| -------------------- | -------- | ----------------------------------------------------------------------------------------------------- |
| **Root CA**          | 10 years | Top of the trust chain. Signs the intermediate CA. Signing key held in KMS.                           |
| **Intermediate CA**  | 2 years  | Signs leaf certificates. Signing key held in KMS.                                                     |
| **Leaf certificate** | 1 month  | What each end presents on the handshake - both your control plane and the appliance. Rotated monthly. |

The tiers trade off security against operational load. The root key is the most sensitive, so it is long-lived and rarely used: it signs only the intermediate. The intermediate carries the day-to-day signing of leaf certificates on a shorter, two-year clock and can be replaced without touching the root.

Leaf certificates are deliberately short-lived and rotated monthly, so a leaked or stale leaf is only useful for a brief window. The appliance renews over the existing authenticated channel - it requests a new leaf before the current one expires, without repeating the cloud-identity attestation - so the long-lived channel stays up across rotations and certificate rollover is invisible to deployments and operations.

Operator certificates are issued from the same CA but are longer-lived (about a year); see [Relationship to operator authentication](#relationship-to-operator-authentication).

## Cutting off an appliance

When your control plane issues an appliance its leaf certificate, it records that leaf's fingerprint against the appliance. Every handshake checks the presented certificate's fingerprint against the recorded one, so revoking an appliance is **immediate**: remove the recorded fingerprint and the cached certificate fails its very next handshake. The appliance cannot reconnect without re-enrolling, which requires a fresh cloud-identity attestation against the role recorded for it.

This doesn't rely on a certificate revocation list - revocation is a single change your control plane makes, enforced on the next handshake.

## Relationship to operator authentication

Two kinds of mTLS clients terminate at your control plane, and they use the same underlying trust model:

|                       | **Appliance identity**                                                             | **Operator identity**                                                                       |
| --------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| **Who**               | An appliance's controller (machine)                                                | A person on your vendor team (human)                                                        |
| **First enrolled by** | A cloud-identity attestation (AWS STS) against the role recorded for the appliance | Redeeming a one-time enrollment bundle                                                      |
| **Credential**        | A CA-issued leaf certificate, rotated \~monthly                                    | A CA-issued leaf certificate, valid \~1 year                                                |
| **Cut off by**        | Remove its pinned leaf fingerprint; the cached cert fails its next handshake       | The same operation, exposed as `iam user revoke` (which also cancels any unredeemed invite) |
| **Covered in**        | This page                                                                          | [IAM Commands](/cli/reference#iam-commands)                                                 |

In both cases your control plane is the certificate authority that issues these certificates and pins each party's leaf fingerprint. Revocation is the same underlying operation for both - remove the pinned fingerprint and the cached certificate fails its next handshake - whether the principal is an appliance or an operator. Appliances connect to receive deployments and operations and to report status; operators connect to drive the CLI. Neither relies on a shared bearer secret.

## What the channel does and doesn't expose

The mTLS channel secures *how* the two ends talk; the [permissions model](/fundamentals/permissions-model) and [secrets handling](/fundamentals/secrets) govern *what* the connection is allowed to do. Independent of mTLS:

* **Application and business data stay in the appliance.** Only control traffic - deployment instructions, operations commands, and status responses - crosses the channel. Your customer's business data never does.
* **Secret values never leave the customer's environment.** The controller detects secrets created in the customer's own secret manager; their values are not transmitted to your control plane. See [Secrets](/fundamentals/secrets).
* **Every operation is authenticated and audited.** Commands sent over the channel run through your control plane's [permissions model](/fundamentals/permissions-model) and are logged.

## Related topics

* [**Your Control Plane**](/fundamentals/control-plane): What the control plane does
* [**Customer Appliances**](/fundamentals/appliances): The appliance and its controller
* [**Permissions Model**](/fundamentals/permissions-model): What the connection is allowed to do
* [**IAM Commands**](/cli/reference#iam-commands): Operator authentication, also built on mTLS
