# PEM Keys

Source: https://docs.ops0.com/docs/settings/pem-keys

Store SSH private keys in ops0 for server authentication. ops0 encrypts every key at rest, verifies them by fingerprint, and uses them across Ansible deployments and server connections.

![PEM Keys management page in ops0 settings](https://docs.ops0.com/images/settings-pemkeys.png)

---

## What are PEM Keys?

PEM keys are SSH private keys stored securely in ops0. ops0 uses them to authenticate when connecting to your servers for:

- **Ansible playbook execution** — the Configurations module uses the selected PEM key to SSH into target servers and run playbooks
- **Server connections** — ops0 uses PEM keys when connecting to servers for health checks and configuration management

**Key privacy guarantee**

ops0 never transmits the raw private key to the browser after upload. The key is stored encrypted and only decrypted server-side at the moment an SSH connection is made.

---

## Adding a PEM Key

### Navigate to PEM Keys
Go to **Settings** → **PEM Keys**.

### Add Key
Click **Add PEM Key** in the top-right corner.

### Enter Key Details
Provide a **Key Name** (e.g., "Production Servers" or "eu-west-1 Auto-Scaling Group").

Optionally add a **Description** to give your team context — for example, `"eu-west-1 production servers"` or `"staging auto-scaling group"`. The description is visible to all org members with access to Settings.

### Upload or Paste the Key Content
Either upload your `.pem` file directly or paste the private key content into the text field. The key must begin with `-----BEGIN ... PRIVATE KEY-----`.

![Add PEM Key dialog in ops0](https://docs.ops0.com/images/settings-pem-key-add.png)

### Save
Click **Save** to securely store the key. ops0 encrypts it immediately and displays the SHA-256 fingerprint for verification.

---

## Key Details

After saving, each key entry shows the following fields:

| Field | Description |
|---|---|
| Name | The label you gave the key |
| Description | Optional context notes |
| Fingerprint | SHA-256 hash of the public key, auto-calculated from the uploaded private key |
| Created | When the key was uploaded |
| Last Used | Most recent time ops0 used this key for a connection |

The SHA-256 fingerprint lets you verify which key is stored without exposing the private key itself. To confirm a match, run the following against your local copy of the key:

```bash
ssh-keygen -l -E sha256 -f your-key.pem
```

The output should match the fingerprint shown in ops0.

---

## Using PEM Keys

PEM keys are referenced in three places across ops0:

1. **Ansible / Configurations** — when running a playbook, select the PEM key to use for SSH authentication to target servers. This is configured per Ansible project or per individual run.

2. **Server Groups** — set a default PEM key for all servers in a group so you do not need to select it individually for each server. Servers in the group inherit the group's default key unless overridden at the server level.

---

## Replacing a Key

You cannot edit or overwrite an uploaded key in place. To replace a key:

### Upload the new key
Add the new key with a distinct name, such as `"Production Key v2"`.

### Update all references
Go to every server connection and Ansible project that references the old key and switch it to the new key.

### Delete the old key
Once all references are updated, delete the old key from the PEM Keys list.

**Deleting a key is permanent**

Deleting a PEM key removes it from ops0 permanently. Any server connection or Ansible project still referencing the deleted key will fail to connect until updated to use a different key.

---

## Security

- Keys are encrypted at rest using **AES-256-GCM**
- The raw private key is **never returned to the browser** after upload
- Only the **SHA-256 fingerprint** is displayed for verification purposes
- All key usage is recorded in **Audit Logs** — including which server was accessed, which playbook triggered the connection, and a timestamp
- Managing PEM keys requires the **org Admin role** or above

---

## Key Migration and Re-encryption

If your organization rotates its master encryption key (the key ops0 uses to encrypt stored PEM keys), existing PEM keys need to be re-encrypted under the new master key. ops0 provides a migration endpoint for this.

### When to Migrate

- Your organization rotates the `MASTER_ENCRYPTION_KEY` environment variable in the ops0 deployment
- You are migrating ops0 to a new deployment with a different encryption key

### Running a Migration

Contact your ops0 administrator or use the ops0 admin API to trigger key re-encryption. The migration decrypts each PEM key with the old master key and re-encrypts it with the new one. The private key content is not exposed or exported during this process.

**Admin only**

Key migration requires organization Owner or platform Admin access. The operation is logged in Audit Logs.

### Testing a Key

After migration, verify the key still works by clicking **Test Key** on any PEM key entry. This runs a connection test to a server that uses the key, confirming the key can be decrypted and used successfully.

---

## Supported Key Formats

| Format | Supported |
|---|---|
| RSA (PKCS#1, PKCS#8) | Yes |
| Ed25519 | Yes |
| ECDSA | Yes |
| DSA | No — deprecated, not supported |
| Password-protected keys | No — passphrase-protected keys are not supported |

**Removing a passphrase from a key**

If your key is passphrase-protected, remove the passphrase before uploading:

```bash
ssh-keygen -p -f your-key.pem
```

Enter the existing passphrase when prompted, then leave the new passphrase blank and press Enter.

---

## Related

- [Infrastructure](https://docs.ops0.com/docs/settings/infrastructure): Register and manage servers using PEM keys for SSH authentication.

- [Configurations Deployments](https://docs.ops0.com/docs/configurations/deployments): Run Ansible playbooks against your servers using a selected PEM key.

- [Audit Logs](https://docs.ops0.com/docs/settings/audit-logs): Review a full history of PEM key usage, including which connections each key was used for.
