Go语言 使用Vault API软件包的身份验证方法

hec6srdp  于 2023-01-28  发布在  Go
关注(0)|答案(4)|浏览(139)

我正在尝试使用Vault Golang Package通过API进行身份验证。
我创建了一个新的客户端,然后可以设置我的令牌:

client, err := api.NewClient(&api.Config{Address: vaultAddr, HttpClient: httpClient})

 if err != nil {
   return nil, errors.Wrap(err, "could not create vault client")
 }

client.SetToken(token)

这很好,但是我想使用其他认证方法(LDAP、Userpass等)对API进行认证
这可能吗?我如何使用API检索令牌?
我想我可以只使用net/http通过API调用来检索令牌,但是否有其他方法来实际进行身份验证?

zaq34kh6

zaq34kh61#

我终于想明白了,虽然不是很明显,但还是有道理的。
Vault具有用于写入数据的通用写入方法。您可以利用此方法通过API执行登录,只需构建URL并向该端点发送PUT请求即可
它看起来有点像这样:

// create a vault client
client, err := api.NewClient(&api.Config{Address: url, HttpClient: httpClient})
if err != nil {
    panic(err)
}

// to pass the password
options := map[string]interface{}{
   "password": password,        
}

// the login path
// this is configurable, change userpass to ldap etc
path := fmt.Sprintf("auth/userpass/login/%s", username)

// PUT call to get a token
secret, err := client.Logical().Write(path, options)
lbsnaicq

lbsnaicq2#

如果没有足够的信誉,在这里添加一个额外的提示,而不是对接受的答案进行注解。令牌可以从auth响应中提取,如下所示:

client.SetToken(secret.Auth.ClientToken)

相关接口记录如下:
https://godoc.org/github.com/hashicorp/vault/api#Secret
https://godoc.org/github.com/hashicorp/vault/api#SecretAuth

deikduxw

deikduxw3#

我写了一个GitHub gust,其中包含一个函数,可以使用AWS IAM角色验证Go程序,这里是a link
注意:验证到Vault * 只会为您获取令牌 *。如果AWS IAM角色允许,该令牌以后可能会用于读取机密。
您需要创建AWS STS请求,从中提取一些信息,然后将其发送到Vault。
这是GitHub要点中的函数。它将使用AWS IAM角色和一些Vault环境变量,如VAULT_ADDR。下面是Vault Golang库可能读取的其他一些环境变量。它生成经过验证的Vault *api.Client、令牌和来自验证请求的响应。
它基于this GitHub project

package vault

import (
    "encoding/base64"
    "encoding/json"
    "fmt"
    "io/ioutil"

    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/sts"
    "github.com/hashicorp/vault/api"
)

// AWSLogin will create a Vault client, login via an AWS role, and return a valid Vault token and client that can be
// used to get secrets.
// The authProvider is likely "aws". It's the "Path" column as described in these docs:
// https://www.vaultproject.io/api/auth/aws#login.
// The serverID is an optional value to be placed in the X-Vault-AWS-IAM-Server-ID header of the HTTP request.
// The role is an AWS IAM role. It needs to be able to read secrets from Vault.
func AWSLogin(authProvider, serverID, role string) (client *api.Client, token string, secret *api.Secret, err error) {

    // Create the Vault client.
    //
    // Configuration is gathered from environment variables by upstream vault package. Environment variables like
    // VAULT_ADDR and VAULT_SKIP_VERIFY are relevant. The VAULT_TOKEN environment variable shouldn't be needed.
    // https://www.vaultproject.io/docs/commands#environment-variables
    if client, err = api.NewClient(nil); err != nil {
        return nil, "", nil, fmt.Errorf("failed to create Vault client: %w", err)
    }

    // Acquire an AWS session.
    var sess *session.Session
    if sess, err = session.NewSession(); err != nil {
        return nil, "", nil, fmt.Errorf("failed to create AWS session: %w", err)
    }

    // Create a Go structure to talk to the AWS token service.
    tokenService := sts.New(sess)

    // Create a request to the token service that will ask for the current host's identity.
    request, _ := tokenService.GetCallerIdentityRequest(&sts.GetCallerIdentityInput{})

    // Add an server ID IAM header, if present.
    if serverID != "" {
        request.HTTPRequest.Header.Add("X-Vault-AWS-IAM-Server-ID", serverID)
    }

    // Sign the request to the AWS token service.
    if err = request.Sign(); err != nil {
        return nil, "", nil, fmt.Errorf("failed to sign AWS identity request: %w", err)
    }

    // JSON marshal the headers.
    var headers []byte
    if headers, err = json.Marshal(request.HTTPRequest.Header); err != nil {
        return nil, "", nil, fmt.Errorf("failed to JSON marshal HTTP headers for AWS identity request: %w", err)
    }

    // Read the body of the request.
    var body []byte
    if body, err = ioutil.ReadAll(request.HTTPRequest.Body); err != nil {
        return nil, "", nil, fmt.Errorf("failed to JSON marshal HTTP body for AWS identity request: %w", err)
    }

    // Create the data to write to Vault.
    data := make(map[string]interface{})
    data["iam_http_request_method"] = request.HTTPRequest.Method
    data["iam_request_url"] = base64.StdEncoding.EncodeToString([]byte(request.HTTPRequest.URL.String()))
    data["iam_request_headers"] = base64.StdEncoding.EncodeToString(headers)
    data["iam_request_body"] = base64.StdEncoding.EncodeToString(body)
    data["role"] = role

    // Create the path to write to for Vault.
    //
    // The authProvider is the value referenced in the "Path" column in this documentation. It's likely "aws".
    // https://www.vaultproject.io/api/auth/aws#login
    path := fmt.Sprintf("auth/%s/login", authProvider)

    // Write the AWS token service request to Vault.
    if secret, err = client.Logical().Write(path, data); err != nil {
        return nil, "", nil, fmt.Errorf("failed to write data to Vault to get token: %w", err)
    }
    if secret == nil {
        return nil, "", nil, fmt.Errorf("failed to get token from Vault: %w", ErrSecret)
    }

    // Get the Vault token from the response.
    if token, err = secret.TokenID(); err != nil {
        return nil, "", nil, fmt.Errorf("failed to get token from Vault response: %w", err)
    }

    // Set the token for the client as the one it just received.
    client.SetToken(token)

    return client, token, secret, nil
}
2guxujil

2guxujil4#

api封装中有一个标准的AuthMethod接口。

type AuthMethod interface {
    Login(ctx context.Context, client *Client) (*Secret, error)
}

可以用任何登录方法实现这个接口。下面是一个基本用户名/密码登录的例子

type CredentialsAuthMethod struct {
    username string
    password string
}

func (m *CredentialsAuthMethod) Login(ctx context.Context, client *api.Client) (*api.Secret, error) {
    options := map[string]any{
        "password": m.password,
    }
    path := fmt.Sprintf("auth/userpass/login/%s", m.username)

    secret, err := client.Logical().WriteWithContext(ctx, path, options)
    if err != nil {
        return nil, errorx.EnhanceStackTrace(err, "failed to authorize in vault with credentials")
    }

    return secret, nil
}

实现新的AuthMethod后,可以使用它为客户端获取令牌:

client, err := api.NewClient(&api.Config{Address: "https://vault.local"})
    if err != nil {
        return nil, errorx.EnhanceStackTrace(err, "failed to initialize vault client")
    }
    
    secret, err := client.Auth().Login(context.Background(), &CredentialsAuthMethod{
        username: c.username,
        password: c.password,
    })
    if err != nil {
        return nil, errorx.EnhanceStackTrace(err, "failed to login in vault")
    }

    token := secret.Auth.ClientToken
    client.SetToken(token)

相关问题