Skip to content

Commit

Permalink
Merge pull request #10 from serverscom/tls-from-annotations
Browse files Browse the repository at this point in the history
add ability to specify tls certs in annotations
  • Loading branch information
olegy89 authored Aug 5, 2024
2 parents 9bfb39a + dc9bb0b commit ea370fa
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 21 deletions.
56 changes: 39 additions & 17 deletions internal/service/sync/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,30 @@ import (
networkv1 "k8s.io/api/networking/v1"
)

const (
TLS_ANNOTATION_PREFIX = "servers.com/certificate-"
)

// SyncTLS syncs ingress tls certs stored in secrets to portal.
// If secret name starts with certManagerPrefix-<certID> we looking for cert from API
// Due to secret name don't support upperCase for such cases we additionally checks annotations
// with TLS_ANNOTATION_PREFIX which overrides ingress tls certs for matching hosts.
// Returns map of hosts to portal cert id
func (s *SyncManager) SyncTLS(ingress *networkv1.Ingress, certManagerPrefix string) (map[string]string, error) {
var sslCerts = make(map[string]string)
for _, tls := range ingress.Spec.TLS {
if strings.HasPrefix(tls.SecretName, certManagerPrefix) {
id := strings.TrimPrefix(tls.SecretName, certManagerPrefix)

hostsSecrets := mergeTLSWithAnnotations(ingress)
for host, secretName := range hostsSecrets {
if strings.HasPrefix(secretName, certManagerPrefix) {
id := strings.TrimPrefix(secretName, certManagerPrefix)
certificate, err := s.tlsMgr.GetByID(id)
if err != nil {
return nil, fmt.Errorf("fetching cert with id %q from API failed: %v", id, err)
}
for _, host := range tls.Hosts {
sslCerts[host] = certificate.ID
}
sslCerts[host] = certificate.ID
continue
}
sKey := ingress.Namespace + "/" + tls.SecretName
sKey := ingress.Namespace + "/" + secretName
secret, err := s.store.GetSecret(sKey)
if err != nil {
return nil, fmt.Errorf("fetching secret with key %q from store failed: %v", sKey, err)
Expand All @@ -47,28 +54,22 @@ func (s *SyncManager) SyncTLS(ingress *networkv1.Ingress, certManagerPrefix stri
primary, chain := tlsmanager.SplitCerts(cert)

fingerprint := tlsmanager.GetPemFingerprint(primary)

if fingerprint == "" {
return nil, fmt.Errorf("can't calculate 'tls.crt' fingerprint for %s", string(cert))
}

if s.tlsMgr.HasRegistration(fingerprint) {
certificate, err := s.tlsMgr.Get(fingerprint)

if err != nil {
return nil, err
}

for _, host := range tls.Hosts {
sslCerts[host] = certificate.ID
}

sslCerts[host] = certificate.ID
continue
}

certificate, err := s.tlsMgr.SyncCertificate(
fingerprint,
tls.SecretName,
secretName,
primary,
tlsmanager.StripSpaces(key),
chain,
Expand All @@ -78,10 +79,31 @@ func (s *SyncManager) SyncTLS(ingress *networkv1.Ingress, certManagerPrefix stri
return nil, err
}

sslCerts[host] = certificate.ID
}
return sslCerts, nil
}

// mergeTLSWithAnnotations merge info about host and associated secret from ingress.Spec.TLS and ingress.Annotations
// returns map[host]secret
func mergeTLSWithAnnotations(ingress *networkv1.Ingress) map[string]string {
res := make(map[string]string)

for _, tls := range ingress.Spec.TLS {
sName := tls.SecretName
for _, host := range tls.Hosts {
sslCerts[host] = certificate.ID
res[host] = sName
}
}

// annotations overrides settings from tls
for k, v := range ingress.Annotations {
if strings.HasPrefix(k, TLS_ANNOTATION_PREFIX) {
if host, ok := strings.CutPrefix(k, TLS_ANNOTATION_PREFIX); ok {
res[host] = v
}
}
}
return sslCerts, nil

return res
}
17 changes: 13 additions & 4 deletions internal/service/sync/tls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"go.uber.org/mock/gomock"
v1 "k8s.io/api/core/v1"
networkv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var (
Expand All @@ -38,6 +39,11 @@ func TestSyncTLS(t *testing.T) {
},
},
},
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
TLS_ANNOTATION_PREFIX + "example1.com": "test-secret",
},
},
}
ingress.Namespace = "default"

Expand All @@ -51,9 +57,9 @@ func TestSyncTLS(t *testing.T) {

t.Run("Successfully syncing TLS", func(t *testing.T) {
g := NewWithT(t)
storeHandler.EXPECT().GetSecret("default/test-secret").Return(secret, nil)
storeHandler.EXPECT().GetSecret("default/test-secret").Return(secret, nil).Times(2)

tlsManagerHandler.EXPECT().HasRegistration(testdata.ValidPEMFingerprint).Return(false)
tlsManagerHandler.EXPECT().HasRegistration(testdata.ValidPEMFingerprint).Return(false).Times(2)

expectedCert := &client.SSLCertificate{ID: "cert-id"}
tlsManagerHandler.EXPECT().SyncCertificate(
Expand All @@ -62,11 +68,12 @@ func TestSyncTLS(t *testing.T) {
gomock.Any(),
gomock.Any(),
gomock.Any()).
Return(expectedCert, nil)
Return(expectedCert, nil).Times(2)

result, err := syncManager.SyncTLS(ingress, scCertManagerPrefix)
g.Expect(err).To(BeNil())
g.Expect(result).To(HaveKeyWithValue("example.com", "cert-id"))
g.Expect(result).To(HaveKeyWithValue("example1.com", "cert-id"))
})

t.Run("Error fetching secret", func(t *testing.T) {
Expand Down Expand Up @@ -131,12 +138,14 @@ func TestSyncTLS(t *testing.T) {
g := NewWithT(t)

ingress.Spec.TLS[0].SecretName = scCertManagerPrefix + "someid"
ingress.Annotations[TLS_ANNOTATION_PREFIX+"example1.com"] = scCertManagerPrefix + "someid"
tlsManagerHandler.EXPECT().
GetByID("someid").
Return(&serverscom.SSLCertificate{ID: "someid"}, nil)
Return(&serverscom.SSLCertificate{ID: "someid"}, nil).Times(2)

result, err := syncManager.SyncTLS(ingress, scCertManagerPrefix)
g.Expect(err).To(BeNil())
g.Expect(result).To(HaveKeyWithValue("example.com", "someid"))
g.Expect(result).To(HaveKeyWithValue("example1.com", "someid"))
})
}

0 comments on commit ea370fa

Please sign in to comment.