Kubernetes secrets 加密处理的3种方式 | IDCF

前言

Kubernetes已经毫无争议地成为了云原生时代的事实标准,在Kubernetes上部署应用程序也变得简单起来(无论是采用kustomize还是helm),虽然对于敏感信息(比如用户名、密码、token和证书等)的处理,Kubernetes自己提供了secret这种方式,但这是一种编码方式,而非加密方式,如果需要用版本控制系统(比如git)来对所有的文件、内容等进行版本控制时,这种用编码来处理敏感信息的方式就显得很不安全了(即使是采用私有库),这一点在实现GitOps时,是一个痛点。

基于此,本文介绍三种可以加密Kubernetessecret的方式:SealedSecrets、HelmSecrets和Kamus。

一、SealedSecrets

SealedSecrets充分利用kuberntes的高扩展性,通过CRD来创建一个SealedSecret对象,通过将加密的内容存储在扩展SealedSecret对象中,而SealedSecret只能够被运行于目标集群上的controller解密,其他人员和方式都无法正确解密原始数据。

SealedSecret对象同时又会生成与其名称相同的secret对象,随后就可以按照常规方式使用secret对象了。最后将加密后的文件直接推送至版本控制系统即可,而不用担心敏感信息被泄漏。

1.1原理

SealedSecrets加解密的原理简单来说就是:安装的时候controller会生成一对用于加密的key,加密时在客户端kubeseal的帮助下,将包含敏感信息的kubernetssecrets内容加密转变为一个包含有加密信息的KubernetesSealedSecrets对象;解密时在controller的帮助下将KubernetesSealedSecrets对象内的内容进行解密,然后生成常规的kubernetessecret对象。

1.2加密(encryption)

kubeseal使用位于clustercontroller生成的publickey来加密,将secrets对象的内容加密转变成SealedSecrets对象。publickey和privatekey在安装controller的时候,以secret(如下的sealed-secrets-key217vf)的形成存放,可以在安装controller所在的ns下面查看。

$kubectl-nkube-systemgetsecret|g//tls26d4h

1.3解密(decryption)

当将加密后生成的SealedSecrets对象进行部署时(kubectlapply/create),controller会先拿privatekey进行解密,然后再生成与SealedSecrets同名的Secret对象,而此时的Secret对象保存的是经过base64编码后的信息,随后可以像正常使用secret一样使用这些信息。

1.4安装

SealedSecrets有两部分组成:

安装于集群侧的controller

客户端工具kubeseal

所以安装也分两步,安装controller和kubeseal。可以先安装controller,执行如下命令即可:

$kubectlapply-f

随后查看kube-systemns下面的controllerpod:

$kubectl-nkube-systemgetpods|grepsealsealed-secrets-controller-64b74f67b-4wtj71/1Running0153m

接着安装客户端工具kubeseal。这个可以根据自己的OS来选用不同的安装方式,以MacOs为例:

$brewinstallkubeseal

通过查看kubeseal的版本来确定是否安装成功:

$kubeseal--versionkubesealversion:

此时,两部分均安装成功,下面可以使用了。

1.5使用

选择一个包含有需要加密的secret的文件,内容如下:

apiVersion:v1data:username:eGlhb21hZ2U=password:cGFzc3cwcmQ=token:MWU0ZGdyNWZncmgzcmZmZ3JodG9ubmhyaHI=kind:Secretmetadata:name:seal-test-secretnamespace:testtype:Opaque

将上述内容写入一个yaml文件,比如,然后执行如下命令加密:

$

可以查看文件的内容:

