# Set up server access with SSH certificates

Let people reach Linux servers with SSH certificates that are valid for five minutes, signed by your project's own certificate authority.

With server access, nobody holds a standing key to a server. Each server trusts one SSH certificate authority (CA), your project's. A person who was granted access receives a certificate for one session, and it expires after 5 minutes.

Use this guide to register a Linux server, make it trust your project, and decide who may connect. The AuthFI console calls a server a _target_.

## How server access works

1. Your project has an SSH certificate authority. Its private key never leaves the key service.
2. Each server is configured to trust certificates signed by that authority.
3. A person asks to connect. AuthFI checks their grant on that server.
4. AuthFI signs the person's public key into a certificate for that server.
5. The person connects with ordinary SSH. The server checks the signature and the expiry.

No `authorized_keys` file is involved, and removing someone's access needs no change on the server.

## Before you begin

You need:

- A Linux server that runs `sshd`, and permission to run commands on it as an administrator.
- Access to **Zero-Code > Servers** in the AuthFI console.
- The group in your project whose members should connect. See [Roles, groups and grants](/concepts/access).

<Steps>

### Register the target

In the console, open **Zero-Code > Servers**, open the **Targets** tab, and choose **Register a target**.

| Field     | Enter                                                                              |
| --------- | ---------------------------------------------------------------------------------- |
| Name      | How the target reads in the console. It must be unique.                            |
| Hostname  | What people connect to, and what the node agent reports as its hostname            |
| Port      | The SSH port. The default is `22`.                                                 |
| Principal | The account on the server that the certificate is issued for, for example `ubuntu` |

Choose **Register**. The console opens the target's page. Nobody may connect until you grant access.

### Make the server trust your project

Install the AuthFI node agent on the server. In **Zero-Code > Servers**, the **Overview** tab has a block named **Putting the agent on a host**. Copy the command from that block and run it on the server. The server appears in the console when the node agent first checks in.

The node agent writes your authority's public key and one line of SSH configuration that points at it, and reloads `sshd`.

```text
# /etc/ssh/sshd_config.d/authfi.conf
TrustedUserCAKeys /var/lib/authfi/ssh_ca.pub
```

From then on, the server accepts a certificate signed by your project, for the principal named in it, until the certificate expires.

### Grant access to the target

On the target's page, choose **Grant access**.

| Field            | Choose                                                                                         |
| ---------------- | ---------------------------------------------------------------------------------------------- |
| Who              | **A person** or **A group**, then the person or the group                                      |
| What they may do | **Open sessions**                                                                              |
| For how long     | **Until somebody takes it away**, **One hour**, **Eight hours**, **One day** or **Seven days** |

Choose **Grant access**. The holder appears in the target's **Access** section, under **Who may connect**.

A group holds the grant for every member, including anybody added later.

</Steps>

## Check that it works

As a person who holds a grant, open the target's page in **Zero-Code > Servers**.

1. Choose **Open a session**.
2. Paste your public key into **Your SSH public key**, in `authorized_keys` form: `ssh-ed25519 AAAA…`. The key is certified, and is not stored as a credential.
3. Choose **Mint the certificate**. The certificate is shown once.
4. Save the certificate beside the key you pasted, as `<key>-cert.pub`.
5. Connect within 5 minutes.

```bash
ssh -p $PORT $PRINCIPAL@$HOSTNAME
```

`$PORT`, `$PRINCIPAL` and `$HOSTNAME` are the target's port, principal and hostname. To copy the whole command, open the **More** menu on the target's page and choose **Copy ssh command**.

Then check the records of the session:

- The **Sessions** tab lists the session.
- The server's own `sshd` log shows the certificate's key ID for the sign-in, for example `user:ada@acme.com@build-01`.
- The [audit record](/security/audit) has a `pam.session.opened` entry.

## What the certificate contains

