【翻译】外部秘密社区的诞生

本文探讨了Kubernetes中管理外部秘密的挑战,介绍了几个流行的解决方案,如Kubernetes-External-Secrets、Container Solutions External Secrets Operator和AWS Secret Operator。随着多个类似项目的出现,社区开始整合工作,形成了新的外部秘密项目。这个新的中央解决方案,基于Go语言和Kubebuilder,旨在统一和简化跨云服务的外部秘密管理。

在Kubernetes中管理秘密可能是一项繁琐的工作。在一个多服务多环境的设置中,你可能在不知不觉中拥有数百个秘密。很难跟踪所有的东西,同时管理秘密的轮换,加入新的服务,并以正确的访问权限加入新的人员。

有很多现有的解决方案来管理这些问题,如AWS Secret Manager和Vault。这些解决方案的功能通常远远超过我们在库存Kubernetes中的功能。而你的组织很有可能已经在使用这样的解决方案,他们对此很满意。因此,很多人认为,"为什么我不能在Kubernetes中使用这个?"

这导致了大量的项目,用于从云服务中同步秘密并将其注入Kubernetes秘密。

通过这篇博文,我们想向你展示这个领域的热门项目,并解释一个社区是如何在新的 外部秘密 项目上形成的

TL;DR:

-
-
- -
🧵👇-

Repo链接:https://github.com/external-secrets/external-secrets

学校里最受欢迎的孩子

GoDaddy的 kubernetes-external-secrets (简称KES)是最受欢迎的外部秘密同步解决方案,在GitHub上有超过1700颗星,有大量的用户。这个解决方案很稳定,社区参与度很高,活跃的维护者经常推送改进。这个解决方案获得青睐的一个重要原因是,它可以很容易地扩展到支持任何你想使用的外部秘密供应商。

目前,它支持以下供应商:

  • 阿里巴巴云秘密管理器
  • Azure Key Vault
  • 谷歌云秘密管理器
  • IBM云秘密管理器
  • AWS秘密管理器
  • AWS系统管理器
  • 和Hashicorp Vault

为了更深入地了解KES的工作原理,你可以看一下这篇博文,"Kubernetes外部秘密"。但简而言之,就像我们在这里描述的所有解决方案一样,它从外部供应商那里读取秘密,并将其同步到本地Kubernetes秘密中。

PSarchitecture

KES似乎是成为处理外部秘密的事实方式的完美候选者,考虑到它支持所有重要的供应商,拥有一个伟大的社区,并积极维护,对吗?但它有一个问题:它是用JavaScript开发的。

JavaScript本身并没有什么不好,但在这个用例中,使用Go有一些很大的优势。主要原因是Kubernetes中对Go的一流SDK支持。另一个原因是工具:使用Golang,我们可以利用 KubebuilderOperator SDK 来帮助我们启动和遵循Kubernetes Operator的最佳实践和标准。

其他的一些孩子

从事一个让你烦恼的问题,有趣的是,有时这个问题也会让很多其他人烦恼。但有时人们开始新的项目来解决他们的问题,而不是改进现有的项目。有时是因为有一个非常具体的要求,或者只是不知道有另一个目标相似的项目。我们想在本节中描述一些其他类似的项目。

Container Solutions External Secrets Operator

这个项目有182颗星,在 ArgoCD文档中提到了它 ,它是由 Riccardo M. Cefala创建的 ,因为Container Solutions内部有一个特殊的客户需求。它是用Go编写的,是可以作为新的中央解决方案的基础的候选人之一。它支持GCP SM、AWS SM、Credstash Gitlab CI变量和Azure密钥库。关于该项目的更多信息可以在项目的 Readme 上找到 。Container Solutions也在帮助启动新的中央工作,包括工程时间和借用基础设施,以实现e2e测试。

Itscontained Secret Manager

这个项目有36颗星,由 Kellin McAvoyNicholas St. Germain创建 。这个项目特别有意思,因为它是为了遵守新的共同 CRD讨论而创建的 (后面会有更多的介绍)。它支持AWS SM、GCP SM和Hashicorp Vault。它也是可能成为新的中央解决方案的基础的候选项目之一。更多关于这个项目的信息请看它的 Readme

AWS Secret Operator

另一个比较受欢迎的项目,有220颗星,由 Yusuke Kuoka创建 。这个项目是特定于供应商的,只支持AWS,而不能扩展到其他供应商。这是一个更容易使用的选择,而且特定于供应商可以简化其代码。更多关于这个项目 的信息请见自述。这也是引发最初讨论的项目,我们将在下一节中讨论。

聚会

在上一节中,我们谈到了类似的项目是如何开始在周围出现的,在我们的案例中,我们注意到,当 这个问题 开始被其他类似的解决方案所填充。

AWSissue