{"kind":"SealedSecret","apiVersion":"/v1alpha1","metadata":{"name":"seal-test-secret","namespace":"test","creationTimestamp":null},"spec":{"template":{"metadata":{"name":"seal-test-secret","namespace":"test","creationTimestamp":null},"type":"Opaque"},"encryptedData":{"password":"AgCHLFSlGFpX2B9QDhWbMTfT83aopXMisR5XnUPZNcbvvnQzqgyG8fBVknT8LCNF5ExtUCCcNLsvWRrZY+9BJqf5dlBl6DkLV1acuPicP0vuGaUQwmc5BY/5Bj53Oj9uMYLNdVHoQ3E6kQgeJPa5v4rvwRXsB0EneYPcT88KyMg+tn4OY9JH+hpg2XMXZudyyZsocE852J5nfN4P7WZQYaG2eIBqRSQvQXUflQQvZ5wBCkTvmaZYfxz+Lxuf3wDWdSlPjcgSVnn5tWNP7u0ErdVy8LwTL5HzJdcoSviDysTq3VVA8W9Nmn0CM3QS0R0Nbi3JfalUdxfBMK+yb7t6Z72oJyoxGfCa07iKnkM37SSw4vl1nXiYy3FMWuzDtWLVk6XzjBZR2ChoeClqbGDg8KeSWZg/rO3Xku98vCmCa004OetJKBMc9Db3q+gX53ThdU70VvRol9rLPFBPHB8NTjD+Bu0Ss4XzIzZzi8J+Ov5xE7G8LnPLSZtZQyD/qGZK4n7pU1YNLROJ+fz1W5edPdpb5szUOqs1bpFfGleUiPZo1sGA0f1EsDvJShptgtT44YzGRkkgrP1LGp2AVIpnt9meE5WNCoSEPZJVx7wWMV9CHMOyyUi8zi+oG/S2NkI3rc2sC8AFp0DqP9m/HaX1GG+6vw9oHAbhxpR4v3mDyBIq+/8UEMtkybIEDQGHqyQ5CfRow+A80cA4Hw==","token":"AgBRi4NZunaJtHyP5aAoWmGtEXBipbFIb/n4ep8wdg+eka5xbDeLZwNCLofbUL+u0pP/CHSJeWl62mVPJhZdOKE+Su0b8a78im0+xsochaMQf0AI1GGL/Fo08HI8paP8k404gwAtonocIFSis3YooU0nyVD+lYH+k09FGABI+RmVLc2XkuIr96TTL4xsdSM5L0Ks2SFQKcQ42JfFWtNdXz6lr/IODsZop0/xAk6ffbsGGmCUjwusUU3Wp0MR25ntYT8ySuO6W7xkfGozEFzztteBJs28SHLf5HUi6BbYVnsZibrFF3BZP5aNnBg2TIgo3+dbX6EPHM904By3Z9XTBxsQfH6p1VoyUf0EGKZnUnJFezFtN9m2tyKbV/Z/5vCh9kVp6Yn/BE/AwGAH7kqqjPtHTnZiq+Xy1UwV4/eHkxGAvSAR3Z6wTQCt/rwqGrQi2eGpIcyjxTwlPYaVjfx3L+1tnBR966lGLnhwX0I6b6whXAm3hRb1AhYFnuyF/CoG/PEmQsMU5GfkroQkb5LL+UeCYKbjvMvgCe2hFxfh3dcGJ9E3dad9W0rSKrPd5t/dR1kDtItHau36+G9PSVyqRD1yt0MS2vLLUQu7t2RhiIPrl20fkbnum9JAfmLlgliHIiQPHASL32CXB6EzsgqRX6w8TmWNOSvlR7LU8JZtd4Gmiw9wGBh7JEGodkaH6lc5ndQluykC18RUXtuLft+S4dnQCApHX6FoIGZjug==","username":"AgCgBQc/fhGqB0YBGfXzhybC6YXJeLkOZyi7Z7Y+HjfnYSg4Q/Zh8Kn7UEbq9CwEl+CtagARjKmLfhIcAqFWS8+h8j4A2xNq7gzLnv+eCo0vFDPTddDVvdb6ixmRvF5rzD1gZ2vxWzlWVqk7x0wt8wCE90S0yu40j+JOaqH35Ir3kb4NgTMXk6Yqlidw06r3P2cqbZ0jBleOFf5eRfiu0ZquU5PJ/J7t9Pecx9S8mlitTtFPlvpVprNPB+XPSz2uwcwNW9i5OBUgR3PXsOjILLog8SiWYyk7bHaWnJtZ+JVEi9isy4EiwyrDY5kHRK2kB9Nnf6a9zz2krP7W+w9a3qXJkv8GP9D2+FN9Pj+2WP4r0hz7JL0i5q9bcc5HgBKP946u87z2lEjv2ioUAghaG/zwol3q+tKv0i6pPe0guGRCdpMlXa1Z1deOBJvxJXanTrIwi7dVc/bCsRGMRyYwD6hWhe1JjxgBjc/YbbBj8JJVdHrc2tGYFBU9qG2Kv3cAZMRrMXvKUkTK8JiMVzN0/DHEtdNv1PW4U3hlAqt5b62WahyzdHNVqHycwe+Ogz0BfTdohlxftv5qQYx0SEynXaIY+WltRnCnYrY1Kg1/DmsWYCGy++TO+6cEEwISPe/FM1peidsXVf5S3DCUQWE6aMK/6XDzukZoTjor/8JPkHc56Pk1Paty0yrP+YdL5R5m3IERzHoD"}}}

