1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-28 02:18:15 +00:00

feat: make cert renewer private and add server name support (#4904)

* fix: remove unnecessary dependencies from tls package

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* feat: make cert renewer private and add server name support

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* nits

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2022-10-13 11:46:05 +02:00 committed by GitHub
parent cd5e0cfa74
commit 090b68e55d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 58 additions and 57 deletions

View file

@ -414,7 +414,7 @@ func createrLeaderControllers(
configuration config.Configuration,
metricsConfig *metrics.MetricsConfig,
eventGenerator event.Interface,
certRenewer *tls.CertRenewer,
certRenewer tls.CertRenewer,
runtime runtimeutils.Runtime,
) ([]controller, error) {
policyCtrl, err := policy.NewPolicyController(
@ -564,7 +564,7 @@ func main() {
logger.Error(err, "Failed to create openapi manager")
os.Exit(1)
}
certRenewer, err := tls.NewCertRenewer(
certRenewer := tls.NewCertRenewer(
metrics.ObjectClient[*corev1.Secret](
metrics.NamespacedClientQueryRecorder(metricsConfig, config.KyvernoNamespace(), "Secret", metrics.KubeClient),
kubeClient.CoreV1().Secrets(config.KyvernoNamespace()),
@ -574,10 +574,6 @@ func main() {
tls.TLSValidityDuration,
serverIP,
)
if err != nil {
logger.Error(err, "failed to initialize CertRenewer")
os.Exit(1)
}
policyCache := policycache.NewCache()
eventGenerator := event.NewEventGenerator(
dynamicClient,

View file

@ -26,7 +26,7 @@ const (
)
type controller struct {
renewer *tls.CertRenewer
renewer tls.CertRenewer
// listers
secretLister corev1listers.SecretLister
@ -36,7 +36,7 @@ type controller struct {
secretEnqueue controllerutils.EnqueueFunc
}
func NewController(secretInformer corev1informers.SecretInformer, certRenewer *tls.CertRenewer) controllers.Controller {
func NewController(secretInformer corev1informers.SecretInformer, certRenewer tls.CertRenewer) controllers.Controller {
queue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), ControllerName)
c := controller{
renewer: certRenewer,

View file

@ -50,7 +50,7 @@ func generateCA(key *rsa.PrivateKey, certValidityDuration time.Duration) (*rsa.P
// generateTLS takes the results of GenerateCACert and uses it to create the
// PEM-encoded public certificate and private key, respectively
func generateTLS(serverIP string, caCert *x509.Certificate, caKey *rsa.PrivateKey, certValidityDuration time.Duration) (*rsa.PrivateKey, *x509.Certificate, error) {
func generateTLS(server string, caCert *x509.Certificate, caKey *rsa.PrivateKey, certValidityDuration time.Duration) (*rsa.PrivateKey, *x509.Certificate, error) {
now := time.Now()
begin, end := now.Add(-1*time.Hour), now.Add(certValidityDuration)
dnsNames := []string{
@ -59,13 +59,23 @@ func generateTLS(serverIP string, caCert *x509.Certificate, caKey *rsa.PrivateKe
InClusterServiceName(),
}
var ips []net.IP
if serverIP != "" {
if strings.Contains(serverIP, ":") {
host, _, _ := net.SplitHostPort(serverIP)
serverIP = host
if server != "" {
serverHost := ""
if strings.Contains(server, ":") {
host, _, err := net.SplitHostPort(server)
if err != nil {
logger.Error(err, "failed to split server host/port", "server", server)
}
serverHost = host
}
if serverHost != "" {
ip := net.ParseIP(serverHost)
if ip == nil || ip.IsUnspecified() {
dnsNames = append(dnsNames, serverHost)
} else {
ips = append(ips, ip)
}
}
ip := net.ParseIP(serverIP)
ips = append(ips, ip)
}
templ := &x509.Certificate{
SerialNumber: big.NewInt(1),

View file

@ -23,7 +23,7 @@ func ReadRootCASecret(client controllerutils.GetClient[*corev1.Secret]) ([]byte,
result := stlsca.Data[corev1.TLSCertKey]
// if not there, try old "rootCA.crt"
if len(result) == 0 {
result = stlsca.Data[RootCAKey]
result = stlsca.Data[rootCAKey]
}
if len(result) == 0 {
return nil, errors.Errorf("%s in secret %s/%s", ErrorsNotFound, config.KyvernoNamespace(), stlsca.Name)

View file

@ -17,54 +17,49 @@ import (
const (
// CertRenewalInterval is the renewal interval for rootCA
CertRenewalInterval time.Duration = 12 * time.Hour
CertRenewalInterval = 12 * time.Hour
// CAValidityDuration is the valid duration for CA certificates
CAValidityDuration time.Duration = 365 * 24 * time.Hour
CAValidityDuration = 365 * 24 * time.Hour
// TLSValidityDuration is the valid duration for TLS certificates
TLSValidityDuration time.Duration = 150 * 24 * time.Hour
// ManagedByLabel is added to Kyverno managed secrets
ManagedByLabel string = "cert.kyverno.io/managed-by"
RootCAKey string = "rootCA.crt"
TLSValidityDuration = 150 * 24 * time.Hour
// managedByLabel is added to Kyverno managed secrets
managedByLabel = "cert.kyverno.io/managed-by"
rootCAKey = "rootCA.crt"
)
// CertRenewer creates rootCA and pem pair to register
type CertRenewer interface {
// RenewCA renews the CA certificate if needed
RenewCA() error
// RenewTLS renews the TLS certificate if needed
RenewTLS() error
}
// certRenewer creates rootCA and pem pair to register
// webhook configurations and webhook server
// renews RootCA at the given interval
type CertRenewer struct {
type certRenewer struct {
client controllerutils.ObjectClient[*corev1.Secret]
certRenewalInterval time.Duration
caValidityDuration time.Duration
tlsValidityDuration time.Duration
// IP address where Kyverno controller runs. Only required if out-of-cluster.
serverIP string
// server is an IP address or domain name where Kyverno controller runs. Only required if out-of-cluster.
server string
}
// NewCertRenewer returns an instance of CertRenewer
func NewCertRenewer(client controllerutils.ObjectClient[*corev1.Secret], certRenewalInterval, caValidityDuration, tlsValidityDuration time.Duration, serverIP string) (*CertRenewer, error) {
return &CertRenewer{
func NewCertRenewer(client controllerutils.ObjectClient[*corev1.Secret], certRenewalInterval, caValidityDuration, tlsValidityDuration time.Duration, server string) CertRenewer {
return &certRenewer{
client: client,
certRenewalInterval: certRenewalInterval,
caValidityDuration: caValidityDuration,
tlsValidityDuration: tlsValidityDuration,
serverIP: serverIP,
}, nil
server: server,
}
}
// InitTLSPemPair Loads or creates PEM private key and TLS certificate for webhook server.
// Created pair is stored in cluster's secret.
func (c *CertRenewer) InitTLSPemPair() error {
if err := c.RenewCA(); err != nil {
return err
}
if err := c.RenewTLS(); err != nil {
return err
}
return nil
}
// RenewTLS renews the CA certificate if needed
func (c *CertRenewer) RenewCA() error {
// RenewCA renews the CA certificate if needed
func (c *certRenewer) RenewCA() error {
secret, key, certs, err := c.decodeCASecret()
if err != nil && !apierrors.IsNotFound(err) {
logger.Error(err, "failed to read CA")
@ -96,7 +91,7 @@ func (c *CertRenewer) RenewCA() error {
}
// RenewTLS renews the TLS certificate if needed
func (c *CertRenewer) RenewTLS() error {
func (c *certRenewer) RenewTLS() error {
_, caKey, caCerts, err := c.decodeCASecret()
if err != nil {
logger.Error(err, "failed to read CA")
@ -117,7 +112,7 @@ func (c *CertRenewer) RenewTLS() error {
logger.Error(err, "tls is not valid but certificates are not managed by kyverno, we can't renew them")
return err
}
tlsKey, tlsCert, err := generateTLS(c.serverIP, caCerts[len(caCerts)-1], caKey, c.tlsValidityDuration)
tlsKey, tlsCert, err := generateTLS(c.server, caCerts[len(caCerts)-1], caKey, c.tlsValidityDuration)
if err != nil {
logger.Error(err, "failed to generate TLS")
return err
@ -131,7 +126,7 @@ func (c *CertRenewer) RenewTLS() error {
}
// ValidateCert validates the CA Cert
func (c *CertRenewer) ValidateCert() (bool, error) {
func (c *certRenewer) ValidateCert() (bool, error) {
_, _, caCerts, err := c.decodeCASecret()
if err != nil {
return false, err
@ -143,7 +138,7 @@ func (c *CertRenewer) ValidateCert() (bool, error) {
return validateCert(time.Now(), cert, caCerts...), nil
}
func (c *CertRenewer) getSecret(name string) (*corev1.Secret, error) {
func (c *certRenewer) getSecret(name string) (*corev1.Secret, error) {
if s, err := c.client.Get(context.TODO(), name, metav1.GetOptions{}); err != nil {
return nil, err
} else {
@ -151,7 +146,7 @@ func (c *CertRenewer) getSecret(name string) (*corev1.Secret, error) {
}
}
func (c *CertRenewer) decodeSecret(name string) (*corev1.Secret, *rsa.PrivateKey, []*x509.Certificate, error) {
func (c *certRenewer) decodeSecret(name string) (*corev1.Secret, *rsa.PrivateKey, []*x509.Certificate, error) {
secret, err := c.getSecret(name)
if err != nil {
return nil, nil, nil, err
@ -161,7 +156,7 @@ func (c *CertRenewer) decodeSecret(name string) (*corev1.Secret, *rsa.PrivateKey
keyBytes = secret.Data[corev1.TLSPrivateKeyKey]
certBytes = secret.Data[corev1.TLSCertKey]
if len(certBytes) == 0 {
certBytes = secret.Data[RootCAKey]
certBytes = secret.Data[rootCAKey]
}
}
var key *rsa.PrivateKey
@ -175,11 +170,11 @@ func (c *CertRenewer) decodeSecret(name string) (*corev1.Secret, *rsa.PrivateKey
return secret, key, pemToCertificates(certBytes), nil
}
func (c *CertRenewer) decodeCASecret() (*corev1.Secret, *rsa.PrivateKey, []*x509.Certificate, error) {
func (c *certRenewer) decodeCASecret() (*corev1.Secret, *rsa.PrivateKey, []*x509.Certificate, error) {
return c.decodeSecret(GenerateRootCASecretName())
}
func (c *CertRenewer) decodeTLSSecret() (*corev1.Secret, *rsa.PrivateKey, *x509.Certificate, error) {
func (c *certRenewer) decodeTLSSecret() (*corev1.Secret, *rsa.PrivateKey, *x509.Certificate, error) {
secret, key, certs, err := c.decodeSecret(GenerateTLSPairSecretName())
if err != nil {
return nil, nil, nil, err
@ -193,7 +188,7 @@ func (c *CertRenewer) decodeTLSSecret() (*corev1.Secret, *rsa.PrivateKey, *x509.
}
}
func (c *CertRenewer) writeSecret(name string, key *rsa.PrivateKey, certs ...*x509.Certificate) error {
func (c *certRenewer) writeSecret(name string, key *rsa.PrivateKey, certs ...*x509.Certificate) error {
logger := logger.WithValues("name", name, "namespace", config.KyvernoNamespace())
secret, err := c.getSecret(name)
if err != nil && !apierrors.IsNotFound(err) {
@ -206,7 +201,7 @@ func (c *CertRenewer) writeSecret(name string, key *rsa.PrivateKey, certs ...*x5
Name: name,
Namespace: config.KyvernoNamespace(),
Labels: map[string]string{
ManagedByLabel: kyvernov1.ValueKyvernoApp,
managedByLabel: kyvernov1.ValueKyvernoApp,
},
},
Type: corev1.SecretTypeTLS,
@ -236,11 +231,11 @@ func (c *CertRenewer) writeSecret(name string, key *rsa.PrivateKey, certs ...*x5
}
// writeCASecret stores the CA cert in secret
func (c *CertRenewer) writeCASecret(key *rsa.PrivateKey, certs ...*x509.Certificate) error {
func (c *certRenewer) writeCASecret(key *rsa.PrivateKey, certs ...*x509.Certificate) error {
return c.writeSecret(GenerateRootCASecretName(), key, certs...)
}
// writeTLSSecret Writes the pair of TLS certificate and key to the specified secret.
func (c *CertRenewer) writeTLSSecret(key *rsa.PrivateKey, cert *x509.Certificate) error {
func (c *certRenewer) writeTLSSecret(key *rsa.PrivateKey, cert *x509.Certificate) error {
return c.writeSecret(GenerateTLSPairSecretName(), key, cert)
}

View file

@ -104,7 +104,7 @@ func IsSecretManagedByKyverno(secret *corev1.Secret) bool {
if labels == nil {
return false
}
if labels[ManagedByLabel] != kyvernov1.ValueKyvernoApp {
if labels[managedByLabel] != kyvernov1.ValueKyvernoApp {
return false
}
}