Skip to content

upcoming: [UIE-10333] - Allow Creating Secure Linodes without Root Password#13516

Open
harsh-akamai wants to merge 8 commits intolinode:developfrom
harsh-akamai:uie-10333-password-less-linodes
Open

upcoming: [UIE-10333] - Allow Creating Secure Linodes without Root Password#13516
harsh-akamai wants to merge 8 commits intolinode:developfrom
harsh-akamai:uie-10333-password-less-linodes

Conversation

@harsh-akamai
Copy link
Contributor

@harsh-akamai harsh-akamai commented Mar 23, 2026

Description 📝

This PR eliminates the root password requirement during Linode creation and supports SSH key-based authentication without disrupting existing customer workflows.

For Linode Create, Rebuild and Create Linode Disk flows

  • Make Root Password an optional field if SSH Keys are passed

Changes 🔄

  • PasswordLess Linodes feature flag toggle added to our dev tool
  • Updated the Linode Create, Rebuild and Disk Create validations
  • Added new Security layouts as per figma

Scope 🚢

Upon production release, changes in this PR will be visible to:

  • All customers
  • Some customers (e.g. in Beta or Limited Availability)
  • No customers / Not applicable

Target release date 🗓️

Please specify a release date (and environment, if applicable) to guarantee timely review of this PR. If exact date is not known, please approximate and update it as needed.

Preview 📷

Linode Create

Before After
image image
Error Message Layout
Before After
image image

Linode Rebuild

Before After
image image

Create Linode Disk

Before After
image image

How to test 🧪

Prerequisites

  • Enable the "PasswordLess Lindoes" flag in devtools

Verification steps

Note

The API doesn’t currently support creating a Linode using only SSH keys. To verify the changes, we should ensure the validation behaves as expected. In cases where a root password isn’t provided, the API request should not include the root_pass parameter.

Linode Create

  • Navigate to the Linode Create page
  • Select any tab where Root Password is required (OS, Quick Deploy Apps, StackScripts, or Images)
  • Try submitting the form without Root Password and SSH keys.
  • Verify the error message is thrown as expected
  • Submit the form with only SSH keys provided
  • Verify that the form submits successfully and an API call is triggered

Linode Rebuild Form and Create Linode Disk Drawer(From Image)

  • Try submitting the form without Root Password and SSH keys.
  • Verify the error message is thrown as expected
  • Submit the form with only SSH keys provided
  • Verify that the form submits successfully and an API call is triggered
Author Checklists

As an Author, to speed up the review process, I considered 🤔

👀 Doing a self review
❔ Our contribution guidelines
🤏 Splitting feature into small PRs
➕ Adding a changeset
🧪 Providing/improving test coverage
🔐 Removing all sensitive information from the code and PR description
🚩 Using a feature flag to protect the release
👣 Providing comprehensive reproduction steps
📑 Providing or updating our documentation
🕛 Scheduling a pair reviewing session
📱 Providing mobile support
♿ Providing accessibility support


  • I have read and considered all applicable items listed above.

As an Author, before moving this PR from Draft to Open, I confirmed ✅

  • All tests and CI checks are passing
  • TypeScript compilation succeeded without errors
  • Code passes all linting rules

@harsh-akamai harsh-akamai self-assigned this Mar 23, 2026
@harsh-akamai harsh-akamai marked this pull request as ready for review March 24, 2026 04:19
@harsh-akamai harsh-akamai requested a review from a team as a code owner March 24, 2026 04:19
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Enables a feature-flagged “passwordless Linode” flow in Manager UI so users can create/rebuild/deploy-from-image disks using SSH key auth without requiring a root password, while updating shared validation and API types to support new/adjusted payload shapes.

Changes:

  • Adds passwordlessLinodes feature flag and a useIsPasswordLessLinodesEnabled helper hook (plus dev-tools toggle + tests).
  • Updates Manager UI + validation selection for Create, Rebuild, and Create Disk-from-image to allow SSH-key-only authentication when flagged on.
  • Extends shared validation/API typings (e.g., kernel, boot_size) and introduces new validation schema variants for disk-from-image.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