可以看到内容已经得到了加密,接下来就需要创建SealedSecret对象了:

$

接着查看SealedSecret和secret:

$kubectl-ntestgetSealedSecret,/seal-test-secret4ssecret/seal-test-secretOpaque33s

在如下的Deployment中以环境变量的形式引用上述生成的secret:

apiVersion:apps/v1kind:Deploymentmetadata:labels:app:devopsname:devopsspec:replicas:1selector:matchLabels:app:devopstemplate:metadata:labels:app:devopsspec:restartPolicy:Alwayscontainers:-name:devopsimage:dllhb/devopsday::AlwaysenvFrom:-secretRef:name:test-secretports:-containerPort:9999name:httpprotocol:TCP

使用下面命令部署:

$/devopscreated

查看pod状态,并查看环境变量(secret是以环境变量的形式注入pod内的):

$kubectl-ntestgetpodsdevops-b48df6659-gmjtr1/1Running021s$kubectl-ntestexec-itdevops-b48df6659-gmjtrshenv|grep-E"username|password|token"username=xiaomagetoken=1e4dgr5fgrh3rffgrhtonnhrhrpassword=passw0rd

说明secret注入成功。其他的secret类型,比如tls、dockerconfigjson等都可以用上面的方式进行使用。

最后就可以将包含secret信息且经过加密的文件推送至版本管理系统,比如GitHub。

二、HelmSecrets

HelmSecrets是Helm的一个插件,用来对于HelmChart中的敏感信息进行加密。

2.1原理

HelmSecretsPlugin可以使用多种加密方式来对敏感信息进行加解密(本文介绍sops)。加密时使用helmsecretsenc命令对需要加密的文件内容进行加密;解密时helmsecrets使用dec将加密内容进行解密,并添加在文件中,后续的使用直接取用文件中的值即可。

2.2加密

使用helmsecertsenc对位于helm_vars目录下的secrets文件加密时,helmsecretsplugin会使用publickey对内容进行加密。

2.3解密

使用helmsecretsinstall/upgrade命令对应用程序进行安装或更新的过程中,需要指定经过加密后的secret文件(-f指定,通常位于helm_vars目录下),helmsecretsplugin会选择privatekey对加密的数据进行解密,解密后的数据在文件中可找到,在helmchart的template目录下的secret文件只需要引用相关的值即可(.)。

2.4安装

安装的前提条件:

helm(2.3)

sops

sops是一个加密文件的编辑器,支持YAML、JSON、ENV、INI和二进制格式,并使用AWSKMS、GCPKMS、AzureKeyVault和PGP进行加密。

PGP(PrettyGoodPrivacy)是一种常用的加密方式。在1990s(1991年)由PhilZimmermann所开发,现在归属于Symantec公司,它是商业软件,需要付费才能使用。而GPG(GNUPrivacyGuard)是一种基于OpenPGP标准的加密方式。它是开源且免费的。所以本文的演示将使用GPG的方式。

由于sops采用非对称加密,所以需要先生成一对key。使用gpg--full-generate-key并输入必要的参数即可生成key,如下:

