5
5
package cluster
6
6
7
7
import (
8
+ "bytes"
8
9
"context"
10
+ "encoding/base64"
9
11
"errors"
10
12
"fmt"
11
13
"math/big"
@@ -23,6 +25,8 @@ import (
23
25
"github.com/dustin/go-humanize"
24
26
"github.com/google/uuid"
25
27
"github.com/hashicorp/go-getter/v2"
28
+ "github.com/klauspost/compress/zstd"
29
+ "github.com/siderolabs/crypto/x509"
26
30
"github.com/siderolabs/gen/maps"
27
31
"github.com/siderolabs/go-blockdevice/v2/encryption"
28
32
"github.com/siderolabs/go-kubeconfig"
@@ -40,10 +44,12 @@ import (
40
44
clientconfig "github.com/siderolabs/talos/pkg/machinery/client/config"
41
45
"github.com/siderolabs/talos/pkg/machinery/config"
42
46
"github.com/siderolabs/talos/pkg/machinery/config/bundle"
47
+ "github.com/siderolabs/talos/pkg/machinery/config/configloader"
43
48
"github.com/siderolabs/talos/pkg/machinery/config/configpatcher"
44
49
"github.com/siderolabs/talos/pkg/machinery/config/encoder"
45
50
"github.com/siderolabs/talos/pkg/machinery/config/generate"
46
51
"github.com/siderolabs/talos/pkg/machinery/config/machine"
52
+ "github.com/siderolabs/talos/pkg/machinery/config/types/security"
47
53
"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1"
48
54
"github.com/siderolabs/talos/pkg/machinery/constants"
49
55
"github.com/siderolabs/talos/pkg/machinery/nethelpers"
@@ -752,6 +758,24 @@ func create(ctx context.Context) error {
752
758
)
753
759
}
754
760
761
+ var slb * siderolinkBuilder
762
+
763
+ if withSiderolinkAgent .IsEnabled () {
764
+ slb , err = newSiderolinkBuilder (gatewayIPs [0 ].String (), withSiderolinkAgent .IsTLS ())
765
+ if err != nil {
766
+ return err
767
+ }
768
+ }
769
+
770
+ if trustedRootsConfig := slb .TrustedRootsConfig (); trustedRootsConfig != nil {
771
+ trustedRootsPatch , err := configloader .NewFromBytes (trustedRootsConfig )
772
+ if err != nil {
773
+ return fmt .Errorf ("error loading trusted roots config: %w" , err )
774
+ }
775
+
776
+ configBundleOpts = append (configBundleOpts , bundle .WithPatch ([]configpatcher.Patch {configpatcher .NewStrategicMergePatch (trustedRootsPatch )}))
777
+ }
778
+
755
779
configBundle , err := bundle .NewBundle (configBundleOpts ... )
756
780
if err != nil {
757
781
return err
@@ -795,15 +819,6 @@ func create(ctx context.Context) error {
795
819
extraKernelArgs = procfs .NewCmdline (extraBootKernelArgs )
796
820
}
797
821
798
- var slb * siderolinkBuilder
799
-
800
- if withSiderolinkAgent .IsEnabled () {
801
- slb , err = newSiderolinkBuilder (gatewayIPs [0 ].String ())
802
- if err != nil {
803
- return err
804
- }
805
- }
806
-
807
822
err = slb .SetKernelArgs (extraKernelArgs , withSiderolinkAgent .IsTunnel ())
808
823
if err != nil {
809
824
return err
@@ -1255,7 +1270,7 @@ func init() {
1255
1270
Cmd .AddCommand (createCmd )
1256
1271
}
1257
1272
1258
- func newSiderolinkBuilder (wgHost string ) (* siderolinkBuilder , error ) {
1273
+ func newSiderolinkBuilder (wgHost string , useTLS bool ) (* siderolinkBuilder , error ) {
1259
1274
prefix , err := networkPrefix ("" )
1260
1275
if err != nil {
1261
1276
return nil , err
@@ -1268,6 +1283,16 @@ func newSiderolinkBuilder(wgHost string) (*siderolinkBuilder, error) {
1268
1283
nodeIPv6Addr : prefix .Addr ().Next ().String (),
1269
1284
}
1270
1285
1286
+ if useTLS {
1287
+ ca , err := x509 .NewSelfSignedCertificateAuthority (x509 .ECDSA (true ), x509 .IPAddresses ([]net.IP {net .ParseIP (wgHost )}))
1288
+ if err != nil {
1289
+ return nil , err
1290
+ }
1291
+
1292
+ result .apiCert = ca .CrtPEM
1293
+ result .apiKey = ca .KeyPEM
1294
+ }
1295
+
1271
1296
var resultErr error
1272
1297
1273
1298
for range 10 {
@@ -1312,6 +1337,9 @@ type siderolinkBuilder struct {
1312
1337
apiPort int
1313
1338
sinkPort int
1314
1339
logPort int
1340
+
1341
+ apiCert []byte
1342
+ apiKey []byte
1315
1343
}
1316
1344
1317
1345
// DefineIPv6ForUUID defines an IPv6 address for a given UUID. It is safe to call this method on a nil pointer.
@@ -1340,6 +1368,8 @@ func (slb *siderolinkBuilder) SiderolinkRequest() provision.SiderolinkRequest {
1340
1368
return provision.SiderolinkRequest {
1341
1369
WireguardEndpoint : net .JoinHostPort (slb .wgHost , strconv .Itoa (slb .wgPort )),
1342
1370
APIEndpoint : ":" + strconv .Itoa (slb .apiPort ),
1371
+ APICertificate : slb .apiCert ,
1372
+ APIKey : slb .apiKey ,
1343
1373
SinkEndpoint : ":" + strconv .Itoa (slb .sinkPort ),
1344
1374
LogEndpoint : ":" + strconv .Itoa (slb .logPort ),
1345
1375
SiderolinkBind : maps .ToSlice (slb .binds , func (k uuid.UUID , v netip.Addr ) provision.SiderolinkBind {
@@ -1351,6 +1381,24 @@ func (slb *siderolinkBuilder) SiderolinkRequest() provision.SiderolinkRequest {
1351
1381
}
1352
1382
}
1353
1383
1384
+ // TrustedRootsConfig returns the trusted roots config for the current builder.
1385
+ func (slb * siderolinkBuilder ) TrustedRootsConfig () []byte {
1386
+ if slb == nil || slb .apiCert == nil {
1387
+ return nil
1388
+ }
1389
+
1390
+ trustedRootsConfig := security .NewTrustedRootsConfigV1Alpha1 ()
1391
+ trustedRootsConfig .MetaName = "siderolink-ca"
1392
+ trustedRootsConfig .Certificates = string (slb .apiCert )
1393
+
1394
+ marshaled , err := encoder .NewEncoder (trustedRootsConfig , encoder .WithComments (encoder .CommentsDisabled )).Encode ()
1395
+ if err != nil {
1396
+ panic (fmt .Sprintf ("failed to marshal trusted roots config: %s" , err ))
1397
+ }
1398
+
1399
+ return marshaled
1400
+ }
1401
+
1354
1402
// SetKernelArgs sets the kernel arguments for the current builder. It is safe to call this method on a nil pointer.
1355
1403
func (slb * siderolinkBuilder ) SetKernelArgs (extraKernelArgs * procfs.Cmdline , tunnel bool ) error {
1356
1404
switch {
@@ -1361,7 +1409,13 @@ func (slb *siderolinkBuilder) SetKernelArgs(extraKernelArgs *procfs.Cmdline, tun
1361
1409
extraKernelArgs .Get ("talos.logging.kernel" ) != nil :
1362
1410
return errors .New ("siderolink kernel arguments are already set, cannot run with --with-siderolink" )
1363
1411
default :
1364
- apiLink := "grpc://" + net .JoinHostPort (slb .wgHost , strconv .Itoa (slb .apiPort )) + "?jointoken=foo"
1412
+ scheme := "grpc://"
1413
+
1414
+ if slb .apiCert != nil {
1415
+ scheme = "https://"
1416
+ }
1417
+
1418
+ apiLink := scheme + net .JoinHostPort (slb .wgHost , strconv .Itoa (slb .apiPort )) + "?jointoken=foo"
1365
1419
1366
1420
if tunnel {
1367
1421
apiLink += "&grpc_tunnel=true"
@@ -1371,6 +1425,26 @@ func (slb *siderolinkBuilder) SetKernelArgs(extraKernelArgs *procfs.Cmdline, tun
1371
1425
extraKernelArgs .Append ("talos.events.sink" , net .JoinHostPort (slb .nodeIPv6Addr , strconv .Itoa (slb .sinkPort )))
1372
1426
extraKernelArgs .Append ("talos.logging.kernel" , "tcp://" + net .JoinHostPort (slb .nodeIPv6Addr , strconv .Itoa (slb .logPort )))
1373
1427
1428
+ if trustedRootsConfig := slb .TrustedRootsConfig (); trustedRootsConfig != nil {
1429
+ var buf bytes.Buffer
1430
+
1431
+ zencoder , err := zstd .NewWriter (& buf )
1432
+ if err != nil {
1433
+ return fmt .Errorf ("failed to create zstd encoder: %w" , err )
1434
+ }
1435
+
1436
+ _ , err = zencoder .Write (trustedRootsConfig )
1437
+ if err != nil {
1438
+ return fmt .Errorf ("failed to write zstd data: %w" , err )
1439
+ }
1440
+
1441
+ if err = zencoder .Close (); err != nil {
1442
+ return fmt .Errorf ("failed to close zstd encoder: %w" , err )
1443
+ }
1444
+
1445
+ extraKernelArgs .Append (constants .KernelParamConfigInline , base64 .StdEncoding .EncodeToString (buf .Bytes ()))
1446
+ }
1447
+
1374
1448
return nil
1375
1449
}
1376
1450
}
@@ -1444,6 +1518,10 @@ func (a *agentFlag) String() string {
1444
1518
return "wireguard"
1445
1519
case 2 :
1446
1520
return "grpc-tunnel"
1521
+ case 3 :
1522
+ return "wireguard+tls"
1523
+ case 4 :
1524
+ return "grpc-tunnel+tls"
1447
1525
default :
1448
1526
return "none"
1449
1527
}
@@ -1455,13 +1533,18 @@ func (a *agentFlag) Set(s string) error {
1455
1533
* a = 1
1456
1534
case "tunnel" :
1457
1535
* a = 2
1536
+ case "wireguard+tls" :
1537
+ * a = 3
1538
+ case "grpc-tunnel+tls" :
1539
+ * a = 4
1458
1540
default :
1459
- return fmt .Errorf ("unknown type: %s, possible values: 'true', 'wireguard' for the usual WG; 'tunnel' for WG over GRPC" , s )
1541
+ return fmt .Errorf ("unknown type: %s, possible values: 'true', 'wireguard' for the usual WG; 'tunnel' for WG over GRPC, add '+tls' to enable TLS for API " , s )
1460
1542
}
1461
1543
1462
1544
return nil
1463
1545
}
1464
1546
1465
1547
func (a * agentFlag ) Type () string { return "agent" }
1466
1548
func (a * agentFlag ) IsEnabled () bool { return * a != 0 }
1467
- func (a * agentFlag ) IsTunnel () bool { return * a == 2 }
1549
+ func (a * agentFlag ) IsTunnel () bool { return * a == 2 || * a == 4 }
1550
+ func (a * agentFlag ) IsTLS () bool { return * a == 3 || * a == 4 }
0 commit comments