Skip to content

Commit

Permalink
implement configuration option
Browse files Browse the repository at this point in the history
  • Loading branch information
porthorian committed Jan 17, 2025
1 parent 8b85f01 commit 13074ee
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 37 deletions.
50 changes: 33 additions & 17 deletions internal/mode/static/state/dataplane/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,14 @@ func BuildConfiguration(
BackendGroups: backendGroups,
SSLKeyPairs: buildSSLKeyPairs(g.ReferencedSecrets, g.Gateway.Listeners),
Version: configVersion,
CertBundles: buildCertBundles(g.ReferencedCaCertConfigMaps, backendGroups),
Telemetry: buildTelemetry(g),
BaseHTTPConfig: baseHTTPConfig,
Logging: buildLogging(g),
MainSnippets: buildSnippetsForContext(g.SnippetsFilters, ngfAPI.NginxContextMain),
AuxiliarySecrets: buildAuxiliarySecrets(g.PlusSecrets),
CertBundles: buildCertBundles(
buildRefCertificateBundles(g.ReferencedSecrets, g.ReferencedCaCertConfigMaps),
backendGroups),
Telemetry: buildTelemetry(g),
BaseHTTPConfig: baseHTTPConfig,
Logging: buildLogging(g),
MainSnippets: buildSnippetsForContext(g.SnippetsFilters, ngfAPI.NginxContextMain),
AuxiliarySecrets: buildAuxiliarySecrets(g.PlusSecrets),
}

return config
Expand Down Expand Up @@ -224,8 +226,24 @@ func buildSSLKeyPairs(
return keyPairs
}

func buildRefCertificateBundles(
secrets map[types.NamespacedName]*graph.Secret,
configMaps map[types.NamespacedName]*graph.CaCertConfigMap) []graph.CertificateBundle {
bundles := []graph.CertificateBundle{}

for _, secret := range secrets {
bundles = append(bundles, *secret.CertBundle)
}

for _, configMap := range configMaps {
bundles = append(bundles, *configMap.CertBundle)
}

return bundles
}

func buildCertBundles(
caCertConfigMaps map[types.NamespacedName]*graph.CaCertConfigMap,
refCertBundles []graph.CertificateBundle,
backendGroups []BackendGroup,
) map[CertBundleID]CertBundle {
bundles := make(map[CertBundleID]CertBundle)
Expand All @@ -247,18 +265,16 @@ func buildCertBundles(
}
}

