Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit38f9dfc

Browse files
committed
fix(agent/agentssh): pin random seed for RSA key generation
Change-Id: I8c7e3070324e5d558374fd6891eea9d48660e1e9Signed-off-by: Thomas Kosiewski <tk@coder.com>
1 parentdedc32f commit38f9dfc

File tree

2 files changed

+59
-8
lines changed

2 files changed

+59
-8
lines changed

‎agent/agent.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"encoding/json"
77
"errors"
88
"fmt"
9+
"hash/fnv"
910
"io"
1011
"net/http"
1112
"net/netip"
@@ -372,7 +373,6 @@ func (a *agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentM
372373
// Important: if the command times out, we may see a misleading error like
373374
// "exit status 1", so it's important to include the context error.
374375
err=errors.Join(err,ctx.Err())
375-
376376
iferr!=nil {
377377
result.Error=fmt.Sprintf("run cmd: %+v",err)
378378
}
@@ -906,6 +906,14 @@ func (a *agent) handleManifest(manifestOK *checkpoint) func(ctx context.Context,
906906
}
907907
a.client.RewriteDERPMap(manifest.DERPMap)
908908

909+
seed,err:=stringToInt64Hash(manifest.WorkspaceID)
910+
iferr!=nil {
911+
returnxerrors.Errorf("generate hash from workspace id: %w",err)
912+
}
913+
iferr:=a.sshServer.UpdateHostSigner(seed);err!=nil {
914+
returnxerrors.Errorf("update host signer: %w",err)
915+
}
916+
909917
// Expand the directory and send it back to coderd so external
910918
// applications that rely on the directory can use it.
911919
//
@@ -1850,3 +1858,16 @@ func PrometheusMetricsHandler(prometheusRegistry *prometheus.Registry, logger sl
18501858
}
18511859
})
18521860
}
1861+
1862+
// stringToInt64Hash converts a WorkspaceID UUID to an int64 hash.
1863+
// This uses the FNV-1a hash algorithm which provides decent distribution and collision
1864+
// resistance for string inputs.
1865+
funcstringToInt64Hash(workspaceID uuid.UUID) (int64,error) {
1866+
h:=fnv.New64a()
1867+
_,err:=h.Write(workspaceID[:])
1868+
iferr!=nil {
1869+
return42,err
1870+
}
1871+
1872+
returnint64(h.Sum64()),nil
1873+
}

‎agent/agentssh/agentssh.go

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ package agentssh
33
import (
44
"bufio"
55
"context"
6-
"crypto/rand"
76
"crypto/rsa"
87
"errors"
98
"fmt"
109
"io"
10+
"math/rand"
1111
"net"
1212
"os"
1313
"os/exec"
@@ -131,14 +131,15 @@ func NewServer(ctx context.Context, logger slog.Logger, prometheusRegistry *prom
131131
// Clients' should ignore the host key when connecting.
132132
// The agent needs to authenticate with coderd to SSH,
133133
// so SSH authentication doesn't improve security.
134-
randomHostKey,err:=rsa.GenerateKey(rand.Reader,2048)
135-
iferr!=nil {
136-
returnnil,err
137-
}
138-
randomSigner,err:=gossh.NewSignerFromKey(randomHostKey)
134+
135+
// Create a fixed host key, as at least one host key has to
136+
// exist for the SSH server to start. We'll later replace
137+
// the host key with one that's based off the workspace uuid.
138+
coderSigner,err:=coderSigner(42)
139139
iferr!=nil {
140140
returnnil,err
141141
}
142+
142143
ifconfig==nil {
143144
config=&Config{}
144145
}
@@ -206,7 +207,7 @@ func NewServer(ctx context.Context, logger slog.Logger, prometheusRegistry *prom
206207
slog.Error(err))
207208
},
208209
Handler:s.sessionHandler,
209-
HostSigners: []ssh.Signer{randomSigner},
210+
HostSigners: []ssh.Signer{coderSigner},
210211
LocalPortForwardingCallback:func(ctx ssh.Context,destinationHoststring,destinationPortuint32)bool {
211212
// Allow local port forwarding all!
212213
s.logger.Debug(ctx,"local port forward",
@@ -1099,3 +1100,32 @@ func userHomeDir() (string, error) {
10991100
}
11001101
returnu.HomeDir,nil
11011102
}
1103+
1104+
// UpdateHostSigner updates the host signer with a new key generated from the provided seed.
1105+
// This function replaces the previously used host key with the newly generated one.
1106+
func (s*Server)UpdateHostSigner(seedint64)error {
1107+
key,err:=coderSigner(seed)
1108+
iferr!=nil {
1109+
returnerr
1110+
}
1111+
1112+
s.mu.Lock()
1113+
defers.mu.Unlock()
1114+
1115+
s.srv.AddHostKey(key)
1116+
1117+
returnnil
1118+
}
1119+
1120+
// coderSigner generates a deterministic SSH signer based on the provided seed.
1121+
// It uses RSA with a key size of 2048 bits.
1122+
funccoderSigner(seedint64) (gossh.Signer,error) {
1123+
// nolint: gosec
1124+
deterministicRand:=rand.New(rand.NewSource(seed))
1125+
coderHostKey,err:=rsa.GenerateKey(deterministicRand,2048)
1126+
iferr!=nil {
1127+
returnnil,err
1128+
}
1129+
coderSigner,err:=gossh.NewSignerFromKey(coderHostKey)
1130+
returncoderSigner,err
1131+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp