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

# SSH certificate authorities

> Register an SSH certificate authority to authenticate users to your instances with signed certificates instead of individual SSH keys.

SSH certificate authorities (CAs) let you authenticate users to instances using signed SSH certificates instead of distributing individual public keys. You register your CA's public key with Nscale, and any instance created with that CA automatically trusts certificates signed by it.

<Note>
  **Prerequisites:** You need an existing [project](/docs/manage/projects), a [VPC network](/docs/network/vpc-networks), and at least one [security group](/docs/network/security-groups) with SSH (TCP port 22) allowed.
</Note>

## How it works

1. You generate an SSH CA key pair on your local machine
2. You register the CA's **public key** with Nscale at the project level
3. When you create an instance, you specify the SSH CA to trust
4. Nscale configures the instance to accept certificates signed by that CA
5. You sign user SSH keys with your CA private key and use them to connect

This eliminates the need to upload individual SSH keys to each instance. Anyone with a certificate signed by the CA can connect.

## Availability

SSH certificate authorities are available in the **reserved cloud service environment.**

## Step 1: Generate an SSH CA key pair

If you don't already have a CA key pair, generate one:

```bash theme={null}
ssh-keygen -t ed25519 -f ~/.ssh/nscale-ca -C "nscale SSH CA"
```

This creates two files:

* `~/.ssh/nscale-ca` — the CA private key (keep this secure)
* `~/.ssh/nscale-ca.pub` — the CA public key (you'll register this with Nscale)

<Warning>
  **Keep your CA private key secure.** Anyone with access to it can sign certificates that grant SSH access to your instances. Store it in a secrets manager or hardware security module for production use.
</Warning>

## Step 2: Register the CA with Nscale

Register the CA public key using the API. The CA is scoped to an organization and project.

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST "https://region.nks.europe-west4.nscale.com/api/v2/sshcertificateauthorities" \
    -H "Authorization: Bearer $NSCALE_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "metadata": {
        "name": "my-ssh-ca",
        "description": "Team SSH certificate authority"
      },
      "spec": {
        "organizationId": "<org-id>",
        "projectId": "<project-id>",
        "publicKey": "'"$(cat ~/.ssh/nscale-ca.pub)"'"
      }
    }'
  ```

  ```python Python theme={null}
  import os
  import requests

  token = os.environ["NSCALE_TOKEN"]
  with open(os.path.expanduser("~/.ssh/nscale-ca.pub")) as f:
      ca_public_key = f.read().strip()

  response = requests.post(
      "https://region.nks.europe-west4.nscale.com/api/v2/sshcertificateauthorities",
      headers={"Authorization": f"Bearer {token}"},
      json={
          "metadata": {
              "name": "my-ssh-ca",
              "description": "Team SSH certificate authority",
          },
          "spec": {
              "organizationId": "<org-id>",
              "projectId": "<project-id>",
              "publicKey": ca_public_key,
          },
      },
  )
  print(response.json())
  ```

  ```go Go theme={null}
  package main

  import (
  	"bytes"
  	"encoding/json"
  	"fmt"
  	"net/http"
  	"os"
  )

  func main() {
  	pubKey, _ := os.ReadFile(os.Getenv("HOME") + "/.ssh/nscale-ca.pub")
  	body, _ := json.Marshal(map[string]any{
  		"metadata": map[string]string{
  			"name":        "my-ssh-ca",
  			"description": "Team SSH certificate authority",
  		},
  		"spec": map[string]string{
  			"organizationId": "<org-id>",
  			"projectId":      "<project-id>",
  			"publicKey":      string(pubKey),
  		},
  	})
  	req, _ := http.NewRequest("POST",
  		"https://region.nks.europe-west4.nscale.com/api/v2/sshcertificateauthorities",
  		bytes.NewReader(body))
  	req.Header.Set("Authorization", "Bearer "+os.Getenv("NSCALE_TOKEN"))
  	req.Header.Set("Content-Type", "application/json")
  	resp, _ := http.DefaultClient.Do(req)
  	fmt.Println(resp.Status)
  }
  ```

  ```typescript TypeScript theme={null}
  import { readFileSync } from "node:fs";
  import { homedir } from "node:os";

  const pubKey = readFileSync(`${homedir()}/.ssh/nscale-ca.pub`, "utf8").trim();

  const response = await fetch(
    "https://region.nks.europe-west4.nscale.com/api/v2/sshcertificateauthorities",
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.NSCALE_TOKEN}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        metadata: {
          name: "my-ssh-ca",
          description: "Team SSH certificate authority",
        },
        spec: {
          organizationId: "<org-id>",
          projectId: "<project-id>",
          publicKey: pubKey,
        },
      }),
    }
  );

  console.log(await response.json());
  ```
</CodeGroup>

The response includes the CA's ID, which you'll use when creating instances.

## Step 3: Create an instance with SSH CA trust

When creating an instance, specify the `sshCertificateAuthorityId` to configure the instance to trust your CA:

```bash theme={null}
curl -X POST "https://compute.nscale.com/api/v2/instances" \
  -H "Authorization: Bearer $NSCALE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "metadata": {
      "name": "my-instance"
    },
    "spec": {
      "organizationId": "<org-id>",
      "projectId": "<project-id>",
      "regionId": "<region-id>",
      "flavorId": "<flavor-id>",
      "imageId": "<image-id>",
      "networkId": "<network-id>",
      "sshCertificateAuthorityId": "<ssh-ca-id>"
    }
  }'
