关于【Kubernetes密钥】的设置和管理进行解释说明

image.png

首先

近年,Kubernetes已成为容器编排的标准。由于企业逐渐采用容器优先的开发结构,大部分现有工作负载都在公共云或私有数据中心的虚拟机上运行。因此,很多企业正在从以前的方法转向Kubernetes,但事实上他们面临着许多问题。

将工作载迁移到Kubernetes会对整个DevOps流程产生影响,包括监控、日志记录、持续集成/持续部署以及最为重要的安全性。安全性可以在集群级别和应用程序级别都进行处理。

在这篇文章中,我们将更详细地介绍如何在Kubernetes中有效地管理应用程序的机密信息。

在Kubernetes中,机密信息如API整合令牌、OAuth令牌、数据库密码等,通过Secret对象进行管理。这些Secret可以作为挂载的卷被Pod访问到。

如果在不同的环境中运行不同的Kubernetes集群(推荐),建议将特定于环境的所有秘密保存在一个地方。然后,确保有一个可以智能识别部署Pod所在环境并相应获取秘密的秘密管理工具。关于此,我将在本帖的后半部分进行详细说明。

Kubernetes秘密管理入门

使用Kubectl创建机密并将其作为卷挂载

让应用程序创建用于在第三方服务中进行身份验证的令牌密钥。

您可以通过文字值或者文件来创建一个秘钥。在这种情况下,我们把秘钥信息存放在名为access.txt的文件中。

$cat access.txt
APP_AUTH_TOKEN=WEj4VmNF755uc9vZdz98zvPXB6DkHp

$ kubectl create secret generic auth-token --from-file=./access.txt
secret "auth-token" created

$kubectl get secrets
NAME                  TYPE                                  DATA      AGE
auth-token            Opaque                                1         14s
default-token-k7vmv   kubernetes.io/service-account-token   3         17m

$ kubectl describe secret auth-token
Name:         auth-token
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
access.txt:  46 bytes

让我们将这个秘密作为挂载在 Pod 上的卷来使用。

首先,创建一个演示Pod,然后应用清单。

$ cat pod.yaml 
---
apiVersion: v1
kind: Pod
metadata:
  name: demo-pod
spec:
  containers:
  - name: demo-pod
    image: ubuntu
    command: ["/bin/bash", "-ec", "while :; do echo '.'; sleep 5 ; done"] 
    volumeMounts:
    - name: myvolume
      mountPath: "/tmp"
      readOnly: true
  volumes:
  - name: myvolume
    secret:
      secretName: auth-token

$ kubectl apply -f pod.yaml
pod "demo-pod" created

$ kubectl get pods
NAME       READY     STATUS    RESTARTS   AGE
demo-pod   1/1       Running   0          1m

在这里,如果在此Pod内执行,应该能够找到挂载在/tmp目录的密钥。

$ kubectl exec -it demo-pod /bin/bash
root@demo-pod:/# ls /tmp
access.txt
root@demo-pod:/# cat /tmp/access.txt 
APP_AUTH_TOKEN=WEj4VmNF755uc9vZdz98zvPXB6DkHp
root@demo-pod:/# 

使用该方法,可以安全地挂载包含机密数据的配置文件。然后,可以从挂载的目录中由应用程序进行读取。但是,有时候想要将机密数据作为应用程序的envvar使用。让我们在下一节中尝试一下这个。

使得秘密可以作为Pod环境变量可用。

为了能够将秘密作为环境变量使用,创建并应用秘密对象清单。在将数据放入秘密文件之前,首先对数据进行编码,确保数据以纯文本形式存储。

$ echo WEj4VmNF755uc9vZdz98zvPXB6DkHp | base64
V0VqNFZtTkY3NTV1Yzl2WmR6OTh6dlBYQjZEa0hwCg==

$ cat auth_secret.yaml 
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  auth_token: V0VqNFZtTkY3NTV1Yzl2WmR6OTh6dlBYQjZEa0hwCg==

$ kubectl apply -f auth_secret.yaml
secret "mysecret" created

$ kubectl describe secret mysecret
Name:         mysecret
Namespace:    default
Labels:       <none>
Annotations:  
Type:         Opaque

Data
====
auth_token:  31 bytes

要将secret作为envvar插入,需要使用保存secret的密钥访问secret,并将其映射到pod的envvar中。下面的示例使用另一个演示pod demo-pod-2 来完成这个操作。

$ cat pod-2.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: demo-pod-2
spec:
  containers:
  - name: demo-pod-2
    image: ubuntu
    command: ["/bin/bash", "-ec", "while :; do echo '.'; sleep 5 ; done"] 
    env:
      - name: APP_AUTH_TOKEN
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: auth_token