$gpg--full-generate-keygpg(GnuPG)2.2.12;Copyright(C)2018FreeSoftwareFoundation,:,:(1)RSAandRSA(default)(2)DSAandElgamal(3)DSA(signonly)(4)RSA(signonly)Yourselection?1?(3072)4096Re=keydoesnotexpiren=keyexpiresinndaysnw=keyexpiresinnweeksnm=keyexpiresinnmonthsny=keyexpiresinnyearsKeyisvalidfor?(0)1yKeyexpiresatSatJan812:12:102022UTCIsthiscorrect?(y/N):xiaomageEmailaddress:devops@:gpgkeygenerationYouselectedthisUSER-ID:"xiaomage(gpgkeygeneration)devops@"Change(N)ame,(C)omment,(E)mailor(O)kay/(Q)uit?(typeonthekeyboard,movethemouse,utilizethedisks)duringtheprimegeneration;th(typeonthekeyboard,movethemouse,utilizethedisks)duringtheprimegeneration;th:key8BA2C5716B5C007Fmarkedasultimatelytrustedgpg:revocationcertificatestoredas'/root/.gnupg//'[SC][expires:2022-01-08]BCEB5797691E6C95E33A465D8BA2C5716B5C007Fuidxiaomage(gpgkeygeneration)devops@[E][expires:2022-01-08]

可以查看生成的privatekey和publickey:

privatekey查看

gpg-K(gpg--list-secret-keys)/root/.gnupg/[SC][expires:2022-01-08]BCEB5797691E6C95E33A465D8BA2C5716B5C007Fuid[ultimate]xiaomage(gpgkeygeneration)devops@[E][expires:2022-01-08]

publickey查看

gpg-k(gpg--list-keys)gpg:checkingthetrustdbgpg:marginalsneeded:3completesneeded:1trustmodel:pgpgpg:depth:0valid:2signed:0trust:0-,0q,0n,0m,0f,2ugpg:nexttrustdbcheckdueat2022-01-08/root/.gnupg/[SC][expires:2022-01-08]BCEB5797691E6C95E33A465D8BA2C5716B5C007Fuid[ultimate]xiaomage(gpgkeygeneration)devops@[E][expires:2022-01-08]

在用sops加密数据之前,先创建一个.文件,写一个加密的规则,比如只加密key是username和password的敏感信息,而且需要指定gpg的fingerprint。

_rules:-encrypted_regex:'^(username|password)#39;pgp:'B1C77B2CCF5575FAF0DA6B882CA51446C98C9D85'EOF

接着,将下面的敏感信息写入一个yaml文件:

:xiaomagepassword:passw0rdEOF

现在就可以用sops来加密数据了:

