Commit c1490e9
feat: per-edge bootstrap join token for agent registration (#106)
* feat: per-edge bootstrap join token for agent registration
Adds Edge.Status.JoinToken generated by the hub controller on edge
creation. The agent can present this token to authenticate its first
WebSocket connection without needing a full kubeconfig.
- Edge controller generates a random 32-byte base64url token on creation
- Agent proxy builder accepts Bearer join token as auth alternative
- kedge edge create prints formatted join command after polling for token
- kedge edge join-command <name> reprints/regenerates the command
- kedge agent join/run accept --token flag (--token already wired through)
Closes #105
Co-authored-by: Mangirdas Judeikis <mangirdas@judeikis.lt>
* chore: run make codegen to update CRDs and kcp schemas for JoinToken field
* fix: address PR review comments
- CLI: update kubernetes join command to use OCI helm chart format
(oci://ghcr.io/faroshq/charts/kedge-agent); also show kedge agent
run command as alternative since chart exists in deploy/charts/
- Hub: return X-Kedge-Agent-Token response header after successful
join token authentication (token-exchange flow)
- Tunnel: thread onAgentToken callback through StartProxyTunnel so
agents can receive and persist the durable token
- Agent: save returned durable token to ~/.kedge/agent-<name>.json
after first successful join; reload on restart if --token omitted
Co-authored-by: Mangirdas Judeikis <mangirdas@judeikis.lt>
* test: e2e tests for join token feature (#105)
- JoinTokenIsSetAfterEdgeCreation: verifies hub controller generates token
- AgentConnectsWithJoinToken: agent bootstrap via join token works
- InvalidJoinTokenReturns401: wrong token is rejected
Co-authored-by: Mangirdas Judeikis <mangirdas@judeikis.lt>
* feat: kedge install command + kubeconfig exchange on join token
- Hub returns X-Kedge-Agent-Kubeconfig on successful join token auth
- Agent saves kubeconfig to ~/.kedge/agent-<name>.kubeconfig; reuses on restart
- New 'kedge install --type server' installs agent as systemd service
- New 'kedge install --type kubernetes' generates/applies agent manifest
- kedge edge create output updated to show kedge install command
Co-authored-by: Mangirdas Judeikis <mangirdas@judeikis.lt>
* fix: join token agent registration and cluster discovery
In join-token mode the Edge resource is pre-provisioned by the admin;
the join token is a hub-side bootstrap credential only (not a kcp
ServiceAccount token), so the kcp API rejects any Get/Create call with
Unauthorized.
Two bugs fixed:
1. Skip registerEdge when opts.Token is set — the edge pre-exists and
the join token cannot be used to authenticate kcp API calls.
2. Cluster name was unknown at first boot: the join token carries no JWT
claims so extractClusterNameFromToken() always returned "default",
making the WebSocket path use /services/agent-proxy/default/... which
would cause authorizeByJoinToken to search the wrong kcp cluster.
Fix: extract the cluster name from the hub kubeconfig (written by
kedge login) and pass it via --cluster to kedge agent join in the e2e
framework.
Test changes:
- framework.TokenAgent gains WithCluster() so the e2e test can supply
the correct cluster name.
- AgentConnectsWithJoinToken now calls ClusterNameFromKubeconfig (already
present in the framework) after login and passes it to WithCluster().
Co-authored-by: Mangirdas Judeikis <mangirdas@judeikis.lt>
* fix: hub marks edge Ready/Disconnected for join-token connections
In join-token mode the agent's edge_reporter cannot call the kcp API
(join token is not a valid kcp credential) so the hub now takes
ownership of edge status transitions for that auth path:
- edge_status.go: add markEdgeConnected() -- patches edge to
Connected=true / Phase=Ready using the hub's own kcp credentials
- agent_proxy_builder_v2.go: call markEdgeConnected() immediately after
the WebSocket tunnel is established when authenticatedByJoinToken=true
- agent.go: skip edge_reporter in join-token mode (hub owns status);
drain tunnelState channel to avoid goroutine leak
Co-authored-by: Mangirdas Judeikis <mangirdas@judeikis.lt>
* Fix join token
* Fix ssh flow
* clean join token if kubeconfig is provided
* fix: Docker e2e test uses hub-generated join token, fix goimports
SSHDockerServerModeConnect was starting the agent with --token dev-token
(a static kcp token) which the agent now treats as a join token (opts.Token
!= "" → join mode). Static tokens are hub-internal auth and are not valid
join tokens, so authorizeByJoinToken rejects the connection and the edge
never becomes Ready.
Fix: pre-create the Edge resource as admin, wait for the hub's
TokenReconciler to populate status.joinToken, then pass that real join
token to the Docker container. This exercises the full join-token bootstrap
flow end-to-end and removes the static-token dependency from the agent test.
Also fix goimports: remove extraneous alignment spaces in main.go
introduced by ca5611d (golangci-lint goimports check).
Co-authored-by: Mangirdas Judeikis <mangirdas@judeikis.lt>
---------
Co-authored-by: OpenClaw Bot <bot@openclaw.ai>
Co-authored-by: Mangirdas Judeikis <mangirdas@judeikis.lt>
Co-authored-by: mjudeikis-bot <mjudeikis-bot@users.noreply.github.com>1 parent c64e2d6 commit c1490e9
25 files changed
Lines changed: 1924 additions & 161 deletions
File tree
- apis/kedge/v1alpha1
- cmd/kedge-agent
- config
- crds
- kcp
- hack/scripts
- pkg
- agent
- tunnel
- cli/cmd
- hub
- bootstrap/crds
- controllers/edge
- virtual/builder
- test/e2e
- cases
- framework
- suites/standalone
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
162 | 162 | | |
163 | 163 | | |
164 | 164 | | |
165 | | - | |
| 165 | + | |
166 | 166 | | |
167 | 167 | | |
168 | | - | |
169 | 168 | | |
170 | 169 | | |
171 | 170 | | |
172 | 171 | | |
173 | 172 | | |
174 | 173 | | |
175 | 174 | | |
176 | | - | |
177 | | - | |
178 | | - | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
179 | 179 | | |
180 | 180 | | |
181 | | - | |
| 181 | + | |
| 182 | + | |
182 | 183 | | |
183 | 184 | | |
184 | 185 | | |
| |||
247 | 248 | | |
248 | 249 | | |
249 | 250 | | |
250 | | - | |
| 251 | + | |
251 | 252 | | |
252 | 253 | | |
253 | 254 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
147 | 147 | | |
148 | 148 | | |
149 | 149 | | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
150 | 159 | | |
151 | 160 | | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
152 | 168 | | |
153 | 169 | | |
154 | 170 | | |
| |||
179 | 195 | | |
180 | 196 | | |
181 | 197 | | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
182 | 202 | | |
183 | 203 | | |
184 | 204 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
43 | 59 | | |
44 | 60 | | |
45 | 61 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
150 | 150 | | |
151 | 151 | | |
152 | 152 | | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
153 | 211 | | |
154 | 212 | | |
155 | 213 | | |
| |||
158 | 216 | | |
159 | 217 | | |
160 | 218 | | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
161 | 226 | | |
162 | 227 | | |
163 | 228 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
65 | 65 | | |
66 | 66 | | |
67 | 67 | | |
68 | | - | |
| 68 | + | |
69 | 69 | | |
70 | 70 | | |
71 | 71 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| |||
146 | 146 | | |
147 | 147 | | |
148 | 148 | | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
149 | 207 | | |
150 | 208 | | |
151 | 209 | | |
| |||
154 | 212 | | |
155 | 213 | | |
156 | 214 | | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
157 | 222 | | |
158 | 223 | | |
159 | 224 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | | - | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
47 | 68 | | |
48 | 69 | | |
49 | 70 | | |
50 | 71 | | |
51 | 72 | | |
52 | 73 | | |
| 74 | + | |
53 | 75 | | |
54 | 76 | | |
55 | | - | |
56 | | - | |
57 | | - | |
58 | | - | |
59 | | - | |
60 | | - | |
61 | | - | |
62 | | - | |
63 | | - | |
64 | | - | |
65 | | - | |
66 | | - | |
67 | | - | |
68 | | - | |
69 | | - | |
70 | | - | |
71 | | - | |
72 | | - | |
73 | | - | |
74 | | - | |
75 | | - | |
76 | | - | |
77 | | - | |
78 | | - | |
79 | | - | |
80 | | - | |
81 | | - | |
82 | | - | |
83 | | - | |
84 | | - | |
85 | | - | |
86 | | - | |
87 | | - | |
88 | | - | |
89 | | - | |
90 | | - | |
91 | 77 | | |
92 | 78 | | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
93 | 82 | | |
0 commit comments