Skip to content

Conversation

@fdcastel
Copy link
Contributor

@fdcastel fdcastel commented Oct 30, 2025

⚠️ RFC: Do not merge. ⚠️

TL;DR

  • Adds Powershell scripts to install/uninstall opkssh in OpenSSH Server configuration.
  • Windows: use $env:ProgramData\opk\logs instead of /var/log/.
  • Windows: use $env:ProgramData\opk instead of /etc/opk/.
  • Adapt permschecker to work with Windows ACLs.
  • Adapt OpenSSH version check to work with Windows builds.
  • Minor: Replaces certain instances of path.Join with filepath.Join.

Fix #370.

To Do:

  • Run Go tests (opkssh binary) on Windows
  • Port Bash tests (opkssh installer) for Windows
  • Port GitHub OIDC test for Windows
  • Review current Windows folder structure ($env:ProgramData/opk) -- Is it acceptable?
  • Enforce stricter permissions of opkssh configuration files -- is this necessary on Windows?
  • Per-user configurations? (stricter permissions, and the -NoHomeProfile installer option)
  • Plugin support

How to test

⚠️ This is an early alpha release. It goes without saying, but... do NOT use this in production! ⚠️

#
# Setup OpenSSH Server
#   https://gist.github.com/fdcastel/9648325ae5be548d1664c5433fd6e9ae
#
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0        # NOP in Server 2025 (already installed)
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0        # NOP in Server 2025 (already installed)

# Enable OpenSSH Server
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'

# Enable OpenSSH for ALL profiles in Firewall
Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" | Set-NetFirewallRule -Profile Any
#
# Setup opkssh server
#   Custom build from https://github.com/fdcastel/opkssh/releases which includes the updates from this PR.
#
$version = 'v0.10.0-win3'

# Download the install script to $env:TEMP folder
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -Uri "https://github.com/fdcastel/opkssh/releases/download/$version/Install-OpksshServer.ps1" -OutFile "$env:TEMP/Install-OpksshServer.ps1"

$canUseSystemAccount = (Get-Command sshd).Version -ge [version]'8.9'
if ($canUseSystemAccount) {
    & $env:TEMP/Install-OpksshServer.ps1
} else {
    & $env:TEMP/Install-OpksshServer.ps1 -AuthCmdUser 'opksshuser'
}