packages/validation/src/linodes.schema.ts Makes root_pass optional in base schemas; adds disk-from-image schema variants; adds kernel/boot_size fields.
packages/manager/src/utilities/linodes.ts Adds useIsPasswordLessLinodesEnabled feature-flag hook.
packages/manager/src/utilities/linodes.test.ts Adds unit tests for the new feature-flag hook.
packages/manager/src/features/Linodes/LinodesDetail/LinodeStorage/CreateDiskDrawer.tsx Switches disk validation schema based on mode + passwordless flag.
packages/manager/src/features/Linodes/LinodesDetail/LinodeSettings/ImageAndPassword.tsx Updates layout/error presentation when passwordless is enabled.
packages/manager/src/features/Linodes/LinodesDetail/LinodeRebuild/utils.ts Adds passwordless-aware rebuild validation resolver selection.
packages/manager/src/features/Linodes/LinodesDetail/LinodeRebuild/Password.tsx Adds showErrorText option to control inline error rendering.
packages/manager/src/features/Linodes/LinodesDetail/LinodeRebuild/LinodeRebuildForm.tsx Threads passwordless flag into form context and updates authentication UI layout.
packages/manager/src/features/Linodes/LinodeCreate/utilities.ts Adds passwordless flag to RHF context typing; fixes a typo in comment.
packages/manager/src/features/Linodes/LinodeCreate/schemas.ts Adds helpers to wrap schemas with root password required/optional behavior.
packages/manager/src/features/Linodes/LinodeCreate/resolvers.ts Makes schema selection depend on passwordless flag; fixes typos in comments.
packages/manager/src/features/Linodes/LinodeCreate/index.tsx Wires passwordless flag into create form context; updates Security import path.
packages/manager/src/features/Linodes/LinodeCreate/Security/Security.tsx Refactors Security section into Password + SSHKeys components and reorders based on flag.
packages/manager/src/features/Linodes/LinodeCreate/Security/Security.test.tsx Fixes type import path after Security refactor.
packages/manager/src/features/Linodes/LinodeCreate/Security/SSHKeys.tsx New component encapsulating SSH key selection + permissions.
packages/manager/src/features/Linodes/LinodeCreate/Security/Password.tsx New component encapsulating root password input + passwordless error layout.
packages/manager/src/featureFlags.ts Adds passwordlessLinodes to flags interface.
packages/manager/src/dev-tools/FeatureFlagTool.tsx Adds dev-tools toggle for passwordlessLinodes.
packages/api-v4/src/linodes/types.ts Adds kernel/boot_size to CreateLinodeRequest; replaces RebuildRequest infer-type with explicit interface.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

// .concat(rootPasswordValidation),
otherwise: (schema) => schema.notRequired(),
}),
root_pass: string(),
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CreateLinodeDiskSchema no longer enforces root_pass when image is set. This schema is used by the API client (packages/api-v4/src/linodes/disks.ts uses setData(data, CreateLinodeDiskSchema)), so disk creation from an image can now be submitted without a password and without SSH keys, which likely just defers the error to the API. Suggest restoring conditional validation on root_pass when image is present (or adding a dedicated passwordless schema variant and keeping the base schema strict).

Suggested change
root_pass: string(),
root_pass: string().when('image', {
is: (value: any) => Boolean(value),
then: (schema) =>
schema.required(
'You must provide a root password when deploying from an image.',
),
// .concat(rootPasswordValidation),
otherwise: (schema) => schema.notRequired(),
}),

Copilot uses AI. Check for mistakes.
Comment on lines +819 to 821
kernel: string().notRequired(),
boot_size: number().notRequired(),
swap_size: number().notRequired(),
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kernel and boot_size are added as optional fields but are not marked nullable. In packages/api-v4/src/linodes/types.ts they’re typed as null | string / null | number, so passing null (which is allowed by the types) would fail schema validation. Consider using string().nullable().notRequired() / number().nullable().notRequired() (and aligning with how other nullable request fields like backup_id are modeled).

Suggested change
kernel: string().notRequired(),
boot_size: number().notRequired(),
swap_size: number().notRequired(),
kernel: string().nullable().notRequired(),
boot_size: number().nullable().notRequired(),
swap_size: number().nullable().notRequired(),