$:ENC[AES256_GCM,data:s6pInMY3eGM=,iv:5Q7JsntVoKjseD3ApWcgmYeedmGXj2A1/PyGCNFHGdE=,tag:vInq3NBLxvVWXsoVUD46Rw==,type:str]password:ENC[AES256_GCM,data:Ua7de2w6Jgw=,iv:qYIjTW1D0dh20NA8FGu4XEGI16kvYGAWIk4iu3r/Gdg=,tag:b33tpsP1vCgqlpyCEDP88Q==,type:str]sops:kms:[]gcp_kms:[]azure_kv:[]hc_vault:[]lastmodified:'2021-02-06T12:08:57Z'mac:ENC[AES256_GCM,data:QHHDRSO2PyJt0/OA67ex0R39gEjWEnwg0MSnBac8QtLNh3ncY+9D8IZw/WqVnbcaiPta2Pem96yJZTZP4pum9ZX446iRKldsAXNqS4+tmlfowpMWI+1DgOa1QCkhSDH9U/2URA1dzyn3cZLPFzb5Ai6YUEQ93sRjlPI+kHXl16c=,iv:jhFM/uJSeChikUv777qgYVDFCHQhQeXlUSjiHx5X8Ow=,tag:6QTo5CsXQoqr0fK1B947ug==,type:str]pgp:-created_at:'2021-02-06T12:08:51Z'enc:|-----BEGINPGPMESSAGE-----hQIMA/AYjF0OZ4PLAQ/+LRc5vgpRhOez8q9up8t+3OVM5QdnMwSYiuwLvjfInqqkK19jUfUhwXDGGtSMlTotYlTWqWCiSm7sYeqFB0/Lx9lCZY5BhCrVnK7u7m8azpWUosCQNmJehflqqnBmn82nblOGnDjM/FYkcnz4+NHUPNyYV5tWjzw9s8i/WhDeuNrfIPnGKRCGJunWlHDP3yWMo7bnCNU/TmuRiSpf7lQLsp/U71M5t1X8RajatO7DPecqcaq3VZ+Ynx0Qcgyt+aHugZw5Sw9oFOT4WVqwLlC/NKvrjtY8pCQ1HtY5/agLHrDwHn2Phz1aQ+l4EAarphXCiYAFw/LHD2tisbQoApXe5tud9CjiyMu/14qhQalLgQxAyGcMmhEH7Ke4bubaA0ZPo8hBXAkxfdeicSzB/e1IkUP4LtlQiwPldDcDShB6MROHsK3RpELhSaNdfQZxqDVN0CgjRS0/AjboWejjrLQHD1hVcUDAU2WTyfvIaSxKpHIxONo5sTvzYOjU/BRTLn0EujRP414xadOtt+4gEQDrGacYAokuiK2ev0dinHo32EWYj/vsb0o3whNRpBEGMZTUrl9HSkt58FQZsmu5JnL3ZYKiujHFoQS/aOcxD0slUxhCPoCnce6PgmB78RHOLHaXkTrORc+6oMpCGN8/K1hjXE+eH/kk4jv8yVLwmbg9XjLSXgFTcQYs6nVTSoWVea62kRN4qlC/XTJ6D91HXRX5UyB3qrZ3k+w9TOlM9quYYI/BE0FqbFVSKT3ekPQqF91a7tV01FIxpfr4Mvzy2+8xsXiAQtDm52PSlk9eovkAMqU==nafU-----ENDPGPMESSAGE-----fp:B1C77B2CCF5575FAF0DA6B882CA51446C98C9D85encrypted_regex:^(username|password)$version:3.6.1

可以看到username和password的值都被加密了。

2.5安装使用HelmSecretsplugin

执行以下命令安装helm-secretsplugin:

$helmplugininstall

首先,创建一个演示用的helmchart,并在根目录下创建一个名为helm_vars的目录,用来存放用来加密的secret,如下所示:

$tree.└──devsecops├──├──charts├──helm_vars│├──│├──│└──├──templates│├──│├──_│├──│├──│├──│├──│├──│├──│└──tests│└──└──

将需要加密的信息写入文件里面,比如:

_data:username:xiaomagepassword:passw0rdEOF

使用helmsecrets来加密上述文件:

$

查看加密后的文件内容:

secret_data:username:ENC[AES256_GCM,data:O/1pyNsL3Gc=,iv:HZ0MrGWaBxM37cIkp/JdsA5gRzw6aJFfBR19rno3h5I=,tag:2SiMs46lonnwECc8RHfT/Q==,type:str]password:ENC[AES256_GCM,data:l15XlhZ4CsM=,iv:TMbV6+Rh2wGpMlHi7zJsHWM6IxMK2hBuMKsD82p8LiY=,tag:N4Kbftl//B1U2R9Khsduzg==,type:str]sops:kms:[]gcp_kms:[]azure_kv:[]hc_vault:[]lastmodified:'2021-02-07T06:19:15Z'mac:ENC[AES256_GCM,data:dSXjEbKyBXVtqqSqshGXKUwDJcMVZrDf2GxFj0Oor3FDnNeS+bTY4Yubv1J0XlzU6yxO0Y87NzVN84unkF/Ph95JJV2opk6a0VTtaxKYOFUVneyY5WQ2glHEntX+aEq1lJkW1Sd34i/tvWeSABemIX4M2xcIOdIaCHgzk//vi9w=,iv:febius/ashzpdfKStJnQYVG/3FrVaYw102q87P9+egQ=,tag:/MUXrxhhOk6F8MS5wi7cLQ==,type:str]pgp:-created_at:'2021-02-07T06:19:08Z'enc:|-----BEGINPGPMESSAGE-----hQIMA7Oc9Dk1ccccARAAk7l23omTBRThnP7YC5AHdqzEO8Lapxc8ycWg5tsbM8eEJaRFn4u3/+dQdpL6xlHv1wu0kmrZUgG8P41WmNDIKb2GtAlHQk+bjjV2IU0lCEj79UZXuAyhxHtVjHMBnzjppFh+6L0nH2K5AGaJWATwhO9M6CqmdCFnWJx7vAPfVQZFLi9zqHK/YsbwgEWKs0bVvJ1btB7u4J5olKagYaZhaFaLzwjbtXmEqDUpfmPkooNr7kPSVe8IMv/+MUaJY6uYNTBGWGrije4bY4A+hA/dUj4yN0gqqd796oc9GuN1MJSOcAAoiTW2Vrw3OdyP7PIJVuxlS9gXnxtBOjo+p/Ij91ELq+DnC+6bGS9UIeF+Y1RDh4siwx7I7hzk9tp+tXmsfdJit+usK6raPzYkcBgZVF8woKZsp2/qxloYyIFJ0sbKMO67+dcAg+AX0M0/u33t1BAMTt/LJ1V2ZQUl+yzjRSKfZ2bCmd/skkE3VZx2ls44LMngWZG7EzE39Onw9PB3ukXD7W+X+BThc2AJzVotrpDWbSI2/anoM9TMJjYfBjyUxBuTuoviT5ENdm14bGomww9G+Ean3dyC2vWoHhY2KfuPlSxZ6mDIDm5zAPkZZl5AQHjtaPT5qymPCpqy2X3yvK76zyJhfWYFIHguOy3JlDxiONC9DH1M6OVWoC69pPzSXgEtII9fTeLXFU5Jy9gJa5nNKEQY87OkSXl3TFAiQ9OmgDbuUHZuvQzlecsKwR2smS7P7Z3Bb+eRakQ41Gzw4B7wmOrm2w0t4guVJDNIP/gQB0XBO1XZj4RsbMKn070==yQ2R-----ENDPGPMESSAGE-----fp:B1C77B2CCF5575FAF0DA6B882CA51446C98C9D85encrypted_regex:^(data|username|password|.dockerconfigjson|token|token1|key|crt)$version:3.6.1

需要注意的是,此时只是加密了需要加密的内容,但是这些内容该怎么用呢?其实也比较简单,就是:正常用。

举例来说,在helmchart中,正常用secret的方式如下:

apiVersion:v1kind:Secretmetadata:name:testlabels:app:devsecopstype:Opaquedata:{{-range$key,$value:=._data}}{{$key}}:{{$value|b64enc|quote}}{{-}}

而上面循环中引用的值._data就是来自于上面helm_vars目录下的加密文件。

怎么做到的呢?简单点说,就是执行helm的相关命令(install或者upgrade)时,会利用sops的privatekey将helm_vars目录下的加密内容解密,并且“存放在”文件中,接下来的就和正常的helmchart使用是一样的了。在chart中的文件中引用secret:

containers:-name:{{.}}image:"{{.}}:{{.|}}"imagePullPolicy:{{.}}envFrom:-secretRef:name:test

接下来可以使用下面命令将前文的chart进行安装:

$helmsecretsinstalltest.--namespacetest-fhelm_vars/
$kubectl-ntestgetpods,secretpod/test-devsecops-7876ffc8b7-967xr1/1Running06ssecret/testOpaque28s

由于上面的secret是以环境变量的形式注入到pod里面的,可以查看进行验证:

$kubectl-ntestexec-ittest-devsecops-7876ffc8b7-967xrsh$env|grep-E'username|password'username=xiaomagepassword=passw0rd

可以看到secret解密成功,并成功注入pod。

最后就可以将加密后的文件上传至源码管理系统了(比如用gitpush至GitHub)。

三、Kamus

Kamus是一款开源的采用零信任的secret加解密方式为Kubernetes应用程序安全处理secrets的工具。Kamus提供两种方式来对Kubernetessecrets进行加密,即

使用initcontainer:将secrets加密后存储为Kubernetesconfigmap,然后在应用程序的部署中添加一个initcontainer,通过initcontainer将configmap中的加密数据解密至指定文件,应用程序再从此文件读取解密后的secret信息。

使用KamusSecret:创建一个KamusSecret对象(充分利用了Kubernetes的扩展机制),此对象包含了加密之后的数据,在此对象创建的过程中,会创建一个同名的secret对象,secret中的数据是经过base64编码之后的数据,可以被Kubernetes其他对象引用。

3.1原理

Kamus同样是使用客户端工具kamus-cli对于需要加密的数据进行加密(区别于SealedSecrets的是,Kamus的数据需要单独逐一加密,而不是全部存放在secret文件里面一次性加密,下面会看到),下面依旧以加解密的方式分别阐述。

3.2加密

用kamus-cli对需要加密的数据逐一加密时,位于集群上的controller会选择publickey并使用kamusencryptor对数据进行加密,随后将加密内容保存在configmap中(以initcontainer的方式使用)或者KamusSecret中(以secret的方式使用)。

3.3解密

当将加密后的内容进行部署时(kubectlapply/create),位于集群上的controller会选择privatekey,并使用kamusdecryptor对于数据进行解密。

如果是使用KamusSecret存储的数据,则controller将生成一个与KamusSecret对象同名的Secret对象,此Secret中存放由经过base64编码后的信息;

如果是使用configmap的形式,则此configmap会以volume的形式挂载到pod内,随后在pod中使用initcontainer来调用kamus-decryptor的api将加密信息解密,并存放到指定的文件中,随后pod内的应用程序可以通过读取此文件内容来获取敏感信息。

KamusSecret和Secret两者的关系与Deployment和Pod之间的关系类似。

3.4安装

kamus的安装包括controller和客户端工具kamus-cli。

安装controller

$helmrepoaddsoluto$helminstallkamus--namespacekamussoluto/kamus

检查pod状态:

$kubectl-nkamusgetpodsNAMEREADYSTATUSRESTARTSAGEkamus-controller-55d959895d-hdklf1/1Running09m30skamus-decryptor-5974b6ff47-5pkbr1/1Running07m34skamus-decryptor-5974b6ff47-c4jt41/1Running07m34skamus-encryptor-f75dd457-fwp8r1/1Running09m28skamus-encryptor-f75dd457-p9rnx1/1Running09m29s

安装客户端

$npminstall-g@soluto-asurion/kamus-cli

检查安装是否成功:

$

3.5使用

下面分别以initcontainer和KamusSecret的方式来演示使用方式。

1)以initcontainer的方式

