【微服务安全】使用 Spring Boot、Kafka、Vault 和 Kubernetes 保护微服务间通信——第 3 部分:设置 Vault

简介: 【微服务安全】使用 Spring Boot、Kafka、Vault 和 Kubernetes 保护微服务间通信——第 3 部分:设置 Vault
  • 第 1 部分:简介和架构
  • 第 2 部分:设置 Kubernetes 和 Kafka
  • 第 3 部分:设置 Vault <--本文
  • 第 4 部分:构建微服务
  • 第 5 部分:部署和测试

设置Vault

 

  • 如果我们回想一下我们的架构,我们说过我们将提供端到端加密。虽然 Vault 将保护我们的信息,但谁在保护 Vault? - 为此,我们将使用经典的 TLS 连接 (HTTPS) 来保护我们与 Vault 的通信。我们将为此创建一个自签名证书。

使用 TLS 安装

 

> openssl version

 

  • 如果你有 openssl,你应该得到下面的响应(或类似的)。如果您没有 OpenSSL,请从此处 [https://www.openssl.org/] 下载并安装

LibreSSL 2.6.5

 

  • 接下来,运行以下命令为我们的设置设置环境变量

> SERVICE=vault

> NAMESPACE=default

> SECRET_NAME=vault-server-tls

> TMPDIR=/tmp

SERVICE:包含 Vault 的服务名称

NAMESPACE:运行 Vault 的 Kubernetes 命名空间

SECRET_NAME:包含 TLS 证书的 Kubernetes 密钥

TMPDIR:临时工作目录

  • 然后,创建一个用于签名的密钥

> openssl genrsa -out ${TMPDIR}/vault.key 2048

 

  • 我们现在将创建一个证书签名请求 (CSR)。首先,让我们创建一个 CSR 配置文件:

> cat <<EOF >${TMPDIR}/csr.conf

[req]

req_extensions = v3_req

distinguished_name = req_distinguished_name

[req_distinguished_name]

[ v3_req ]

basicConstraints = CA:FALSE

keyUsage = nonRepudiation, digitalSignature, keyEncipherment

extendedKeyUsage = serverAuth

subjectAltName = @alt_names

[alt_names]

DNS.1 = ${SERVICE}

DNS.2 = ${SERVICE}.${NAMESPACE}

DNS.3 = ${SERVICE}.${NAMESPACE}.svc

DNS.4 = ${SERVICE}.${NAMESPACE}.svc.cluster.local

IP.1 = 127.0.0.1

EOF

 

  • 然后,我们将创建 CSR 文件本身

> openssl req -new -key ${TMPDIR}/vault.key -subj "/CN=${SERVICE}.${NAMESPACE}.svc" -out ${TMPDIR}/server.csr -config ${TMPDIR}/csr.conf

 

  • 现在,我们将创建实际的证书。从命令行运行

> export CSR_NAME=vault-csr

 

  • 然后我们将创建一个 csr.yaml 文件

> cat <<EOF >${TMPDIR}/csr.yaml

apiVersion: certificates.k8s.io/v1beta1

kind: CertificateSigningRequest

metadata:

 name: ${CSR_NAME}

spec:

 groups:

 - system:authenticated

 request: $(cat ${TMPDIR}/server.csr | base64 | tr -d '\n')

 usages:

 - digital signature

 - key encipherment

 - server auth

EOF

 

  • 然后我们将在 Kubernetes 中创建一个证书签名请求

> kubectl create -f ${TMPDIR}/csr.yaml

 

  • 要验证是否创建了证书签名请求,请运行以下命令。

> kubectl get csr ${CSR_NAME}

 

  • 然后,批准 CSR。通过此命令,您已签署 CSR

> kubectl certificate approve ${CSR_NAME}

 

  • 之后,将证书导出到名为 vault.crt 的文件中

> serverCert=$(kubectl get csr ${CSR_NAME} -o jsonpath='{.status.certificate}')

> echo "${serverCert}" | openssl base64 -d -A -out ${TMPDIR}/vault.crt

 

  • 同时导出 Kubernetes CA

> kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}' | base64 -d > ${TMPDIR}/vault.ca

 

  • 创建一个秘密存储上面创建的所有文件

