1. 介绍Vault
Vault是一个用于安全存储和访问秘密的开源工具,它提供了一个集中式的管理系统来保护访问各种敏感数据如令牌、密码、证书等。Golang是一种使用Vault管理秘密数据的有力工具。Golang与Vault的结合,可以帮助构建非常安全的应用程序。
2. 最佳实践
2.1 将Vault配置读入环境变量
首先,我们需要在项目的配置文件中指定Vault服务器的地址和其他配置。但是,应该避免在源码或配置文件中曝光Vault接入密钥等机密信息,最好的方式是将其配置为环境变量。以下是Golang中如何读取Vault地址的方法。
import (
"os"
)
func main() {
vaultAddr := os.Getenv("VAULT_ADDR")
if vaultAddr == "" {
panic("VAULT_ADDR environment variable not set")
}
// Do something with the vaultAddr
}
在此示例中,我们使用了os包的Getenv函数从系统环境变量中读取Vault发行版地址。这里使用了panic语句,因为在未设置VAULT_ADDR的情况下无法执行任何必须访问Vault密钥/值的操作。
2.2 使用Vault CLI 创建新的密钥
使用Vault管理机密数据的一个重要方面是创建新的访问密钥、密码、证书等。可以使用Vault CLI来创建该密钥。下面是如何使用Vault CLI创建一个新的密钥。
vault kv put secret/secret_key key1=value1 key2=value2
在此示例中,我们使用Vault的kv模块创建一个名为secret_key的新秘密。该键值对存储在secret/secret_key路径下。使用Vault CLI的另一个优点是可以使用它来更新或删除现有的密钥。
2.3 使用Vault API 访问密钥
Golang可以与Vault API进行交互,从而对保存在Vault中的密钥进行访问。以下是使用Vault API读取密钥的示例。
package main
import (
"fmt"
"github.com/hashicorp/vault/api"
)
func main() {
// Create a new Vault API client
client, err := api.NewClient(&api.Config{Address: "http://127.0.0.1:8200"})
if err != nil {
panic(err)
}
// Set the Vault token
client.SetToken("vault-token")
// Read the secret from Vault
secret, err := client.Logical().Read("secret/secret_key")
if err != nil {
panic(err)
}
// Retrieve the value of the 'key1' field
value, ok := secret.Data["key1"].(string)
if !ok {
panic("Value is not a string")
}
// Print the value
fmt.Println(value)
}
在此示例中,我们通过创建一个新的Vault API客户端来访问Vault中存储的密钥。client.Logical().Read()函数返回包含一组密钥/值的map类型,可以通过类型断言方法正确提取希望读取的值。
2.4 集成Vault托管的TLS证书
使用Vault管理TLS证书是一种可靠的方法,可以在自己的应用程序中保护证书并使证书的使用更加容易,下面是如何在Golang中使用Vault的TLS证书:
package main
import (
"crypto/tls"
"net/http"
"net/url"
"github.com/hashicorp/vault/api"
)
func main() {
// Get the Vault address from the environment variable
vaultAddr := os.Getenv("VAULT_ADDR")
if vaultAddr == "" {
panic("VAULT_ADDR environment variable not set")
}
// Create a new Vault API client
vaultConfig = &api.Config{Address: vaultAddr}
vaultClient, err := api.NewClient(vaultConfig)
if err != nil {
panic(err)
}
// Enable the Vault PKI secrets engine
_, err := vaultClient.Logical().Write("pki/root/generate/internal", map[string]interface{}{
"common_name": "example.com",
})
if err != nil {
panic(err)
}
// Load the TLS secrets from Vault
tlsCert, err := vaultClient.Logical().Read("pki/cert/ca")
if err != nil {
panic(err)
}
tlsKey, err := vaultClient.Logical().Read("pki/private/ca")
if err != nil {
panic(err)
}
// Load the CA certificate and key
cert, err := tls.X509KeyPair([]byte(tlsCert.Data["certificate"].(string)), []byte(tlsKey.Data["private_key"].(string)))
if err != nil {
panic(err)
}
// Configure the TLS client
transport := &http.Transport{
TLSClientConfig: &tls.Config{
Certificates: []tls.Certificate{cert},
ServerName: "example.com",
},
}
// Create a new HTTP client
client := &http.Client{Transport: transport}
// Make a request to the server
resp, err := client.PostForm("https://example.com", url.Values{})
if err != nil {
panic(err)
}
// Decode the server response
decoder := json.NewDecoder(resp.Body)
var response map[string]interface{}
err = decoder.Decode(&response)
if err != nil {
panic(err)
}
fmt.Println(response["message"])
}
在此示例中,我们首先创建了一个新的Vault API客户端并启用了Vault PKI机密引擎来生成一个新的CA证书。然后,我们加载了从Vault读取的TLS证书和密钥,然后创建了一个新的TLS配置,该配置由CA证书和密钥组成。最后,我们使用改配置来创建新的HTTP客户端。
2.5 使用Vault跨多个环境管理密钥
Vault非常适合在多个环境中管理机密数据(例如开发、测试、生产等)。对于这种情况,可以使用Vault提供的代理来使多个环境之间共享机密数据。
package main
import (
"fmt"
"os"
"github.com/hashicorp/vault/api"
)
func main() {
// Get the Vault address from the environment variable
vaultAddr := os.Getenv("VAULT_ADDR")
if vaultAddr == "" {
panic("VAULT_ADDR environment variable not set")
}
// Create a new Vault API client
vaultConfig := &api.Config{Address: vaultAddr}
vaultClient, err := api.NewClient(vaultConfig)
if err != nil {
panic(err)
}
// Set the Vault token
vaultToken := os.Getenv("VAULT_TOKEN")
vaultClient.SetToken(vaultToken)
// Read the secret from Vault
secret, err := vaultClient.Logical().Read("secret/secret_key")
if err != nil {
panic(err)
}
// Retrieve the value of the 'key1' field
value, ok := secret.Data["key1"].(string)
if !ok {
panic("Value is not a string")
}
// Print the value
fmt.Println(value)
}
在此例中,我们首先从环境变量中读取Vault地址和用户令牌信息。然后,我们创建了一个新的Vault API客户端,用我们从环境变量中读取的令牌验证相应的身份验证。如果代理服务器上的多个主机需要访问Vault机密,我们可以使用相同的令牌在多个主机上访问Vault。
3. 总结
在本篇文章中,我们介绍了如何在Golang项目中使用Vault保护敏感数据。我们从将Vault配置读入环境变量开始,继续探讨如何使用Vault CLI创建新的密钥、如何使用Vault API访问密钥、如何在Golang中使用Vault的TLS证书,以及如何使用Vault跨多个环境管理密钥。在Golang项目中使用Vault是保护应用程序中敏感数据的最佳实践之一。在实施这些实践时,您可以从构建更加安全的应用程序中获得巨大利益。