Copilot uses AI. Check for mistakes.
schema.test({
name: 'root-pass-or-authorized-users',
message:
'An SSH Key or a Root Password is required to create an instance. We recommend using an SSH Key for better security.',
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The validation error message here says "required to create an instance", but this schema is used for creating a disk from an image. This is user-facing copy and is likely to be confusing in the disk drawer context; consider wording it specifically for disk creation (or using a more generic "to proceed" message).

Suggested change
'An SSH Key or a Root Password is required to create an instance. We recommend using an SSH Key for better security.',
'An SSH Key or a Root Password is required to create this disk. We recommend using an SSH Key for better security.',

Copilot uses AI. Check for mistakes.
Comment on lines 452 to 456
export const RebuildLinodeSchema = object({
image: string().required('An image is required.'),
root_pass: string().required('Password is required.'),
root_pass: string(),
authorized_keys: array().of(string().required()),
authorized_users: array().of(string().required()),
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RebuildLinodeSchema no longer requires root_pass. This schema is used for request validation in packages/api-v4/src/linodes/actions.ts (setData(data, RebuildLinodeSchema)), so callers can now submit a rebuild without root_pass and without any SSH keys and only find out via a server-side 400. Consider keeping the previous requirement (e.g., require root_pass when both authorized_users and authorized_keys are empty) and introducing a separate passwordless schema variant for the UI feature-flagged flow instead of weakening the base schema.

Copilot uses AI. Check for mistakes.
),
otherwise: (schema) => schema.notRequired(),
}),
root_pass: string(),
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CreateLinodeSchema now declares root_pass: string() with no conditional requirement. Since CreateLinodeSchema is used by the API client (packages/api-v4/src/linodes/linodes.ts uses setData(data, CreateLinodeSchema)), this allows creating an image-based Linode without root_pass or SSH keys and only fails at the API. Consider keeping the base schema’s previous behavior (require root_pass when deploying from an image unless SSH keys are provided), and if needed add a separate passwordless schema for the feature-flagged Manager flow.

Suggested change
root_pass: string(),
root_pass: string().when(['image', 'authorized_keys'], {
is: (image: unknown, authorized_keys: unknown) => {
const hasImage = Boolean(image);
const keys = Array.isArray(authorized_keys) ? authorized_keys : [];
const hasNoKeys = keys.length === 0;
return hasImage && hasNoKeys;
},
then: (schema) =>
schema.required('You must provide a root password or SSH keys.'),
otherwise: (schema) => schema.notRequired(),
}),

Copilot uses AI. Check for mistakes.
Comment on lines +653 to +656
const { authorized_users } = context.parent;
const hasAuthorizedUsers =
Array.isArray(authorized_users) && authorized_users.length > 0;
return Boolean(value) || hasAuthorizedUsers;
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In CreateLinodeDiskFromImageWithoutPasswordSchema, the root_pass requirement is waived only when authorized_users is non-empty, but the schema also supports authorized_keys. If a consumer supplies authorized_keys (public key strings) but not authorized_users, validation will still fail even though SSH-key auth is present. Consider checking both authorized_users and authorized_keys when deciding whether a password can be omitted.

Suggested change
const { authorized_users } = context.parent;
const hasAuthorizedUsers =
Array.isArray(authorized_users) && authorized_users.length > 0;
return Boolean(value) || hasAuthorizedUsers;
const { authorized_users, authorized_keys } = context.parent;
const hasAuthorizedUsers =
Array.isArray(authorized_users) && authorized_users.length > 0;
const hasAuthorizedKeys =
Array.isArray(authorized_keys) && authorized_keys.length > 0;
return Boolean(value) || hasAuthorizedUsers || hasAuthorizedKeys;

Copilot uses AI. Check for mistakes.
is: (value: any) => !Array.isArray(value) || value.length === 0,
then: (schema) =>
schema.required(
'An SSH Key or a Root Password is required to create an instance. We recommend using an SSH Key for better security.'
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new passwordless validation error message says "required to create an instance", but this is the Linode rebuild flow (not creation). Since this message will be shown to end users, consider adjusting the wording to match the rebuild context (or using a generic message that doesn’t mention creation).

Suggested change
'An SSH Key or a Root Password is required to create an instance. We recommend using an SSH Key for better security.'
'An SSH Key or a Root Password is required. We recommend using an SSH Key for better security.'

Copilot uses AI. Check for mistakes.
@linode-gh-bot
Copy link
Collaborator

Cloud Manager UI test results

🔺 3 failing tests on test run #7 ↗︎

❌ Failing✅ Passing↪️ Skipped🕐 Duration
3 Failing877 Passing11 Skipped39m 58s

Details

Failing Tests
SpecTest
object-storage.e2e.spec.tsCloud Manager Cypress Tests→object storage end-to-end tests » can create and delete object storage buckets
access-key.e2e.spec.tsCloud Manager Cypress Tests→object storage access key end-to-end tests » can create an access key with limited access - e2e
lke-create.spec.tsCloud Manager Cypress Tests→LKE Cluster Creation with LKE-E→shows the LKE-E flow with the feature flag on » creates an LKE-E cluster with the account capability

Troubleshooting

Use this command to re-run the failing tests:

pnpm cy:run -s "cypress/e2e/core/objectStorage/object-storage.e2e.spec.ts,cypress/e2e/core/objectStorage/access-key.e2e.spec.ts,cypress/e2e/core/kubernetes/lke-create.spec.ts"

@pmakode-akamai
Copy link
Contributor

Screenshot 2026-03-24 at 5 56 23 PM

I'm getting this error when trying to select only SSH keys while creating a Linode.

@harsh-akamai
Copy link
Contributor Author

I'm getting this error when trying to select only SSH keys while creating a Linode.

@pmakode-akamai This is an error from the API as it is not yet ready to support the changes. As long as the validation from Cloud Manager is working as expected this PR should be good

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Review

Development

Successfully merging this pull request may close these issues.

4 participants