2021-03-16 11:31:04 -07:00
package tls
import (
2022-04-26 22:18:14 +02:00
"context"
2021-03-16 11:31:04 -07:00
"fmt"
"net/url"
"github.com/kyverno/kyverno/pkg/config"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
2022-04-26 22:18:14 +02:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
2021-03-16 11:31:04 -07:00
"k8s.io/client-go/rest"
)
2021-05-04 22:10:01 -07:00
var ErrorsNotFound = "root CA certificate not found"
2021-03-16 11:31:04 -07:00
// ReadRootCASecret returns the RootCA from the pre-defined secret
2022-04-26 22:18:14 +02:00
func ReadRootCASecret ( restConfig * rest . Config , client kubernetes . Interface ) ( result [ ] byte , err error ) {
2021-03-16 11:31:04 -07:00
certProps , err := GetTLSCertProps ( restConfig )
if err != nil {
return nil , errors . Wrap ( err , "failed to get TLS Cert Properties" )
}
2022-04-26 22:18:14 +02:00
depl , err := client . AppsV1 ( ) . Deployments ( certProps . Namespace ) . Get ( context . TODO ( ) , config . KyvernoDeploymentName , metav1 . GetOptions { } )
2022-01-06 14:41:16 +05:30
deplHash := ""
if err == nil {
deplHash = fmt . Sprintf ( "%v" , depl . GetUID ( ) )
}
var deplHashSec string = "default"
var ok , managedByKyverno bool
2022-01-11 14:17:24 +05:30
sname := GenerateRootCASecretName ( certProps )
2022-04-26 22:18:14 +02:00
stlsca , err := client . CoreV1 ( ) . Secrets ( certProps . Namespace ) . Get ( context . TODO ( ) , sname , metav1 . GetOptions { } )
2021-03-16 11:31:04 -07:00
if err != nil {
return nil , err
}
2022-01-06 14:41:16 +05:30
if label , ok := stlsca . GetLabels ( ) [ ManagedByLabel ] ; ok {
managedByKyverno = label == "kyverno"
}
deplHashSec , ok = stlsca . GetAnnotations ( ) [ MasterDeploymentUID ]
2022-01-07 23:03:01 +05:30
if managedByKyverno && ( ok && deplHashSec != deplHash ) {
2022-01-06 14:41:16 +05:30
return nil , fmt . Errorf ( "outdated secret" )
}
2022-04-26 22:18:14 +02:00
result = stlsca . Data [ RootCAKey ]
2021-03-16 11:31:04 -07:00
if len ( result ) == 0 {
2022-04-26 22:18:14 +02:00
return nil , errors . Errorf ( "%s in secret %s/%s" , ErrorsNotFound , certProps . Namespace , stlsca . Name )
2021-03-16 11:31:04 -07:00
}
return result , nil
}
// ReadTLSPair returns the pem pair from the pre-defined secret
2022-04-26 22:18:14 +02:00
func ReadTLSPair ( restConfig * rest . Config , client kubernetes . Interface ) ( * PemPair , error ) {
2021-03-16 11:31:04 -07:00
certProps , err := GetTLSCertProps ( restConfig )
if err != nil {
return nil , errors . Wrap ( err , "failed to get TLS Cert Properties" )
}
2022-04-26 22:18:14 +02:00
depl , err := client . AppsV1 ( ) . Deployments ( certProps . Namespace ) . Get ( context . TODO ( ) , config . KyvernoDeploymentName , metav1 . GetOptions { } )
2022-01-06 14:41:16 +05:30
deplHash := ""
if err == nil {
deplHash = fmt . Sprintf ( "%v" , depl . GetUID ( ) )
}
var deplHashSec string = "default"
var ok , managedByKyverno bool
2022-01-11 14:17:24 +05:30
sname := GenerateTLSPairSecretName ( certProps )
2022-04-26 22:18:14 +02:00
secret , err := client . CoreV1 ( ) . Secrets ( certProps . Namespace ) . Get ( context . TODO ( ) , sname , metav1 . GetOptions { } )
2021-03-16 11:31:04 -07:00
if err != nil {
return nil , fmt . Errorf ( "failed to get secret %s/%s: %v" , certProps . Namespace , sname , err )
}
2022-04-26 22:18:14 +02:00
if label , ok := secret . GetLabels ( ) [ ManagedByLabel ] ; ok {
2022-01-06 14:41:16 +05:30
managedByKyverno = label == "kyverno"
}
2022-04-26 22:18:14 +02:00
deplHashSec , ok = secret . GetAnnotations ( ) [ MasterDeploymentUID ]
2022-01-07 23:03:01 +05:30
if managedByKyverno && ( ok && deplHashSec != deplHash ) {
2022-01-06 14:41:16 +05:30
return nil , fmt . Errorf ( "outdated secret" )
}
2021-03-16 11:31:04 -07:00
// 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
2022-05-10 10:58:51 +02:00
{
2022-01-11 14:17:24 +05:30
sname := GenerateRootCASecretName ( certProps )
2022-04-26 22:18:14 +02:00
_ , err := client . CoreV1 ( ) . Secrets ( certProps . Namespace ) . Get ( context . TODO ( ) , sname , metav1 . GetOptions { } )
2021-03-16 11:31:04 -07:00
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 )
}
}
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
2022-05-10 10:58:51 +02:00
func GetTLSCertProps ( configuration * rest . Config ) ( * CertificateProps , error ) {
2021-03-16 11:31:04 -07:00
apiServerURL , err := url . Parse ( configuration . Host )
if err != nil {
2022-05-10 10:58:51 +02:00
return nil , err
2021-03-16 11:31:04 -07:00
}
2022-05-10 10:58:51 +02:00
return & CertificateProps {
2021-03-16 11:31:04 -07:00
Service : config . KyvernoServiceName ,
Namespace : config . KyvernoNamespace ,
APIServerHost : apiServerURL . Hostname ( ) ,
2022-05-10 10:58:51 +02:00
} , nil
2021-03-16 11:31:04 -07:00
}