-
Notifications
You must be signed in to change notification settings - Fork 140
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
Ensure external certs have a hash #3535
Changes from all commits
ffdde8b
3e6889b
3270939
dd63db6
f3197db
4a3e020
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -329,7 +329,7 @@ func (cm *certificateManager) GetOrCreateKeyPair(cli client.Client, secretName, | |
cm.log.V(3).Info("secret %s has invalid DNS names, the expected names are: %v", secretName, dnsNames) | ||
return keyPair, nil | ||
} | ||
} else if keyPair == nil { | ||
} else { | ||
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. The condition |
||
cm.log.V(1).Info("Keypair wasn't found, create a new one", "namespace", secretNamespace, "name", secretName) | ||
} | ||
|
||
|
@@ -561,19 +561,19 @@ func HasExpectedDNSNames(secretName, secretNamespace string, cert *x509.Certific | |
// It will include: | ||
// - A bundle with Calico's root certificates + any user supplied certificates in /etc/pki/tls/certs/tigera-ca-bundle.crt. | ||
func (cm *certificateManager) CreateTrustedBundle(certificates ...certificatemanagement.CertificateInterface) certificatemanagement.TrustedBundle { | ||
return certificatemanagement.CreateTrustedBundle(append([]certificatemanagement.CertificateInterface{cm.keyPair}, certificates...)...) | ||
return certificatemanagement.CreateTrustedBundle(cm.keyPair, certificates...) | ||
} | ||
|
||
// CreateTrustedBundleWithSystemRootCertificates creates a TrustedBundle, which provides standardized methods for mounting a bundle of certificates to trust. | ||
// It will include: | ||
// - A bundle with Calico's root certificates + any user supplied certificates in /etc/pki/tls/certs/tigera-ca-bundle.crt. | ||
// - A system root certificate bundle in /etc/pki/tls/certs/ca-bundle.crt. | ||
func (cm *certificateManager) CreateTrustedBundleWithSystemRootCertificates(certificates ...certificatemanagement.CertificateInterface) (certificatemanagement.TrustedBundle, error) { | ||
return certificatemanagement.CreateTrustedBundleWithSystemRootCertificates(append([]certificatemanagement.CertificateInterface{cm.keyPair}, certificates...)...) | ||
return certificatemanagement.CreateTrustedBundleWithSystemRootCertificates(cm.keyPair, certificates...) | ||
} | ||
|
||
func (cm *certificateManager) CreateMultiTenantTrustedBundleWithSystemRootCertificates(certificates ...certificatemanagement.CertificateInterface) (certificatemanagement.TrustedBundle, error) { | ||
return certificatemanagement.CreateMultiTenantTrustedBundleWithSystemRootCertificates(append([]certificatemanagement.CertificateInterface{cm.keyPair}, certificates...)...) | ||
return certificatemanagement.CreateMultiTenantTrustedBundleWithSystemRootCertificates(cm.keyPair, certificates...) | ||
} | ||
|
||
func (cm *certificateManager) LoadTrustedBundle(ctx context.Context, client client.Client, ns string) (certificatemanagement.TrustedBundleRO, error) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,15 +41,19 @@ type trustedBundle struct { | |
name string | ||
// systemCertificates is a bundle of certificates loaded from the host systems root location. | ||
systemCertificates []byte | ||
|
||
// This is the CA that signs new certificates that are being created. | ||
ca CertificateInterface | ||
|
||
// certificates is a map of key: hash, value: certificate. | ||
certificates map[string]CertificateInterface | ||
certificates []CertificateInterface | ||
} | ||
|
||
// CreateTrustedBundle creates a TrustedBundle, which provides standardized methods for mounting a bundle of certificates to trust. | ||
// It will include: | ||
// - A bundle with Calico's root certificates + any user supplied certificates in /etc/pki/tls/certs/tigera-ca-bundle.crt. | ||
func CreateTrustedBundle(certificates ...CertificateInterface) TrustedBundle { | ||
bundle, err := createTrustedBundle(false, TrustedCertConfigMapName, certificates...) | ||
func CreateTrustedBundle(ca CertificateInterface, certificates ...CertificateInterface) TrustedBundle { | ||
bundle, err := createTrustedBundle(false, TrustedCertConfigMapName, ca, certificates...) | ||
if err != nil { | ||
panic(err) // This should never happen. | ||
} | ||
|
@@ -60,18 +64,18 @@ func CreateTrustedBundle(certificates ...CertificateInterface) TrustedBundle { | |
// It will include: | ||
// - A bundle with Calico's root certificates + any user supplied certificates in /etc/pki/tls/certs/tigera-ca-bundle.crt. | ||
// - A system root certificate bundle in /etc/pki/tls/certs/ca-bundle.crt. | ||
func CreateTrustedBundleWithSystemRootCertificates(certificates ...CertificateInterface) (TrustedBundle, error) { | ||
return createTrustedBundle(true, TrustedCertConfigMapName, certificates...) | ||
func CreateTrustedBundleWithSystemRootCertificates(ca CertificateInterface, certificates ...CertificateInterface) (TrustedBundle, error) { | ||
return createTrustedBundle(true, TrustedCertConfigMapName, ca, certificates...) | ||
} | ||
|
||
// CreateMultiTenantTrustedBundleWithSystemRootCertificates creates a TrustedBundle with system root certificates that is | ||
// appropraite for a multi-tenant cluster, in which each tenant needs multiple trusted bundles. | ||
func CreateMultiTenantTrustedBundleWithSystemRootCertificates(certificates ...CertificateInterface) (TrustedBundle, error) { | ||
return createTrustedBundle(true, TrustedCertConfigMapNamePublic, certificates...) | ||
func CreateMultiTenantTrustedBundleWithSystemRootCertificates(ca CertificateInterface, certificates ...CertificateInterface) (TrustedBundle, error) { | ||
return createTrustedBundle(true, TrustedCertConfigMapNamePublic, ca, certificates...) | ||
} | ||
|
||
// createTrustedBundle creates a TrustedBundle, which provides standardized methods for mounting a bundle of certificates to trust. | ||
func createTrustedBundle(includeSystemBundle bool, name string, certificates ...CertificateInterface) (TrustedBundle, error) { | ||
func createTrustedBundle(includeSystemBundle bool, name string, ca CertificateInterface, certificates ...CertificateInterface) (TrustedBundle, error) { | ||
var systemCertificates []byte | ||
var err error | ||
if includeSystemBundle { | ||
|
@@ -83,8 +87,12 @@ func createTrustedBundle(includeSystemBundle bool, name string, certificates ... | |
|
||
bundle := &trustedBundle{ | ||
name: name, | ||
ca: ca, | ||
systemCertificates: systemCertificates, | ||
certificates: make(map[string]CertificateInterface), | ||
certificates: []CertificateInterface{}, | ||
} | ||
if ca != nil { | ||
bundle.certificates = append(bundle.certificates, ca) | ||
} | ||
bundle.AddCertificates(certificates...) | ||
|
||
|
@@ -94,21 +102,13 @@ func createTrustedBundle(includeSystemBundle bool, name string, certificates ... | |
// AddCertificates Adds the certificates to the bundle. | ||
func (t *trustedBundle) AddCertificates(certificates ...CertificateInterface) { | ||
for _, cert := range certificates { | ||
// Check if we already trust an issuer of this cert. In practice, this will be 0 or 1 iteration, | ||
// because the issuer is only set when the tigera-ca-private is the issuer. | ||
cur := cert | ||
var skip bool | ||
for cur != nil && !skip { | ||
hash := rmeta.AnnotationHash(cur.GetCertificatePEM()) | ||
cur = cur.GetIssuer() | ||
if _, found := t.certificates[hash]; found { | ||
skip = true | ||
if cert != nil { | ||
// Only if a certificate was not signed by our operator, we should add it to the bundle. | ||
if cert.GetIssuer() != nil && t.ca != nil && | ||
string(cert.GetIssuer().GetCertificatePEM()) == string(t.ca.GetCertificatePEM()) { | ||
continue | ||
} | ||
} | ||
if cert != nil && !skip { | ||
// Add the leaf certificate | ||
hash := rmeta.AnnotationHash(cert.GetCertificatePEM()) | ||
t.certificates[hash] = cert | ||
t.certificates = append(t.certificates, cert) | ||
} | ||
} | ||
} | ||
|
@@ -119,8 +119,8 @@ func (t *trustedBundle) MountPath() string { | |
|
||
func (t *trustedBundle) HashAnnotations() map[string]string { | ||
annotations := make(map[string]string) | ||
for hash, cert := range t.certificates { | ||
annotations[fmt.Sprintf("%s.hash.operator.tigera.io/%s", cert.GetNamespace(), cert.GetName())] = hash | ||
for _, cert := range t.certificates { | ||
annotations[fmt.Sprintf("%s.hash.operator.tigera.io/%s", cert.GetNamespace(), cert.GetName())] = rmeta.AnnotationHash(cert.GetCertificatePEM()) | ||
} | ||
if len(t.systemCertificates) > 0 { | ||
annotations["hash.operator.tigera.io/system"] = rmeta.AnnotationHash(t.systemCertificates) | ||
|
@@ -174,10 +174,8 @@ func (t *trustedBundle) ConfigMap(namespace string) *corev1.ConfigMap { | |
|
||
// Sort the certificates so that we get a consistent ordering. | ||
// This reduces the number of changes we see in the configmap. | ||
certs := []CertificateInterface{} | ||
for _, cert := range t.certificates { | ||
certs = append(certs, cert) | ||
} | ||
var certs []CertificateInterface | ||
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. Changed because it failed static checks. |
||
certs = append(certs, t.certificates...) | ||
sort.Slice(certs, func(i, j int) bool { | ||
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. Is this sorting still needed ? If so, why can't we move this sorting after adding all certificates so that it is available for everybody ? 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. Good point, I think that there should not be a need for it, as the order in which things are added to the bundle (which is now backed by a slice, rather than a map) is deterministic. 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. We decided to keep the sorting regardless. (See last commit message). |
||
return certs[i].GetName() < certs[j].GetName() | ||
}) | ||
|
@@ -249,12 +247,13 @@ var certFiles = []string{ | |
func getSystemCertificates() ([]byte, 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. Removed redundancy which failed the static-checks. |
||
for _, filename := range certFiles { | ||
data, err := os.ReadFile(filename) | ||
if err == nil { | ||
if err != nil { | ||
if !os.IsNotExist(err) { | ||
return nil, fmt.Errorf(fmt.Sprintf("error occurred when loading system root certificate with name %s", filename), err) | ||
} | ||
} else { | ||
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. Nit: No need for else. 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. I think it is needed, if we don't have the else then we'd do the return when os.IsNotExist(err) is true. 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. That's right. |
||
return data, nil | ||
} | ||
if err != nil && !os.IsNotExist(err) { | ||
return nil, fmt.Errorf(fmt.Sprintf("error occurred when loading system root certificate with name %s", filename), err) | ||
} | ||
} | ||
return nil, 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.
Changed for consistency, to ensure that every bundle will contain the ca as well.