mirror of
https://github.com/hashicorp/vault.git
synced 2026-02-20 00:13:53 -05:00
137 lines
3.5 KiB
Go
137 lines
3.5 KiB
Go
package api
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/hashicorp/hcl"
|
|
"github.com/mitchellh/mapstructure"
|
|
)
|
|
|
|
// Default path at which SSH backend will be mounted
|
|
const SSHAgentDefaultMountPoint = "ssh"
|
|
|
|
// This is a structure representing an SSH agent which can talk to vault server
|
|
// in order to verify the OTP entered by the user. It contains the path at which
|
|
// SSH backend is mounted at the server.
|
|
type SSHAgent struct {
|
|
c *Client
|
|
MountPoint string
|
|
}
|
|
|
|
// SSHVerifyResp is a structure representing the fields in Vault server's
|
|
// response.
|
|
type SSHVerifyResponse struct {
|
|
Message string `mapstructure:"message"`
|
|
Username string `mapstructure:"username"`
|
|
IP string `mapstructure:"ip"`
|
|
}
|
|
|
|
// Structure which represents the entries from the agent's configuration file.
|
|
type SSHAgentConfig struct {
|
|
VaultAddr string `hcl:"vault_addr"`
|
|
SSHMountPoint string `hcl:"ssh_mount_point"`
|
|
CACert string `hcl:"ca_cert"`
|
|
CAPath string `hcl:"ca_path"`
|
|
TLSSkipVerify bool `hcl:"tls_skip_verify"`
|
|
AllowedCidrList string `hcl:"allowed_cidr_list"`
|
|
}
|
|
|
|
// Returns a HTTP client that uses TLS verification (TLS 1.2) with the given
|
|
// certificate pool.
|
|
func (c *SSHAgentConfig) TLSClient(certPool *x509.CertPool) *http.Client {
|
|
tlsConfig := &tls.Config{
|
|
InsecureSkipVerify: c.TLSSkipVerify,
|
|
MinVersion: tls.VersionTLS12,
|
|
RootCAs: certPool,
|
|
}
|
|
|
|
client := *http.DefaultClient
|
|
client.Transport = &http.Transport{
|
|
Proxy: http.ProxyFromEnvironment,
|
|
Dial: (&net.Dialer{
|
|
Timeout: 30 * time.Second,
|
|
KeepAlive: 30 * time.Second,
|
|
}).Dial,
|
|
TLSClientConfig: tlsConfig,
|
|
TLSHandshakeTimeout: 10 * time.Second,
|
|
}
|
|
return &client
|
|
}
|
|
|
|
// Loads agent's configuration from the file and populates the corresponding
|
|
// in memory structure.
|
|
func LoadSSHAgentConfig(path string) (*SSHAgentConfig, error) {
|
|
var config SSHAgentConfig
|
|
contents, err := ioutil.ReadFile(path)
|
|
if !os.IsNotExist(err) {
|
|
obj, err := hcl.Parse(string(contents))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := hcl.DecodeObject(&config, obj); err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
return nil, err
|
|
}
|
|
return &config, nil
|
|
}
|
|
|
|
// Creates an SSHAgent object which can talk to Vault server with SSH backend
|
|
// mounted at default path ("ssh").
|
|
func (c *Client) SSHAgent() *SSHAgent {
|
|
return c.SSHAgentWithMountPoint(SSHAgentDefaultMountPoint)
|
|
}
|
|
|
|
// Creates an SSHAgent object which can talk to Vault server with SSH backend
|
|
// mounted at a specific mount point.
|
|
func (c *Client) SSHAgentWithMountPoint(mountPoint string) *SSHAgent {
|
|
return &SSHAgent{
|
|
c: c,
|
|
MountPoint: mountPoint,
|
|
}
|
|
}
|
|
|
|
// Verifies if the key provided by user is present in Vault server. If yes,
|
|
// the response will contain the IP address and username associated with the
|
|
// key.
|
|
func (c *SSHAgent) Verify(otp string) (*SSHVerifyResponse, error) {
|
|
data := map[string]interface{}{
|
|
"otp": otp,
|
|
}
|
|
verifyPath := fmt.Sprintf("/v1/%s/verify", c.MountPoint)
|
|
r := c.c.NewRequest("PUT", verifyPath)
|
|
if err := r.SetJSONBody(data); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
resp, err := c.c.RawRequest(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
secret, err := ParseSecret(resp.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if secret.Data == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
var verifyResp SSHVerifyResponse
|
|
err = mapstructure.Decode(secret.Data, &verifyResp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &verifyResp, nil
|
|
}
|