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:
parent
c97af0094f
commit
a6924a11ab
8 changed files with 138 additions and 173 deletions
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue