Skip to content
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

adding support for secrets for backendtlspolicy #3084

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

porthorian
Copy link

@porthorian porthorian commented Feb 3, 2025

Proposed changes

The proposed changes here adds the support for Secrets to be used according to the BackednTLSPolicy Custom Resource. This helps further the implementation of nginx-gateway-fabric to support the Gateway API more.

Problem

Currently BackendTLSPolicy only supports readying in tls certifications and ca certifications via a config map. This does not work when you are using cert-manager for instance since it puts this information into a kubernetes secret rather then a config map.

Solution

The Solution here is to hook into the existing Configuration structure that builds the dataplane nginx configuration that is served in the pod. Allowing for secrets and configmaps to be read into this array of CertBundles.

Testing

Did some end to end testing here and built 2 packages that can be used with this code.

https://github.com/porthorian/nginx-gateway-fabric/pkgs/container/nginx-gateway-fabric%2Fnginx
https://github.com/porthorian/nginx-gateway-fabric/pkgs/container/nginx-gateway-fabric

These were then deployed and made a BackendTLSPolicy with the secret that was created with cert-manager.

apiVersion: gateway.networking.k8s.io/v1alpha3
kind: BackendTLSPolicy
metadata:
  name: tls-upstream-unifi
spec:
  targetRefs:
    - kind: Service
      name: unifi
      group: ""
  validation:
    caCertificateRefs:
      - name: unifi-signed-cert
        group: ''
        kind: Secret
    hostname: {your-domain-name}



apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: self-signed-svc-cert
spec:
  dnsNames:
    - {your-domain-name}
  secretName: unifi-signed-cert
  commonName: unifi
  issuerRef:
    name: self-signed-ca-issuer
    kind: ClusterIssuer
    group: cert-manager.io
  keystores:
    jks:
      alias: unifi
      create: true
      passwordSecretRef:
        name: unifi-keystore
        key: password

Reviewer Focus

Since this is a working draft here - places that should be focused on is making sure I am inline with the current standards and everyone is statisified with how this was structurally laid out before moving onto polishing it up and writing some additional tests.

Issues

Closes #2629

Checklist

Before creating a PR, run through this checklist and mark each as complete.

  • I have read the CONTRIBUTING doc
  • I have added tests that prove my fix is effective or that my feature works
  • I have checked that all unit tests pass after adding my changes
  • I have updated necessary documentation
  • I have rebased my branch onto main
  • I will ensure my PR is targeting the main branch and pulling from my branch from my own fork

Release notes

* Adds support for secrets to be used in BackendTLSPolicy Gateway API for tls certificates and ca certificates.

@porthorian porthorian requested a review from a team as a code owner February 3, 2025 00:39
Copy link
Collaborator

@sjberman sjberman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall I think the approach looks good here! Haven't yet tested it myself, but will get around to that. Thanks for this.

Comment on lines +73 to +75
CertBundles: buildCertBundles(
buildRefCertificateBundles(g.ReferencedSecrets, g.ReferencedCaCertConfigMaps),
backendGroups),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
CertBundles: buildCertBundles(
buildRefCertificateBundles(g.ReferencedSecrets, g.ReferencedCaCertConfigMaps),
backendGroups),
CertBundles: buildCertBundles(
buildRefCertificateBundles(g.ReferencedSecrets, g.ReferencedCaCertConfigMaps),
backendGroups,
),

nit: style

Comment on lines +242 to +244
func buildRefCertificateBundles(
secrets map[types.NamespacedName]*graph.Secret,
configMaps map[types.NamespacedName]*graph.CaCertConfigMap) []graph.CertificateBundle {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func buildRefCertificateBundles(
secrets map[types.NamespacedName]*graph.Secret,
configMaps map[types.NamespacedName]*graph.CaCertConfigMap) []graph.CertificateBundle {
func buildRefCertificateBundles(
secrets map[types.NamespacedName]*graph.Secret,
configMaps map[types.NamespacedName]*graph.CaCertConfigMap,
) []graph.CertificateBundle {

nit: style

path := field.NewPath("tls.cacertrefs[0]")
return field.Invalid(path, btp.Spec.Validation.CACertificateRefs[0], err.Error())

if selectedCertRef.Kind == "ConfigMap" {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do a switch statement on the Kinds

return field.Invalid(path, selectedCertRef, err.Error())
}
} else {
return fmt.Errorf("`%s` invalid certificate reference supported", selectedCertRef.Kind)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return fmt.Errorf("`%s` invalid certificate reference supported", selectedCertRef.Kind)
return fmt.Errorf("invalid certificate reference %q", selectedCertRef.Kind)

}
block, _ := pem.Decode(data)
if block == nil {
return fmt.Errorf("the data field %s must hold a valid CERTIFICATE PEM block", CAKey)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return fmt.Errorf("the data field %s must hold a valid CERTIFICATE PEM block", CAKey)
return fmt.Errorf("the data field %q must hold a valid CERTIFICATE PEM block", CAKey)

%q will wrap the string in quotes so it's easier to spot in the message.

(I know this was just copied here, but figured we might as well fix it)

return fmt.Errorf("the data field %s must hold a valid CERTIFICATE PEM block", CAKey)
}
if block.Type != "CERTIFICATE" {
return fmt.Errorf("the data field %s must hold a valid CERTIFICATE PEM block, but got '%s'", CAKey, block.Type)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return fmt.Errorf("the data field %s must hold a valid CERTIFICATE PEM block, but got '%s'", CAKey, block.Type)
return fmt.Errorf("the data field %q must hold a valid CERTIFICATE PEM block, but got %q", CAKey, block.Type)

@sindhushiv sindhushiv added this to the v2.0.0 milestone Feb 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: External Pull Requests
Development

Successfully merging this pull request may close these issues.

Allowing CACertificateRef to be loaded from a secret
3 participants