Skip to content

Commit

Permalink
support renegotiationEnabled on ssl custom profiles (#3219)
Browse files Browse the repository at this point in the history
  • Loading branch information
lavanya-f5 authored Jan 5, 2024
1 parent 4429cf2 commit 3732736
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 58 deletions.
24 changes: 18 additions & 6 deletions config/apis/cis/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,12 +178,24 @@ type TLSProfileSpec struct {

// TLS contains required fields for TLS termination
type TLS struct {
Termination string `json:"termination"`
ClientSSL string `json:"clientSSL"`
ClientSSLs []string `json:"clientSSLs"`
ServerSSL string `json:"serverSSL"`
ServerSSLs []string `json:"serverSSLs"`
Reference string `json:"reference"`
Termination string `json:"termination"`
ClientSSL string `json:"clientSSL"`
ClientSSLs []string `json:"clientSSLs"`
ServerSSL string `json:"serverSSL"`
ServerSSLs []string `json:"serverSSLs"`
Reference string `json:"reference"`
ClientSSLParams ClientSSLParams `json:"clientSSLParams"`
ServerSSLParams ServerSSLParams `json:"serverSSLParams"`
}

// ClientSSLParams contains required fields for Client SSL
type ClientSSLParams struct {
RenegotiationEnabled *bool `json:"renegotiationEnabled,omitempty"`
}

// ServerSSLParams contains required fields for Server SSL
type ServerSSLParams struct {
RenegotiationEnabled *bool `json:"renegotiationEnabled,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
Expand Down
30 changes: 22 additions & 8 deletions docs/config_examples/customResource/CustomResource.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,14 +173,28 @@ Note: **monitors** take priority over **monitor** if both are provided in VS spe

**TLSProfile Components**

| PARAMETER | TYPE | REQUIRED | DEFAULT | DESCRIPTION |
|-------------|----------------|-------------|---------|-----------------------------------------------------------------------------------------------------|
| termination | String | Required | NA | Termination on BIG-IP Virtual Server. Allowed options are [edge, reencrypt, passthrough] |
| clientSSL | String | Required | NA | Single ClientSSL Profile on the BIG-IP OR a kubernetes secret. |
| clientSSLs | List of string | Required | NA | Multiple ClientSSL Profiles on the BIG-IP OR list of kubernetes secrets. |
| serverSSL | String | Optional | NA | Single ServerSSL Profile on the BIG-IP OR a kubernetes secret. |
| serverSSLs | List of string | Optional | NA | Multiple ServerSSL Profiles on the BIG-IP OR list of kubernetes secrets. |
| reference | String | Required | NA | Describes the location of profile, BIG-IP or k8s Secrets. We currently support BIG-IP profiles only |
| PARAMETER | TYPE | REQUIRED | DEFAULT | DESCRIPTION |
|-----------------|----------------|----------|---------|----------------------------------------------------------------------------------------------------------------|
| termination | String | Required | NA | Termination on BIG-IP Virtual Server. Allowed options are [edge, reencrypt, passthrough] |
| clientSSL | String | Required | NA | Single ClientSSL Profile on the BIG-IP OR a kubernetes secret. |
| clientSSLs | List of string | Required | NA | Multiple ClientSSL Profiles on the BIG-IP OR list of kubernetes secrets. |
| serverSSL | String | Optional | NA | Single ServerSSL Profile on the BIG-IP OR a kubernetes secret. |
| serverSSLs | List of string | Optional | NA | Multiple ServerSSL Profiles on the BIG-IP OR list of kubernetes secrets. |
| reference | String | Required | NA | Describes the location of profile, BIG-IP or k8s Secrets. We currently support BIG-IP profiles only |
| clientSSLParams | Object | Optional | NA | List of settings that needs to be applied to clientSSL custom profiles created by CIS through reference secret |
| serverSSLParams | Object | Optional | NA | List of settings that needs to be applied to serverSSL custom profiles created by CIS through reference secret |

**ClientSSLParams**

| PARAMETER | TYPE | REQUIRED | DEFAULT | DESCRIPTION |
|----------------------|---------|----------|---------|-----------------------------------------------------------------------------------------------------------|
| renegotiationEnabled | Boolean | Optional | true | If false, disables renegotiation on the custom clientssl profile created by CIS through reference secret. |

**ServerSSLParams**

| PARAMETER | TYPE | REQUIRED | DEFAULT | DESCRIPTION |
|----------------------|---------|----------|---------|-----------------------------------------------------------------------------------------------------------|
| renegotiationEnabled | Boolean | Optional | true | If false, disables renegotiation on the custom serverssl profile created by CIS through reference secret. |

**Note**:
* CIS has a 1:1 mapping for a domain(CommonName) and BIG-IP-VirtualServer.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Disable Renegotiation on Custom SSL Profiles created by CIS through secrets

## tls-ssl-secrets-renegotiation-disabled.yml

By deploying this yaml file in your cluster, CIS will create custom SSL profiles with renegotiation disabled on BIG-IP.

## virtualserver.yml
By deploying this yaml file in your cluster, CIS will create a Virtual Server on BIG-IP with VIP "172.16.3.5".
It will load balance the traffic for domain coffee.example.com
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
apiVersion: cis.f5.com/v1
kind: TLSProfile
metadata:
name: reencrypt-tls-coffee
labels:
f5cr: "true"
spec:
tls:
termination: reencrypt
clientSSL: clientssl-secret
serverSSLs: serverssl-secret
reference: secret
clientSSLParams:
renegotiationEnabled: false
sererSSLParams:
renegotiationEnabled: false
hosts:
- coffee.example.com
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: cis.f5.com/v1
kind: VirtualServer
metadata:
labels:
f5cr: "true"
name: coffee-virtual-server
namespace: default
spec:
tlsProfileName: reencrypt-tls-coffee
host: coffee.example.com
pools:
- path: /lattee
service: svc
servicePort: 80
virtualServerAddress: 172.16.3.5
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,18 @@ spec:
reference:
type: string
enum: [bigip, secret]
clientSSLParams:
type: object
properties:
renegotiationEnabled:
type: boolean
default: true
serverSSLParams:
type: object
properties:
renegotiationEnabled:
type: boolean
default: true
required:
- termination

Expand Down
7 changes: 6 additions & 1 deletion pkg/controller/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -1457,7 +1457,9 @@ func createUpdateTLSServer(prof CustomProfile, svcName string, sharedApp as3Appl
} else {
tlsServer.Ciphers = prof.Ciphers
}

if prof.RenegotiationEnabled != nil {
tlsServer.RenegotiationEnabled = prof.RenegotiationEnabled
}
sharedApp[tlsServerName] = tlsServer
svc.ServerTLS = tlsServerName
updateVirtualToHTTPS(svc)
Expand Down Expand Up @@ -1541,6 +1543,9 @@ func createTLSClient(
} else {
tlsClient.Ciphers = prof.Ciphers
}
if prof.RenegotiationEnabled != nil {
tlsClient.RenegotiationEnabled = prof.RenegotiationEnabled
}
sharedApp[tlsClientName] = tlsClient
svc.ClientTLS = tlsClientName
updateVirtualToHTTPS(svc)
Expand Down
14 changes: 10 additions & 4 deletions pkg/controller/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ func (ctlr *Controller) createSecretClientSSLProfile(
secrets []*v1.Secret,
tlsCipher TLSCipher,
context string,
renegotiationEnabled *bool,
) (error, bool) {

var certificates []certificate
Expand All @@ -35,7 +36,7 @@ func (ctlr *Controller) createSecretClientSSLProfile(
certificates = append(certificates, cert)
}

return ctlr.createClientSSLProfile(rsCfg, certificates, secrets[0].ObjectMeta.Name, secrets[0].ObjectMeta.Namespace, tlsCipher, context)
return ctlr.createClientSSLProfile(rsCfg, certificates, secrets[0].ObjectMeta.Name, secrets[0].ObjectMeta.Namespace, tlsCipher, context, renegotiationEnabled)
}

// Creates a new ClientSSL profile from a Secret
Expand All @@ -46,6 +47,7 @@ func (ctlr *Controller) createClientSSLProfile(
namespace string,
tlsCipher TLSCipher,
context string,
renegotiationEnabled *bool,
) (error, bool) {

// Create Default for SNI profile
Expand All @@ -60,7 +62,7 @@ func (ctlr *Controller) createClientSSLProfile(
}
if _, ok := rsCfg.customProfiles[skey]; !ok {
// This is just a basic profile, so we don't need all the fields
cp := NewCustomProfile(sni, []certificate{}, "", true, "", "", "", tlsCipher)
cp := NewCustomProfile(sni, []certificate{}, "", true, "", "", "", tlsCipher, renegotiationEnabled)
rsCfg.customProfiles[skey] = cp
}

Expand All @@ -83,6 +85,7 @@ func (ctlr *Controller) createClientSSLProfile(
"", // caFile
"", // chainCA,
tlsCipher,
renegotiationEnabled,
)
skey = SecretKey{
Name: cp.Name,
Expand All @@ -108,6 +111,7 @@ func (ctlr *Controller) createSecretServerSSLProfile(
secrets []*v1.Secret,
tlsCipher TLSCipher,
context string,
renegotiationEnabled *bool,
) (error, bool) {

var certificates []certificate
Expand All @@ -123,7 +127,7 @@ func (ctlr *Controller) createSecretServerSSLProfile(
}
certificates = append(certificates, cert)
}
return ctlr.createServerSSLProfile(rsCfg, certificates, "", secrets[0].ObjectMeta.Name, secrets[0].ObjectMeta.Namespace, tlsCipher, context)
return ctlr.createServerSSLProfile(rsCfg, certificates, "", secrets[0].ObjectMeta.Name, secrets[0].ObjectMeta.Namespace, tlsCipher, context, renegotiationEnabled)
}

// Creates a new ServerSSL profile from a Secret
Expand All @@ -135,6 +139,7 @@ func (ctlr *Controller) createServerSSLProfile(
namespace string,
tlsCipher TLSCipher,
context string,
renegotiationEnabled *bool,
) (error, bool) {

// Create Default for SNI profile
Expand All @@ -149,7 +154,7 @@ func (ctlr *Controller) createServerSSLProfile(
}
if _, ok := rsCfg.customProfiles[skey]; !ok {
// This is just a basic profile, so we don't need all the fields
cp := NewCustomProfile(sni, []certificate{}, "", true, "", "", "", tlsCipher)
cp := NewCustomProfile(sni, []certificate{}, "", true, "", "", "", tlsCipher, renegotiationEnabled)
rsCfg.customProfiles[skey] = cp
}
// TODO
Expand All @@ -171,6 +176,7 @@ func (ctlr *Controller) createServerSSLProfile(
"", // caFile
certchain, // certchain,
tlsCipher,
renegotiationEnabled,
)
skey = SecretKey{
Name: cp.Name,
Expand Down
28 changes: 17 additions & 11 deletions pkg/controller/profile_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package controller

import (
"fmt"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
v1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -53,27 +54,27 @@ var _ = Describe("Profile", func() {
secrets := []*v1.Secret{secret}
tlsCipher := mockCtlr.resources.supplementContextCache.baseRouteConfig.TLSCipher

err, updated := mockCtlr.createSecretClientSSLProfile(rsCfg, secrets, tlsCipher, "clientside")
err, updated := mockCtlr.createSecretClientSSLProfile(rsCfg, secrets, tlsCipher, "clientside", nil)
Expect(err).To(BeNil(), "Failed to Create Client SSL")
Expect(updated).To(BeFalse(), "Failed to Create Client SSL")

err, updated = mockCtlr.createSecretClientSSLProfile(rsCfg, secrets, tlsCipher, "clientside")
err, updated = mockCtlr.createSecretClientSSLProfile(rsCfg, secrets, tlsCipher, "clientside", nil)
Expect(err).To(BeNil(), "Failed to Create Client SSL")
Expect(updated).To(BeFalse(), "Failed to Create Client SSL")

secret.Data["tls.crt"] = []byte("dfaf")
err, updated = mockCtlr.createSecretClientSSLProfile(rsCfg, secrets, tlsCipher, "clientside")
err, updated = mockCtlr.createSecretClientSSLProfile(rsCfg, secrets, tlsCipher, "clientside", nil)
Expect(err).To(BeNil(), "Failed to Update Client SSL")
Expect(updated).To(BeTrue(), "Failed to Update Client SSL")

// Negative Cases
delete(secret.Data, "tls.crt")
err, updated = mockCtlr.createSecretClientSSLProfile(rsCfg, secrets, tlsCipher, "clientside")
err, updated = mockCtlr.createSecretClientSSLProfile(rsCfg, secrets, tlsCipher, "clientside", nil)
Expect(err).ToNot(BeNil(), "Failed to Validate Client SSL")
Expect(updated).To(BeFalse(), "Failed to Validate Client SSL")

delete(secret.Data, "tls.key")
err, updated = mockCtlr.createSecretClientSSLProfile(rsCfg, secrets, tlsCipher, "clientside")
err, updated = mockCtlr.createSecretClientSSLProfile(rsCfg, secrets, tlsCipher, "clientside", nil)
Expect(err).ToNot(BeNil(), "Failed to Validate Client SSL")
Expect(updated).To(BeFalse(), "Failed to Validate Client SSL")

Expand Down Expand Up @@ -108,22 +109,27 @@ var _ = Describe("Profile", func() {
secret.Data["tls.crt"] = []byte("ahfa;osejfn;kahse;ha")
secrets := []*v1.Secret{secret}
tlsCipher := mockCtlr.resources.supplementContextCache.baseRouteConfig.TLSCipher
err, updated := mockCtlr.createSecretServerSSLProfile(rsCfg, secrets, tlsCipher, "clientside")
renegotaiationEnabled := true
err, updated := mockCtlr.createSecretServerSSLProfile(rsCfg, secrets, tlsCipher, "clientside", &renegotaiationEnabled)
skey := SecretKey{
Name: fmt.Sprintf("default-%s-%s", "clientside", rsCfg.GetName()),
ResourceName: rsCfg.GetName(),
}
Expect(rsCfg.customProfiles[skey].RenegotiationEnabled).To(Equal(&renegotaiationEnabled), "Failed to Update renegotiationEnabled")
Expect(err).To(BeNil(), "Failed to Create Server SSL")
Expect(updated).To(BeFalse(), "Failed to Create Server SSL")

err, updated = mockCtlr.createSecretServerSSLProfile(rsCfg, secrets, tlsCipher, "clientside")
err, updated = mockCtlr.createSecretServerSSLProfile(rsCfg, secrets, tlsCipher, "clientside", nil)
Expect(err).To(BeNil(), "Failed to Create Server SSL")
Expect(updated).To(BeFalse(), "Failed to Create Server SSL")
Expect(updated).To(BeTrue(), "Failed to Create Server SSL")

secret.Data["tls.crt"] = []byte("dfaf")
err, updated = mockCtlr.createSecretServerSSLProfile(rsCfg, secrets, tlsCipher, "clientside")
err, updated = mockCtlr.createSecretServerSSLProfile(rsCfg, secrets, tlsCipher, "clientside", nil)
Expect(err).To(BeNil(), "Failed to Update Server SSL")
Expect(updated).To(BeTrue(), "Failed to Update Server SSL")

// Negative Cases
delete(secret.Data, "tls.crt")
err, updated = mockCtlr.createSecretServerSSLProfile(rsCfg, secrets, tlsCipher, "clientside")
err, updated = mockCtlr.createSecretServerSSLProfile(rsCfg, secrets, tlsCipher, "clientside", nil)
Expect(err).ToNot(BeNil(), "Failed to Validate Server SSL")
Expect(updated).To(BeFalse(), "Failed to Validate Server SSL")

Expand Down
16 changes: 11 additions & 5 deletions pkg/controller/resourceConfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ func NewCustomProfile(
caFile string,
chainCA string,
tlsCipher TLSCipher,
renegotiation *bool,
) CustomProfile {
cp := CustomProfile{
Name: profile.Name,
Expand All @@ -143,6 +144,9 @@ func NewCustomProfile(
PeerCertMode: peerCertMode,
ChainCA: chainCA,
}
if renegotiation != nil {
cp.RenegotiationEnabled = renegotiation
}
if peerCertMode == PeerCertRequired {
cp.CAFile = caFile
}
Expand Down Expand Up @@ -969,7 +973,7 @@ func (ctlr *Controller) handleTLS(
}
secrets = append(secrets, obj.(*v1.Secret))
}
err, _ := ctlr.createSecretClientSSLProfile(rsCfg, secrets, ctlr.resources.baseRouteConfig.TLSCipher, CustomProfileClient)
err, _ := ctlr.createSecretClientSSLProfile(rsCfg, secrets, ctlr.resources.baseRouteConfig.TLSCipher, CustomProfileClient, tlsContext.bigIPSSLProfiles.clientSSlParams.RenegotiationEnabled)
if err != nil {
log.Errorf("error %v encountered while creating clientssl profile for '%s' '%s'/'%s'",
err, tlsContext.resourceType, tlsContext.namespace, tlsContext.name)
Expand All @@ -991,7 +995,7 @@ func (ctlr *Controller) handleTLS(
return false
}
secrets = append(secrets, obj.(*v1.Secret))
err, _ = ctlr.createSecretServerSSLProfile(rsCfg, secrets, ctlr.resources.baseRouteConfig.TLSCipher, CustomProfileServer)
err, _ = ctlr.createSecretServerSSLProfile(rsCfg, secrets, ctlr.resources.baseRouteConfig.TLSCipher, CustomProfileServer, tlsContext.bigIPSSLProfiles.serverSSlParams.RenegotiationEnabled)
if err != nil {
log.Errorf("error %v encountered while creating serverssl profile for '%s' '%s'/'%s'",
err, tlsContext.resourceType, tlsContext.namespace, tlsContext.name)
Expand All @@ -1005,7 +1009,7 @@ func (ctlr *Controller) handleTLS(
if tlsContext.bigIPSSLProfiles.key != "" && tlsContext.bigIPSSLProfiles.certificate != "" {
cert := certificate{Cert: tlsContext.bigIPSSLProfiles.certificate, Key: tlsContext.bigIPSSLProfiles.key}
err, _ := ctlr.createClientSSLProfile(rsCfg, []certificate{cert},
fmt.Sprintf("%s-clientssl", tlsContext.name), tlsContext.namespace, ctlr.resources.baseRouteConfig.TLSCipher, CustomProfileClient)
fmt.Sprintf("%s-clientssl", tlsContext.name), tlsContext.namespace, ctlr.resources.baseRouteConfig.TLSCipher, CustomProfileClient, tlsContext.bigIPSSLProfiles.clientSSlParams.RenegotiationEnabled)
if err != nil {
log.Debugf("error %v encountered while creating clientssl profile for '%s' '%s'/'%s'",
err, tlsContext.resourceType, tlsContext.namespace, tlsContext.name)
Expand All @@ -1018,10 +1022,10 @@ func (ctlr *Controller) handleTLS(
cert := certificate{Cert: tlsContext.bigIPSSLProfiles.destinationCACertificate}
if tlsContext.bigIPSSLProfiles.caCertificate != "" {
err, _ = ctlr.createServerSSLProfile(rsCfg, []certificate{cert},
tlsContext.bigIPSSLProfiles.caCertificate, tlsContext.name, tlsContext.namespace, ctlr.resources.baseRouteConfig.TLSCipher, CustomProfileServer)
tlsContext.bigIPSSLProfiles.caCertificate, tlsContext.name, tlsContext.namespace, ctlr.resources.baseRouteConfig.TLSCipher, CustomProfileServer, tlsContext.bigIPSSLProfiles.serverSSlParams.RenegotiationEnabled)
} else {
err, _ = ctlr.createServerSSLProfile(rsCfg, []certificate{cert},
"", fmt.Sprintf("%s-serverssl", tlsContext.name), tlsContext.namespace, ctlr.resources.baseRouteConfig.TLSCipher, CustomProfileServer)
"", fmt.Sprintf("%s-serverssl", tlsContext.name), tlsContext.namespace, ctlr.resources.baseRouteConfig.TLSCipher, CustomProfileServer, tlsContext.bigIPSSLProfiles.serverSSlParams.RenegotiationEnabled)
}
if err != nil {
log.Debugf("error %v encountered while creating serverssl profile for '%s' '%s'/'%s'",
Expand Down Expand Up @@ -1216,12 +1220,14 @@ func (ctlr *Controller) handleVirtualServerTLS(
} else if tls.Spec.TLS.ClientSSL != "" {
bigIPSSLProfiles.clientSSLs = append(bigIPSSLProfiles.clientSSLs, tls.Spec.TLS.ClientSSL)
}
bigIPSSLProfiles.clientSSlParams = tls.Spec.TLS.ClientSSLParams
// Giving priority to ServerSSLs over ServerSSL
if len(tls.Spec.TLS.ServerSSLs) > 0 {
bigIPSSLProfiles.serverSSLs = tls.Spec.TLS.ServerSSLs
} else if tls.Spec.TLS.ServerSSL != "" {
bigIPSSLProfiles.serverSSLs = append(bigIPSSLProfiles.serverSSLs, tls.Spec.TLS.ServerSSL)
}
bigIPSSLProfiles.serverSSlParams = tls.Spec.TLS.ServerSSLParams
var poolPathRefs []poolPathRef
for _, pl := range vs.Spec.Pools {
poolBackends := ctlr.GetPoolBackends(&pl)
Expand Down
Loading

0 comments on commit 3732736

Please sign in to comment.