# Reload PATH
$env:Path = (Get-ItemProperty 'HKLM:\System\CurrentControlSet\Control\Session Manager\Environment').Path + ';' + `
            (Get-ItemProperty 'HKCU:\Environment').Path
# Authorize user
opkssh add administrator <YOUR-EMAIL> <YOUR-PROVIDER>

Tested on:

  • Windows Server 2025
  • Windows Server 2022
  • Windows Server 2019
  • Windows 11
  • Windows 10

Long version (grab a ☕!)

I began migrating the existing scripts/install-linux.sh code to PowerShell, aiming to maintain as much fidelity as possible.

During the first run, I quickly encountered an issue with hardcoded POSIX filesystem paths. I adapted these to Windows paths to the best of my (admittedly limited) knowledge of Go 😅 (kudos to Claude Sonnet 4.5 for the assist!)

Some parts of the code depend on specific file permissions to run correctly. Initially, I tried to preserve this behavior by emulating the same permissions through Windows ACLs, hoping to keep the original Go code untouched. However, this turned out to be an ungrateful and impractical task, so I eventually abandoned that path.

A few smaller issues also came up, such as differences in version string formats between Windows builds. I adjusted the Go code to handle those as well.

Then I discovered a major difference in the OpenSSH Server shipped with Windows Server 2025: This PR, merged on March 26, 2021, enables the use of AuthorizedKeysCommandUser = System, eliminating the need to create a dedicated user for running opkssh.

Browsing the Win32-OpenSSH repository, I couldn’t find a clear mapping between specific PRs and releases. However, based on the PR’s merge date and the release history

# https://github.com/powershell/Win32-OpenSSH
05/26/2021   8.6.0.0   https://github.com/PowerShell/openssh-portable/releases/tag/v8.6.0.0
03/17/2022   8.9.0.0   https://github.com/PowerShell/openssh-portable/releases/tag/v8.9.0.0

it’s reasonable to assume that versions 8.9.0.0 and up includes this change.

Unfortunately, it seems that all versions shipped with Windows prior to Server 2025 are earlier than this one. I added a safeguard to detect this condition and alert the user, instructing them to use the appropriate CLI option to create the opksshuser when necessary.

Finally, modifying the system PATH on Windows is not exactly straightforward. I updated the script to handle PATH expansion correctly, avoiding one of Windows’ many quirks.

And so… this is it! Now,

  • it needs tests;
  • it needs feedback; and
  • it surely needs some polishing around the edges.

But... hey! It's working. 😄

@fdcastel fdcastel marked this pull request as draft October 30, 2025 07:21
@fdcastel
Copy link
Contributor Author

Fixed failing test. Rebased onto the latest main branch.

@fdcastel
Copy link
Contributor Author

fdcastel commented Oct 31, 2025

I’ve just pushed an initial Windows container port of the gha.yml workflow (Test GitHub Provider).

Unfortunately, I discovered that docker/build-push-action isn’t compatible with Windows containers. As a result, we have to build the image manually using docker build. This also means we lose the caching benefits provided by docker/build-push-action (via its cache-from and cache-to options).

UPDATE: This version no longer uses Windows containers. See below.

- Adds Powershell scripts to install/uninstall opkssh in OpenSSH Server configuration.
- Windows: use $env:ProgramData\opk\logs instead of `/var/log/`.
- Windows: use $env:ProgramData\opk instead of Posix `/etc/opk/`.
- Adapt permschecker to work with Windows ACLs.
- Adapt OpenSSH version check to work with Windows builds.
- Uses filepath.Join instead of path.Join.
@fdcastel
Copy link
Contributor Author

fdcastel commented Nov 1, 2025

  • Added test runners on Windows.

    • The tests were passing before because they were running only on Linux.
    • Now, on Windows, they fail due to permission differences -- making the problem more visible.
  • Rewrote the GitHub OIDC test to run natively on the GitHub Runner VM instead of using Windows containers (which were painfully slow 🐢).

    • The test now uses the SSH client and server on the same VM -- I'm not sure if this has any side effects, but I believe it doesn't.
    • I can also port this approach to the Linux workflow if you approve (removing the need for Docker).
  • Fixed a minor issue in the providers files (missing newline at the end of the file).

  • Rebased with latest main.

@EthanHeilman EthanHeilman added the enhancement New feature or request label Nov 1, 2025
@EthanHeilman
Copy link
Member

@fdcastel This is looking really nice!

I saw you were doing some refactoring of permissions between windows and linux. OPKSSH doesn't handle file permissions in the most organized way.

We have const ModeSystemPerms = fs.FileMode(0640) but also have adhoc permissions like

if err := afs.MkdirAll(filepath.Dir(configPath), 0o755); err != nil {

If you ended up refactoring my current code into unified permissions struct across all OPKSSH, I would not object. I've been thinking about doing some similar and it seems you probably have to do it to support windows.

@fdcastel
Copy link
Contributor Author

fdcastel commented Nov 3, 2025

If you ended up refactoring my current code into unified permissions struct across all OPKSSH, I would not object.

That's great news! 😄
Give me a few days to put together a plan. I believe it can bring significant benefits to the codebase.

@fdcastel
Copy link
Contributor Author

fdcastel commented Nov 3, 2025

BTW: should we consider removing the Docker container from the gha workflow (like what was done in the Windows version)?

I’d also say the existing workflows could benefit from a little cleanup 😅.

@fdcastel
Copy link
Contributor Author

fdcastel commented Nov 7, 2025

@EthanHeilman I'm considering adding a new opkssh command: something like fix-permissions.

The idea is to centralize all platform-specific permission settings within the application itself.

This would simplify our installer scripts (on both Linux and Windows), which currently handle much of this logic, thereby reducing code duplication and keeping all permission management contained within the app.

It could also be useful for quickly repairing user installations that (for any reason) may have become corrupted.

What do you think?

@EthanHeilman
Copy link
Member

I'm considering adding a new opkssh command: something like fix-permissions.

@fdcastel I think that makes sense. Could you do that as a separate PR or is it required here?

There is some similar work happening here that you might want to coordinate with.
#388

@fdcastel
Copy link
Contributor Author

fdcastel commented Nov 8, 2025

Sure! This entire PR (which is getting quite large, by the way) is meant to serve as a proof of concept for now.

My intention isn’t to merge it as-is. Once everything is working properly and looks good, I plan to split it into several smaller PRs and rebase them as needed -- e.g. to adapt to new changes like #388.

It will likely take me a few more weeks to finish, but progress is looking very promising. There’s still quite a bit of work to do, though (trying to build a good abstract layer for permissions in both Posix and Windows platforms).

@fdcastel
Copy link
Contributor Author

@EthanHeilman Just a quick follow-up:

I had to put this work on hold for a while since things are hectic here toward year-end. 😅

But, just to reinforce, I’m still really interested in getting this done, and I expect to pick it back up soon (most likely at the beginning of January).

I’m currently refactoring the work from this PR to make it simpler and more robust across both platforms. The updated work is happening here: https://github.com/fdcastel/opkssh/tree/issue-370 (note: this is not the same source branch as this PR).

Disclaimer: The branch above is still very much a work in progress and may undergo significant changes or force-pushes. Not exactly reliable for code review 😄

Also, I noticed you’re doing some merges here. If you’d like, I can rebase this PR when I’m back.

Best regards, and happy holidays!

Fabio.

@EthanHeilman
Copy link
Member

Happy holidays! Looking forward to working with you when you get back in early Jan

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for Windows OpenSSH Server?

2 participants