$ kubectl apply -f pod-2.yaml 
pod "demo-pod-2" created

在这里运行demo-pod-2,并检查APP_AUTH_TOKEN环境变量的值,将会显示解码后的秘钥值。

$ kubectl exec -it demo-pod-2 /bin/bash
root@demo-pod-2:/# echo $APP_AUTH_TOKEN
WEj4VmNF755uc9vZdz98zvPXB6DkHp
root@demo-pod-2:/#

文献引用

最近,Kubernetes发布了一个用于加密保存的秘密的新功能。非常强烈地建议您阅读此内容。尽管这个功能是全新的,但我认为仍然值得一试。

Kubernetes秘密的高级管理

迄今为止,我们已经解释了Kubernetes的机密如何工作以及如何在Pod中使用它们。然而,如果您正在运行多个Kubernetes集群(开发/预发布/生产),则需要一个集中的机密存储和安全机制来设置Pod环境所需的机密。

从这里开始,我们将考虑针对这个问题的两种解决方案。

    使用基于Kubernetes的身份验证来使用Vault,在Dockerfiles中集成Chamber,从AWS参数存储输入秘密(针对AWS上的Kubernetes集群)。

使用基于Kubernetes的认证来使用Vault。

Vault基于身份验证的工作流程可以总结如下。

    1. Pod被部署在特定的命名空间中,并与特定的服务账号关联。

 

    1. 与命名空间相关联的服务账号将与Vault后端的Kubernetes认证角色关联。

 

    1. Pod将使用服务账号的令牌在Vault中进行认证,并获取VAULT_TOKEN。

使用VAULT_TOKEN和VAULT_ADDRESS,可以安全地从Vault获取机密信息。

而且,在将这些密码作为环境变量插入到Pod中时,有几个选项可供选择。稍后会进行说明。

Vault 是什么?

Vault是一款轻量级工具,可有效地存储和管理保密信息。它强力支持完全加密的安全Kubernetes认证。通常,Vault由Consul作为存储引擎来支持。因此,Vault具有高可靠性和对节点故障的抗性。

Vault的配置设置

有几种可以为Kubernetes应用程序配置Vault的方法。

    1. 在可跨环境访问的Kubernetes集群中配置Vault。

 

    使用托管的Vault的版本。

虽然本文的目的超出了在Kubernetes中配置Vault的方法,但以下列举了几种可用的资源供参考。

    1. 这是 HashiCorp 宣布发布 Vault Helm Chart 的博客:https://www.hashicorp.com/blog/announcing-the-vault-helm-chart

这是 HashiCorp 官方提供的 Consul Helm 的 GitHub 链接:https://github.com/hashicorp/consul-helm

安装Vault后,可以连接到Kubernetes集群。如前所述,目标是使Pod可以有效地通过Vault进行身份验证,以便应用程序可以获取秘密。

使用 Vault 进行 Kubernetes Pod 的认证

首先,在下述权限下创建一个Kubernetes服务账号。

$ cat vault_sa.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: role-tokenreview-binding
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:auth-delegator
subjects:
- kind: ServiceAccount
  name: vault-auth
  namespace: default

$ kubectl apply -f vault_sa.yaml 
clusterrolebinding.rbac.authorization.k8s.io "role-tokenreview-binding" created

接下来,我们将获取变量并在Vault后端中启用Kubernetes认证。

Kubernetes 主机 – 关联到 Vault 的地址

k8s_host="$(kubectl config view --minify | grep server | cut -f 2- -d ":" | tr -d " ")"

集群授权数据-用于验证连接的证明

k8s_cacert="$(kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}' | base64 --decode)"

用户令牌 – vault-auth服务帐户具有令牌审核器的角色。 Vault使用此服务帐户与集群进行交互。

secret_name="$(kubectl get serviceaccount vault-auth -o go-template='{{ (index .secrets 0).name }}')"

account_token="$(kubectl get secret ${secret_name} -o go-template='{{ .data.token }}' | base64 --decode)"

当获取到这些值之后,您可以在Vault后端中启用Kubernetes认证。

vault auth enable kubernetes
vault write auth/kubernetes/config \
    token_reviewer_jwt=${account_token} \
    kubernetes_host=${k8s_host} \
    kubernetes_ca_cert=${k8s_cacert}

接下来,我们需要确保新启动的Pod可以在Vault服务器上进行身份验证。为此,我们将命名空间绑定到Vault角色,并将来使用该命名空间的服务账户JWT进行身份验证。

vault write auth/kubernetes/role/demo bound_service_account_names=vault-auth bound_service_account_namespaces=default policies=demo-policy ttl=1h

让我们来做个测试吧!

请制作一个演示用的Pod,并使用Vault进行身份验证。

