open-vault/serviceregistration/kubernetes/client/config.go
2020-02-13 09:56:29 -08:00

99 lines
3.6 KiB
Go

package client
import (
"bytes"
"crypto/x509"
"io/ioutil"
"net"
"os"
"github.com/hashicorp/vault/sdk/helper/certutil"
)
const (
// These environment variables aren't set by default.
// Vault may read them in if set through these environment variables.
// Example here:
// https://kubernetes.io/docs/tasks/inject-data-application/environment-variable-expose-pod-information/
// The client itself does nothing directly with these variables, it's
// up to the caller. However, they live here so they'll be consistently
// named should the client ever be reused.
// We generally recommend preferring environmental settings over configured
// ones, allowing settings from the Downward API to override hard-coded
// ones.
EnvVarKubernetesNamespace = "VAULT_K8S_NAMESPACE"
EnvVarKubernetesPodName = "VAULT_K8S_POD_NAME"
// The service host and port environment variables are
// set by default inside a Kubernetes environment.
EnvVarKubernetesServiceHost = "KUBERNETES_SERVICE_HOST"
EnvVarKubernetesServicePort = "KUBERNETES_SERVICE_PORT"
)
var (
// These are presented as variables so they can be updated
// to point at test fixtures if needed. They aren't passed
// into inClusterConfig to avoid dependency injection.
Scheme = "https://"
TokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token"
RootCAFile = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
)
// inClusterConfig returns a config object which uses the service account
// kubernetes gives to services. It's intended for clients that expect to be
// running inside a service running on kubernetes. It will return ErrNotInCluster
// if called from a process not running in a kubernetes environment.
// inClusterConfig is based on this:
// https://github.com/kubernetes/client-go/blob/a56922badea0f2a91771411eaa1173c9e9243908/rest/config.go#L451
func inClusterConfig() (*Config, error) {
host, port := os.Getenv(EnvVarKubernetesServiceHost), os.Getenv(EnvVarKubernetesServicePort)
if len(host) == 0 || len(port) == 0 {
return nil, ErrNotInCluster
}
token, err := ioutil.ReadFile(TokenFile)
if err != nil {
return nil, err
}
caBytes, err := ioutil.ReadFile(RootCAFile)
if err != nil {
return nil, err
}
pool, err := certutil.NewCertPool(bytes.NewReader(caBytes))
if err != nil {
return nil, err
}
return &Config{
Host: Scheme + net.JoinHostPort(host, port),
CACertPool: pool,
BearerToken: string(token),
BearerTokenFile: TokenFile,
}, nil
}
// This config is based on the one returned here:
// https://github.com/kubernetes/client-go/blob/a56922badea0f2a91771411eaa1173c9e9243908/rest/config.go#L451
// It is pared down to the absolute minimum fields used by this code.
// The CACertPool is promoted to the top level from being originally on the TLSClientConfig
// because it is the only parameter of the TLSClientConfig used by this code.
// Also, it made more sense to simply reuse the pool rather than holding raw values
// and parsing it repeatedly.
type Config struct {
CACertPool *x509.CertPool
// Host must be a host string, a host:port pair, or a URL to the base of the apiserver.
// If a URL is given then the (optional) Path of that URL represents a prefix that must
// be appended to all request URIs used to access the apiserver. This allows a frontend
// proxy to easily relocate all of the apiserver endpoints.
Host string
// Server requires Bearer authentication. This client will not attempt to use
// refresh tokens for an OAuth2 flow.
BearerToken string
// Path to a file containing a BearerToken.
// If set, checks for a new token in the case of authorization errors.
BearerTokenFile string
}