```

The instance will be configured during provisioning to trust certificates signed by the specified CA.

## Step 4: Sign a user SSH key

On your local machine, sign a user's public key with the CA:

```bash theme={null}
ssh-keygen -s ~/.ssh/nscale-ca \
  -I "user@example.com" \
  -n ubuntu \
  -V +52w \
  ~/.ssh/id_ed25519.pub
```

| Flag | Description                                         |
| ---- | --------------------------------------------------- |
| `-s` | Path to the CA private key                          |
| `-I` | Certificate identity (for audit logs)               |
| `-n` | Principals (usernames) the certificate is valid for |
| `-V` | Validity period (e.g., `+52w` for one year)         |

This creates `~/.ssh/id_ed25519-cert.pub` alongside the user's existing key.

## Step 5: Connect to the instance

SSH to the instance using the signed certificate. The SSH client automatically presents the certificate when the matching private key is used:

```bash theme={null}
ssh -i ~/.ssh/id_ed25519 ubuntu@<instance-ip>
```

<Info>
  The SSH client uses the certificate file automatically if it's in the same directory and follows the naming convention (`id_ed25519-cert.pub` for an `id_ed25519` key).
</Info>

## Managing SSH CAs

### List CAs

```bash theme={null}
curl "https://region.nks.europe-west4.nscale.com/api/v2/sshcertificateauthorities" \
  -H "Authorization: Bearer $NSCALE_TOKEN"
```

### Get a specific CA

```bash theme={null}
curl "https://region.nks.europe-west4.nscale.com/api/v2/sshcertificateauthorities/<ssh-ca-id>" \
  -H "Authorization: Bearer $NSCALE_TOKEN"
```

### Delete a CA

```bash theme={null}
curl -X DELETE "https://region.nks.europe-west4.nscale.com/api/v2/sshcertificateauthorities/<ssh-ca-id>" \
  -H "Authorization: Bearer $NSCALE_TOKEN"
```

<Warning>
  You cannot delete an SSH CA that is referenced by active instances. Remove or update the instances first.
</Warning>

## Permissions

SSH CA operations require the following RBAC permissions:

| Role       | Permissions          |
| ---------- | -------------------- |
| **Admin**  | Create, read, delete |
| **User**   | Create, read, delete |
| **Viewer** | Read only            |

## Common issues / troubleshooting

**Symptom:** SSH connection is refused or falls back to password auth.

**Likely cause:** The certificate's principal doesn't match the server username.

**Fix:** Re-sign the certificate with the correct `-n` value (e.g., `ubuntu` for Ubuntu images).

***

**Symptom:** Certificate is rejected as expired.

**Likely cause:** The certificate validity period has elapsed.

**Fix:** Sign a new certificate with a fresh validity period using `ssh-keygen -s`.

***

**Symptom:** Can't delete an SSH CA.

**Likely cause:** The CA is still referenced by one or more instances.

**Fix:** Delete or update the instances that reference the CA, then retry the deletion.

***

## Related resources

<CardGroup cols={2}>
  <Card title="Instances" icon="rectangle-history-circle-plus" href="/docs/compute/create-new-instances">
    Create instances that trust your SSH CA
  </Card>

  <Card title="Security groups" icon="shield" href="/docs/network/security-groups">
    Allow SSH traffic to your instances
  </Card>

  <Card title="Service tokens" icon="key" href="/docs/manage/service-tokens">
    Create API tokens for programmatic access
  </Card>

  <Card title="API reference" icon="code" href="/api-reference">
    Full API documentation for SSH CAs
  </Card>
</CardGroup>