一个因为 单个类似项目而产生的问题 开始扩展;很多其他项目基本上做同样的事情。列举几个(如果我们错过了提到你们中的某一个,很抱歉,请联系我们,我们可以在这里给予赞扬

😀: http

有很多类似的解决方案到处冒出来,这很好地说明这是一个值得解决的问题,有很多社区的兴趣。考虑到这一点,我们考虑合并工作,由于上一节提到的原因,我们决定让新的重写使用Golang和Kubebuilder。

Container SolutionsItscontained 都有Golang的项目,可以作为新的重写 初始代码基础(externalsecret-operatorsecret-manager)。我们最终决定从头开始,只是复制和改编新的中央解决方案中的代码。

派对开始

合并工作倡议的第一步是想出一个共同的自定义资源定义(CRD),与我们能想到的每个用例相一致。 Moritz Johner 带头

提出

CRD提案的 初稿 ;在社区的审查下,我们对CRD进行了调整,以符合我们的 要求

以下是讨论后的SecretStore CRD的第一个版本:

apiVerson: external-secrets.k8s.io/v1alpha1
kind: SecretStore # or ClusterSecretStore
metadata:
name: vault
namespace: example-ns
spec:

# optional.
# used to select the correct KES controller(think: ingress.ingressClassName)
# KES控制器以特定的控制器名称实例化
# 并根据此属性过滤ES
controller: "dev"

store:
type: vault
parameters: # 提供者特定的 k/v 对
服务器: " https://vault.example.com "
path: path/on/vault/store
auth: {}.# provider specific k/v pairs

status:
#* Pending: e.g. referenced secret containing credentials is missing
#* Running: all dependencies are met, sync
phase: 运行中
条件:
- type: Ready
status: "False"
reason: "ErrorConfig"
message: "Unable to assume role arn:xxxx"
lastTransitionTime: "2019-08-12T12:33:02Z"

下面是讨论后的ExternalSecret CRD的第一个版本:

apiVersion: external-secrets.k8s.io/v1alpha1
kind: ExternalSecret
metadata:
name: foo
spec:
storeRef:
kind: SecretStore # ClusterSecretStore
name: my-store
target:
name: my-secret
template:
type: kubernetes.io/TLS
data:
tls.crt:
key: /corp.org/dev/certs/ingress
property: pubcert
tls.key:
key: /corp.org/dev/certs/ingress
property: privkey

随着CRD提案的完成,我们创建了一个新的公司中立的组织,并 在其下开始了一个新的项目。在这里,我们开始使用Kubebuilder启动项目, Jonatas Baldin 开始实施最初的对账循环逻辑。

GoDaddy同意将原来的KES项目转移到新的公司中立组织中,现在它就住在 这里。这很好,因为当 外部秘密操作者(ESO)一切准备就绪后 ,我们可以使用 外部秘密/kubernetes-external-secrets 星,使新的重写像它的兄弟姐妹一样受欢迎

外部秘密操作者介绍

secretslogo

随着CRD、语言选择和初始调和回路的完成,新的中央解决方案诞生了。第一个预发布版本带有对AWS Secret Manager、AWS Parameter Store和Hashicorp Vault供应商的支持。我们还 external-secrets.io上推出了一个带有文档的简单网站 。这个版本之所以能够实现,是因为 Moritz JohnerKellin McAvoyJonatas BaldinMarkus MagaSilas Boyd-Wickizer你本人以及 其他贡献者做的伟大工作 。(当然,还有以前的解决方案的贡献者,我们从他们那里复制了,并计划继续复制大量的代码和想法!)

PSdiagrams-high-level-cluster-detail

新的中央解决方案的工作方式与原来的非常相似。当然,我们将外部第三方服务的秘密同步到Kubernetes的秘密中。

通过添加一个新的提供者来解释内部工作原理

解释ESO如何工作的一个非常好的方法是直接引导你如何做出一个新的秘密提供者的贡献,解释抽象和你将插入新的实现的地方。让我们这样做吧!

observeactdiff如果你对运营商不熟悉,让我们快速回顾一下。与Kubernetes控制器非常相似,运营商是运行在集群上的应用程序,通过Kubernetes资源配置,在这里是自定义资源定义。他们观察集群中的其他资源,看它们是否遵循CRD中的配置状态。如果它们不是,操作者就会采取行动,并将其纠正为声明的状态。这是一个非常简单的控制方法,但非常有效,是一切Kubernetes的基础。

之前你可能已经注意到,我们有一个SecretStore的CRD和另一个ExternalSecret的CRD。SecretStore的CRD让操作者知道在哪里可以找到外部提供者,调用其API的凭证是什么,它是什么类型的提供者,以及其他提供者的具体信息。ExternalSecret让操作者知道要同步什么秘密,什么秘密版本,刷新间隔,等等。

你可以在 external-secrets/pkg/controllers找到我们的控制器 ,在这里你可以找到用于同步秘密的主要调和逻辑。我们为每个基本的自定义资源都有一个控制器,我们使用这些自定义资源来配置我们希望在集群中的秘密状态。如果我们看一下 ExternalSecret控制器,它首先寻找提到的CRD,然后创建一个客户端与外部提供者API交互,然后在你的集群中创建或更新Kubernetes秘密。

这是

非常简单的。

假设你想贡献一个新的外部秘密提供者。首先,你必须查看我们的通用 Provider接口 ,以了解你必须在你的特定Provider结构中实现什么。

软件包 provider


import (
"context"


"sigs.k8s.io/controller-runtime/pkg/client"


esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
)

// Provider是一个与秘密后端交互的通用接口。
type Provider interface {
// NewClient构造一个SecretsManager Provider
NewClient(ctx context.Context, store esv1alpha1.GenericStore, kube client.Client, namespace string) (SecretsClient, error)
}

// SecretsClient提供对秘密的访问。
type SecretsClient interface {
// GetSecret returns a single secret from the provider
GetSecret(ctx context.Context, ref esv1alpha1

.ExternalSecretDataRemoteRef.

ExternalSecretDataRemoteRef) ([]byte, error)
// GetSecretMap从提供者那里返回多个k/v对
GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error)

}

