mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 10:27:26 +00:00
Bring back ssh host read permission
This commit is contained in:
@@ -412,7 +412,7 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
|
|||||||
sshHostId: z.string().trim().describe(SSH_HOSTS.GET_USER_CA_PUBLIC_KEY.sshHostId)
|
sshHostId: z.string().trim().describe(SSH_HOSTS.GET_USER_CA_PUBLIC_KEY.sshHostId)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.string()
|
200: z.string().describe(SSH_HOSTS.GET_USER_CA_PUBLIC_KEY.publicKey)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
@@ -433,7 +433,7 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
|
|||||||
sshHostId: z.string().trim().describe(SSH_HOSTS.GET_HOST_CA_PUBLIC_KEY.sshHostId)
|
sshHostId: z.string().trim().describe(SSH_HOSTS.GET_HOST_CA_PUBLIC_KEY.sshHostId)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.string()
|
200: z.string().describe(SSH_HOSTS.GET_HOST_CA_PUBLIC_KEY.publicKey)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export enum ProjectPermissionGroupActions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum ProjectPermissionSshHostActions {
|
export enum ProjectPermissionSshHostActions {
|
||||||
|
Read = "read",
|
||||||
Create = "create",
|
Create = "create",
|
||||||
Edit = "edit",
|
Edit = "edit",
|
||||||
Delete = "delete",
|
Delete = "delete",
|
||||||
@@ -657,6 +658,7 @@ const buildAdminPermissionRules = () => {
|
|||||||
can(
|
can(
|
||||||
[
|
[
|
||||||
ProjectPermissionSshHostActions.Edit,
|
ProjectPermissionSshHostActions.Edit,
|
||||||
|
ProjectPermissionSshHostActions.Read,
|
||||||
ProjectPermissionSshHostActions.Create,
|
ProjectPermissionSshHostActions.Create,
|
||||||
ProjectPermissionSshHostActions.Delete,
|
ProjectPermissionSshHostActions.Delete,
|
||||||
ProjectPermissionSshHostActions.IssueHostCert
|
ProjectPermissionSshHostActions.IssueHostCert
|
||||||
@@ -924,6 +926,8 @@ const buildMemberPermissionRules = () => {
|
|||||||
can([ProjectPermissionActions.Create], ProjectPermissionSub.SshCertificates);
|
can([ProjectPermissionActions.Create], ProjectPermissionSub.SshCertificates);
|
||||||
can([ProjectPermissionActions.Read], ProjectPermissionSub.SshCertificateTemplates);
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.SshCertificateTemplates);
|
||||||
|
|
||||||
|
can([ProjectPermissionSshHostActions.Read], ProjectPermissionSub.SshHosts);
|
||||||
|
|
||||||
can(
|
can(
|
||||||
[
|
[
|
||||||
ProjectPermissionCmekActions.Create,
|
ProjectPermissionCmekActions.Create,
|
||||||
|
|||||||
@@ -415,7 +415,7 @@ export const sshHostServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await permissionService.getProjectPermission({
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
projectId: host.projectId,
|
projectId: host.projectId,
|
||||||
@@ -424,6 +424,13 @@ export const sshHostServiceFactory = ({
|
|||||||
actionProjectType: ActionProjectType.SSH
|
actionProjectType: ActionProjectType.SSH
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionSshHostActions.Read,
|
||||||
|
subject(ProjectPermissionSub.SshHosts, {
|
||||||
|
hostname: host.hostname
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
return host;
|
return host;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -430,7 +430,8 @@ export const validateExternalSshCaKeyPair = async (publicKey: string, privateKey
|
|||||||
|
|
||||||
if (publicKey.trim() !== derivedPublicKey.trim()) {
|
if (publicKey.trim() !== derivedPublicKey.trim()) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "Failed to validate matching SSH key pair."
|
message:
|
||||||
|
"Failed to validate matching SSH key pair: The provided public key does not match the public key derived from the private key."
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1381,10 +1381,12 @@ export const SSH_HOSTS = {
|
|||||||
signedKey: "The SSH certificate or signed SSH public key."
|
signedKey: "The SSH certificate or signed SSH public key."
|
||||||
},
|
},
|
||||||
GET_USER_CA_PUBLIC_KEY: {
|
GET_USER_CA_PUBLIC_KEY: {
|
||||||
sshHostId: "The ID of the SSH host to get the user SSH CA public key for."
|
sshHostId: "The ID of the SSH host to get the user SSH CA public key for.",
|
||||||
|
publicKey: "The public key of the user SSH CA linked to the SSH host."
|
||||||
},
|
},
|
||||||
GET_HOST_CA_PUBLIC_KEY: {
|
GET_HOST_CA_PUBLIC_KEY: {
|
||||||
sshHostId: "The ID of the SSH host to get the host SSH CA public key for."
|
sshHostId: "The ID of the SSH host to get the host SSH CA public key for.",
|
||||||
|
publicKey: "The public key of the host SSH CA linked to the SSH host."
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError, subject } from "@casl/ability";
|
||||||
import slugify from "@sindresorhus/slugify";
|
import slugify from "@sindresorhus/slugify";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -15,6 +15,7 @@ import { TPermissionServiceFactory } from "@app/ee/services/permission/permissio
|
|||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSecretActions,
|
ProjectPermissionSecretActions,
|
||||||
|
ProjectPermissionSshHostActions,
|
||||||
ProjectPermissionSub
|
ProjectPermissionSub
|
||||||
} from "@app/ee/services/permission/project-permission";
|
} from "@app/ee/services/permission/project-permission";
|
||||||
import { TProjectTemplateServiceFactory } from "@app/ee/services/project-template/project-template-service";
|
import { TProjectTemplateServiceFactory } from "@app/ee/services/project-template/project-template-service";
|
||||||
@@ -1077,7 +1078,7 @@ export const projectServiceFactory = ({
|
|||||||
actor,
|
actor,
|
||||||
projectId
|
projectId
|
||||||
}: TListProjectSshHostsDTO) => {
|
}: TListProjectSshHostsDTO) => {
|
||||||
await permissionService.getProjectPermission({
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
projectId,
|
projectId,
|
||||||
@@ -1086,8 +1087,27 @@ export const projectServiceFactory = ({
|
|||||||
actionProjectType: ActionProjectType.SSH
|
actionProjectType: ActionProjectType.SSH
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const allowedHosts = [];
|
||||||
|
|
||||||
|
// (dangtony98): room to optimize
|
||||||
const hosts = await sshHostDAL.findSshHostsWithLoginMappings(projectId);
|
const hosts = await sshHostDAL.findSshHostsWithLoginMappings(projectId);
|
||||||
return hosts;
|
|
||||||
|
for (const host of hosts) {
|
||||||
|
try {
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionSshHostActions.Read,
|
||||||
|
subject(ProjectPermissionSub.SshHosts, {
|
||||||
|
hostname: host.hostname
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
allowedHosts.push(host);
|
||||||
|
} catch {
|
||||||
|
// intentionally ignore projects where user lacks access
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allowedHosts;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ unauthorized access, and SSH key sprawl.
|
|||||||
The following concepts are useful to know when working with Infisical SSH:
|
The following concepts are useful to know when working with Infisical SSH:
|
||||||
|
|
||||||
- SSH Certificate Authority (CA): A trusted authority that issues SSH certificates.
|
- SSH Certificate Authority (CA): A trusted authority that issues SSH certificates.
|
||||||
- Certificate Template: A set of policies bound to a SSH CA for certificates issued under that template; a CA can possess multiple templates, each with different policies for a different purpose (e.g. for admin versus developer access).
|
- Certificate Template: A set of policies bound to an SSH CA for certificates issued under that template; a CA can possess multiple templates, each with different policies for a different purpose (e.g. for admin versus developer access).
|
||||||
- SSH Certificate: A short-lived, credential issued by the SSH CA granting time-bound access to infrastructure.
|
- SSH Certificate: A short-lived, credential issued by the SSH CA granting time-bound access to infrastructure.
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
@@ -30,10 +30,10 @@ graph TD
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
When using Infisical SSH to provision client access to a remote host, an operator must create a SSH CA in Infisical; a certificate template under it,
|
When using Infisical SSH to provision client access to a remote host, an operator must create an SSH CA in Infisical; a certificate template under it,
|
||||||
specifying policies such as allowed users that can be requested under that template by a client; and configure the host to trust certificates issued by the Infisical SSH CA.
|
specifying policies such as allowed users that can be requested under that template by a client; and configure the host to trust certificates issued by the Infisical SSH CA.
|
||||||
|
|
||||||
When a client needs access to a host, they authenticate with Infisical and request a SSH certificate (and optionally key pair)
|
When a client needs access to a host, they authenticate with Infisical and request an SSH certificate (and optionally key pair)
|
||||||
to be used to access the host for a time-bound session as part of the SSH operation.
|
to be used to access the host for a time-bound session as part of the SSH operation.
|
||||||
|
|
||||||
## Client Workflow
|
## Client Workflow
|
||||||
@@ -68,7 +68,7 @@ At a high-level, Infisical issues a signed SSH certificate to a client that can
|
|||||||
To be more specific:
|
To be more specific:
|
||||||
|
|
||||||
1. The client authenticates with Infisical; this can be done using a user or machine identity [authentication method](/documentation/platform/identities/machine-identities) or a user [authentication method](/documentation/platform/identities/user-identities).
|
1. The client authenticates with Infisical; this can be done using a user or machine identity [authentication method](/documentation/platform/identities/machine-identities) or a user [authentication method](/documentation/platform/identities/user-identities).
|
||||||
2. The client makes an authenticated request for an SSH certificate via either the `/api/v1/ssh/issue` or `/api/v1/ssh/sign` endpoints. Note that if the client wishes to use an existing SSH key pair, it can use the `/api/v1/ssh/sign` endpoint; otherwise, it can use the `/api/v1/ssh/issue` endpoint to have Infisical issue a new SSH key pair in conjunction with the certificate.
|
2. The client makes an authenticated request for an SSH certificate via either the `/api/v1/ssh/issue` or `/api/v1/ssh/sign` endpoints. Note that if the client wishes to use an existing SSH key pair, it can use the `/api/v1/ssh/sign` endpoint; otherwise, it can use the `/api/v1/ssh/issue` endpoint to have Infisical issue a new SSH key pair along with the certificate.
|
||||||
3. The client uses the issued SSH certificate (and potentially SSH key pair) to temporarily access the host.
|
3. The client uses the issued SSH certificate (and potentially SSH key pair) to temporarily access the host.
|
||||||
|
|
||||||
<Note>
|
<Note>
|
||||||
@@ -83,12 +83,12 @@ In the following steps, we explore how to configure Infisical SSH to start issui
|
|||||||
as part of the SSH operation.
|
as part of the SSH operation.
|
||||||
|
|
||||||
<Steps>
|
<Steps>
|
||||||
<Step title="Configuring a SSH CA for client key signing">
|
<Step title="Configuring an SSH CA for client key signing">
|
||||||
1.1. Start by creating a SSH project in the SSH tab of your organization.
|
1.1. Start by creating an SSH project in the SSH tab of your organization.
|
||||||
|
|
||||||

|

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

|

|
||||||
@@ -125,7 +125,7 @@ as part of the SSH operation.
|
|||||||
- Allow Host Certificates: Whether or not to allow issuance of host certificates; this is not relevant for this step.
|
- 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.
|
- 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.
|
||||||
|
|
||||||
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.
|
2.2. Finally, add the user(s) you wish to be able to request an SSH certificate to the SSH project through the **Access Control** tab.
|
||||||
|
|
||||||
</Step>
|
</Step>
|
||||||
<Step title="Configuring the remote host to trust the client">
|
<Step title="Configuring the remote host to trust the client">
|
||||||
@@ -185,7 +185,7 @@ infisical login
|
|||||||
```
|
```
|
||||||
|
|
||||||
</Step>
|
</Step>
|
||||||
<Step title="Obtain a SSH certificate for the client and load it into the SSH agent">
|
<Step title="Obtain an 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.
|
Run the `infisical ssh issue-credentials` command, specifying the `--addToAgent` flag to automatically load the SSH certificate into the SSH agent.
|
||||||
```bash
|
```bash
|
||||||
infisical ssh issue-credentials --certificateTemplateId=<certificate-template-id> --principals=<username> --addToAgent
|
infisical ssh issue-credentials --certificateTemplateId=<certificate-template-id> --principals=<username> --addToAgent
|
||||||
@@ -229,7 +229,7 @@ If the remote host does not have an existing SSH key pair, you can generate a ne
|
|||||||
</Note>
|
</Note>
|
||||||
|
|
||||||
<Steps>
|
<Steps>
|
||||||
<Step title="Configuring a SSH CA for host key signing">
|
<Step title="Configuring an 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.
|
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.
|
||||||
|
|
||||||

|

|
||||||
@@ -266,7 +266,7 @@ If the remote host does not have an existing SSH key pair, you can generate a ne
|
|||||||
</Step>
|
</Step>
|
||||||
<Step title="Configuring the remote host with an SSH certificate">
|
<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.
|
3.1. Obtain an SSH certificate for the host by requesting one from the **Certificates** tab.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -280,15 +280,15 @@ If the remote host does not have an existing SSH key pair, you can generate a ne
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
2.2. Create a file containing the certificate in the SSH folder of the remote host; we'll call it `ssh_host_key-cert.pub`.
|
3.2. Create a file containing the certificate in the SSH folder of the remote host; we'll call it `ssh_host_key-cert.pub`.
|
||||||
|
|
||||||
2.3. Set permissions on the certificate to be `0640`:
|
3.3. Set permissions on the certificate to be `0640`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo chmod 0640 /etc/ssh/ssh_host_key-cert.pub
|
sudo chmod 0640 /etc/ssh/ssh_host_key-cert.pub
|
||||||
```
|
```
|
||||||
|
|
||||||
2.4. Next, add the following lines to the `/etc/ssh/sshd_config` file on the remote host.
|
3.4. Next, add the following lines to the `/etc/ssh/sshd_config` file on the remote host.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
HostKey /etc/ssh/ssh_host_rsa_key
|
HostKey /etc/ssh/ssh_host_rsa_key
|
||||||
@@ -299,7 +299,7 @@ If the remote host does not have an existing SSH key pair, you can generate a ne
|
|||||||
You should adjust the `HostKey` directive to match the path to the host's SSH private key as used in step 1.
|
You should adjust the `HostKey` directive to match the path to the host's SSH private key as used in step 1.
|
||||||
</Note>
|
</Note>
|
||||||
|
|
||||||
2.5. Finally, reload the SSH daemon on the remote host to apply the changes.
|
3.5. Finally, reload the SSH daemon on the remote host to apply the changes.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo systemctl reload sshd
|
sudo systemctl reload sshd
|
||||||
@@ -307,7 +307,7 @@ If the remote host does not have an existing SSH key pair, you can generate a ne
|
|||||||
|
|
||||||
</Step>
|
</Step>
|
||||||
<Step title="Configuring the client to trust the remote host">
|
<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.
|
4.1. Begin by downloading the host CA's public key from the CA's details section.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -315,7 +315,7 @@ If the remote host does not have an existing SSH key pair, you can generate a ne
|
|||||||
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).
|
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>
|
</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`).
|
4.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
|
```bash
|
||||||
@cert-authority *.example.com ssh-rsa ...
|
@cert-authority *.example.com ssh-rsa ...
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ description: "Learn how to securely provision user SSH access to your infrastruc
|
|||||||
|
|
||||||
## Concept
|
## Concept
|
||||||
|
|
||||||
Infisical SSH can be used to provide users short-lived, secure SSH access to infrastructure; the underlying technology is powered by SSH certificates
|
Infisical SSH can be configured to provide users on your team short-lived, secure SSH access to infrastructure. Under the hood, it uses SSH certificates
|
||||||
and improves on the limitations of traditional SSH key-based authentication via mitigation of private key compromise, static key management,
|
and improves upon traditional SSH key-based authentication by mitigating private key compromise, static key management,
|
||||||
unauthorized access, and SSH key sprawl.
|
unauthorized access, and SSH key sprawl.
|
||||||
|
|
||||||
The following entities and concepts are important to understand when using Infisical SSH:
|
The following entities and concepts are important to understand when using Infisical SSH:
|
||||||
@@ -90,6 +90,17 @@ we will register a remote host with Infisical through a [machine identity](/docu
|
|||||||
📄 Updated sshd_config entries
|
📄 Updated sshd_config entries
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Finally, use the following command to reload the SSH daemon on the remote host to apply the changes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl reload sshd
|
||||||
|
```
|
||||||
|
|
||||||
|
<Note>
|
||||||
|
The command may differ depending on the host. For older versions of Ubuntu/Debian/CentOS, you may need to use `sudo service ssh reload` instead;
|
||||||
|
for Alpine or minimal systems, `/etc/init.d/sshd reload`.
|
||||||
|
</Note>
|
||||||
|
|
||||||
Back in Infisical, you should now see the remote host you just registered in the Infisical SSH project you created in step 1 under the **Hosts** tab.
|
Back in Infisical, you should now see the remote host you just registered in the Infisical SSH project you created in step 1 under the **Hosts** tab.
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
@@ -76,6 +76,7 @@ export enum ProjectPermissionGroupActions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum ProjectPermissionSshHostActions {
|
export enum ProjectPermissionSshHostActions {
|
||||||
|
Read = "read",
|
||||||
Create = "create",
|
Create = "create",
|
||||||
Edit = "edit",
|
Edit = "edit",
|
||||||
Delete = "delete",
|
Delete = "delete",
|
||||||
|
|||||||
+5
@@ -110,6 +110,7 @@ const GroupPolicyActionSchema = z.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const SshHostPolicyActionSchema = z.object({
|
const SshHostPolicyActionSchema = z.object({
|
||||||
|
[ProjectPermissionSshHostActions.Read]: z.boolean().optional(),
|
||||||
[ProjectPermissionSshHostActions.Create]: z.boolean().optional(),
|
[ProjectPermissionSshHostActions.Create]: z.boolean().optional(),
|
||||||
[ProjectPermissionSshHostActions.Edit]: z.boolean().optional(),
|
[ProjectPermissionSshHostActions.Edit]: z.boolean().optional(),
|
||||||
[ProjectPermissionSshHostActions.Delete]: z.boolean().optional(),
|
[ProjectPermissionSshHostActions.Delete]: z.boolean().optional(),
|
||||||
@@ -610,6 +611,9 @@ export const rolePermission2Form = (permissions: TProjectPermission[] = []) => {
|
|||||||
[ProjectPermissionSshHostActions.Create]: action.includes(
|
[ProjectPermissionSshHostActions.Create]: action.includes(
|
||||||
ProjectPermissionSshHostActions.Create
|
ProjectPermissionSshHostActions.Create
|
||||||
),
|
),
|
||||||
|
[ProjectPermissionSshHostActions.Read]: action.includes(
|
||||||
|
ProjectPermissionSshHostActions.Read
|
||||||
|
),
|
||||||
[ProjectPermissionSshHostActions.IssueHostCert]: action.includes(
|
[ProjectPermissionSshHostActions.IssueHostCert]: action.includes(
|
||||||
ProjectPermissionSshHostActions.IssueHostCert
|
ProjectPermissionSshHostActions.IssueHostCert
|
||||||
),
|
),
|
||||||
@@ -945,6 +949,7 @@ export const PROJECT_PERMISSION_OBJECT: TProjectPermissionObject = {
|
|||||||
[ProjectPermissionSub.SshHosts]: {
|
[ProjectPermissionSub.SshHosts]: {
|
||||||
title: "SSH Hosts",
|
title: "SSH Hosts",
|
||||||
actions: [
|
actions: [
|
||||||
|
{ label: "Read", value: ProjectPermissionSshHostActions.Read },
|
||||||
{ label: "Create", value: ProjectPermissionSshHostActions.Create },
|
{ label: "Create", value: ProjectPermissionSshHostActions.Create },
|
||||||
{ label: "Modify", value: ProjectPermissionSshHostActions.Edit },
|
{ label: "Modify", value: ProjectPermissionSshHostActions.Edit },
|
||||||
{ label: "Remove", value: ProjectPermissionSshHostActions.Delete },
|
{ label: "Remove", value: ProjectPermissionSshHostActions.Delete },
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ const schema = z
|
|||||||
(val) => ms(val) > 0,
|
(val) => ms(val) > 0,
|
||||||
"TTL must be a valid time string such as 2 days, 1d, 2h 1y, ..."
|
"TTL must be a valid time string such as 2 days, 1d, 2h 1y, ..."
|
||||||
)
|
)
|
||||||
.default("8h"),
|
.default("8h, 1d, 30m"),
|
||||||
loginMappings: z
|
loginMappings: z
|
||||||
.object({
|
.object({
|
||||||
loginUser: z.string().trim().min(1),
|
loginUser: z.string().trim().min(1),
|
||||||
@@ -206,7 +206,7 @@ export const SshHostModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
errorText={error?.message}
|
errorText={error?.message}
|
||||||
isRequired
|
isRequired
|
||||||
>
|
>
|
||||||
<Input {...field} placeholder="8h" />
|
<Input {...field} placeholder="8h, 1d, 30m" />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -328,7 +328,7 @@ export const SshHostModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
{(value.length === 0 ? [""] : value).map(
|
{(value.length === 0 ? [""] : value).map(
|
||||||
(principal: string, principalIndex: number) => (
|
(principal: string, principalIndex: number) => (
|
||||||
<div
|
<div
|
||||||
key={`${metadataFieldId}-principal-${principal || principalIndex}`}
|
key={`${metadataFieldId}-principal-${principal}`}
|
||||||
className="flex items-center space-x-2"
|
className="flex items-center space-x-2"
|
||||||
>
|
>
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
|
|||||||
Reference in New Issue
Block a user