> kubectl create secret generic ${SECRET_NAME} --namespace ${NAMESPACE} --from-file=vault.key=${TMPDIR}/vault.key --from-file=vault.crt=${TMPDIR}/vault.crt --from-file=vault.ca=${TMPDIR}/vault.ca

 

  • 接下来,我们将在 $PROJECTS/k8s 文件夹中创建一个名为 custom-values.yaml 的文件。该文件的内容应为:

global:

 enabled: true

 tlsDisable: false

server:

 extraEnvironmentVars:

   VAULT_CACERT: /vault/userconfig/vault-server-tls/vault.ca

 extraVolumes:

   - type: secret

     name: vault-server-tls

 standalone:

   enabled: true

   config: |

     listener "tcp" {

       address = "[::]:8200"

       cluster_address = "[::]:8201"

       tls_cert_file = "/vault/userconfig/vault-server-tls/vault.crt"

       tls_key_file  = "/vault/userconfig/vault-server-tls/vault.key"

       tls_client_ca_file = "/vault/userconfig/vault-server-tls/vault.ca"

     }


     storage "file" {

       path = "/vault/data"

     }

  • 然后,我们将使用 Helm 安装通过我们的自签名 SSL 保护的独立 Vault。将命令行控制台指向文件夹 $PROJECTS/k8s 并运行:

> helm repo add hashicorp https://helm.releases.hashicorp.com

> helm install vault -f custom-values.yaml hashicorp/vault

 

  • 要验证 Vault 是否正在运行,请运行以下命令:

> kubectl get pods

 

  • 您应该在 pod 列表中看到 vault

网络异常,图片无法展示
|

保险库 Kubernetes 服务

 

  • 运行以下命令以获取服务列表

> kubectl get svc

  • 您应该看到下面的列表。Vault服务的名称是“Vault”。由于 Vault 在默认集群中运行,因此 Vault 服务(在 Kubernetes 内)的完全限定域名应该是 vault.default.svc。

网络异常,图片无法展示
|

 

初始化Vault

  • 要初始化 Vault,我们需要运行以下命令:

> kubectl exec -ti vault-0 -- vault operator init -format=json > cluster-keys.json

 

  • 这将创建一个包含 5 个键的 json 文件。 json 文件的内容可能如下所示:

{

 "keys": [

   "dea...94",

   "0c0...10",

   "800...29",

   "88e...1e",

   "5by...8z"

 ],

 "keys_base64": [

   "...",

   "...",

   "...",

   "...",

   "..."

 ],

 "root_token": "s.Tyu...d"

}

开封保险库

 

  • 初始化 Vault 时,它以密封模式运行。我们需要解封它才能使 Vault 有用。
  • 您还需要在每次重新启动时解封 Vault
  • 在上面的步骤(Initialize Vault)中,我们创建了一个包含 5 个密钥的子文件。我们需要提供 3 个密钥来解封 Vault。要解封,请运行以下命令:

> kubectl exec -ti vault-0 -- vault operator unseal

 

  • 此命令将提示输入密钥。键入其中一个键并按回车键。
  • 您将得到以下结果:

Key             Value

---             -----

Seal Type       shamir

Initialized     true

Sealed          false

Total Shares    5

Threshold       3

Version         1.5.2

Cluster Name    vault-cluster-e4b6a573

Cluster ID      80...b

HA Enabled      false

 

  • 每次使用不同的键重新运行以上命令 2 次
  • 祝贺。你有开封Vault。

暴露 Vault web ui

 

  • 接下来,我们将使用他之前在 Kafka 中使用的 port-forward 命令将 Vault 暴露给 Kubernetes 之外的世界。请注意,使用 Vault,我们通过端口转发而不是 pod 公开服务。

> kubectl port-forward service/vault 8200:8200

 

创建中转(transit )引擎

 

  • Vault Transit 引擎是 Vault 提供的一种加密即服务工具。我们将使用它来加密我们的消息。
  • 将浏览器指向地址 https://localhost:8200(注意它是 https)。您可能会看到一个对话框,您需要在其中接受自签名证书。单击确定。