首先需要加密secret。kamus加密secret时需要和一个serviceaccount关联起来,此serviceaccount会在后续的应用部署中使用,所以先创建一个serviceaccount(本文所有demo均在testns下):

$kubectl-ntestcreatesaxiaomage

接着使用客户端工具kamus-cli来加密secret(username的值为xiaomge,password的值为passw0rd):

$kamus-cliencrypt--secretxiaomage--service-accountxiaomage--namespacetest--kamus-urlhttp://localhost:9999--allow-insecure-url[infokamus-cli]:Encryptionstarted[infokamus-cli]:serviceaccount:xiaomage[infokamus-cli]:namespace:test[warnkamus-cli]:Authoptionswerenotprovided,willtrytoencryptwithoutauthenticationtokamus[infokamus-cli]:Successfullyencrypteddatatoxiaomageserviceaccountintestnamespace[infokamus-cli]:Encrypteddata:CxujUBK4jgdjt+wP5mXyDA==:+CoXRDJVtW3EZ2FpterVTA==

返回的CxujUBK4jgdjt+wP5mXyDA==:+CoXRDJVtW3EZ2FpterVTA==就是xiaomage这个值经过加密后的值,用同样的方法,可以将passw0rd进行加密:

$kamus-cliencrypt--secretpassw0rd--service-accountxiaomage--namespacetest--kamus-urlhttp://localhost:9999--allow-insecure-url[infokamus-cli]:Encryptionstarted[infokamus-cli]:serviceaccount:xiaomage[infokamus-cli]:namespace:test[warnkamus-cli]:Authoptionswerenotprovided,willtrytoencryptwithoutauthenticationtokamus[infokamus-cli]:Successfullyencrypteddatatoxiaomageserviceaccountintestnamespace[infokamus-cli]:Encrypteddata:ChmNEPM8Nj7Huh1YwO5xOA==:r9MHhEyTIEaQ4hw837lA9w==

