1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00
kyverno/pkg/tls/reader.go
Kumar Mallikarjuna 214f338ec3
Fix TLS inconsitency in HA (#2910)
* Fix TLS inconsitency in HA

Signed-off-by: Kumar Mallikarjuna <kumar@nirmata.com>

* Add error checks

Signed-off-by: Kumar Mallikarjuna <kumar@nirmata.com>

* Remove rendundant err definitions

Signed-off-by: Kumar Mallikarjuna <kumar@nirmata.com>

* Handle all Secret errors

Signed-off-by: Kumar Mallikarjuna <kumar@nirmata.com>
2022-01-06 09:11:16 +00:00

143 lines
4.5 KiB
Go

package tls
import (
"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"
"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) {
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)
deplHash := ""
if err == nil {
deplHash = fmt.Sprintf("%v", depl.GetUID())
}
var deplHashSec string = "default"
var ok, managedByKyverno bool
sname := generateRootCASecretName(certProps)
stlsca, err := client.GetResource("", "Secret", certProps.Namespace, sname)
if err != nil {
return nil, err
}
if label, ok := stlsca.GetLabels()[ManagedByLabel]; ok {
managedByKyverno = label == "kyverno"
}
deplHashSec, ok = stlsca.GetAnnotations()[MasterDeploymentUID]
if managedByKyverno && (!ok || deplHashSec != deplHash) {
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]
if len(result) == 0 {
return nil, errors.Errorf("%s in secret %s/%s", ErrorsNotFound, certProps.Namespace, tlsca.Name)
}
return result, nil
}
// ReadTLSPair returns the pem pair from the pre-defined secret
func ReadTLSPair(restConfig *rest.Config, client *client.Client) (*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)
deplHash := ""
if err == nil {
deplHash = fmt.Sprintf("%v", depl.GetUID())
}
var deplHashSec string = "default"
var ok, managedByKyverno bool
sname := generateTLSPairSecretName(certProps)
unstrSecret, err := client.GetResource("", "Secret", certProps.Namespace, sname)
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 {
managedByKyverno = label == "kyverno"
}
deplHashSec, ok = unstrSecret.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()
if _, ok := annotations[SelfSignedAnnotation]; ok {
sname := generateRootCASecretName(certProps)
_, err := client.GetResource("", "Secret", certProps.Namespace, sname)
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],
PrivateKey: secret.Data[v1.TLSPrivateKeyKey],
}
if len(pemPair.Certificate) == 0 {
return nil, fmt.Errorf("TLS Certificate not found in secret %s/%s", certProps.Namespace, sname)
}
if len(pemPair.PrivateKey) == 0 {
return nil, fmt.Errorf("TLS PrivateKey not found in secret %s/%s", certProps.Namespace, sname)
}
return &pemPair, nil
}
//GetTLSCertProps provides the TLS Certificate Properties
func GetTLSCertProps(configuration *rest.Config) (certProps CertificateProps, err error) {
apiServerURL, err := url.Parse(configuration.Host)
if err != nil {
return certProps, err
}
certProps = CertificateProps{
Service: config.KyvernoServiceName,
Namespace: config.KyvernoNamespace,
APIServerHost: apiServerURL.Hostname(),
}
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
}