func NewInsecureRawClient() (*vaultapi.Client, error) {
	config := vaultapi.DefaultConfig()
	if config.Error != nil {
		return nil, config.Error
	}
	config.HttpClient.Transport.(*http.Transport).TLSHandshakeTimeout = 5 * time.Second
	config.HttpClient.Transport.(*http.Transport).TLSClientConfig.InsecureSkipVerify = true
	return vaultapi.NewClient(config)
}
NewInsecureRawClient creates a new raw Vault client with insecure TLS.
package vault
import (
	"context"
	"crypto/sha256"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"
	"cloud.google.com/go/compute/metadata"
	credentials "cloud.google.com/go/iam/credentials/apiv1"
	"emperror.dev/errors"
	"github.com/fsnotify/fsnotify"
	vaultapi "github.com/hashicorp/vault/api"
	"github.com/leosayous21/go-azure-msi/msi"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/iam/v1"
	credentialspb "google.golang.org/genproto/googleapis/iam/credentials/v1"
)
const (
	awsEC2PKCS7Url = "http://169.254.169.254/latest/dynamic/instance-identity/pkcs7"
	defaultJWTFile = "/var/run/secrets/kubernetes.io/serviceaccount/token"
)
func NewData(cas int, data map[string]interface{}) map[string]interface{} {
	return map[string]interface{}{
		"options": map[string]interface{}{"cas": cas},
		"data":    data,
	}
}
type clientOptions struct {
	url            string
	role           string
	authPath       string
	tokenPath      string
	token          string
	timeout        time.Duration
	logger         Logger
	authMethod     ClientAuthMethod
	existingSecret string
	vaultNamespace string
}
type ClientOption interface {
	apply(o *clientOptions)
}
type ClientURL string
func (co ClientURL) apply(o *clientOptions) {
	o.url = string(co)
}
type ClientRole string
func (co ClientRole) apply(o *clientOptions) {
	o.role = string(co)
}
type ClientAuthPath string
func (co ClientAuthPath) apply(o *clientOptions) {
	o.authPath = string(co)
}
type ClientTokenPath string
func (co ClientTokenPath) apply(o *clientOptions) {
	o.tokenPath = string(co)
}
type ClientToken string
func (co ClientToken) apply(o *clientOptions) {
	o.token = string(co)
}
type ClientTimeout time.Duration
func (co ClientTimeout) apply(o *clientOptions) {
	o.timeout = time.Duration(co)
}
func ClientLogger(logger Logger) clientLogger {  
	return clientLogger{logger: logger}
}
type clientLogger struct {
	logger Logger
}
func (co clientLogger) apply(o *clientOptions) {
	o.logger = co.logger
}
type ClientAuthMethod string
func (co ClientAuthMethod) apply(o *clientOptions) {
	o.authMethod = co
}
type ExistingSecret string
func (co ExistingSecret) apply(o *clientOptions) {
	o.existingSecret = string(co)
}
type VaultNamespace string
func (co VaultNamespace) apply(o *clientOptions) {
	o.vaultNamespace = string(co)
}
const (
	AWSEC2AuthMethod ClientAuthMethod = "aws-ec2"
	GCPGCEAuthMethod ClientAuthMethod = "gcp-gce"
	GCPIAMAuthMethod ClientAuthMethod = "gcp-iam"
	JWTAuthMethod ClientAuthMethod = "jwt"
	AzureMSIAuthMethod ClientAuthMethod = "azure"
	NamespacedSecretAuthMethod ClientAuthMethod = "namespaced"
)
type Client struct {
	Transit *Transit
	client       *vaultapi.Client
	logical      *vaultapi.Logical
	tokenWatcher *vaultapi.Renewer
	closed       bool
	watch        *fsnotify.Watcher
	mu           sync.Mutex
	logger       Logger
}
func NewClient(role string) (*Client, error) {
	return NewClientWithOptions(ClientRole(role))
}
func NewClientWithOptions(opts ...ClientOption) (*Client, error) {
	config := vaultapi.DefaultConfig()
	if config.Error != nil {
		return nil, config.Error
	}
	return NewClientFromConfig(config, opts...)
}
func NewClientWithConfig(config *vaultapi.Config, role, path string) (*Client, error) {
	return NewClientFromConfig(config, ClientRole(role), ClientAuthPath(path))
}
func NewClientFromConfig(config *vaultapi.Config, opts ...ClientOption) (*Client, error) {
	rawClient, err := vaultapi.NewClient(config)
	if err != nil {
		return nil, err
	}
	client, err := NewClientFromRawClient(rawClient, opts...)
	if err != nil {
		return nil, err
	}
	caCertPath := os.Getenv(vaultapi.EnvVaultCACert)
	caCertReload := os.Getenv("VAULT_CACERT_RELOAD") != "false"
	if caCertPath != "" && caCertReload {
		watch, err := fsnotify.NewWatcher()
		if err != nil {
			return nil, err
		}
		caCertFile := filepath.Clean(caCertPath)
		configDir, _ := filepath.Split(caCertFile)
		_ = watch.Add(configDir)
		go func() {
			for {
				client.mu.Lock()
				if client.closed {
					client.mu.Unlock()
					break
				}
				client.mu.Unlock()
				select {
				case event := <-watch.Events:
					if filepath.Clean(event.Name) == caCertFile || filepath.Base(event.Name) == "..data" {
						if event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create {
							err := config.ReadEnvironment()
							if err != nil {
								client.logger.Error("failed to reload Vault config", map[string]interface{}{"err": err})
							} else {
								client.logger.Info("CA certificate reloaded")
							}
						}
					}
				case err := <-watch.Errors:
					client.logger.Error("watcher error", map[string]interface{}{"err": err})
				}
			}
		}()
		client.watch = watch
	}
	return client, nil
}
func NewClientFromRawClient(rawClient *vaultapi.Client, opts ...ClientOption) (*Client, error) {
	logical := rawClient.Logical()
	transit := &Transit{
		client: rawClient,
	}
	client := &Client{
		Transit: transit,
		client:  rawClient,
		logical: logical,
		logger:  noopLogger{},
	}
	var tokenWatcher *vaultapi.Renewer
	o := &clientOptions{}
	for _, opt := range opts {
		opt.apply(o)
	}
	if o.logger != nil {
		client.logger = o.logger
	}
	if o.url != "" {
		err := rawClient.SetAddress(o.url)
		if err != nil {
			return nil, err
		}
	}
	if o.role == "" {
		o.role = "default"
	}
	if o.authPath == "" {
		o.authPath = "kubernetes"
	}
	if o.authMethod == "" {
		o.authMethod = JWTAuthMethod
	}
	if o.tokenPath == "" {
		o.tokenPath = os.Getenv("HOME") + "/.vault-token"
		if env, ok := os.LookupEnv("VAULT_TOKEN_PATH"); ok {
			o.tokenPath = env
		}
	}
	if o.vaultNamespace != "" {
		rawClient.SetNamespace(o.vaultNamespace)
	}
	if o.timeout == 0 {
		o.timeout = 10 * time.Second
		if env, ok := os.LookupEnv("VAULT_CLIENT_TIMEOUT"); ok {
			var err error
			if o.timeout, err = time.ParseDuration(env); err != nil {
				return nil, errors.Wrap(err, "could not parse timeout duration")
			}
		}
	}
	if o.token != "" {
		rawClient.SetToken(o.token)
	} else if rawClient.Token() == "" {
		token, err := ioutil.ReadFile(o.tokenPath)
		if err == nil {
			rawClient.SetToken(string(token))
		} else {
			jwtFile := defaultJWTFile
			if file := os.Getenv("KUBERNETES_SERVICE_ACCOUNT_TOKEN"); file != "" {
				jwtFile = file
			} else if file := os.Getenv("VAULT_JWT_FILE"); file != "" {
				jwtFile = file
			}
			var loginDataFunc func() (map[string]interface{}, error)
			switch o.authMethod {  
			case AWSEC2AuthMethod:
				loginDataFunc = func() (map[string]interface{}, error) {
					resp, err := http.Get(awsEC2PKCS7Url)  
					if err != nil {
						return nil, err
					}
					defer resp.Body.Close()
					if resp.StatusCode != http.StatusOK {
						return nil, errors.Errorf("failed to get EC2 instance metadata: %s", resp.Status)
					}
					pkcs7Data, err := ioutil.ReadAll(resp.Body)
					if err != nil {
						return nil, err
					}
					pkcs7 := strings.ReplaceAll(string(pkcs7Data), "\n", "")
					jwt, err := ioutil.ReadFile(jwtFile)
					if err != nil {
						return nil, err
					}
					nonce := fmt.Sprintf("%x", sha256.Sum256(jwt))
					return map[string]interface{}{
						"pkcs7": pkcs7,
						"nonce": nonce,
						"role":  o.role,
					}, nil
				}
			case GCPGCEAuthMethod:
				loginDataFunc = func() (map[string]interface{}, error) {
					tokenSource, err := google.DefaultTokenSource(context.TODO(), iam.CloudPlatformScope)
					if err != nil {
						return nil, err
					}
					jwt, err := tokenSource.Token()
					if err != nil {
						return nil, err
					}
					return map[string]interface{}{
						"jwt":  jwt,
						"role": o.role,
					}, nil
				}
			case GCPIAMAuthMethod:
				loginDataFunc = func() (map[string]interface{}, error) {
					c, err := credentials.NewIamCredentialsClient(context.TODO())
					if err != nil {
						return nil, err
					}
					metadataClient := metadata.NewClient(nil)
					serviceAccountEmail, err := metadataClient.Email("default")
					if err != nil {
						return nil, err
					}
					jwtPayload := map[string]interface{}{
						"aud": fmt.Sprintf("vault/%s", o.role),
						"sub": serviceAccountEmail,
						"exp": time.Now().Add(time.Minute * 10).Unix(),
					}
					payloadBytes, err := json.Marshal(jwtPayload)
					if err != nil {
						return nil, err
					}
					req := &credentialspb.SignJwtRequest{
						Name:    fmt.Sprintf("projects/-/serviceAccounts/%s", serviceAccountEmail),
						Payload: string(payloadBytes),
					}
					resp, err := c.SignJwt(context.TODO(), req)
					if err != nil {
						return nil, err
					}
					return map[string]interface{}{
						"jwt":  resp.SignedJwt,
						"role": o.role,
					}, nil
				}
			case AzureMSIAuthMethod:
				loginDataFunc = func() (map[string]interface{}, error) {
					metadata, err := msi.GetInstanceMetadata()
					if err != nil {
						return nil, err
					}
					token, err := msi.GetMsiToken()
					if err != nil {
						return nil, err
					}
					return map[string]interface{}{
						"role":                o.role,
						"jwt":                 token.AccessToken,
						"subscription_id":     metadata.SubscriptionId,
						"resource_group_name": metadata.ResourceGroupName,
						"vm_name":             metadata.VMName,
						"vmss_name":           metadata.VMssName,
					}, nil
				}
			case NamespacedSecretAuthMethod:
				loginDataFunc = func() (map[string]interface{}, error) {
					if len(o.existingSecret) > 0 {
						return map[string]interface{}{
							"jwt":  o.existingSecret,
							"role": o.role,
						}, nil
					}
					jwt, err := ioutil.ReadFile(jwtFile)
					if err != nil {
						return nil, err
					}
					return map[string]interface{}{
						"jwt":  string(jwt),
						"role": o.role,
					}, nil
				}
			default:
				loginDataFunc = func() (map[string]interface{}, error) {
					jwt, err := ioutil.ReadFile(jwtFile)
					if err != nil {
						return nil, err
					}
					return map[string]interface{}{
						"jwt":  string(jwt),
						"role": o.role,
					}, nil
				}
			}
			initialTokenArrived := make(chan string, 1)
			initialTokenSent := false
			go func() {
				for {
					client.mu.Lock()
					if client.closed {
						client.mu.Unlock()
						break
					}
					client.mu.Unlock()
					loginData, err := loginDataFunc()
					if err != nil {
						client.logger.Error("failed to read login data", map[string]interface{}{
							"err":  err,
							"type": o.authMethod,
						})
						continue
					}
					secret, err := logical.Write(fmt.Sprintf("auth/%s/login", o.authPath), loginData)
					if err != nil {
						client.logger.Error("failed to request new Vault token", map[string]interface{}{"err": err})
						time.Sleep(1 * time.Second)
						continue
					}
					if secret == nil {
						client.logger.Debug("received empty answer from Vault, retrying")
						time.Sleep(1 * time.Second)
						continue
					}
					client.logger.Info("received new Vault token", map[string]interface{}{
						"addr": o.url,
						"role": o.role,
						"path": o.authPath,
					})
					rawClient.SetToken(secret.Auth.ClientToken)
					if !initialTokenSent {
						initialTokenArrived <- secret.LeaseID
						initialTokenSent = true
					}
					tokenWatcher, err = rawClient.NewLifetimeWatcher(&vaultapi.LifetimeWatcherInput{Secret: secret})
					if err != nil {
						client.logger.Error("failed to watch Vault token", map[string]interface{}{"err": err})
						continue
					}
					client.mu.Lock()
					client.tokenWatcher = tokenWatcher
					client.mu.Unlock()
					go tokenWatcher.Start()
					client.runRenewChecker(tokenWatcher)
				}
				client.logger.Info("Vault token renewal closed")
			}()
			select {
			case <-initialTokenArrived:
				client.logger.Info("initial Vault token arrived")
			case <-time.After(o.timeout):
				client.Close()
				return nil, errors.Errorf("timeout [%s] during waiting for Vault token", o.timeout)
			}
		}
	}
	return client, nil
}
func (client *Client) runRenewChecker(tokenWatcher *vaultapi.Renewer) {
	for {
		select {
		case err := <-tokenWatcher.DoneCh():
			if err != nil {
				client.logger.Error("error in Vault token renewal", map[string]interface{}{"err": err})
			}
			return
		case o := <-tokenWatcher.RenewCh():
			ttl, _ := o.Secret.TokenTTL()
			client.logger.Info("renewed Vault token", map[string]interface{}{"ttl": ttl})
		}
	}
}
func (client *Client) Vault() *vaultapi.Client {
	return client.RawClient()
}
func (client *Client) RawClient() *vaultapi.Client {
	return client.client
}
func (client *Client) Close() {
	client.mu.Lock()
	defer client.mu.Unlock()
	client.closed = true
	if client.tokenWatcher != nil {
		client.tokenWatcher.Stop()
	}
	if client.watch != nil {
		_ = client.watch.Close()
	}
}
func NewRawClient() (*vaultapi.Client, error) {
	config := vaultapi.DefaultConfig()
	if config.Error != nil {
		return nil, config.Error
	}
	config.HttpClient.Transport.(*http.Transport).TLSHandshakeTimeout = 5 * time.Second
	return vaultapi.NewClient(config)
}