6
6
"encoding/json"
7
7
"errors"
8
8
"fmt"
9
+ "hash/fnv"
9
10
"io"
10
11
"net/http"
11
12
"net/netip"
@@ -340,7 +341,7 @@ func (a *agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentM
340
341
// if it can guarantee the clocks are synchronized.
341
342
CollectedAt : now ,
342
343
}
343
- cmdPty , err := a .sshServer .CreateCommand (ctx , md .Script , nil )
344
+ cmdPty , err := a .sshServer .CreateCommand (ctx , md .Script , nil , nil )
344
345
if err != nil {
345
346
result .Error = fmt .Sprintf ("create cmd: %+v" , err )
346
347
return result
@@ -372,7 +373,6 @@ func (a *agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentM
372
373
// Important: if the command times out, we may see a misleading error like
373
374
// "exit status 1", so it's important to include the context error.
374
375
err = errors .Join (err , ctx .Err ())
375
-
376
376
if err != nil {
377
377
result .Error = fmt .Sprintf ("run cmd: %+v" , err )
378
378
}
@@ -995,7 +995,6 @@ func (a *agent) createOrUpdateNetwork(manifestOK, networkOK *checkpoint) func(co
995
995
if err := manifestOK .wait (ctx ); err != nil {
996
996
return xerrors .Errorf ("no manifest: %w" , err )
997
997
}
998
- var err error
999
998
defer func () {
1000
999
networkOK .complete (retErr )
1001
1000
}()
@@ -1004,9 +1003,20 @@ func (a *agent) createOrUpdateNetwork(manifestOK, networkOK *checkpoint) func(co
1004
1003
network := a .network
1005
1004
a .closeMutex .Unlock ()
1006
1005
if network == nil {
1006
+ keySeed , err := WorkspaceKeySeed (manifest .WorkspaceID , manifest .AgentName )
1007
+ if err != nil {
1008
+ return xerrors .Errorf ("generate seed from workspace id: %w" , err )
1009
+ }
1007
1010
// use the graceful context here, because creating the tailnet is not itself tied to the
1008
1011
// agent API.
1009
- network , err = a .createTailnet (a .gracefulCtx , manifest .AgentID , manifest .DERPMap , manifest .DERPForceWebSockets , manifest .DisableDirectConnections )
1012
+ network , err = a .createTailnet (
1013
+ a .gracefulCtx ,
1014
+ manifest .AgentID ,
1015
+ manifest .DERPMap ,
1016
+ manifest .DERPForceWebSockets ,
1017
+ manifest .DisableDirectConnections ,
1018
+ keySeed ,
1019
+ )
1010
1020
if err != nil {
1011
1021
return xerrors .Errorf ("create tailnet: %w" , err )
1012
1022
}
@@ -1146,7 +1156,13 @@ func (a *agent) trackGoroutine(fn func()) error {
1146
1156
return nil
1147
1157
}
1148
1158
1149
- func (a * agent ) createTailnet (ctx context.Context , agentID uuid.UUID , derpMap * tailcfg.DERPMap , derpForceWebSockets , disableDirectConnections bool ) (_ * tailnet.Conn , err error ) {
1159
+ func (a * agent ) createTailnet (
1160
+ ctx context.Context ,
1161
+ agentID uuid.UUID ,
1162
+ derpMap * tailcfg.DERPMap ,
1163
+ derpForceWebSockets , disableDirectConnections bool ,
1164
+ keySeed int64 ,
1165
+ ) (_ * tailnet.Conn , err error ) {
1150
1166
// Inject `CODER_AGENT_HEADER` into the DERP header.
1151
1167
var header http.Header
1152
1168
if client , ok := a .client .(* agentsdk.Client ); ok {
@@ -1173,6 +1189,10 @@ func (a *agent) createTailnet(ctx context.Context, agentID uuid.UUID, derpMap *t
1173
1189
}
1174
1190
}()
1175
1191
1192
+ if err := a .sshServer .UpdateHostSigner (keySeed ); err != nil {
1193
+ return nil , xerrors .Errorf ("update host signer: %w" , err )
1194
+ }
1195
+
1176
1196
sshListener , err := network .Listen ("tcp" , ":" + strconv .Itoa (workspacesdk .AgentSSHPort ))
1177
1197
if err != nil {
1178
1198
return nil , xerrors .Errorf ("listen on the ssh port: %w" , err )
@@ -1850,3 +1870,20 @@ func PrometheusMetricsHandler(prometheusRegistry *prometheus.Registry, logger sl
1850
1870
}
1851
1871
})
1852
1872
}
1873
+
1874
+ // WorkspaceKeySeed converts a WorkspaceID UUID and agent name to an int64 hash.
1875
+ // This uses the FNV-1a hash algorithm which provides decent distribution and collision
1876
+ // resistance for string inputs.
1877
+ func WorkspaceKeySeed (workspaceID uuid.UUID , agentName string ) (int64 , error ) {
1878
+ h := fnv .New64a ()
1879
+ _ , err := h .Write (workspaceID [:])
1880
+ if err != nil {
1881
+ return 42 , err
1882
+ }
1883
+ _ , err = h .Write ([]byte (agentName ))
1884
+ if err != nil {
1885
+ return 42 , err
1886
+ }
1887
+
1888
+ return int64 (h .Sum64 ()), nil
1889
+ }
0 commit comments