介绍
随着云计算解决方案的普及,构建分布式应用程序已经变得越来越普遍。随之而来的挑战是如何管理和保护分布式系统中的敏感信息。
本文将介绍如何使用Golang和Vault来构建安全的分布式应用程序。
什么是Vault?
Vault 是一个开源的工具,用于安全地管理和保护敏感的数据和令牌。它提供了加密、静态和动态密钥、秘密存储和访问控制等功能。 Vault 是 HashiCorp 公司出品的又一个响当当的项目。
Vault的安装和配置
首先,你需要安装并启动 Vault。 你可以从官方网站下载Vault,官方网站提供了Linux、Windows和macOS的二进制文件
$ wget https://releases.hashicorp.com/vault/1.7.1/vault_1.7.1_linux_amd64.zip
$ unzip vault_1.7.1_linux_amd64.zip
$ sudo mv vault /usr/local/bin
接下来,使用以下命令来启动Vault
$ vault server -dev -dev-root-token-id="00000000-0000-0000-0000-000000000000"
该命令将在您的本机上启动 Vault 服务器。
Vault 启动后,可以使用以下命令检查它是否正在运行:
$ vault status
Success! Vault is initialized
使用Vault API读取和写入秘密
Vault API 具有对数据进行读取和写入的功能。通过使用Vault 的 API,应用程序能够将秘密存储在Vault 中,然后在需要时从Vault 中获取它们。
接下来,让我们尝试将一个字符串写入Vault中:
package main
import (
"fmt"
"github.com/hashicorp/vault/api"
)
func main() {
// 首先,连接到Vault API
client, err := api.NewClient(api.DefaultConfig())
if err != nil {
fmt.Println("Error connecting to the Vault API:", err)
return
}
// 设置Vault的访问令牌
client.SetToken("00000000-0000-0000-0000-000000000000")
// 将字符串写入Vault
secret := map[string]interface{}{
"value": "hello world",
}
_, err = client.Logical().Write("secret/myapp", secret)
if err != nil {
fmt.Println("Error writing to Vault:", err)
return
}
fmt.Println("Secret successfully written to Vault!")
}
现在,我们可以使用以下代码从Vault中读取刚刚写入的秘密:
package main
import (
"fmt"
"github.com/hashicorp/vault/api"
)
func main() {
// 首先,连接到Vault API
client, err := api.NewClient(api.DefaultConfig())
if err != nil {
fmt.Println("Error connecting to the Vault API:", err)
return
}
// 设置Vault的访问令牌
client.SetToken("00000000-0000-0000-0000-000000000000")
// 从Vault中读取秘密
secret, err := client.Logical().Read("secret/myapp")
if err != nil {
fmt.Println("Error reading from Vault:", err)
return
}
// 检查秘密是否存在
if secret == nil {
fmt.Println("No secret found in Vault.")
return
}
// 显示秘密
value, ok := secret.Data["value"].(string)
if !ok {
fmt.Println("Secret value is not a string!")
return
}
fmt.Println(value)
}
使用Vault保护分布式应用程序中的敏感信息
Vault 可以轻松地集成到您的应用程序中。使用Vault,您可以以安全的方式存储和管理访问令牌、数据库凭据、API 密钥等重要信息。
假设您正在编写一个使用 MongoDB 作为后端的分布式Web应用程序。代码如下:
package main
import (
"fmt"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"os"
)
func main() {
// 获取 MongoDB 连接配置
mongoUrl := os.Getenv("MONGODB_URL")
if mongoUrl == "" {
fmt.Println("MONGODB_URL environment variable not set!")
return
}
// 创建 MongoDB 客户端
clientOptions := options.Client().ApplyURI(mongoUrl)
client, err := mongo.NewClient(clientOptions)
if err != nil {
fmt.Println("Error creating MongoDB client:", err)
return
}
// 连接 MongoDB
err = client.Connect(nil)
if err != nil {
fmt.Println("Error connecting to MongoDB:", err)
return
}
// 断开与 MongoDB 的连接
err = client.Disconnect(nil)
if err != nil {
fmt.Println("Error disconnecting from MongoDB:", err)
return
}
fmt.Println("Successfully connected to MongoDB!")
}
该应用程序从名为 MONGODB_URL 的环境变量中获取MongoDB的连接URL。 但是,如果您使用程序中的明文密码,则可能会有安全风险。
为了解决这个问题,我们可以使用Vault将敏感的MongoDB凭据存储在Vault中,然后在应用程序中使用Vault API读取它们。
编写代码以将MongoDB连接信息存储在Vault中:
package main
import (
"fmt"
"github.com/hashicorp/vault/api"
"go.mongodb.org/mongo-driver/mongo/options"
"os"
)
func main() {
// 获取 MongoDB 连接配置
mongoUrl := os.Getenv("MONGODB_URL")
if mongoUrl == "" {
fmt.Println("MONGODB_URL environment variable not set!")
return
}
// 连接到Vault API
client, err := api.NewClient(api.DefaultConfig())
if err != nil {
fmt.Println("Error connecting to the Vault API:", err)
return
}
// 设置Vault的访问令牌
client.SetToken("00000000-0000-0000-0000-000000000000")
// 将数据库凭据写入Vault
data := map[string]interface{}{
"mongodbUrl": mongoUrl,
"mongodbUsername": "myuser",
"mongodbPassword": "mypassword",
"mongodbCertificate": "mycertificate",
}
_, err = client.Logical().Write("secret/mongodb", data)
if err != nil {
fmt.Println("Error writing to Vault:", err)
return
}
fmt.Println("Credentials successfully written to Vault!")
}
现在,在原来的Web应用程序中,我们可以使用Vault API来检索与MongoDB连接相关的敏感信息:
package main
import (
"fmt"
"github.com/hashicorp/vault/api"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"os"
)
func main() {
// 连接到Vault API
client, err := api.NewClient(api.DefaultConfig())
if err != nil {
fmt.Println("Error connecting to the Vault API:", err)
return
}
// 设置Vault的访问令牌
client.SetToken("00000000-0000-0000-0000-000000000000")
// 从Vault读取数据库凭据
secret, err := client.Logical().Read("secret/mongodb")
if err != nil {
fmt.Println("Error reading from Vault:", err)
return
}
// 检查是否存在凭证
if secret == nil {
fmt.Println("No credentials found in Vault.")
return
}
// 获取MongoDB连接的敏感信息
mongoUrl := secret.Data["mongodbUrl"].(string)
mongoUsername := secret.Data["mongodbUsername"].(string)
mongoPassword := secret.Data["mongodbPassword"].(string)
mongoCertificate := secret.Data["mongodbCertificate"].(string)
// 创建MongoDB客户端
clientOptions := options.Client().
ApplyURI(mongoUrl).
SetAuth(options.Credential{
AuthSource: "admin",
Username: mongoUsername,
Password: mongoPassword,
}).
SetTLSConfig(&tls.Config{
RootCAs: mongoCertificate,
InsecureSkipVerify: true,
})
client, err := mongo.NewClient(clientOptions)
if err != nil {
fmt.Println("Error creating MongoDB client:", err)
return
}
// 连接到MongoDB
err = client.Connect(nil)
if err != nil {
fmt.Println("Error connecting to MongoDB:", err)
return
}
// 断开与MongoDB的连接
err = client.Disconnect(nil)
if err != nil {
fmt.Println("Error disconnecting from MongoDB:", err)
return
}
fmt.Println("Successfully connected to MongoDB!")
}
通过使用Vault,您可以简单地存储和保护分布式系统中的敏感信息,同时保护它们不受未经授权的访问和恶意攻击。