1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

refactor: use typed k8s client in tls package (#3678)

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
This commit is contained in:
Charles-Edouard Brétéché 2022-04-26 22:18:14 +02:00 committed by GitHub
parent c97af0094f
commit a6924a11ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 138 additions and 173 deletions

View file

@ -20,7 +20,7 @@ import (
"github.com/kyverno/kyverno/pkg/utils"
coord "k8s.io/api/coordination/v1"
"k8s.io/apimachinery/pkg/api/errors"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/klog/v2"
"k8s.io/klog/v2/klogr"
@ -33,11 +33,11 @@ var (
clientRateLimitQPS float64
clientRateLimitBurst int
updateLabelSelector = &v1.LabelSelector{
MatchExpressions: []v1.LabelSelectorRequirement{
updateLabelSelector = &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: policyreport.LabelSelectorKey,
Operator: v1.LabelSelectorOpDoesNotExist,
Operator: metav1.LabelSelectorOpDoesNotExist,
Values: []string{},
},
},
@ -83,8 +83,14 @@ func main() {
os.Exit(1)
}
kubeClient, err := utils.NewKubeClient(clientConfig)
if err != nil {
setupLog.Error(err, "Failed to create kubernetes client")
os.Exit(1)
}
// Exit for unsupported version of kubernetes cluster
if !utils.HigherThanKubernetesVersion(client, log.Log, 1, 16, 0) {
if !utils.HigherThanKubernetesVersion(kubeClient.Discovery(), log.Log, 1, 16, 0) {
os.Exit(1)
}
@ -100,12 +106,6 @@ func main() {
{clusterPolicyViolation, ""},
}
kubeClientLeaderElection, err := utils.NewKubeClient(clientConfig)
if err != nil {
setupLog.Error(err, "Failed to create kubernetes client")
os.Exit(1)
}
ctx, cancel := context.WithCancel(context.Background())
go func() {
@ -127,7 +127,7 @@ func main() {
os.Exit(1)
}
depl, err := client.GetResource("", "Deployment", config.KyvernoNamespace, config.KyvernoDeploymentName)
depl, err := kubeClient.AppsV1().Deployments(config.KyvernoNamespace).Get(context.TODO(), config.KyvernoDeploymentName, metav1.GetOptions{})
deplHash := ""
if err != nil {
log.Log.Info("failed to fetch deployment '%v': %v", config.KyvernoDeploymentName, err.Error())
@ -136,16 +136,16 @@ func main() {
deplHash = fmt.Sprintf("%v", depl.GetUID())
name := tls.GenerateRootCASecretName(certProps)
secretUnstr, err := client.GetResource("", "Secret", config.KyvernoNamespace, name)
secret, err := kubeClient.CoreV1().Secrets(config.KyvernoNamespace).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
log.Log.Info("failed to fetch secret '%v': %v", name, err.Error())
if !errors.IsNotFound(err) {
os.Exit(1)
}
} else if tls.CanAddAnnotationToSecret(deplHash, secretUnstr) {
secretUnstr.SetAnnotations(map[string]string{tls.MasterDeploymentUID: deplHash})
_, err = client.UpdateResource("", "Secret", certProps.Namespace, secretUnstr, false)
} else if tls.CanAddAnnotationToSecret(deplHash, secret) {
secret.SetAnnotations(map[string]string{tls.MasterDeploymentUID: deplHash})
_, err = kubeClient.CoreV1().Secrets(config.KyvernoNamespace).Update(context.TODO(), secret, metav1.UpdateOptions{})
if err != nil {
log.Log.Info("failed to update cert: %v", err.Error())
os.Exit(1)
@ -153,23 +153,23 @@ func main() {
}
name = tls.GenerateTLSPairSecretName(certProps)
secretUnstr, err = client.GetResource("", "Secret", config.KyvernoNamespace, name)
secret, err = kubeClient.CoreV1().Secrets(config.KyvernoNamespace).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
log.Log.Info("failed to fetch secret '%v': %v", name, err.Error())
if !errors.IsNotFound(err) {
os.Exit(1)
}
} else if tls.CanAddAnnotationToSecret(deplHash, secretUnstr) {
secretUnstr.SetAnnotations(map[string]string{tls.MasterDeploymentUID: deplHash})
_, err = client.UpdateResource("", "Secret", certProps.Namespace, secretUnstr, false)
} else if tls.CanAddAnnotationToSecret(deplHash, secret) {
secret.SetAnnotations(map[string]string{tls.MasterDeploymentUID: deplHash})
_, err = kubeClient.CoreV1().Secrets(certProps.Namespace).Update(context.TODO(), secret, metav1.UpdateOptions{})
if err != nil {
log.Log.Info("failed to update cert: %v", err.Error())
os.Exit(1)
}
}
_, err = kubeClientLeaderElection.CoordinationV1().Leases(config.KyvernoNamespace).Get(ctx, "kyvernopre-lock", v1.GetOptions{})
_, err = kubeClient.CoordinationV1().Leases(config.KyvernoNamespace).Get(ctx, "kyvernopre-lock", metav1.GetOptions{})
if err != nil {
log.Log.Info("Lease 'kyvernopre-lock' not found. Starting clean-up...")
} else {
@ -198,11 +198,11 @@ func main() {
}
lease := coord.Lease{
ObjectMeta: v1.ObjectMeta{
ObjectMeta: metav1.ObjectMeta{
Name: "kyvernopre-lock",
},
}
_, err = kubeClientLeaderElection.CoordinationV1().Leases(config.KyvernoNamespace).Create(ctx, &lease, v1.CreateOptions{})
_, err = kubeClient.CoordinationV1().Leases(config.KyvernoNamespace).Create(ctx, &lease, metav1.CreateOptions{})
if err != nil {
log.Log.Info("Failed to create lease 'kyvernopre-lock'")
}
@ -212,7 +212,7 @@ func main() {
os.Exit(0)
}
le, err := leaderelection.New("kyvernopre", config.KyvernoNamespace, kubeClientLeaderElection, run, nil, log.Log.WithName("kyvernopre/LeaderElection"))
le, err := leaderelection.New("kyvernopre", config.KyvernoNamespace, kubeClient, run, nil, log.Log.WithName("kyvernopre/LeaderElection"))
if err != nil {
setupLog.Error(err, "failed to elect a leader")
os.Exit(1)
@ -344,7 +344,7 @@ func removeClusterPolicyReport(client *client.Client, kind string) error {
func removePolicyReport(client *client.Client, kind string) error {
logger := log.Log.WithName("removePolicyReport")
polrs, err := client.ListResource("", kind, v1.NamespaceAll, policyreport.LabelSelector)
polrs, err := client.ListResource("", kind, metav1.NamespaceAll, policyreport.LabelSelector)
if err != nil {
logger.Error(err, "failed to list policyReport")
return nil
@ -376,7 +376,7 @@ func addClusterPolicyReportSelectorLabel(client *client.Client) {
func addPolicyReportSelectorLabel(client *client.Client) {
logger := log.Log.WithName("addPolicyReportSelectorLabel")
polrs, err := client.ListResource("", policyReportKind, v1.NamespaceAll, updateLabelSelector)
polrs, err := client.ListResource("", policyReportKind, metav1.NamespaceAll, updateLabelSelector)
if err != nil {
logger.Error(err, "failed to list policyReport")
return
@ -451,7 +451,7 @@ func addSelectorLabel(client *client.Client, apiversion, kind, ns, name string)
return
}
l, err := v1.LabelSelectorAsMap(policyreport.LabelSelector)
l, err := metav1.LabelSelectorAsMap(policyreport.LabelSelector)
if err != nil {
log.Log.Error(err, "failed to convert labels", "labels", policyreport.LabelSelector)
return

View file

@ -218,6 +218,7 @@ func main() {
webhookCfg := webhookconfig.NewRegister(
clientConfig,
client,
kubeClient,
pclient,
kubeInformer.Admissionregistration().V1().MutatingWebhookConfigurations(),
kubeInformer.Admissionregistration().V1().ValidatingWebhookConfigurations(),
@ -368,7 +369,7 @@ func main() {
promConfig,
)
certRenewer := ktls.NewCertRenewer(client, clientConfig, ktls.CertRenewalInterval, ktls.CertValidityDuration, serverIP, log.Log.WithName("CertRenewer"))
certRenewer := ktls.NewCertRenewer(kubeClient, clientConfig, ktls.CertRenewalInterval, ktls.CertValidityDuration, serverIP, log.Log.WithName("CertRenewer"))
certManager, err := webhookconfig.NewCertManager(
kubeKyvernoInformer.Core().V1().Secrets(),
kubeClient,

View file

@ -1,9 +1,9 @@
package tls
import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"time"
@ -11,12 +11,12 @@ import (
"github.com/cenkalti/backoff"
"github.com/go-logr/logr"
"github.com/kyverno/kyverno/pkg/config"
client "github.com/kyverno/kyverno/pkg/dclient"
"github.com/pkg/errors"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
k8errors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
@ -34,7 +34,7 @@ const (
// webhook configurations and webhook server
// renews RootCA at the given interval
type CertRenewer struct {
client *client.Client
client kubernetes.Interface
clientConfig *rest.Config
certRenewalInterval time.Duration
certValidityDuration time.Duration
@ -46,7 +46,7 @@ type CertRenewer struct {
}
// NewCertRenewer returns an instance of CertRenewer
func NewCertRenewer(client *client.Client, clientConfig *rest.Config, certRenewalInterval, certValidityDuration time.Duration, serverIP string, log logr.Logger) *CertRenewer {
func NewCertRenewer(client kubernetes.Interface, clientConfig *rest.Config, certRenewalInterval, certValidityDuration time.Duration, serverIP string, log logr.Logger) *CertRenewer {
return &CertRenewer{
client: client,
clientConfig: clientConfig,
@ -57,7 +57,7 @@ func NewCertRenewer(client *client.Client, clientConfig *rest.Config, certRenewa
}
}
func (c *CertRenewer) Client() *client.Client {
func (c *CertRenewer) Client() kubernetes.Interface {
return c.client
}
@ -119,65 +119,62 @@ func (c *CertRenewer) WriteCACertToSecret(caPEM *PemPair, props CertificateProps
logger := c.log.WithName("CAcert")
name := GenerateRootCASecretName(props)
depl, err := c.client.GetResource("", "Deployment", props.Namespace, config.KyvernoDeploymentName)
depl, err := c.client.AppsV1().Deployments(props.Namespace).Get(context.TODO(), config.KyvernoDeploymentName, metav1.GetOptions{})
deplHash := ""
if err == nil {
deplHash = fmt.Sprintf("%v", depl.GetUID())
}
secretUnstr, err := c.client.GetResource("", "Secret", props.Namespace, name)
secret := &v1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: props.Namespace,
Annotations: map[string]string{
SelfSignedAnnotation: "true",
MasterDeploymentUID: deplHash,
},
Labels: map[string]string{
ManagedByLabel: "kyverno",
},
},
Data: map[string][]byte{
RootCAKey: caPEM.Certificate,
},
Type: v1.SecretTypeOpaque,
}
secret, err := c.client.CoreV1().Secrets(props.Namespace).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
if k8errors.IsNotFound(err) {
_, err = c.client.CreateResource("", "Secret", props.Namespace, secret, false)
secret = &v1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: props.Namespace,
Annotations: map[string]string{
SelfSignedAnnotation: "true",
MasterDeploymentUID: deplHash,
},
Labels: map[string]string{
ManagedByLabel: "kyverno",
},
},
Data: map[string][]byte{
RootCAKey: caPEM.Certificate,
},
Type: v1.SecretTypeOpaque,
}
_, err = c.client.CoreV1().Secrets(props.Namespace).Create(context.TODO(), secret, metav1.CreateOptions{})
if err == nil {
logger.Info("secret created", "name", name, "namespace", props.Namespace)
}
}
return err
} else if CanAddAnnotationToSecret(deplHash, secretUnstr) {
_, err = c.client.UpdateResource("", "Secret", props.Namespace, secret, false)
} else if CanAddAnnotationToSecret(deplHash, secret) {
_, err = c.client.CoreV1().Secrets(props.Namespace).Update(context.TODO(), secret, metav1.UpdateOptions{})
if err == nil {
logger.Info("secret updated", "name", name, "namespace", props.Namespace)
}
return err
}
if _, ok := secretUnstr.GetAnnotations()[SelfSignedAnnotation]; !ok {
secretUnstr.SetAnnotations(map[string]string{SelfSignedAnnotation: "true"})
if _, ok := secret.GetAnnotations()[SelfSignedAnnotation]; !ok {
secret.SetAnnotations(map[string]string{SelfSignedAnnotation: "true"})
}
dataMap := map[string]interface{}{
RootCAKey: base64.StdEncoding.EncodeToString(caPEM.Certificate)}
if err = unstructured.SetNestedMap(secretUnstr.Object, dataMap, "data"); err != nil {
return err
dataMap := map[string][]byte{
RootCAKey: caPEM.Certificate,
}
_, err = c.client.UpdateResource("", "Secret", props.Namespace, secretUnstr, false)
secret.Data = dataMap
_, err = c.client.CoreV1().Secrets(props.Namespace).Update(context.TODO(), secret, metav1.UpdateOptions{})
if err != nil {
return err
}
@ -192,47 +189,46 @@ func (c *CertRenewer) WriteTLSPairToSecret(props CertificateProps, pemPair *PemP
name := GenerateTLSPairSecretName(props)
depl, err := c.client.GetResource("", "Deployment", props.Namespace, config.KyvernoDeploymentName)
depl, err := c.client.AppsV1().Deployments(props.Namespace).Get(context.TODO(), config.KyvernoDeploymentName, metav1.GetOptions{})
deplHash := ""
if err == nil {
deplHash = fmt.Sprintf("%v", depl.GetUID())
}
secretUnstr, err := c.client.GetResource("", "Secret", props.Namespace, name)
secretPtr := &v1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: props.Namespace,
Annotations: map[string]string{
MasterDeploymentUID: deplHash,
},
Labels: map[string]string{
ManagedByLabel: "kyverno",
},
},
Data: map[string][]byte{
v1.TLSCertKey: pemPair.Certificate,
v1.TLSPrivateKeyKey: pemPair.PrivateKey,
},
Type: v1.SecretTypeTLS,
}
secret, err := c.client.CoreV1().Secrets(props.Namespace).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
if k8errors.IsNotFound(err) {
_, err = c.client.CreateResource("", "Secret", props.Namespace, secretPtr, false)
secret = &v1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: props.Namespace,
Annotations: map[string]string{
MasterDeploymentUID: deplHash,
},
Labels: map[string]string{
ManagedByLabel: "kyverno",
},
},
Data: map[string][]byte{
v1.TLSCertKey: pemPair.Certificate,
v1.TLSPrivateKeyKey: pemPair.PrivateKey,
},
Type: v1.SecretTypeTLS,
}
_, err = c.client.CoreV1().Secrets(props.Namespace).Create(context.TODO(), secret, metav1.CreateOptions{})
if err == nil {
logger.Info("secret created", "name", name, "namespace", props.Namespace)
}
}
return err
} else if CanAddAnnotationToSecret(deplHash, secretUnstr) {
_, err = c.client.UpdateResource("", "Secret", props.Namespace, secretPtr, false)
} else if CanAddAnnotationToSecret(deplHash, secret) {
_, err = c.client.CoreV1().Secrets(props.Namespace).Update(context.TODO(), secret, metav1.UpdateOptions{})
if err == nil {
logger.Info("secret updated", "name", name, "namespace", props.Namespace)
}
@ -244,13 +240,9 @@ func (c *CertRenewer) WriteTLSPairToSecret(props CertificateProps, pemPair *PemP
v1.TLSPrivateKeyKey: pemPair.PrivateKey,
}
secret, err := convertToSecret(secretUnstr)
if err != nil {
return err
}
secret.Data = dataMap
_, err = c.client.UpdateResource("", "Secret", props.Namespace, secret, false)
_, err = c.client.CoreV1().Secrets(props.Namespace).Update(context.TODO(), secret, metav1.UpdateOptions{})
if err != nil {
return err
}
@ -263,35 +255,23 @@ func (c *CertRenewer) WriteTLSPairToSecret(props CertificateProps, pemPair *PemP
// It is used when the rootCA is renewed, the restart of
// Kyverno pod will register webhook server with new cert
func (c *CertRenewer) RollingUpdate() error {
update := func() error {
deploy, err := c.client.GetResource("", "Deployment", config.KyvernoNamespace, config.KyvernoDeploymentName)
deploy, err := c.client.AppsV1().Deployments(config.KyvernoNamespace).Get(context.TODO(), config.KyvernoDeploymentName, metav1.GetOptions{})
if err != nil {
return errors.Wrap(err, "failed to find Kyverno")
}
if IsKyvernoInRollingUpdate(deploy.UnstructuredContent(), c.log) {
if IsKyvernoInRollingUpdate(deploy, c.log) {
return nil
}
annotations, ok, err := unstructured.NestedStringMap(deploy.UnstructuredContent(), "spec", "template", "metadata", "annotations")
if err != nil {
return errors.Wrap(err, "bad annotations")
if deploy.Spec.Template.Annotations == nil {
deploy.Spec.Template.Annotations = map[string]string{}
}
if !ok {
annotations = map[string]string{}
}
deploy.Spec.Template.Annotations[rollingUpdateAnnotation] = time.Now().String()
annotations[rollingUpdateAnnotation] = time.Now().String()
if err = unstructured.SetNestedStringMap(deploy.UnstructuredContent(),
annotations,
"spec", "template", "metadata", "annotations",
); err != nil {
return errors.Wrapf(err, "set annotation %s", rollingUpdateAnnotation)
}
if _, err = c.client.UpdateResource("", "Deployment", config.KyvernoNamespace, deploy, false); err != nil {
if _, err = c.client.AppsV1().Deployments(config.KyvernoNamespace).Update(context.TODO(), deploy, metav1.UpdateOptions{}); err != nil {
return errors.Wrap(err, "update Kyverno deployment")
}
return nil
@ -321,30 +301,30 @@ func (c *CertRenewer) ValidCert() (bool, error) {
var managedByKyverno bool
snameTLS := GenerateTLSPairSecretName(certProps)
snameCA := GenerateRootCASecretName(certProps)
unstrSecret, err := c.client.GetResource("", "Secret", certProps.Namespace, snameTLS)
secret, err := c.client.CoreV1().Secrets(certProps.Namespace).Get(context.TODO(), snameTLS, metav1.GetOptions{})
if err != nil {
return false, nil
}
if label, ok := unstrSecret.GetLabels()[ManagedByLabel]; ok {
if label, ok := secret.GetLabels()[ManagedByLabel]; ok {
managedByKyverno = label == "kyverno"
}
_, ok := unstrSecret.GetAnnotations()[MasterDeploymentUID]
_, ok := secret.GetAnnotations()[MasterDeploymentUID]
if managedByKyverno && !ok {
return false, nil
}
unstrSecret, err = c.client.GetResource("", "Secret", certProps.Namespace, snameCA)
secret, err = c.client.CoreV1().Secrets(certProps.Namespace).Get(context.TODO(), snameCA, metav1.GetOptions{})
if err != nil {
return false, nil
}
if label, ok := unstrSecret.GetLabels()[ManagedByLabel]; ok {
if label, ok := secret.GetLabels()[ManagedByLabel]; ok {
managedByKyverno = label == "kyverno"
}
_, ok = unstrSecret.GetAnnotations()[MasterDeploymentUID]
_, ok = secret.GetAnnotations()[MasterDeploymentUID]
if managedByKyverno && !ok {
return false, nil
}
@ -407,16 +387,12 @@ func (c *CertRenewer) ValidCert() (bool, error) {
}
// IsKyvernoInRollingUpdate returns true if Kyverno is in rolling update
func IsKyvernoInRollingUpdate(deploy map[string]interface{}, logger logr.Logger) bool {
replicas, _, err := unstructured.NestedFloat64(deploy, "spec", "replicas")
if err != nil {
logger.Error(err, "unable to fetch spec.replicas")
}
nonTerminatedReplicas, _, err := unstructured.NestedFloat64(deploy, "status", "replicas")
if err != nil {
logger.Error(err, "unable to fetch status.replicas")
func IsKyvernoInRollingUpdate(deploy *appsv1.Deployment, logger logr.Logger) bool {
var replicas int32 = 1
if deploy.Spec.Replicas != nil {
replicas = *deploy.Spec.Replicas
}
nonTerminatedReplicas := deploy.Status.Replicas
if nonTerminatedReplicas > replicas {
logger.Info("detect Kyverno is in rolling update, won't trigger the update again")
@ -434,7 +410,7 @@ func GenerateRootCASecretName(props CertificateProps) string {
return generateInClusterServiceName(props) + ".kyverno-tls-ca"
}
func CanAddAnnotationToSecret(deplHash string, secret *unstructured.Unstructured) bool {
func CanAddAnnotationToSecret(deplHash string, secret *v1.Secret) bool {
var deplHashSec string = "default"
var ok, managedByKyverno bool

View file

@ -1,28 +1,28 @@
package tls
import (
"context"
"fmt"
"net/url"
"github.com/kyverno/kyverno/pkg/config"
client "github.com/kyverno/kyverno/pkg/dclient"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
var ErrorsNotFound = "root CA certificate not found"
// ReadRootCASecret returns the RootCA from the pre-defined secret
func ReadRootCASecret(restConfig *rest.Config, client *client.Client) (result []byte, err error) {
func ReadRootCASecret(restConfig *rest.Config, client kubernetes.Interface) (result []byte, err error) {
certProps, err := GetTLSCertProps(restConfig)
if err != nil {
return nil, errors.Wrap(err, "failed to get TLS Cert Properties")
}
depl, err := client.GetResource("", "Deployment", certProps.Namespace, config.KyvernoDeploymentName)
depl, err := client.AppsV1().Deployments(certProps.Namespace).Get(context.TODO(), config.KyvernoDeploymentName, metav1.GetOptions{})
deplHash := ""
if err == nil {
@ -33,7 +33,7 @@ func ReadRootCASecret(restConfig *rest.Config, client *client.Client) (result []
var ok, managedByKyverno bool
sname := GenerateRootCASecretName(certProps)
stlsca, err := client.GetResource("", "Secret", certProps.Namespace, sname)
stlsca, err := client.CoreV1().Secrets(certProps.Namespace).Get(context.TODO(), sname, metav1.GetOptions{})
if err != nil {
return nil, err
}
@ -46,27 +46,22 @@ func ReadRootCASecret(restConfig *rest.Config, client *client.Client) (result []
return nil, fmt.Errorf("outdated secret")
}
tlsca, err := convertToSecret(stlsca)
if err != nil {
return nil, errors.Wrapf(err, "failed to convert secret %s/%s", certProps.Namespace, sname)
}
result = tlsca.Data[RootCAKey]
result = stlsca.Data[RootCAKey]
if len(result) == 0 {
return nil, errors.Errorf("%s in secret %s/%s", ErrorsNotFound, certProps.Namespace, tlsca.Name)
return nil, errors.Errorf("%s in secret %s/%s", ErrorsNotFound, certProps.Namespace, stlsca.Name)
}
return result, nil
}
// ReadTLSPair returns the pem pair from the pre-defined secret
func ReadTLSPair(restConfig *rest.Config, client *client.Client) (*PemPair, error) {
func ReadTLSPair(restConfig *rest.Config, client kubernetes.Interface) (*PemPair, error) {
certProps, err := GetTLSCertProps(restConfig)
if err != nil {
return nil, errors.Wrap(err, "failed to get TLS Cert Properties")
}
depl, err := client.GetResource("", "Deployment", certProps.Namespace, config.KyvernoDeploymentName)
depl, err := client.AppsV1().Deployments(certProps.Namespace).Get(context.TODO(), config.KyvernoDeploymentName, metav1.GetOptions{})
deplHash := ""
if err == nil {
@ -77,32 +72,28 @@ func ReadTLSPair(restConfig *rest.Config, client *client.Client) (*PemPair, erro
var ok, managedByKyverno bool
sname := GenerateTLSPairSecretName(certProps)
unstrSecret, err := client.GetResource("", "Secret", certProps.Namespace, sname)
secret, err := client.CoreV1().Secrets(certProps.Namespace).Get(context.TODO(), sname, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("failed to get secret %s/%s: %v", certProps.Namespace, sname, err)
}
if label, ok := unstrSecret.GetLabels()[ManagedByLabel]; ok {
if label, ok := secret.GetLabels()[ManagedByLabel]; ok {
managedByKyverno = label == "kyverno"
}
deplHashSec, ok = unstrSecret.GetAnnotations()[MasterDeploymentUID]
deplHashSec, ok = secret.GetAnnotations()[MasterDeploymentUID]
if managedByKyverno && (ok && deplHashSec != deplHash) {
return nil, fmt.Errorf("outdated secret")
}
// If secret contains annotation 'self-signed-cert', then it's created using helper scripts to setup self-signed certificates.
// As the root CA used to sign the certificate is required for webhook configuration, check if the corresponding secret is created
annotations := unstrSecret.GetAnnotations()
annotations := secret.GetAnnotations()
if _, ok := annotations[SelfSignedAnnotation]; ok {
sname := GenerateRootCASecretName(certProps)
_, err := client.GetResource("", "Secret", certProps.Namespace, sname)
_, err := client.CoreV1().Secrets(certProps.Namespace).Get(context.TODO(), sname, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("rootCA secret is required while using self-signed certificate TLS pair, defaulting to generating new TLS pair %s/%s", certProps.Namespace, sname)
}
}
secret, err := convertToSecret(unstrSecret)
if err != nil {
return nil, err
}
pemPair := PemPair{
Certificate: secret.Data[v1.TLSCertKey],
@ -133,11 +124,3 @@ func GetTLSCertProps(configuration *rest.Config) (certProps CertificateProps, er
}
return certProps, nil
}
func convertToSecret(obj *unstructured.Unstructured) (v1.Secret, error) {
secret := v1.Secret{}
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &secret); err != nil {
return secret, err
}
return secret, nil
}

View file

@ -19,6 +19,7 @@ import (
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
@ -226,9 +227,9 @@ func NormalizeSecret(resource *unstructured.Unstructured) (unstructured.Unstruct
}
// HigherThanKubernetesVersion compare Kubernetes client version to user given version
func HigherThanKubernetesVersion(client *client.Client, log logr.Logger, major, minor, patch int) bool {
func HigherThanKubernetesVersion(client discovery.ServerVersionInterface, log logr.Logger, major, minor, patch int) bool {
logger := log.WithName("CompareKubernetesVersion")
serverVersion, err := client.DiscoveryClient.GetServerVersion()
serverVersion, err := client.ServerVersion()
if err != nil {
logger.Error(err, "Failed to get kubernetes server version")
return false

View file

@ -25,7 +25,7 @@ func (wrc *Register) readCaData() []byte {
// Check if ca is defined in the secret tls-ca
// assume the key and signed cert have been defined in secret tls.kyverno
if caData, err = tls.ReadRootCASecret(wrc.clientConfig, wrc.client); err == nil {
if caData, err = tls.ReadRootCASecret(wrc.clientConfig, wrc.kubeClient); err == nil {
logger.V(4).Info("read CA from secret")
return caData
}

View file

@ -225,11 +225,11 @@ func lastRequestTimeFromAnnotation(leaseClient coordinationv1.LeaseInterface, lo
// skipWebhookCheck returns true if Kyverno is in rolling update
func skipWebhookCheck(register *Register, logger logr.Logger) bool {
_, deploy, err := register.GetKubePolicyDeployment()
deploy, _, err := register.GetKubePolicyDeployment()
if err != nil {
logger.Info("unable to get Kyverno deployment", "reason", err.Error())
return false
}
return tls.IsKyvernoInRollingUpdate(deploy.UnstructuredContent(), logger)
return tls.IsKyvernoInRollingUpdate(deploy, logger)
}

View file

@ -27,6 +27,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
adminformers "k8s.io/client-go/informers/admissionregistration/v1"
informers "k8s.io/client-go/informers/apps/v1"
"k8s.io/client-go/kubernetes"
admlisters "k8s.io/client-go/listers/admissionregistration/v1"
listers "k8s.io/client-go/listers/apps/v1"
rest "k8s.io/client-go/rest"
@ -46,6 +47,7 @@ const (
// 5. Webhook Status Mutation
type Register struct {
client *client.Client
kubeClient kubernetes.Interface
clientConfig *rest.Config
resCache resourcecache.ResourceCache
@ -76,6 +78,7 @@ type Register struct {
func NewRegister(
clientConfig *rest.Config,
client *client.Client,
kubeClient kubernetes.Interface,
kyvernoClient *kyvernoclient.Clientset,
mwcInformer adminformers.MutatingWebhookConfigurationInformer,
vwcInformer adminformers.ValidatingWebhookConfigurationInformer,
@ -92,6 +95,7 @@ func NewRegister(
register := &Register{
clientConfig: clientConfig,
client: client,
kubeClient: kubeClient,
resCache: resCache,
serverIP: serverIP,
timeoutSeconds: webhookTimeout,