Skip to content

Commit 30e68a8

Browse files
Merge pull request #580 from rgrunber/code-sshd-7.109.x
Support VS Code (local) to Devworkspace over SSH (#560)
2 parents 4df1d27 + ad8836e commit 30e68a8

File tree

4 files changed

+167
-0
lines changed

4 files changed

+167
-0
lines changed

.github/workflows/image-publish.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,4 +198,5 @@ jobs:
198198
run: |
199199
SHORT_SHA1=$(git rev-parse --short=7 HEAD)
200200
docker buildx build --platform linux/amd64 -f build/dockerfiles/dev.Dockerfile --push -t quay.io/che-incubator/che-code-dev:insiders -t quay.io/che-incubator/che-code-dev:next -t quay.io/che-incubator/che-code-dev:insiders-${SHORT_SHA1} .
201+
docker buildx build --platform linux/amd64 -f build/dockerfiles/dev.sshd.Dockerfile --push -t quay.io/che-incubator/che-code-sshd:insiders -t quay.io/che-incubator/che-code-sshd:next -t quay.io/che-incubator/che-code-sshd:insiders-${SHORT_SHA1} .
201202
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Copyright (c) 2025 Red Hat, Inc.
2+
# This program and the accompanying materials are made
3+
# available under the terms of the Eclipse Public License 2.0
4+
# which is available at https://www.eclipse.org/legal/epl-2.0/
5+
#
6+
# SPDX-License-Identifier: EPL-2.0
7+
#
8+
9+
FROM quay.io/devfile/universal-developer-image:latest
10+
11+
USER 0
12+
13+
RUN dnf -y install libsecret openssh-server && \
14+
dnf -y clean all --enablerepo='*'
15+
16+
# Step 1. Generate SSH Host keys
17+
RUN mkdir /opt/ssh
18+
RUN chmod 755 /opt/ssh
19+
RUN chown -R root:root /opt/ssh/
20+
21+
RUN ssh-keygen -q -N "" -t dsa -f /opt/ssh/ssh_host_dsa_key && \
22+
ssh-keygen -q -N "" -t rsa -b 4096 -f /opt/ssh/ssh_host_rsa_key && \
23+
ssh-keygen -q -N "" -t ecdsa -f /opt/ssh/ssh_host_ecdsa_key && \
24+
ssh-keygen -q -N "" -t ed25519 -f /opt/ssh/ssh_host_ed25519_key
25+
26+
# Step 2. Configure SSH as non-root user
27+
RUN cp /etc/ssh/sshd_config /opt/ssh/
28+
29+
# Step 3. Fix permissions
30+
RUN chmod 644 /opt/ssh/ssh_host_* /opt/ssh/sshd_config
31+
32+
# Use non-privileged port, set user authorized keys, disable strict checks
33+
RUN sed -i \
34+
-e 's|#Port 22|Port 2022|' \
35+
-e 's|AuthorizedKeysFile .ssh/authorized_keys|AuthorizedKeysFile /home/user/ssh/authorized_keys|' \
36+
-e 's|#StrictModes yes|StrictModes=no|' \
37+
-e 's|#PidFile /var/run/sshd.pid|PidFile /tmp/sshd.pid|' \
38+
-e 's|#LogLevel INFO|LogLevel DEBUG3|' \
39+
/opt/ssh/sshd_config
40+
41+
# Provide new path containing host keys
42+
RUN sed -i \
43+
-e 's|#HostKey /etc/ssh/ssh_host_rsa_key|HostKey /opt/ssh/ssh_host_rsa_key|' \
44+
-e 's|#HostKey /etc/ssh/ssh_host_ecdsa_key|HostKey /opt/ssh/ssh_host_ecdsa_key|' \
45+
-e 's|#HostKey /etc/ssh/ssh_host_ed25519_key|HostKey /opt/ssh/ssh_host_ed25519_key|' \
46+
/opt/ssh/sshd_config
47+
48+
# Prepare SSH Keys
49+
RUN ssh-keygen -q -N "" -t ed25519 -f /opt/ssh/ssh_client_ed25519_key
50+
RUN chmod 644 /opt/ssh/ssh_client_*
51+
52+
# Add script to start and stop the service
53+
COPY --chown=0:0 /build/scripts/sshd.start /
54+
55+
RUN mkdir /opt/www
56+
COPY /build/scripts/server.js /opt/www/
57+
58+
# Lock down /etc/passwd until fixed in UDI
59+
RUN chmod 644 /etc/passwd
60+
61+
# Bypass nologin shell for random generated user
62+
RUN cp /bin/bash /sbin/nologin
63+
64+
EXPOSE 2022 3400
65+
66+
USER 10001

build/scripts/server.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
Copyright (c) 2025 Red Hat, Inc.
3+
This program and the accompanying materials are made
4+
available under the terms of the Eclipse Public License 2.0
5+
which is available at https://www.eclipse.org/legal/epl-2.0/
6+
7+
SPDX-License-Identifier: EPL-2.0
8+
*/
9+
10+
const http = require('http');
11+
const fs = require('fs');
12+
const os = require('os');
13+
14+
const hostname = '127.0.0.1';
15+
const port = 3400;
16+
17+
const server = http.createServer((req, res) => {
18+
res.statusCode = 200;
19+
res.setHeader('Content-Type', 'text/html');
20+
21+
let hasUserPrefSSHKey = fs.existsSync('/etc/ssh/dwo_ssh_key.pub');
22+
23+
let pubKey = "PUBLIC KEY COULD NOT BE DISPLAYED";
24+
try {
25+
pubKey = fs.readFileSync('/etc/ssh/dwo_ssh_key.pub', 'utf8');
26+
} catch (err) {
27+
// continue
28+
}
29+
30+
let genKey = "PRIVATE KEY NOT FOUND";
31+
try {
32+
genKey = fs.readFileSync('/opt/ssh/ssh_client_ed25519_key', 'utf8');
33+
} catch (err) {
34+
// continue
35+
}
36+
37+
let keyMessage = `
38+
<pre>${hasUserPrefSSHKey ? pubKey : genKey}</pre>`;
39+
40+
res.end(`
41+
<!DOCTYPE html>
42+
<html>
43+
<head>
44+
<title>${process.env["DEVWORKSPACE_NAME"]}</title>
45+
</head>
46+
<body>
47+
<h1>Workspace ${process.env["DEVWORKSPACE_NAME"]} is running</h1>
48+
<div class="border">
49+
<ol>
50+
<li>Make sure your local oc client is logged in to your OpenShift cluster</li>
51+
<li><p class="center">Run <code><b>oc port-forward ${process.env["HOSTNAME"]} 2022:2022</b></code>. This establishes a connection to the workspace.</p></li>
52+
<li>
53+
<p>In your local VS Code, connect to <code>localhost</code> on port <code>2022</code> with user <code>${os.userInfo().username}</code> ${hasUserPrefSSHKey ? `. The SSH key, corresponding to the following public key, configured in the "SSH Keys" tab of "User Preferences" has been authorized to connect :` : `and the following identity file :`} ${keyMessage}</p>
54+
<p>
55+
This can also be configured locally in <code>$HOME/.ssh/config</code> with the following :
56+
<pre><b>
57+
Host localhost
58+
HostName 127.0.0.1
59+
User ${os.userInfo().username}
60+
Port 2022
61+
IdentityFile /path/to/the/ssh_client_ed25519_key
62+
UserKnownHostsFile /dev/null
63+
</b></pre>
64+
</p>
65+
</li>
66+
</ol>
67+
<h3>Troubleshooting</h3>
68+
<p>If the connection fails with "<code>WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED</code>", it may be necessary to remove the <code>localhost</code> or <code>127.0.0.1</code> entries from <code>$HOME/.ssh/known_hosts</code>. This is because the SSHD service container (to which <code>oc port-forward</code> is forwarding) may change. This can be bypassed by setting <code>UserKnownHostsFile /dev/null</code></p>
69+
<p>Please ensure the permissions on the private key used are restricted to allow only the file owner to read/write. The SSH service may fail to correctly authenticate otherwise.</p>
70+
<p>The most common setup is to connect to the workspace using the "Remote - SSH Connection" from the corresponding editor's extension marketplace. If this setup fails to connect to the workspace, consider disabling the setting <code><b>remote.SSH.useExecServer</b></code> (set to false)</p>
71+
<p>For any other issues, relating to the use of a VS Code-based editor and the "Remote - SSH connection", the "Remote - SSH" logs from the "Output" view are very helpful in diagnosing the issue.</p>
72+
</div>
73+
</body>
74+
</html>
75+
`);
76+
});
77+
78+
server.listen(port, hostname, () => {
79+
console.log(`Server running at http://${hostname}:${port}/`);
80+
});

build/scripts/sshd.start

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/bin/bash
2+
#
3+
# Copyright (c) 2025 Red Hat, Inc.
4+
# This program and the accompanying materials are made
5+
# available under the terms of the Eclipse Public License 2.0
6+
# which is available at https://www.eclipse.org/legal/epl-2.0/
7+
#
8+
# SPDX-License-Identifier: EPL-2.0
9+
#
10+
11+
rm -rf /home/user/ssh
12+
mkdir -p /home/user/ssh
13+
if [ -f /etc/ssh/dwo_ssh_key.pub ]; then
14+
cp /etc/ssh/dwo_ssh_key.pub /home/user/ssh/authorized_keys
15+
else
16+
cp /opt/ssh/ssh_client_ed25519_key.pub /home/user/ssh/authorized_keys
17+
fi
18+
19+
# start
20+
/usr/sbin/sshd -D -f /opt/ssh/sshd_config -E /tmp/sshd.log

0 commit comments

Comments
 (0)