| Property    | Value                                                                               |
| ----------- | ----------------------------------------------------------------------------------- |
| Signed with | Ed25519, by your project's SSH authority                                            |
| Valid for   | 5 minutes                                                                           |
| Key ID      | Who it was issued to and for which server, for example `user:ada@acme.com@build-01` |
| Principal   | The server's principal, and nothing else                                            |
| Allows      | A terminal. No port, agent or X11 forwarding.                                       |

The 5 minutes is how long a person has to **start** a session. A session that is already open stays open when the certificate expires.

The key ID is what the server's `sshd` log shows for the sign-in. The server's log therefore names the person, and not a shared account.

## Who may connect

AuthFI checks the grant before it signs anything. A person with no grant is denied, and no certificate is issued.

A project rule can also require fresh multi-factor authentication (MFA) before the certificate is issued.

## See the sessions

In **Zero-Code > Servers**, the **Sessions** tab lists the sessions on every target. The **Sessions** section of a target's page lists the sessions on that target.

The columns are **Opened**, **Who**, **Target**, **Channel**, **Certificate**, **End** and **Recording**. **Target** is shown on the **Sessions** tab only, and **Recording** shows the size of the recording.

Filter the list with **every session**, **possibly open** or **ended**, or search by person, target or certificate.

## Control privileged commands

On a server that runs the AuthFI node agent, you can decide who may run which command as an administrator. This part is in pilot.

In **Zero-Code > Servers**, open the **Sudo** tab and choose **Add a rule**.

| Field               | Enter                                                                       |
| ------------------- | --------------------------------------------------------------------------- |
| Who                 | **A person** or **A group**, then the person or the group                   |
| Command             | An absolute path, or `*` for every command. The default is `*`.             |
| Action              | **Deny**, **Allow** or **Require MFA**. The default is **Deny**.            |
| MFA window, seconds | With **Require MFA**: how fresh the MFA must be. From 1 minute to 24 hours. |
| Why                 | Free text for the person who reads the rule later                           |

Choose **Add the rule**. The rule appears in the **Rules** block of the **Sudo** tab.

The rule is checked in the kernel when the command starts, so it applies however the command was reached.

A rule denies what you name, and a command with no rule runs as normal. To hold a group to a short list of commands, allow those commands and add a `*` deny for the group beneath them.

To remove a rule, choose **Delete** on its row and confirm with **Delete the rule**.

## Remove someone's access

On the target's page, open the **Access** section. Under **Who may connect**, choose **Revoke** on the holder's row, then confirm with **Revoke**. Taking a person out of the group has the same effect for that person.

No new certificate is issued. The last certificate they held expires within 5 minutes of when it was issued.

## What is recorded

Each of these events is an entry in the [audit record](/security/audit).

| Event                    | When                                                                   |
| ------------------------ | ---------------------------------------------------------------------- |
| `pam.session.opened`     | A certificate was issued                                               |
| `pam.session.denied`     | Someone was denied, with the reason                                    |
| `pam.session.ended`      | A browser-terminal session closed, or a certificate's 5 minutes passed |
| `pam.target.provisioned` | A server was added                                                     |

## Troubleshooting

| What you see                                         | Cause                                      | Fix                                                           |
| ---------------------------------------------------- | ------------------------------------------ | ------------------------------------------------------------- |
| A person is denied, and no certificate is issued     | The person has no grant on the target      | Choose **Grant access** on the target's page                  |
| A `pam.session.denied` entry in the audit record     | AuthFI denied the request                  | Read the reason in the entry                                  |
| The server rejects a certificate that worked earlier | The certificate is more than 5 minutes old | Choose **Open a session** again, and connect within 5 minutes |

## Next steps

<Cards>
  <Card href="/concepts/access" title="Roles, groups and grants">
    How a grant to a group reaches every member.
  </Card>
  <Card href="/security/audit" title="Use the audit record">
    Search the session events, and send them to your log tools.
  </Card>
  <Card href="/security/keys" title="Keys and secrets">
    The SSH authority and the other keys your project signs with.
  </Card>
  <Card href="/access/cloud" title="Grant cloud roles without stored keys">
    Give people temporary AWS credentials in the same way.
  </Card>
</Cards>
