Skip to content

SSH UI Adjustments + Documentation for Host Key Signing #2918

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
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
4 changes: 2 additions & 2 deletions backend/src/ee/routes/v1/ssh-certificate-template-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ export const registerSshCertificateTemplateRouter = async (server: FastifyZodPro
allowHostCertificates: z.boolean().describe(SSH_CERTIFICATE_TEMPLATES.CREATE.allowHostCertificates),
allowCustomKeyIds: z.boolean().describe(SSH_CERTIFICATE_TEMPLATES.CREATE.allowCustomKeyIds)
})
.refine((data) => ms(data.maxTTL) > ms(data.ttl), {
message: "Max TLL must be greater than TTL",
.refine((data) => ms(data.maxTTL) >= ms(data.ttl), {
message: "Max TLL must be greater or equal to TTL",
path: ["maxTTL"]
}),
response: {
Expand Down
148 changes: 125 additions & 23 deletions docs/documentation/platform/ssh.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -83,70 +83,73 @@ In the following steps, we explore how to configure Infisical SSH to start issui
as part of the SSH operation.

<Steps>
<Step title="Configuring Infisical SSH">
<Step title="Configuring a SSH CA for client key signing">
1.1. Start by creating a SSH project in the SSH tab of your organization.

![ssh project create](/images/platform/ssh/ssh-project.png)

1.2. Next, create a CA in the **Certificate Authorities** tab of the
project.
1.2. Next, create a SSH CA in the **Certificate Authorities** tab of the
project; this CA will be used for client key signing.

![ssh create ca](/images/platform/ssh/ssh-create-ca-1.png)
![ssh create client ca](/images/platform/ssh/ssh-client-create-ca-1.png)

![ssh create ca popup](/images/platform/ssh/ssh-create-ca-2.png)
![ssh create client ca popup](/images/platform/ssh/ssh-client-create-ca-2.png)

Here's some guidance on each field:

- Friendly Name: A friendly name for the CA; this is only for display.
- Key Algorithm: The type of public key algorithm and size, in bits, of the key pair for the CA. Supported key algorithms are `RSA 2048`, `RSA 4096`, `ECDSA P-256`, and `ECDSA P-384` with the default being `RSA 2048`.

1.3. Next, create a certificate template in the **Certificate Templates** section of the newly-created CA.
</Step>
<Step title="Configuring a certificate template on the CA">

2.1. Next, create a certificate template in the **Certificate Templates** section of the newly-created CA.

A certificate template is a set of policies for certificates issued under that template; each template is bound to a specific CA.

With certificate templates, you can specify, for example, that certificates issued under a template are only allowed for users with a specific username like `ec2-user` or perhaps that the max TTL requested cannot exceed 1 year.
With certificate templates, you can specify, for example, that certificates issued under a template are only allowed for users with a specific username like `ec2-user` or perhaps that the max TTL requested cannot exceed 1 hour.

![ssh create template](/images/platform/ssh/ssh-create-template-1.png)
![ssh client create template](/images/platform/ssh/ssh-client-create-template-1.png)

![ssh create template popup](/images/platform/ssh/ssh-create-template-2.png)
![ssh client create template popup](/images/platform/ssh/ssh-client-create-template-2.png)

Here's some guidance on each field:

- SSH Template Name: A name for the certificate template; this must be a valid slug.
- Allowed Users: A comma-separated list of valid usernames (e.g. `ec2-user`) on the remote host for which a client can request a certificate for. If you wish to allow a client to request a certificate for any username, set this to `*`; alternatively, if left blank, the template will not allow issuance of certificates under any username.
- Allowed Hosts: A comma-separated list of valid hostnames/domains on the remote host for which a client can request a certificate for. Each item in the list can be either a wildcard hostname (e.g. `*.acme.com`), a specific hostname (e.g. `example.com`), an IPv4 address (e.g. `192.168.1.1`), or an IPv6 address. If left empty, the template will not allow any hostnames; if set to `*`, the template will allow any hostname.
- Default TTL: The default Time-to-Live (TTL) for certificates issued under this template when a client does not explicitly specify a TTL in the certificate request.
- Default TTL: The default Time-to-Live (TTL) for certificates issued under this template when a client does not explicitly specify a TTL in the certificate request. We recommend setting a shorter **Default TTL** for client certificates such as `30m`.
- Max TTL: The maximum TTL for certificates issued under this template.
- Allow User Certificates: Whether or not to allow issuance of user certificates.
- Allow Host Certificates: Whether or not to allow issuance of host certificates.
- Allow User Certificates: Whether or not to allow issuance of user certificates; this should be set to `true`.
- Allow Host Certificates: Whether or not to allow issuance of host certificates; this is not relevant for this step.
- Allow Custom Key IDs: Whether or not to allow clients to specify a custom key ID to be included on the certificate as part of the certificate request.

1.4. Finally, add the user(s) you wish to be able to request a SSH certificate to the SSH project through the **Access Control** tab.
2.2. Finally, add the user(s) you wish to be able to request a SSH certificate to the SSH project through the **Access Control** tab.

</Step>
<Step title="Configuring the remote host">
<Step title="Configuring the remote host to trust the client">

2.1. Begin by downloading the CA's public key from the CA's details section.
3.1. Begin by downloading the client CA's public key from the CA's details section.

![ssh ca public key](/images/platform/ssh/ssh-ca-public-key.png)
![ssh ca public key](/images/platform/ssh/ssh-client-ca-public-key.png)

<Note>
The CA's public key can also be retrieved programmatically via API by making a `GET` request to the `/ssh/ca/<ca-id>/public-key` endpoint.
The CA's public key can also be retrieved programmatically via API by making a `GET` request to the endpoint [here](/api-reference/endpoints/ssh/ca/public-key).
</Note>

2.2. Next, create a file containing this public key in the SSH folder of the remote host; we'll call the file `ca.pub`.
3.2. Next, create a file containing this public key in the SSH folder of the remote host; we'll call the file `ca.pub`.

This would result in the file at the path `/etc/ssh/ca.pub`.

2.3. Next, add the following lines to the `/etc/ssh/sshd_config` file on the remote host.
3.3. Next, add the following lines to the `/etc/ssh/sshd_config` file on the remote host.

```bash
TrustedUserCAKeys /etc/ssh/ca.pub

PubkeyAcceptedKeyTypes=+ssh-rsa,[email protected]
```

2.4. Finally, reload the SSH daemon on the remote host to apply the changes.
3.4. Finally, reload the SSH daemon on the remote host to apply the changes.

```bash
sudo systemctl reload sshd
Expand All @@ -159,7 +162,7 @@ as part of the SSH operation.

## Guide to Using Infisical SSH to Access a Host

We show how to obtain a SSH certificate and use it for a client to access a host via CLI:
In the following steps, we show how to obtain a SSH certificate and use it for a client to access a host via CLI:

<Note>
The subsequent guide assumes the following prerequisites:
Expand All @@ -181,7 +184,7 @@ infisical login
```

</Step>
<Step title="Obtain a SSH certificate and load it into the SSH agent">
<Step title="Obtain a SSH certificate for the client and load it into the SSH agent">
Run the `infisical ssh issue-credentials` command, specifying the `--addToAgent` flag to automatically load the SSH certificate into the SSH agent.
```bash
infisical ssh issue-credentials --certificateTemplateId=<certificate-template-id> --principals=<username> --addToAgent
Expand All @@ -207,4 +210,103 @@ infisical login
<Note>
Note that the above workflow can be executed via API or other client methods
such as SDK.
</Note>
</Note>

## Guide to Configuring Host Key Signing

In the following steps, we show how to configure host key signing for clients to verify the identity of a remote host before attempting the SSH operation; this is recommended to reduce the probability of a client accessing a malicious machine.

<Steps>
<Step title="Configuring a SSH CA for host key signing">
1.1. In the same SSH project, create another SSH CA in the **Certificate Authorities** tab; this CA will be used for host key signing.

![ssh create host ca](/images/platform/ssh/ssh-host-create-ca-1.png)

![ssh create host ca popup](/images/platform/ssh/ssh-host-create-ca-2.png)

Here's some guidance on each field:

- Friendly Name: A friendly name for the CA; this is only for display.
- Key Algorithm: The type of public key algorithm and size, in bits, of the key pair for the CA. Supported key algorithms are `RSA 2048`, `RSA 4096`, `ECDSA P-256`, and `ECDSA P-384` with the default being `RSA 2048`.

</Step>
<Step title="Configuring a certificate template on the CA">

2.1. Next, create a certificate template in the **Certificate Templates** section of the newly-created CA.

![ssh host create template](/images/platform/ssh/ssh-host-create-template-1.png)

![ssh host create template popup](/images/platform/ssh/ssh-host-create-template-2.png)

Here's some guidance on each field:

- SSH Template Name: A name for the certificate template; this must be a valid slug.
- Allowed Users: A comma-separated list of valid usernames (e.g. `ec2-user`) on the remote host for which a client can request a certificate for. If you wish to allow a client to request a certificate for any username, set this to `*`; alternatively, if left blank, the template will not allow issuance of certificates under any username.
- Allowed Hosts: A comma-separated list of valid hostnames/domains on the remote host for which a client can request a certificate for. Each item in the list can be either a wildcard hostname (e.g. `*.acme.com`), a specific hostname (e.g. `example.com`), an IPv4 address (e.g. `192.168.1.1`), or an IPv6 address. If left empty, the template will not allow any hostnames; if set to `*`, the template will allow any hostname.
- Default TTL: The default Time-to-Live (TTL) for certificates issued under this template when a client does not explicitly specify a TTL in the certificate request. We recommend setting a longer **Default TTL** for host certificates such as `2y`.
- Max TTL: The maximum TTL for certificates issued under this template.
- Allow User Certificates: Whether or not to allow issuance of user certificates; this is not relevant for this step.
- Allow Host Certificates: Whether or not to allow issuance of host certificates; this should be set to `true`.
- Allow Custom Key IDs: Whether or not to allow clients to specify a custom key ID to be included on the certificate as part of the certificate request.
</Step>
<Step title="Configuring the remote host with an SSH certificate">

2.1. Obtain a SSH certificate for the host by requesting one from the **Certificates** tab.

![ssh host issue certificate 1](/images/platform/ssh/ssh-host-issue-cert-1.png)

![ssh host issue certificate 2](/images/platform/ssh/ssh-host-issue-cert-2.png)

<Note>
You should select **Sign SSH Key** under the **Operation** field.

Then input your host's public key under the **SSH Public Key** field and hostname under the **Principal(s)** field; the host's public key is likely in the `/etc/ssh` folder of the host.
</Note>

![ssh host issue certificate 3](/images/platform/ssh/ssh-host-issue-cert-3.png)

2.2. Create a file containing the certificate in the SSH folder of the remote host; we'll call it `key-cert.pub`.

2.2. Set permissions on the certificate to be `0640`:

```bash
sudo chmod 0640 /etc/ssh/ssh_host_key-cert.pub
```

2.3. Next, add the following lines to the `/etc/ssh/sshd_config` file on the remote host.

```bash
HostKey /etc/ssh/ssh_host_key
HostCertificate /etc/ssh/ssh_host_key-cert.pub
```

2.4. Finally, reload the SSH daemon on the remote host to apply the changes.

```bash
sudo systemctl reload sshd
```

</Step>
<Step title="Configuring the client to trust the remote host">
3.1. Begin by downloading the host CA's public key from the CA's details section.

![ssh host ca public key](/images/platform/ssh/ssh-host-ca-public-key.png)

<Note>
The CA's public key can also be retrieved programmatically via API by making a `GET` request to the endpoint [here](/api-reference/endpoints/ssh/ca/public-key).
</Note>

3.2. Next, add the resulting public key to the `known_hosts` file on the client machine (e.g. at the path `~/.ssh/known_hosts`).

```bash
@cert-authority *.example.com ssh-rsa ...
```
</Step>
<Step title="SSH into the host">
Finally, SSH into the desired host as usual; the SSH operation will now also include client-side host verification.

```bash
ssh username@hostname
```
</Step>
</Steps>
Binary file removed docs/images/platform/ssh/ssh-ca-public-key.png
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/images/platform/ssh/ssh-create-ca-1.png
Binary file not shown.
Binary file removed docs/images/platform/ssh/ssh-create-ca-2.png
Binary file not shown.
Binary file removed docs/images/platform/ssh/ssh-create-template-1.png
Binary file not shown.
Binary file removed docs/images/platform/ssh/ssh-create-template-2.png
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion frontend/src/helpers/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export const getProjectHomePage = (workspace: Workspace) => {
return `/${workspace.type}/${workspace.id}/kms`;
}

return `/${workspace.type}/${workspace.id}/ssh`;
return `/${workspace.type}/${workspace.id}/certificates`;
};

export const getProjectTitle = (type: ProjectType) => {
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/layouts/AppLayout/AppLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -386,9 +386,9 @@ export const AppLayout = ({ children }: LayoutProps) => {
<Link href={`/org/${currentOrg?.id}/ssh/overview`} passHref>
<a>
<MenuItem
isSelected={
router.asPath === `/org/${currentWorkspace?.id}/ssh/overview`
}
isSelected={router.asPath.includes(
`/${ProjectType.SSH}/overview`
)}
icon="system-regular-126-verified-hover-verified"
>
SSH
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,25 @@ export const ProjectSidebarItem = () => {
</Link>
)}
{isSsh && (
<Link href={`/${ProjectType.SSH}/${currentWorkspace?.id}/ssh`} passHref>
<Link href={`/${ProjectType.SSH}/${currentWorkspace?.id}/certificates`} passHref>
<a>
<MenuItem
isSelected={router.asPath === `/${ProjectType.SSH}/${currentWorkspace?.id}/ssh`}
isSelected={router.asPath === `/${ProjectType.SSH}/${currentWorkspace?.id}/certificates`}
icon="system-outline-90-lock-closed"
>
Overview
Certificates
</MenuItem>
</a>
</Link>
)}
{isSsh && (
<Link href={`/${ProjectType.SSH}/${currentWorkspace?.id}/cas`} passHref>
<a>
<MenuItem
isSelected={router.asPath === `/${ProjectType.SSH}/${currentWorkspace?.id}/cas`}
icon="system-outline-90-lock-closed"
>
Certificate Authorities
</MenuItem>
</a>
</Link>
Expand Down
23 changes: 23 additions & 0 deletions frontend/src/pages/ssh/[id]/cas/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useTranslation } from "react-i18next";
import Head from "next/head";

import { SshCasPage } from "@app/views/Project/SshCasPage";

const SshCas = () => {
const { t } = useTranslation();

return (
<div className="h-full bg-bunker-800">
<Head>
<title>{t("common.head-title", { title: "Certificate Authorities" })}</title>
<link rel="icon" href="/infisical.ico" />
<meta property="og:image" content="/images/message.png" />
</Head>
<SshCasPage />
</div>
);
};

export default SshCas;

SshCas.requireAuth = true;
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useTranslation } from "react-i18next";
import Head from "next/head";

import { SshPage } from "@app/views/Project/SshPage";
import { SshCertificatesPage } from "@app/views/Project/SshCertificatesPage";

const Ssh = () => {
const SshCertificates = () => {
const { t } = useTranslation();

return (
Expand All @@ -13,11 +13,11 @@ const Ssh = () => {
<link rel="icon" href="/infisical.ico" />
<meta property="og:image" content="/images/message.png" />
</Head>
<SshPage />
<SshCertificatesPage />
</div>
);
};

export default Ssh;
export default SshCertificates;

Ssh.requireAuth = true;
SshCertificates.requireAuth = true;
6 changes: 3 additions & 3 deletions frontend/src/views/Project/SshCaPage/SshCaPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { useDeleteSshCa, useGetSshCaById } from "@app/hooks/api";
import { ProjectType } from "@app/hooks/api/workspace/types";
import { usePopUp } from "@app/hooks/usePopUp";

import { SshCaModal } from "../SshPage/components/SshCaModal";
import { SshCaModal } from "../SshCasPage/components/SshCaModal";
import { SshCaDetailsSection, SshCertificateTemplatesSection } from "./components";

export const SshCaPage = withProjectPermission(
Expand Down Expand Up @@ -51,7 +51,7 @@ export const SshCaPage = withProjectPermission(
});

handlePopUpClose("deleteSshCa");
router.push(`/project/${projectId}/ssh`);
router.push(`/project/${projectId}/cas`);
} catch (err) {
console.error(err);
createNotification({
Expand All @@ -69,7 +69,7 @@ export const SshCaPage = withProjectPermission(
variant="link"
type="submit"
leftIcon={<FontAwesomeIcon icon={faChevronLeft} />}
onClick={() => router.push(`/${ProjectType.SSH}/${projectId}/ssh`)}
onClick={() => router.push(`/${ProjectType.SSH}/${projectId}/cas`)}
className="mb-4"
>
SSH Certificate Authorities
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const SshCertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
const { currentWorkspace } = useWorkspace();
const projectId = currentWorkspace?.id || "";
const [operation, setOperation] = useState<SshCertificateOperation>(
SshCertificateOperation.SIGN_SSH_KEY
SshCertificateOperation.ISSUE_SSH_CREDS
);
const [certificateDetails, setCertificateDetails] = useState<TSshCertificateDetails | null>(null);

Expand Down Expand Up @@ -315,7 +315,7 @@ export const SshCertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
errorText={error?.message}
isRequired
>
<Input {...field} placeholder="ec2-user" />
<Input {...field} placeholder="ec2-user, example.com" />
</FormControl>
)}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ const schema = z
allowHostCertificates: z.boolean().optional().default(false),
allowCustomKeyIds: z.boolean().optional().default(false)
})
.refine((data) => ms(data.maxTTL) > ms(data.ttl), {
message: "Max TLL must be greater than TTL",
.refine((data) => ms(data.maxTTL) >= ms(data.ttl), {
message: "Max TLL must be greater than or equal to TTL",
path: ["maxTTL"]
});

Expand Down
Loading
Loading