2021-08-10 20:22:40 +00:00
|
|
|
package k8s
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
admissionv1 "k8s.io/api/admissionregistration/v1"
|
|
|
|
v1 "k8s.io/api/core/v1"
|
|
|
|
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/client-go/kubernetes"
|
|
|
|
)
|
|
|
|
|
|
|
|
type k8s struct {
|
|
|
|
clientset kubernetes.Interface
|
|
|
|
}
|
|
|
|
|
2021-09-16 20:59:26 +00:00
|
|
|
func New(clientset kubernetes.Interface) *k8s {
|
|
|
|
if clientset == nil {
|
|
|
|
log.Fatal("no kubernetes client given")
|
2021-08-10 20:22:40 +00:00
|
|
|
}
|
|
|
|
|
2021-09-16 20:59:26 +00:00
|
|
|
return &k8s{
|
|
|
|
clientset: clientset,
|
2021-08-10 20:22:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// PatchWebhookConfigurations will patch validatingWebhook and mutatingWebhook clientConfig configurations with
|
|
|
|
// the provided ca data. If failurePolicy is provided, patch all webhooks with this value
|
|
|
|
func (k8s *k8s) PatchWebhookConfigurations(
|
2021-09-16 20:59:26 +00:00
|
|
|
configurationName string,
|
|
|
|
ca []byte,
|
2021-08-10 20:22:40 +00:00
|
|
|
failurePolicy *admissionv1.FailurePolicyType,
|
2021-09-16 20:59:26 +00:00
|
|
|
patchMutating bool,
|
|
|
|
patchValidating bool,
|
|
|
|
) {
|
|
|
|
log.Infof("patching webhook configurations '%s' mutating=%t, validating=%t, failurePolicy=%s", configurationName, patchMutating, patchValidating, *failurePolicy)
|
2021-08-10 20:22:40 +00:00
|
|
|
|
|
|
|
if patchValidating {
|
2021-09-16 20:59:26 +00:00
|
|
|
k8s.patchValidating(configurationName, ca, failurePolicy)
|
2021-08-10 20:22:40 +00:00
|
|
|
} else {
|
|
|
|
log.Debug("validating hook patching not required")
|
|
|
|
}
|
|
|
|
|
|
|
|
if patchMutating {
|
2021-09-16 20:59:26 +00:00
|
|
|
k8s.patchMutating(configurationName, ca, failurePolicy)
|
|
|
|
} else {
|
|
|
|
log.Debug("mutating hook patching not required")
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Info("Patched hook(s)")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k8s *k8s) patchValidating(configurationName string, ca []byte, failurePolicy *admissionv1.FailurePolicyType) {
|
|
|
|
valHook, err := k8s.clientset.
|
|
|
|
AdmissionregistrationV1().
|
|
|
|
ValidatingWebhookConfigurations().
|
|
|
|
Get(context.TODO(), configurationName, metav1.GetOptions{})
|
|
|
|
if err != nil {
|
|
|
|
log.WithField("err", err).Fatal("failed getting validating webhook")
|
|
|
|
}
|
2021-08-10 20:22:40 +00:00
|
|
|
|
2021-09-16 20:59:26 +00:00
|
|
|
for i := range valHook.Webhooks {
|
|
|
|
h := &valHook.Webhooks[i]
|
|
|
|
h.ClientConfig.CABundle = ca
|
|
|
|
if *failurePolicy != "" {
|
|
|
|
h.FailurePolicy = failurePolicy
|
2021-08-10 20:22:40 +00:00
|
|
|
}
|
2021-09-16 20:59:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if _, err = k8s.clientset.AdmissionregistrationV1().
|
|
|
|
ValidatingWebhookConfigurations().
|
|
|
|
Update(context.TODO(), valHook, metav1.UpdateOptions{}); err != nil {
|
|
|
|
log.WithField("err", err).Fatal("failed patching validating webhook")
|
|
|
|
}
|
|
|
|
log.Debug("patched validating hook")
|
|
|
|
}
|
2021-08-10 20:22:40 +00:00
|
|
|
|
2021-09-16 20:59:26 +00:00
|
|
|
func (k8s *k8s) patchMutating(configurationName string, ca []byte, failurePolicy *admissionv1.FailurePolicyType) {
|
|
|
|
mutHook, err := k8s.clientset.
|
|
|
|
AdmissionregistrationV1().
|
|
|
|
MutatingWebhookConfigurations().
|
|
|
|
Get(context.TODO(), configurationName, metav1.GetOptions{})
|
|
|
|
if err != nil {
|
|
|
|
log.WithField("err", err).Fatal("failed getting mutating webhook")
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := range mutHook.Webhooks {
|
|
|
|
h := &mutHook.Webhooks[i]
|
|
|
|
h.ClientConfig.CABundle = ca
|
|
|
|
if *failurePolicy != "" {
|
|
|
|
h.FailurePolicy = failurePolicy
|
2021-08-10 20:22:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-16 20:59:26 +00:00
|
|
|
if _, err = k8s.clientset.AdmissionregistrationV1().
|
|
|
|
MutatingWebhookConfigurations().
|
|
|
|
Update(context.TODO(), mutHook, metav1.UpdateOptions{}); err != nil {
|
|
|
|
log.WithField("err", err).Fatal("failed patching mutating webhook")
|
|
|
|
}
|
|
|
|
log.Debug("patched mutating hook")
|
2021-08-10 20:22:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetCaFromSecret will check for the presence of a secret. If it exists, will return the content of the
|
|
|
|
// "ca" from the secret, otherwise will return nil
|
|
|
|
func (k8s *k8s) GetCaFromSecret(secretName string, namespace string) []byte {
|
|
|
|
log.Debugf("getting secret '%s' in namespace '%s'", secretName, namespace)
|
|
|
|
secret, err := k8s.clientset.CoreV1().Secrets(namespace).Get(context.TODO(), secretName, metav1.GetOptions{})
|
|
|
|
if err != nil {
|
|
|
|
if k8serrors.IsNotFound(err) {
|
|
|
|
log.WithField("err", err).Info("no secret found")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
log.WithField("err", err).Fatal("error getting secret")
|
|
|
|
}
|
|
|
|
|
|
|
|
data := secret.Data["ca"]
|
|
|
|
if data == nil {
|
|
|
|
log.Fatal("got secret, but it did not contain a 'ca' key")
|
|
|
|
}
|
|
|
|
log.Debug("got secret")
|
|
|
|
return data
|
|
|
|
}
|
|
|
|
|
|
|
|
// SaveCertsToSecret saves the provided ca, cert and key into a secret in the specified namespace.
|
|
|
|
func (k8s *k8s) SaveCertsToSecret(secretName, namespace, certName, keyName string, ca, cert, key []byte) {
|
|
|
|
log.Debugf("saving to secret '%s' in namespace '%s'", secretName, namespace)
|
|
|
|
secret := &v1.Secret{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: secretName,
|
|
|
|
},
|
|
|
|
Data: map[string][]byte{"ca": ca, certName: cert, keyName: key},
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Debug("saving secret")
|
|
|
|
_, err := k8s.clientset.CoreV1().Secrets(namespace).Create(context.TODO(), secret, metav1.CreateOptions{})
|
|
|
|
if err != nil {
|
|
|
|
log.WithField("err", err).Fatal("failed creating secret")
|
|
|
|
}
|
|
|
|
log.Debug("saved secret")
|
|
|
|
}
|