ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Talos Linux 集群身份配置详解:DiscoveryIdentityConfig 配置文档指南

Talos Linux 集群身份配置详解:DiscoveryIdentityConfig 配置文档指南 Talos Linux 集群身份配置详解DiscoveryIdentityConfig 配置文档指南【免费下载链接】talosTalos Linux is a modern Linux distribution built for Kubernetes.项目地址: https://gitcode.com/gh_mirrors/ta/talos导读DiscoveryIdentityConfig是 Talos Linux 中一个专门用于配置集群身份的配置文档config document它向 Talos 的 discovery service集群发现服务提供全局唯一的集群标识符cluster ID与共享密钥cluster secret。本文将基于 Talos Linux v1.15 的官方参考文档结合仓库源码深入剖析该配置文档的结构、字段语义、校验规则、生成方式以及与旧版.cluster.id/.cluster.secret配置的迁移关系。读完本文你将掌握如何阅读、生成、验证与迁移DiscoveryIdentityConfig并理解其在集群发现与 KubeSpan 网络中的安全作用。一、DiscoveryIdentityConfig 是什么Talos Linux 使用 discovery service 让集群中的节点彼此发现、交换信息从而完成 etcd 集群组建、KubeSpan 加密网络建立等任务。为了让集群之间的信息隔离discovery service 需要一个集群身份cluster identity由两部分组成cluster ID全局唯一标识符用于识别集群cluster secret集群共享密钥用于加密与认证集群成员之间的通信。在 v1.15 版本中该身份以独立的多文档multi-doc配置形式存在即本文主角DiscoveryIdentityConfig。其官方描述为DiscoveryIdentityConfig is a config document to configure the cluster identity used by the discovery service见 官网参考文档。从源码接口定义看DiscoveryIdentityConfig提供的正是这两个核心访问器见 pkg/machinery/config/config/cluster.go// DiscoveryIdentityConfig provides the cluster identity (ID and shared secret) used by the // discovery service and KubeSpan. type DiscoveryIdentityConfig interface { ClusterID() string ClusterSecret() string }注意注释中同时提到了KubeSpan集群身份不仅服务于 discovery service还被 KubeSpan 用于集群成员之间的加密网络认证。二、配置文档结构DiscoveryIdentityConfig是一个标准的 YAML 配置文档与其他 Talos 配置文档一样通过apiVersion与kind标识自身。官方参考文档给出的完整示例如下apiVersion: v1alpha1 kind: DiscoveryIdentityConfig clusterID: cluster-id-base64-encoded-32-bytes # Globally unique identifier for this cluster (base64 encoded random 32 bytes). clusterSecret: cluster-secret-base64-encoded-32-bytes # Shared secret of cluster (base64 encoded random 32 bytes).其字段定义如下表来自 官方参考文档FieldTypeDescriptionValue(s)clusterIDstringGlobally unique identifier for this cluster (base64 encoded random 32 bytes).clusterSecretstringShared secret of cluster (base64 encoded random 32 bytes).This secret is shared among cluster members but should never be sent over the network.两个字段均为必填项在 JSON Schema 中标记为schemaRequired: true这在源码结构体中也有体现见 pkg/machinery/config/types/cluster/discovery_identity.gotype DiscoveryIdentityConfigV1Alpha1 struct { meta.Meta yaml:,inline // description: | // Globally unique identifier for this cluster (base64 encoded random 32 bytes). // schemaRequired: true MetaClusterID string yaml:clusterID // description: | // Shared secret of cluster (base64 encoded random 32 bytes). // This secret is shared among cluster members but should never be sent over the network. // schemaRequired: true MetaClusterSecret string yaml:clusterSecret }从meta.Meta内嵌结构可知该文档通过MetaKind: DiscoveryIdentityConfig与MetaAPIVersion: v1alpha1完成自身标识见 pkg/machinery/config/types/cluster/discovery_identity.go 中NewDiscoveryIdentityConfigV1Alpha1构造函数。三、字段语义与安全要点3.1 clusterID全局唯一标识符clusterID是集群的全局唯一标识符本质是32 字节随机数经过 base64 编码后的字符串。Talos 官方文档与源码注释均强调其作用仅用于唯一标识集群不会在网络上传输discovery service 端只用它做身份关联因为是唯一标识而非密钥代码中从不解码它因此校验时只检查非空不校验 base64 编码与 32 字节长度。这一点在Validate()的注释中写得非常明确见 pkg/machinery/config/types/cluster/discovery_identity.go// We dont need to validate the clusterID is base64 encoded nor that its 32 bytes long, // because we only use it as a unique identifier. We never need to decode it.3.2 clusterSecret集群共享密钥clusterSecret是集群成员之间共享的密钥官方文档特别强调This secret is shared among cluster members but should never be sent over the network.该密钥在集群成员间共享但绝不应通过网络发送。与clusterID不同clusterSecret的约束严格得多。源码注释给出了根本原因见 pkg/machinery/config/types/cluster/discovery_identity.goThe cluster secret is used as an AES encryption key, so it must:be base64 encoded (via StdEncoding)decode to 32 bytes for AES-256即clusterSecret 被用作 AES-256 加密密钥因此必须是合法的 base64 编码字符串使用 StdEncoding解码后恰好为 32 字节对应 AES-256 密钥长度。3.3 编码标准的变化1.14 起统一为 StdEncoding仓库源码还记录了编码标准的一段历史见 pkg/machinery/config/types/cluster/discovery_identity.go 与 Validate 注释var ( ClusterIDEncoding base64.StdEncoding ClusterSecretEncoding base64.StdEncoding )在 Talos 1.14 之前talosctl gen secrets生成的 cluster ID 使用URLEncoding而代码库其余部分使用StdEncoding从 Talos 1.14 开始两者已对齐统一采用StdEncoding生成 cluster ID。这意味着如果手工构造配置务必使用标准 base64 编码带、/而非-、_。四、校验规则源码级验证逻辑DiscoveryIdentityConfigV1Alpha1实现了config.Validator接口其Validate()方法完整逻辑如下见 pkg/machinery/config/types/cluster/discovery_identity.gofunc (s *DiscoveryIdentityConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) { if s.MetaClusterID { return nil, errors.New(clusterID is required) } if s.MetaClusterSecret { return nil, errors.New(clusterSecret is required) } if err : ValidateBase64WithLen(s.MetaClusterSecret, ClusterSecretEncoding, constants.DefaultClusterSecretSize); err ! nil { return nil, fmt.Errorf(invalid clusterSecret: %w, err) } return nil, nil }其中ValidateBase64WithLen是一个通用校验函数见 pkg/machinery/config/types/cluster/discovery_identity.gofunc ValidateBase64WithLen(base64Str string, encoding *base64.Encoding, wantLenBytes int) error { decoded, err : encoding.DecodeString(base64Str) if err ! nil { return fmt.Errorf(failed to decode from base64: %s; %w, base64Str, err) } if len(decoded) ! wantLenBytes { return fmt.Errorf(expected %d bytes, got %d: %s, wantLenBytes, len(decoded), base64Str) } return nil }对应的常量定义见 pkg/machinery/constants/constants.go// DefaultClusterIDSize is the default size in bytes for the cluster ID token. DefaultClusterIDSize 32 // DefaultClusterSecretSize is the default size in bytes for the cluster secret. DefaultClusterSecretSize 32校验规则汇总规则说明clusterID非空必填不校验 base64 与长度仅作唯一标识从不解码clusterSecret非空必填clusterSecret合法 base64使用 StdEncoding 解码失败则报invalid clusterSecret: failed to decode from base64: ...clusterSecret解码 32 字节对应 AES-256 密钥长度不符则报invalid clusterSecret: expected 32 bytes, got N: ...以上规则均有对应测试用例覆盖见 pkg/machinery/config/types/cluster/discovery_identity_test.go包括合法配置、缺失 clusterID、非法 base64 的 clusterSecret、clusterSecret 长度错误16 字节/66 字节/0 字节等场景并断言了精确的错误前缀。五、如何生成talosctl gen secrets 与自动注入5.1 手工生成随机值由于clusterSecret必须是32 字节随机数的 base64 编码最稳妥的方式是使用talosctl gen secrets生成完整 secrets bundle而不是手工拼凑。该命令的实现位于 cmd/talosctl/cmd/mgmt/gen/secrets.gotalosctl gen secrets -o secrets.yaml其核心逻辑调用secrets.NewBundle()在填充 bundle 时生成随机的 cluster ID 与 cluster secret见 pkg/machinery/config/generate/secrets/bundle.goif bundle.Cluster.ID { clusterID, err : randBytes(constants.DefaultClusterIDSize) ... bundle.Cluster.ID cluster.ClusterIDEncoding.EncodeToString(clusterID) } if bundle.Cluster.Secret { clusterSecret, err : randBytes(constants.DefaultClusterSecretSize) ... bundle.Cluster.Secret cluster.ClusterSecretEncoding.EncodeToString(clusterSecret) }可以看到生成逻辑严格遵循32 字节随机数 StdEncoding base64 编码的规范。5.2 配置生成时的自动注入在通过talosctl gen config生成机器配置时只要目标 Talos 版本满足条件控制平面与 worker 配置都会自动携带DiscoveryIdentityConfig文档。生成器在版本契约判断通过后调用构造函数注入见 pkg/machinery/config/generate/init.go 与 pkg/machinery/config/generate/worker.goif in.Options.VersionContract.DiscoveryIdentityMultidocConfig() { documents append(documents, clustertypes.NewDiscoveryIdentityConfigV1Alpha1( in.Options.SecretsBundle.Cluster.ID, in.Options.SecretsBundle.Cluster.Secret, )) }版本契约判断定义如下见 pkg/machinery/config/contract.go// DiscoveryIdentityMultidocConfig returns true if version of Talos should use the multi-doc DiscoveryIdentityConfig. func (contract *VersionContract) DiscoveryIdentityMultidocConfig() bool { return contract.Greater(TalosVersion1_13) }即Talos 1.14 及以上版本采用独立的多文档DiscoveryIdentityConfig而旧版本继续使用 legacy 的.cluster.id/.cluster.secret字段。这一行为有专门的生成测试验证见 pkg/machinery/config/generate/generate_test.go1.14 版本契约生成 1 个DiscoveryIdentityConfig文档同时 legacy 的.cluster.id/.cluster.secret为空1.13 版本契约不生成该文档身份写入 legacy 字段无论哪种形式最终都能通过统一的cfg.DiscoveryIdentityConfig()访问器读到身份信息。5.3 一个真实的合法示例仓库测试数据中保存了一份完整可用的DiscoveryIdentityConfig配置见 pkg/machinery/config/types/cluster/testdata/discoveryidentityconfig.yamlapiVersion: v1alpha1 kind: DiscoveryIdentityConfig clusterID: MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDE clusterSecret: vlf2HU1NEZL3Ezi9TkRZBLJUbjnsHnTzs3wK9JNk6Q注意这里clusterID恰好是一个 StdEncoding 编码的 32 字节 base64 字符串而clusterSecret是标准 32 字节 base64 编码。该文件被用于 marshal/unmarshal 稳定性测试见 pkg/machinery/config/types/cluster/discovery_identity_test.go序列化后与源文件逐字节一致反序列化后能通过provider.DiscoveryIdentityConfig()访问器正确读取ClusterID()与ClusterSecret()。六、与旧版配置的关系与迁移6.1 互斥约束DiscoveryIdentityConfig文档与旧版 v1alpha1 配置中的.cluster.id/.cluster.secret互斥。该约束通过container.V1Alpha1ConflictValidator接口实现见 pkg/machinery/config/types/cluster/discovery_identity.go// The multi-doc DiscoveryIdentityConfig is mutually exclusive with the v1alpha1 cluster identity config. func (s *DiscoveryIdentityConfigV1Alpha1) V1Alpha1ConflictValidate(v1alpha1Cfg *v1alpha1.Config) error { if v1alpha1Cfg.ClusterConfig ! nil (v1alpha1Cfg.ClusterConfig.ClusterID ! || v1alpha1Cfg.ClusterConfig.ClusterSecret ! ) { return errors.New(cluster identity is already configured in .cluster.id/.cluster.secret of the v1alpha1 config) } return nil }对应的冲突测试覆盖了三种情况v1alpha1 配置为空、只有 ClusterConfig 但无身份字段、legacy 字段存在见 pkg/machinery/config/types/cluster/discovery_identity_test.go。6.2 访问器优先级在多文档容器中DiscoveryIdentityConfig()访问器的取用逻辑是legacy 优先、文档兜底见 pkg/machinery/config/container/container.go// The dedicated document and the deprecated v1alpha1 cluster identity (.cluster.id/.cluster.secret) are // mutually exclusive (enforced by DiscoveryIdentityConfigV1Alpha1.V1Alpha1ConflictValidate); the v1alpha1 // config takes priority. func (container *Container) DiscoveryIdentityConfig() config.DiscoveryIdentityConfig { // v1alpha1 cluster identity takes priority when it yields a config if container.v1alpha1Config ! nil { if legacy : container.v1alpha1Config.DiscoveryIdentityConfig(); legacy ! nil { return legacy } } // fallback to dedicated multi-doc. Take first, since this doc is not named. if docs : findMatchingDocsconfig.DiscoveryIdentityConfig; len(docs) 0 { return docs[0] } return nil }旧版字段通过一个适配器类型转换为统一接口见 pkg/machinery/config/types/v1alpha1/v1alpha1_discoveryidentity.go只有.cluster.id或.cluster.secret至少存在一个时才返回身份对象。这意味着 Talos 内部如 secrets bundle 重建、discovery 校验可以透明地处理新旧两种形式。七、依赖关系与运行时校验7.1 discovery service 强依赖集群身份容器级校验确保只要启用了集群发现DiscoveryServiceConfig就必须存在集群身份无论它以DiscoveryIdentityConfig文档还是 legacy 字段形式提供见 pkg/machinery/config/container/validate.go// Discovery requires a cluster identity if discoveryConfigs : container.DiscoveryServiceConfigs(); len(discoveryConfigs) 0 { identity : container.DiscoveryIdentityConfig() if identity nil || identity.ClusterID() { errs multierror.Append(errs, fmt.Errorf(cluster ID (.cluster.id or DiscoveryIdentityConfig) should be set when cluster discovery (DiscoveryServiceConfig) is enabled)) } if identity nil || identity.ClusterSecret() { errs multierror.Append(errs, fmt.Errorf(cluster secret (.cluster.secret or DiscoveryIdentityConfig) should be set when cluster discovery (DiscoveryServiceConfig) is enabled)) } }7.2 KubeSpan 的联动要求同一段校验代码还确认启用 KubeSpan 必须同时启用集群发现见 pkg/machinery/config/container/validate.go而集群发现又依赖集群身份因此DiscoveryIdentityConfig是 KubeSpan 加密网络得以成立的前置条件之一。7.3 secrets bundle 的逆向读取在从已有控制平面配置重建 secrets bundle 的场景中NewBundleFromConfig会通过统一访问器读取集群身份见 pkg/machinery/config/generate/secrets/bundle.gocluster : Cluster{} if identity : c.DiscoveryIdentityConfig(); identity ! nil { cluster.ID identity.ClusterID() cluster.Secret identity.ClusterSecret() }这保证了无论配置采用哪种形式存储身份后续工具链都能正确取回。八、敏感信息处理与 Redact由于clusterSecret属于机密信息DiscoveryIdentityConfig实现了config.SecretDocument接口在导出/脱敏配置时会将 secret 替换为占位符而保留非机密的clusterID见 pkg/machinery/config/types/cluster/discovery_identity.go// Redact implements config.SecretDocument interface. func (s *DiscoveryIdentityConfigV1Alpha1) Redact(replacement string) { if s.MetaClusterSecret ! { s.MetaClusterSecret replacement } }对应的 Redact 测试验证了两点见 pkg/machinery/config/types/cluster/discovery_identity_test.go设置 secret 后Redact(**.***)会把ClusterSecret()替换为占位符ClusterID()保持不变它本身不是密钥。容器级测试同样验证了脱敏后的配置可通过访问器读到占位符见 pkg/machinery/config/container/container_test.go。因此在分享或归档机器配置时可以放心依赖 Talos 的脱敏机制避免泄露 cluster secret。九、实践要点速查不要手工编造clusterSecret它必须是合法 StdEncoding base64 且解码后恰好 32 字节AES-256 密钥。优先使用talosctl gen secrets -o secrets.yaml生成。1.14 及以上版本自动生成talosctl gen config会根据版本契约自动在控制平面与 worker 配置中注入DiscoveryIdentityConfig文档无需手工添加。与旧版互斥若配置中仍存在.cluster.id/.cluster.secret再添加DiscoveryIdentityConfig文档会触发校验错误需二选一。clusterID仅作标识它不会被解码因此校验宽松但为了保证全局唯一性仍应按规范使用 32 字节随机数的 base64 编码。保密意识clusterSecret在集群成员间共享但绝不应出现在网络上导出配置时使用脱敏后的版本。JSON Schema完整的字段约束也体现在 website/content/v1.15/schemas/config.schema.json 的cluster.DiscoveryIdentityConfigV1Alpha1定义中可用于编辑器提示与静态校验。十、深入阅读官方参考文档website/content/v1.15/reference/configuration/cluster/discoveryidentityconfig.md核心实现pkg/machinery/config/types/cluster/discovery_identity.go单元测试pkg/machinery/config/types/cluster/discovery_identity_test.go测试样例pkg/machinery/config/types/cluster/testdata/discoveryidentityconfig.yaml生成链路pkg/machinery/config/generate/init.go、pkg/machinery/config/generate/worker.go、pkg/machinery/config/generate/secrets/bundle.go版本契约pkg/machinery/config/contract.go容器访问与校验pkg/machinery/config/container/container.go、pkg/machinery/config/container/validate.go命令入口cmd/talosctl/cmd/mgmt/gen/secrets.go【免费下载链接】talosTalos Linux is a modern Linux distribution built for Kubernetes.项目地址: https://gitcode.com/gh_mirrors/ta/talos创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表