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:
parent
cd5e0cfa74
commit
090b68e55d
6 changed files with 58 additions and 57 deletions
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue