-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: certificates generation package and secrets #777
Changes from all commits
8bead45
bc8e152
7b9da28
4e213d0
82b12a9
d4a3b61
c5a217e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe something for later, but I would also rename this file since it can mislead into thinking each Policy Server has a dedicated CA |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,21 +12,18 @@ | |
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" | ||
|
||
"github.com/kubewarden/kubewarden-controller/internal/pkg/admissionregistration" | ||
"github.com/kubewarden/kubewarden-controller/internal/pkg/certs" | ||
"github.com/kubewarden/kubewarden-controller/internal/pkg/constants" | ||
) | ||
|
||
type generateCAFunc = func() (*admissionregistration.CA, error) | ||
type pemEncodeCertificateFunc = func(certificate []byte) ([]byte, error) | ||
type generateCertFunc = func(ca []byte, commonName string, extraSANs []string, CAPrivateKey *rsa.PrivateKey) ([]byte, []byte, error) | ||
|
||
func (r *Reconciler) fetchOrInitializePolicyServerCASecret(ctx context.Context, policyServer *policiesv1.PolicyServer, caSecret *corev1.Secret, generateCert generateCertFunc) error { | ||
func (r *Reconciler) fetchOrInitializePolicyServerCASecret(ctx context.Context, policyServer *policiesv1.PolicyServer, caSecret *corev1.Secret) error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, there's a bit of naming confusion here we inherited from the past. This method creates the certificate used by a specific Policy Server instance, there's no CA associated with a Policy Server |
||
policyServerSecret := &corev1.Secret{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Namespace: r.DeploymentsNamespace, | ||
Name: policyServer.NameWithPrefix(), | ||
}, | ||
} | ||
|
||
_, err := controllerutil.CreateOrPatch(ctx, r.Client, policyServerSecret, func() error { | ||
if err := controllerutil.SetOwnerReference(policyServer, policyServerSecret, r.Client.Scheme()); err != nil { | ||
return errors.Join(errors.New("failed to set policy server secret owner reference"), err) | ||
|
@@ -36,22 +33,34 @@ | |
_, hasTLSCert := policyServerSecret.Data[constants.PolicyServerTLSCert] | ||
_, hasTLSKey := policyServerSecret.Data[constants.PolicyServerTLSKey] | ||
if !hasTLSCert || !hasTLSKey { | ||
admissionregCA, err := extractCaFromSecret(caSecret) | ||
caCert, caPrivateKey, err := extractCAFromSecret(caSecret) | ||
if err != nil { | ||
return err | ||
} | ||
servingCert, servingKey, err := generateCert( | ||
admissionregCA.CaCert, | ||
|
||
cert, privateKey, err := certs.GenerateCert( | ||
caCert, | ||
fmt.Sprintf("%s.%s.svc", policyServer.NameWithPrefix(), r.DeploymentsNamespace), | ||
[]string{fmt.Sprintf("%s.%s.svc", policyServer.NameWithPrefix(), r.DeploymentsNamespace)}, | ||
admissionregCA.CaPrivateKey) | ||
caPrivateKey) | ||
if err != nil { | ||
return fmt.Errorf("cannot generate policy-server %s certificate: %w", policyServer.NameWithPrefix(), err) | ||
} | ||
|
||
certPEM, err := certs.PEMEncodeCertificate(cert) | ||
if err != nil { | ||
return fmt.Errorf("cannot PEM encode policy-server %s certificate: %w", policyServer.NameWithPrefix(), err) | ||
} | ||
|
||
privateKeyPEM, err := certs.PEMEncodePrivateKey(privateKey) | ||
if err != nil { | ||
return fmt.Errorf("cannot PEM encode policy-server %s private key: %w", policyServer.NameWithPrefix(), err) | ||
} | ||
|
||
policyServerSecret.Type = corev1.SecretTypeOpaque | ||
policyServerSecret.StringData = map[string]string{ | ||
constants.PolicyServerTLSCert: string(servingCert), | ||
constants.PolicyServerTLSKey: string(servingKey), | ||
constants.PolicyServerTLSCert: string(certPEM), | ||
constants.PolicyServerTLSKey: string(privateKeyPEM), | ||
} | ||
} | ||
|
||
|
@@ -65,6 +74,7 @@ | |
) | ||
return errors.Join(errors.New("cannot fetch or initialize Policy Server CA secret"), err) | ||
} | ||
|
||
setTrueConditionType( | ||
&policyServer.Status.Conditions, | ||
string(policiesv1.PolicyServerCASecretReconciled), | ||
|
@@ -73,37 +83,40 @@ | |
return nil | ||
} | ||
|
||
func extractCaFromSecret(caSecret *corev1.Secret) (*admissionregistration.CA, error) { | ||
func extractCAFromSecret(caSecret *corev1.Secret) ([]byte, *rsa.PrivateKey, error) { | ||
caCert, ok := caSecret.Data[constants.PolicyServerCARootCACert] | ||
if !ok { | ||
return nil, fmt.Errorf("CA could not be extracted from secret %s", caSecret.Kind) | ||
return nil, nil, fmt.Errorf("CA could not be extracted from secret %s", caSecret.Kind) | ||
} | ||
caPrivateKeyBytes, ok := caSecret.Data[constants.PolicyServerCARootPrivateKeyCertName] | ||
|
||
privateKeyBytes, ok := caSecret.Data[constants.PolicyServerCARootPrivateKeyCertName] | ||
if !ok { | ||
return nil, fmt.Errorf("CA private key bytes could not be extracted from secret %s", caSecret.Kind) | ||
return nil, nil, fmt.Errorf("CA private key bytes could not be extracted from secret %s", caSecret.Kind) | ||
} | ||
|
||
caPrivateKey, err := x509.ParsePKCS1PrivateKey(caPrivateKeyBytes) | ||
privateKey, err := x509.ParsePKCS1PrivateKey(privateKeyBytes) | ||
if err != nil { | ||
return nil, fmt.Errorf("CA private key could not be extracted from secret %s", caSecret.Kind) | ||
return nil, nil, fmt.Errorf("CA private key could not be extracted from secret %s", caSecret.Kind) | ||
} | ||
return &admissionregistration.CA{CaCert: caCert, CaPrivateKey: caPrivateKey}, nil | ||
|
||
return caCert, privateKey, nil | ||
} | ||
|
||
func (r *Reconciler) fetchOrInitializePolicyServerCARootSecret(ctx context.Context, policyServer *policiesv1.PolicyServer, generateCA generateCAFunc, pemEncodeCertificate pemEncodeCertificateFunc) (*corev1.Secret, error) { | ||
func (r *Reconciler) fetchOrInitializePolicyServerCARootSecret(ctx context.Context, policyServer *policiesv1.PolicyServer) (*corev1.Secret, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, the naming is confusing since no CA is stored inside of the |
||
policyServerSecret := &corev1.Secret{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Namespace: r.DeploymentsNamespace, | ||
Name: constants.PolicyServerCARootSecretName, | ||
}, | ||
} | ||
|
||
_, err := controllerutil.CreateOrPatch(ctx, r.Client, policyServerSecret, func() error { | ||
_, hasCARootCert := policyServerSecret.Data[constants.PolicyServerCARootCACert] | ||
_, hasCARootPem := policyServerSecret.Data[constants.PolicyServerCARootPemName] | ||
_, hasCARootPrivateKey := policyServerSecret.Data[constants.PolicyServerCARootPrivateKeyCertName] | ||
|
||
if !hasCARootCert || !hasCARootPem || !hasCARootPrivateKey { | ||
return updateSecretCA(policyServerSecret, generateCA, pemEncodeCertificate) | ||
return updateCASecret(policyServerSecret) | ||
} | ||
return nil | ||
}) | ||
|
@@ -115,29 +128,34 @@ | |
) | ||
return nil, errors.Join(errors.New("cannot fetch or initialize Policy Server CA secret"), err) | ||
} | ||
|
||
setTrueConditionType( | ||
&policyServer.Status.Conditions, | ||
string(policiesv1.PolicyServerCARootSecretReconciled), | ||
) | ||
|
||
return policyServerSecret, nil | ||
} | ||
|
||
func updateSecretCA(policyServerSecret *corev1.Secret, generateCA generateCAFunc, pemEncodeCertificate pemEncodeCertificateFunc) error { | ||
caRoot, err := generateCA() | ||
func updateCASecret(policyServerSecret *corev1.Secret) error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function is always generating the CA, it doesn't look into the contents of the secret that is passed as parameter. Why don't we change the signature of the function to be something like that? func createInternalCASecret() (policyServerSecret *corev1.Secret, error) |
||
caCert, privateKey, err := certs.GenerateCA() | ||
if err != nil { | ||
return fmt.Errorf("cannot generate policy-server secret CA: %w", err) | ||
} | ||
caPEMEncoded, err := pemEncodeCertificate(caRoot.CaCert) | ||
|
||
caCertPEM, err := certs.PEMEncodeCertificate(caCert) | ||
if err != nil { | ||
return fmt.Errorf("cannot encode policy-server secret CA: %w", err) | ||
return fmt.Errorf("cannot PEM encode policy-server secret CA certificate: %w", err) | ||
} | ||
caPrivateKeyBytes := x509.MarshalPKCS1PrivateKey(caRoot.CaPrivateKey) | ||
|
||
privateKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey) | ||
secretContents := map[string][]byte{ | ||
constants.PolicyServerCARootCACert: caRoot.CaCert, | ||
constants.PolicyServerCARootPemName: caPEMEncoded, | ||
constants.PolicyServerCARootPrivateKeyCertName: caPrivateKeyBytes, | ||
constants.PolicyServerCARootCACert: caCert, | ||
constants.PolicyServerCARootPemName: caCertPEM, | ||
constants.PolicyServerCARootPrivateKeyCertName: privateKeyBytes, | ||
} | ||
policyServerSecret.Type = corev1.SecretTypeOpaque | ||
policyServerSecret.Data = secretContents | ||
|
||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is retrieving the Root CA created by our controller. I suggest to rename this helper function to reflect that.
Maybe something like
getInternalRootCASecret
?