for cmName, cm := range caCertConfigMaps {
id := generateCertBundleID(cmName)
for _, bundle := range refCertBundles {
id := generateCertBundleID(bundle.Name)
if _, exists := refByBG[id]; exists {
if cm.CACert != nil || len(cm.CACert) > 0 {
// the cert could be base64 encoded or plaintext
data := make([]byte, base64.StdEncoding.DecodedLen(len(cm.CACert)))
_, err := base64.StdEncoding.Decode(data, cm.CACert)
if err != nil {
data = cm.CACert
}
bundles[id] = data
// the cert could be base64 encoded or plaintext
data := make([]byte, base64.StdEncoding.DecodedLen(len(bundle.Cert.CACert)))
_, err := base64.StdEncoding.Decode(data, bundle.Cert.CACert)
if err != nil {
data = bundle.Cert.CACert
}
bundles[id] = data
}
}

Expand Down
24 changes: 14 additions & 10 deletions internal/mode/static/state/graph/certificate_bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,33 @@ const CAKey = "ca.crt"
type CertificateBundle struct {
Name types.NamespacedName
Kind v1.Kind
Cert *Certificate
}

// Required ...
type Certificate struct {
TLSCert []byte
TLSPrivateKey []byte
CACert []byte
}

// Optional
CACert []byte
func NewCertificateBundle(name types.NamespacedName, kind string, cert *Certificate) *CertificateBundle {
return &CertificateBundle{
Name: name,
Kind: v1.Kind(kind),
Cert: cert,
}
}

func (cb *CertificateBundle) validate() error {
_, err := tls.X509KeyPair(cb.TLSCert, cb.TLSPrivateKey)
func validateTLS(tlsCert, tlsPrivateKey []byte) error {
_, err := tls.X509KeyPair(tlsCert, tlsPrivateKey)
if err != nil {
return fmt.Errorf("TLS secret is invalid: %w", err)
}

if err = validateCA(cb.CACert); len(cb.CACert) >= 1 && err != nil {
return fmt.Errorf("Certificate in secret is invalid: %w", err)
}

return nil
}

// validateCA validates the ca.crt entry in the ConfigMap. If it is valid, the function returns nil.
// validateCA validates the ca.crt entry in the Certificate. If it is valid, the function returns nil.
func validateCA(caData []byte) error {
data := make([]byte, base64.StdEncoding.DecodedLen(len(caData)))
_, err := base64.StdEncoding.Decode(data, caData)
Expand Down
15 changes: 8 additions & 7 deletions internal/mode/static/state/graph/configmaps.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ type CaCertConfigMap struct {
// Source holds the actual ConfigMap resource. Can be nil if the ConfigMap does not exist.
Source *apiv1.ConfigMap
// CACert holds the actual CA Cert data.
CACert []byte
CACert []byte
CertBundle *CertificateBundle
}

type caCertConfigMapEntry struct {
Expand Down Expand Up @@ -44,32 +45,32 @@ func (r *configMapResolver) resolve(nsname types.NamespacedName) error {
cm, exist := r.clusterConfigMaps[nsname]

var validationErr error
var caCert []byte
cert := &Certificate{}

if !exist {
validationErr = errors.New("ConfigMap does not exist")
} else {
if cm.Data != nil {
if _, exists := cm.Data[CAKey]; exists {
validationErr = validateCA([]byte(cm.Data[CAKey]))
caCert = []byte(cm.Data[CAKey])
cert.CACert = []byte(cm.Data[CAKey])
}
}
if cm.BinaryData != nil {
if _, exists := cm.BinaryData[CAKey]; exists {
validationErr = validateCA(cm.BinaryData[CAKey])
caCert = cm.BinaryData[CAKey]
cert.CACert = cm.BinaryData[CAKey]
}
}
if len(caCert) == 0 {
if len(cert.CACert) == 0 {
validationErr = fmt.Errorf("ConfigMap does not have the data or binaryData field %v", CAKey)
}
}

r.resolvedCaCertConfigMaps[nsname] = &caCertConfigMapEntry{
caCertConfigMap: CaCertConfigMap{
Source: cm,
CACert: caCert,
Source: cm,
CertBundle: NewCertificateBundle(nsname, "ConfigMap", cert),
},
err: validationErr,
}
Expand Down
9 changes: 6 additions & 3 deletions internal/mode/static/state/graph/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,20 @@ func (r *secretResolver) resolve(nsname types.NamespacedName) error {

default:
// A TLS Secret is guaranteed to have these data fields.
certBundle = &CertificateBundle{
cert := &Certificate{
TLSCert: secret.Data[apiv1.TLSCertKey],
TLSPrivateKey: secret.Data[apiv1.TLSPrivateKeyKey],
}

// Not always guaranteed to have a ca certificate in the secret.
if _, exists := secret.Data[CAKey]; exists {
certBundle.CACert = secret.Data[CAKey]
cert.CACert = secret.Data[CAKey]
}

validationErr = certBundle.validate()
validationErr = validateTLS(cert.TLSCert, cert.TLSPrivateKey)
validationErr = validateCA(cert.CACert)

certBundle = NewCertificateBundle(nsname, secret.Kind, cert)
}

r.resolvedSecrets[nsname] = &secretEntry{
Expand Down

0 comments on commit 13074ee

Please sign in to comment.