kubectl run -it --rm --image=ubuntu --serviceaccount=vault-auth test -- /bin/bash
root$ apt-get update -y && apt-get install vim curl jq mysql-client -y

#Let's get the service account JWT token
root$ JWT="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"

#Now we can use this to get the vault token
root$ VAULT_TOKEN="$(curl --request POST --data '{"jwt": "'"$JWT"'", "role": "demo"}' -s -k https://${VAULT_ADDRESS}/v1/auth/kubernetes/login | jq -r '.auth.client_token')"

现在,您可以使用VAULT_TOKEN在Vault上进行身份验证并获取秘密。但这只是战斗的一半。我们的目标是将Vault秘密设置到环境变量中,以便应用程序可以使用它们。

如果应用程序中存在使用VAULT_TOKEN和VAULT_ADDRESS环境变量直接从Vault中读取逻辑,您可以完全跳过这部分。否则,您可以执行以下操作。

    1. 将vaultenv与Docker容器集成。

 

    在入口脚本的开头使用vaultenv,将数据输入到环境中。

将秘密保存在AWS参数存储中。

请使用中文为以下内容进行释义,只需要提供一种版本:

– I am going to the store to buy some groceries.

AWS参数存储是什么?

在中国土生土长人士的母语中改写:
AWS参数存储是由AWS提供的非常可扩展且安全的服务,用于存储机密信息。您可以使用AWSCLI来读写机密信息。如果要从EC2实例或ECS任务进行访问,则需要设置适当的IAM角色。

“什么是乐室?”

Chamber是一款有用的命令行工具,用于从AWS参数存储中读取和写入机密信息。它支持许多其他命令,以便将机密信息输入到执行环境中,或以各种格式进行导出。

开始这个的话,需要以下的信息。

    1. AWS_DEFAULT_REGION:AWS的默认区域

 

    1. AWS_SECRET_KEY_ID:AWS的密钥ID

 

    AWS_SECRET_ACCESS_KEY:AWS的访问密钥

把Chamber安装到本地

如果您正在使用Mac,可以使用以下命令将Chamber安装到本地。

brew update 
brew install chamber

请确认笔记本电脑上已经配置了AWSCLI。

使用以下方法将秘密写入AWS参数存储。

chamber write <service> <key> <value>

使用下面的代码,从AWS参数存储中读取秘密。

chamber read <service> <key>

将Chamber与Kubernetes应用程序相融合

要将Chamber与Kubernetes应用程序集成,需要进行一些小的更改。

    • アプリのDockerfile

 

    • スクリプトのエントリポイント

 

    • デプロイメントマニフェストファイル

 

    Dockerfileの上部に、次のコンテンツを追加
FROM golang:1.10.4 AS build

RUN CGO_ENABLED=0 GOOS=linux go get -v github.com/segmentio/chamber

FROM <existing base image>

COPY --from=build /go/bin/chamber /chamber
…

根据这个,chamber二进制文件将被构建并集成到容器中。
在入口脚本中,我们将进行以下更改。
在主入口逻辑启动之前,我们将添加以下语句来设置环境变量。

eval "$(chamber env $SERVICE)"

以下的环境变量需要在部署清单中进行设置。

AWS_DEFAULT_REGION:これはアクセス認証情報のデフォルトリージョンに対応します

SERVICE:これは、Chamberを使用してパラメータストアからシークレットを読み取りたいサービスに対応します

Chamber需要访问AWS_SECRET_KEY_ID和AWS_SECRET_ACCESS_KEY,但不建议在Pod Manifest文件中设置这些。强烈推荐使用IAM角色为基础的权限方法来在AWS参数存储中进行身份验证。要实现这一点,请确保赋予了Kubernetes工作节点上分配的IAM角色ssm:GetParameters权限操作。

当设置好这些后,容器在服务环境变量下会读取秘钥。然后,请使用AWS参数存储进行身份验证,并在容器环境中设置该服务所需的所有秘钥。

总结

如果正确管理,Kubernetes的Secret可以大大简化部署过程。您可以将它们插入应用程序的执行环境,或者选择使用自定义构建逻辑来即时读取它们。

如果将Kubernetes集群部署到AWS云上,强烈建议使用Chamber和AWS参数存储库的集成,因为它是最简单和安全的启动方式。

此外,您可以使用Kiam来管理对参数存储的访问,通过使用细粒度的IAM访问控制。这样一来,只有在集群中的特定Pod才能从AWS参数存储获取和使用机密信息。不过,这涉及到另一个讨论话题。

如果您需要监控Kubernetes的设置,请预订MetricFire的演示并直接联系我们。我们已经帮助了许多MetricFire客户监视他们的Kubernetes集群。

广告
将在 10 秒后关闭
bannerAds