返回的ChmNEPM8Nj7Huh1YwO5xOA==:r9MHhEyTIEaQ4hw837lA9w==就是passw0rd这个值经过加密后的值,将上述两个加密后的值放在configmap中:

apiVersion:v1kind:ConfigMapmetadata:name:kamus-encrypted-secrets-cmnamespace:testdata:username:CxujUBK4jgdjt+wP5mXyDA==:+CoXRDJVtW3EZ2FpterVTA==password:ChmNEPM8Nj7Huh1YwO5xOA==:r9MHhEyTIEaQ4hw837lA9w==

接下来,将上述configmap以volume的方式挂在到pod中,随后使用initcontainer来解密数据,且将数据存放在一个文件中:

apiVersion:v1kind:Podmetadata:namespace:testname:kamus-podspec:serviceAccountName:xiaomageautomountServiceAccountToken:trueinitContainers:-name:"kamus-init"image:"soluto/kamus-init-container:latest"imagePullPolicy:IfNotPresentenv:-name:KAMUS_URLvalue::["-e","/encrypted-secrets","-d","/decrypted-secrets","-n",""]containers:-name:kamus-testimage:dllhb/devopsday::IfNotPresentvolumeMounts:-name:decrypted-secretsmountPath:/secretsvolumes:-name:encrypted-secretsconfigMap:name:kamus-encrypted-secrets-cm-name:decrypted-secretsemptyDir:medium:Memory

接下来,部署configmap和pod并查看:

$$$kubectl-ntestgetpods,cmNAMEREADYSTATUSRESTARTSAGEpod/kamus-pods1/1Running04h3mNAMEDATAAGEconfigmap/kamus-encrypted-secrets-cm230s

进入pod查看解密后的数据:

$kubectl-ntestexec-itkamus-deploysh$cat/secrets/{"password":"passw0rd","username":"username"}

可以看到secet已经被解密到了文件中,应用程序只需要读取此文件即可获得secret的相关数据。

2)以KamusSecret的方式

kamus对Kubernetes进行了扩展,有了自己支持的KamusSecret对象,将上述加密后的数据存放在KamusSecret中:

apiVersion:"/v1alpha2"kind:KamusSecretmetadata:name:kamus-testnamespace:testtype:OpaquestringData:username:CxujUBK4jgdjt+wP5mXyDA==:+CoXRDJVtW3EZ2FpterVTA==password:ChmNEPM8Nj7Huh1YwO5xOA==:r9MHhEyTIEaQ4hw837lA9w==serviceAccount:xiaomage

创建KamusSecret对象:

$

查看生成的KamusSecret和Secret:

$kubectl-ntestgetKamusSecret,/kamus-test60sNAMETYPEDATAAGEsecret/kamus-testOpaque259s

可以看到KamusSecret生成了一个和自己同名的secret,接着查看secret的内容:

apiVersion:v1data:password:cGFzc3cwcmQ=username:eGlhb21hZ2U=

解码后为:

password:passw0rdusername:xiaomage

此时,可以像正常方式在pod中引用此secret(像前文的SealedSecret章节所演示的一样,再次不再赘述)。

最后就可以将加密后的文件上传至源码管理系统了(比如gitpush至GitHub)。

写在最后

其实,安全处理Kubernetessecret的方式不仅仅上面的三种形式,还可以利用诸如vault等来管理应用程序部署中的敏感信息。但是不同的工具、不同的方式,其背后的思想和思路都差不太多。

总结起来,差不多有以下几点:

充分利用Kubernetes的扩展能力,自定义一个secret对象用来存储加密后的数据(诸如SealedSecrets的SealedSecret对象;Kamus的KamusSecret),让这些扩展的对象生成对应的secret对象,再正常使用secret对象。

利用外部的敏感信息管理工具(诸如vault或者其他云厂商提供的服务)。

sops是一种使用方便的加密工具,也是上述工具实现加密的秘密武器。

没有一劳永逸的安全,只有永不止步的行动。任何改变都是重要的。

参考

+“CH050791”可入qun交流~

免责声明:本文章如果文章侵权,请联系我们处理,本站仅提供信息存储空间服务如因作品内容、版权和其他问题请于本站联系