pomerium/internal/zero/bootstrap/writers/k8s/rest/config.go
Joe Kralicky de603f87de
Add new configurable bootstrap writers (#2405) (#5114)
* Add new configurable bootstrap writers (#2405)

This PR adds the ability to configure different backends to use for
storing modifications to the zero bootstrap config. The two currently
implemented backends allow writing changes to a file or to a Kubernetes
secret. Backend selection is determined by the scheme in a URI passed to
the flag '--config-writeback-uri'.

In a Kubernetes environment, where the bootstrap config is mounted into
the pod from a secret, this option allows Pomerium to write changes back
to the secret, as writes to the mounted secret file on disk are not
persisted.

* Use env vars for bootstrap config filepath/writeback uri

* linter pass and code cleanup

* Add new config writer options mechanism

This moves the encryption cipher parameter out of the WriteConfig()
method in the ConfigWriter interface and into a new ConfigWriterOptions
struct. Options (e.g. cipher) can be applied to an existing ConfigWriter
to allow customizing implementation-specific behavior.

* Code cleanup/lint fixes

* Move vendored k8s code into separate package, and add license header and package comment
2024-05-31 12:26:17 -04:00

86 lines
2.9 KiB
Go

/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// This package contains some of the in-cluster configuration logic from [config.go]
// to avoid a dependency on k8s.io/client-go. Only code used in Pomerium is
// included, and some usages of helper functions/types have been refactored out.
//
// [config.go]: https://github.com/kubernetes/client-go/blob/d11d5308d688d65723cb1bfcaeb7703b95debc5a/rest/config.go
package rest
import (
"crypto/tls"
"crypto/x509"
"errors"
"net"
"os"
)
var ErrNotInCluster = errors.New("unable to load in-cluster configuration, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined")
// Config holds the common attributes that can be passed to a Kubernetes client on
// initialization.
type Config struct {
// 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
// TLSClientConfig contains settings to enable transport layer security
TLSClientConfig *tls.Config
// Server requires Bearer authentication. This client will not attempt to use
// refresh tokens for an OAuth2 flow.
BearerToken string
}
// InClusterConfig returns a config object which uses the service account
// kubernetes gives to pods. It's intended for clients that expect to be
// running inside a pod running on kubernetes. It will return ErrNotInCluster
// if called from a process not running in a kubernetes environment.
func InClusterConfig() (*Config, error) {
var (
tokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token" //nolint:gosec
rootCAFile = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
)
host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")
if len(host) == 0 || len(port) == 0 {
return nil, ErrNotInCluster
}
token, err := os.ReadFile(tokenFile)
if err != nil {
return nil, err
}
tlsClientConfig := &tls.Config{
MinVersion: tls.VersionTLS12,
}
cacert, err := os.ReadFile(rootCAFile)
if err != nil {
return nil, err
}
pool := x509.NewCertPool()
pool.AppendCertsFromPEM(cacert)
tlsClientConfig.RootCAs = pool
return &Config{
Host: "https://" + net.JoinHostPort(host, port),
TLSClientConfig: tlsClientConfig,
BearerToken: string(token),
}, nil
}