网络异常,图片无法展示
|

  • 然后您将看到下面的页面。在 Token 字段中,键入刚才在初始化期间创建的 cluster-key.json 文件中的 root_token 值。

网络异常,图片无法展示
|

  • 然后,点击启用新引擎

网络异常,图片无法展示
|

  • 选择过境,然后点击下一步

网络异常,图片无法展示
|

  • 然后,在 Path 字段中输入“transit”,然后单击 Enable Engine

网络异常,图片无法展示
|

  • 您将获得您的秘密中列出的运输引擎

网络异常,图片无法展示
|

  • 在中转页面上,单击“创建加密密钥”

网络异常,图片无法展示
|

  • 在“创建加密密钥”页面中,在名称字段中输入 my-encryption-key,然后单击创建加密密钥

网络异常,图片无法展示
|

  • 您将看到已创建加密密钥

网络异常,图片无法展示
|

  • 祝贺。您创建了一个 Transit 引擎

管理访问权限和策略

 

  • 单击菜单策略。然后单击“创建 ACL 策略”

网络异常,图片无法展示
|

  • 在名称中,输入 my-encrypt-policy。在策略中放入下面的代码。这将允许此策略仅加密以下数据。完成后,单击“创建策略”:

path "transit/decrypt/my-encryption-key" {

 capabilities = [ "update" ]

}

网络异常,图片无法展示
|

  • 再次单击策略 > 创建 ACL 策略。在 Name 中输入“my-encrypy-policy”,在 Policy 中输入下面的代码。然后点击“创建策略”

path "transit/encrypt/my-encryption-key" {

 capabilities = [ "update" ]

}

网络异常,图片无法展示
|

  • 您现在应该设置 2 个策略:

网络异常,图片无法展示
|

  • 然后启动你的命令行控制台并运行下面的 curl 命令。请注意,下面的值 s.Tyu…d 是从上面的文件 cluster-keys.json 获得的根令牌的值。我们创建的策略 my-encrypt-policy 的值也在下面指定。 (我们在 curl 命令上使用选项 -k 因为我们使用的证书是自签名的。没有 -k,curl 命令将抱怨我们的证书)

> curl --header "X-Vault-Token: s.Tyu...d" --request POST --data '{"policies": ["my-encrypt-policy"]}' -k https://localhost:8200/v1/auth/token/create

 

  • 你应该得到下面的回应。请注意客户端令牌的 values.O1...k。让我们称之为加密令牌

{

  "request_id":"d5b47829-53f0-a35e-4b7c-0e9d8f4f3cbc",

  "lease_id":"",

  "renewable":false,

  "lease_duration":0,

  "data":null,

  "wrap_info":null,

  "warnings":null,

  "auth":{

     "client_token":"s.O1sI3QhVvSmbG1lyfKSMXXFk",

     "accessor":"T...8",

     "policies":[

        "default",

        "my-encrypt-policy"

     ],

     "token_policies":[

        "default",

        "my-encrypt-policy"

     ],

     "metadata":null,

     "lease_duration":2764800,

     "renewable":true,

     "entity_id":"",

     "token_type":"service",

     "orphan":false

  }

}

 

  • 让我们重复相同的 curl 命令,这一次,我们将使用 my-decrypt-policy 策略

curl --header "X-Vault-Token: s.WuTNTDpBqsspinc6dlDN0cbz" --request POST --data '{"policies": ["my-decrypt-policy"]}' -k https://localhost:8200/v1/auth/token/create

 

  • 我们应该看到下面的结果。注意客户端令牌(s.7x…Xv)。我们将此令牌称为解密器令牌