这里你可以看到,我们的提供者接口只有一个方法,返回一个SecretsClient。而SecretsClient只有两个方法:一个是获取一个简单的秘密,另一个是获取一个秘密地图(一个包含多个密钥值的JSON字符串的秘密)。所以实现一个遵循该规范的结构是非常简单的。

// 你可能需要从头开始创建一个客户端,并使用所需的方法,这取决于你是如何导入客户端功能
func newExampleCLient(c *exampleLib.Config) (Client, error) {
return exampleLib.
NewClient(c)
}

type Example struct {
newExampleCLient func(c *exampleLib.Config) (Client, error)
}

type Client struct {
}
09 func (c *Example) NewClient(ctx context.Context, store esv1alpha1.GenericStore, kube kclient.Client, namespace string) (supper.SecretsClient, error) {
// 在这里插入需要准备的代码,并设置配置以获得客户端

client, err := c.newExampleCLient(cfg)
if err != nil {
return nil, fmt.Errorf(errExampleCLient, err)
}

return client, nil
}

func (v *Client) GetSecret(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
data, err := v.MethodInYourCLientThatGetsValueOfASecret(ctx, ref.Key, ref.Version) // Of course change this to what makes sense in your case
if err ! =nil {
return nil, err
}
value, exists := data[ref.Key]
if!existence {
return nil, fmt.Errorf(errSecretKeyFmt,

ref.

key)
}
return value, nil
}

func (v *Client) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {

log.Info("fetching secret map", "key", ref.Key)
data, err := v.MethodInYourCLientThatGetsValueOfASecret(ctx, ref.Key, ref.Version) // Of course change this to what makes sense in your case
if err !
=nil {
return nil, err
}
kv:= make(map[string]string)
err = json.Unmarshal(data, &kv) if err != nil {
return nil, fmt.Errorf(" unable to unmarshal secret %s: %w", ref. Key, err)

}


secretData := make(map[string][]byte)
for k, v := range kv {

secretData[k] = []byte(v)

}


return secretData, nil

}

要了解ESO如何知道在每种情况下使用哪个提供商,请查看 pkg/provider/schema/schema.go 实现。我们在内存中的存储地图中注册了我们支持的存储,我们只需在控制器的调和循环中通过它的名字获得正确的存储。

其他可以看的地方有:

  • apis/externalsecrets/v1alpha1,这样你就可以声明新的存储类型;
  • deploy/crds,这样你就可以更新SecretStore和ClusterSecretStore,以包括你的新提供者对象
  • 。 当然,你的pkg/provider/your_provider/your_provider_test.go,因为测试对我们包括新的提供者非常重要。

参与!

我们欢迎并鼓励所有类型的人对我们的项目作出贡献!任何事情都可以,不管它是否是技术性的。我们也非常感谢你帮助手动测试解决方案,特别是在最初的冲刺阶段,以便我们验证和准备稳定发布。

现在,我们正集中精力进行自动化e2e测试,这只是因为Container Solutions提供了一些基础设施供我们使用,所以才有可能做到这一点!任何其他类似的捐赠都会对项目的发展有巨大的帮助,所以请继续捐赠。

我们也希望人们能加入我们的双周社区会议,了解更多关于这个项目如何满足你的需求。如果你有一个有待解决的挑战的拉动请求,你也可以加入;如果你认为通过音频和视频同步会更容易,我们完全可以只分享一些屏幕和讨论代码。来帮助我们使这个解决方案成为处理Kubernetes集群以外的秘密的事实方式

Download our free eBook: WTF is the External Secrets Operator
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值