{

  "request_id":"d5b47829-53f0-a35e-4b7c-0e9d8f4f3cbc",

  "lease_id":"",

  "renewable":false,

  "lease_duration":0,

  "data":null,

  "wrap_info":null,

  "warnings":null,

  "auth":{

     "client_token":"s.7xdIhRPcJXFw2B1s6fKasHXv",

     "accessor":"TSNoAMVNwFEUzlmx8tjRh9w8",

     "policies":[

        "default",

        "my-encrypt-policy"

     ],

     "token_policies":[

        "default",

        "my-encrypt-policy"

     ],

     "metadata":null,

     "lease_duration":2764800,

     "renewable":true,

     "entity_id":"",

     "token_type":"service",

     "orphan":false

  }

测试 Vault 的加密即服务

 

  • 因此,让我们测试一下我们的设置。首先,我们需要一个 base-64 字符串。打开命令行控制台并运行以下命令。这会将字符串编码为 base-64。当然,您可以使用“Hello world”以外的其他语言。

> echo -n 'Hello world'|openssl base64

 

  • 你会得到

SGVsbG8gd29ybGQ=

 

  • 让我们使用加密器令牌加密该字符串。

> curl --header "X-Vault-Token: s.O1sI3QhVvSmbG1lyfKSMXXFk" --request POST --data '{"plaintext": "SGVsbG8gd29ybGQ="}' -k https://127.0.0.1:8200/v1/transit/encrypt/my-encryption-key

 

  • 您将收到以下回复。加密数据在字段密文中。

{

  "request_id":"c345db50-2517-90de-cc8c-f66812b27d6b",

  "lease_id":"",

  "renewable":false,

  "lease_duration":0,

  "data":{

     "ciphertext":"vault:v1:+VZG+5sZA0AQworFh5+o/kTyri6I+ooKWjfwbVOtB+lY/AWRurhO",

     "key_version":1

  },

  "wrap_info":null,

  "warnings":null,

}

 

  • 现在,让我们尝试使用解密器令牌进行解密。请注意,字段密文包含上面的加密数据

curl --header "X-Vault-Token: s.7xdIhRPcJXFw2B1s6fKasHXv" --request POST --data '{"ciphertext":"vault:v1:+VZG+5sZA0AQworFh5+o/kTyri6I+ooKWjfwbVOtB+lY/AWRurhO"}' -k https://127.0.0.1:8200/v1/transit/decrypt/my-encryption-key

 

  • 然后你会得到下面的回复。请注意,我们取回了我们之前加密的 base 64 字符串。

{

  "request_id":"7d00a316-90ff-9c94-3e6f-d8e60b0560e3",

  "lease_id":"",

  "renewable":false,

  "lease_duration":0,

  "data":{

     "plaintext":"SGVsbG8gd29ybGQ="

  },

  "wrap_info":null,

  "warnings":null,

  "auth":null

}

 

  • 现在,让我们尝试一个否定的测试用例。让我们尝试加密数据,但改用解密器令牌

> curl --header "X-Vault-Token: s.7xdIhRPcJXFw2B1s6fKasHXv" --request POST --data '{"plaintext": "SGVsbG8gd29ybGQ="}' -k https://127.0.0.1:8200/v1/transit/encrypt/my-encryption-key

 

  • 您最终会遇到错误

{"errors":["1 error occurred:\n\t* permission denied\n\n"]}

 

  • 您可以尝试相反,尝试使用加密令牌进行解密

> curl --header "X-Vault-Token: s.O1sI3QhVvSmbG1lyfKSMXXFk" --request POST --data '{"ciphertext":"vault:v1:+VZG+5sZA0AQworFh5+o/kTyri6I+ooKWjfwbVOtB+lY/AWRurhO"}' -k https://127.0.0.1:8200/v1/transit/decrypt/my-encryption-key

您最终将遇到与上述相同的错误

{"errors":["1 error occurred:\n\t* permission denied\n\n"]}

为加密和解密创建令牌

 

  • 回想一下我们的架构,其中 Transaction Services 和 DepositAccount Service 都需要消费和发送消息。这意味着他们需要加密和解密功能。要创建具有这两个功能的令牌,只需指定两个策略:

curl --header "X-Vault-Token: s.WuTNTDpBqsspinc6dlDN0cbz" --request POST --data '{"policies": ["my-decrypt-policy", "my-encrypt-policy"]}' -k https://localhost:8200/v1/auth/token/create

 

  • 您将收到以下回复。您可以使用“client_token”安全地登录到 Vault 以获得加密和解密功能:

{

 "request_id": "a1f0fc87-5c27-94e3-b043-29adc5c87557",

 "lease_id": "",

 "renewable": false,

 "lease_duration": 0,

 "data": null,

 "wrap_info": null,

 "warnings": null,

 "auth": {

   "client_token": "s.WuTNTDpBqsspinc6dlDN0cbz",

   "accessor": "Qc...dU",

   "policies": [

     "default",

     "my-decrypt-policy",

     "my-encrypt-policy"

   ],

   "token_policies": [

     "default",

     "my-decrypt-policy",

     "my-encrypt-policy"

   ],

   "metadata": null,

   "lease_duration": 2764800,

   "renewable": true,

   "entity_id": "",

   "token_type": "service",

   "orphan": false

 }

}

Vault的结论

我们终于在我们的 Kubernetes 集群中安装和设置了 Vault(独立设置)。我们已经激活了加密即服务引擎,并创建了两个具有两种不同功能的不同令牌。加密器令牌用于加密数据,解密器令牌用于解密数据。我们还使用令牌测试了引擎的 API,我们看到正面和负面的测试用例都通过了。最后,我们创建了一个用于加密和解密功能的令牌。


Tags

本文:https://architect.pub/secure-inter-micro-service-communication-spring-boot-kafka-vault-and-kubernetes-part-3-setting

相关文章
|
弹性计算 关系型数据库 微服务
基于 Docker 与 Kubernetes(K3s)的微服务:阿里云生产环境扩容实践
在微服务架构中,如何实现“稳定扩容”与“成本可控”是企业面临的核心挑战。本文结合 Python FastAPI 微服务实战,详解如何基于阿里云基础设施,利用 Docker 封装服务、K3s 实现容器编排,构建生产级微服务架构。内容涵盖容器构建、集群部署、自动扩缩容、可观测性等关键环节,适配阿里云资源特性与服务生态,助力企业打造低成本、高可靠、易扩展的微服务解决方案。
2731 10
|
监控 Kubernetes Java
使用 New Relic APM 和 Kubernetes Metrics 监控 EKS 上的 Java 微服务
在阿里云AKS上运行Java微服务常遇性能瓶颈与OOMKilled等问题。本文教你通过New Relic实现集群与JVM双层监控,集成Helm部署、JVM代理注入、GC调优及告警仪表盘,打通从节点资源到应用内存的全链路观测,提升排障效率,保障服务稳定。
792 115
|
安全 Java Apache
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 身份和权限认证
本文介绍了 Apache Shiro 的身份认证与权限认证机制。在身份认证部分,分析了 Shiro 的认证流程,包括应用程序调用 `Subject.login(token)` 方法、SecurityManager 接管认证以及通过 Realm 进行具体的安全验证。权限认证部分阐述了权限(permission)、角色(role)和用户(user)三者的关系,其中用户可拥有多个角色,角色则对应不同的权限组合,例如普通用户仅能查看或添加信息,而管理员可执行所有操作。
745 0
|
安全 Java 数据安全/隐私保护
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 三大核心组件
本课程介绍如何在Spring Boot中集成Shiro框架,主要讲解Shiro的认证与授权功能。Shiro是一个简单易用的Java安全框架,用于认证、授权、加密和会话管理等。其核心组件包括Subject(认证主体)、SecurityManager(安全管理员)和Realm(域)。Subject负责身份认证,包含Principals(身份)和Credentials(凭证);SecurityManager是架构核心,协调内部组件运作;Realm则是连接Shiro与应用数据的桥梁,用于访问用户账户及权限信息。通过学习,您将掌握Shiro的基本原理及其在项目中的应用。
591 0
|
NoSQL Java 关系型数据库
微服务——SpringBoot使用归纳——Spring Boot 中集成Redis——Redis 介绍
本文介绍在 Spring Boot 中集成 Redis 的方法。Redis 是一种支持多种数据结构的非关系型数据库(NoSQL),具备高并发、高性能和灵活扩展的特点,适用于缓存、实时数据分析等场景。其数据以键值对形式存储,支持字符串、哈希、列表、集合等类型。通过将 Redis 与 Mysql 集群结合使用,可实现数据同步,提升系统稳定性。例如,在网站架构中优先从 Redis 获取数据,故障时回退至 Mysql,确保服务不中断。
571 0
微服务——SpringBoot使用归纳——Spring Boot 中集成Redis——Redis 介绍
|
消息中间件 存储 Java
微服务——SpringBoot使用归纳——Spring Boot中集成ActiveMQ——ActiveMQ安装
本教程介绍ActiveMQ的安装与基本使用。首先从官网下载apache-activemq-5.15.3版本,解压后即可完成安装,非常便捷。启动时进入解压目录下的bin文件夹,根据系统选择win32或win64,运行activemq.bat启动服务。通过浏览器访问`http://127.0.0.1:8161/admin/`可进入管理界面,默认用户名密码为admin/admin。ActiveMQ支持两种消息模式:点对点(Queue)和发布/订阅(Topic)。前者确保每条消息仅被一个消费者消费,后者允许多个消费者同时接收相同消息。
683 0
微服务——SpringBoot使用归纳——Spring Boot中集成ActiveMQ——ActiveMQ安装
|
消息中间件 Java 微服务
微服务——SpringBoot使用归纳——Spring Boot中集成ActiveMQ——发布/订阅消息的生产和消费
本文详细讲解了Spring Boot中ActiveMQ的发布/订阅消息机制,包括消息生产和消费的具体实现方式。生产端通过`sendMessage`方法发送订阅消息,消费端则需配置`application.yml`或自定义工厂以支持topic消息监听。为解决点对点与发布/订阅消息兼容问题,可通过设置`containerFactory`实现两者共存。最后,文章还提供了测试方法及总结,帮助读者掌握ActiveMQ在异步消息处理中的应用。
673 0
|
消息中间件 网络协议 Java
微服务——SpringBoot使用归纳——Spring Boot中集成ActiveMQ——ActiveMQ集成
本文介绍了在 Spring Boot 中集成 ActiveMQ 的详细步骤。首先通过引入 `spring-boot-starter-activemq` 依赖并配置 `application.yml` 文件实现基本设置。接着,创建 Queue 和 Topic 消息类型,分别使用 `ActiveMQQueue` 和 `ActiveMQTopic` 类完成配置。随后,利用 `JmsMessagingTemplate` 实现消息发送功能,并通过 Controller 和监听器实现点对点消息的生产和消费。最后,通过浏览器访问测试接口验证消息传递的成功性。
1026 0
|
消息中间件 Java API
微服务——SpringBoot使用归纳——Spring Boot中集成ActiveMQ—— JMS 和 ActiveMQ 介绍
本文介绍如何在Spring Boot中集成ActiveMQ,首先阐述了JMS(Java消息服务)的概念及其作为与具体平台无关的API在异步通信中的作用。接着说明了JMS的主要对象模型,如连接工厂、会话、生产者和消费者等,并指出JMS支持点对点和发布/订阅两种消息类型。随后重点讲解了ActiveMQ,作为Apache开源的消息总线,它完全支持JMS规范,适用于异步消息处理。最后,文章探讨了在Spring Boot中使用队列(Queue)和主题(Topic)这两种消息通信形式的方法。
524 0
|
NoSQL Java API
微服务——SpringBoot使用归纳——Spring Boot 中集成Redis——Spring Boot 集成 Redis
本文介绍了在Spring Boot中集成Redis的方法,包括依赖导入、Redis配置及常用API的使用。通过导入`spring-boot-starter-data-redis`依赖和配置`application.yml`文件,可轻松实现Redis集成。文中详细讲解了StringRedisTemplate的使用,适用于字符串操作,并结合FastJSON将实体类转换为JSON存储。还展示了Redis的string、hash和list类型的操作示例。最后总结了Redis在缓存和高并发场景中的应用价值,并提供课程源代码下载链接。
2921 0