Skip to content

Commit

Permalink
Add TLS support for multiple endpoints and support for creating custo…
Browse files Browse the repository at this point in the history
…m Issuer

Some services create multiple endpoints, therefore have service per endpoint, which needs to support TLS.
The TypeSecretName is added to Service struct to support this scenario.

Signed-off-by: Veronika Fisarova <[email protected]>
  • Loading branch information
Deydra71 committed Nov 6, 2023
1 parent 46f2fdb commit aae9cda
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 1 deletion.
62 changes: 61 additions & 1 deletion modules/common/tls/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (

"github.com/openstack-k8s-operators/lib-common/modules/common/helper"
"github.com/openstack-k8s-operators/lib-common/modules/common/secret"
"github.com/openstack-k8s-operators/lib-common/modules/common/service"
corev1 "k8s.io/api/core/v1"
"k8s.io/utils/ptr"
)
Expand All @@ -39,6 +40,8 @@ type Service struct {
// +kubebuilder:validation:Optional
SecretName string `json:"secretName,omitempty"`
// +kubebuilder:validation:Optional
TypedSecretName map[service.Endpoint]string `json:"typedSecretName,omitempty"`
// +kubebuilder:validation:Optional
DisableNonTLSListeners bool `json:"disableNonTLSListeners,omitempty"`
}

Expand All @@ -50,13 +53,15 @@ type Ca struct {
}

// TLS - a generic type, which encapsulates both the service and CA configurations
// Service is for the services with a single endpoint
// TypedSecretName handles multiple service endpoints with respective secrets
type TLS struct {
Service *Service `json:"service"`
Ca *Ca `json:"ca"`
}

// NewTLS - initialize and return a TLS struct
func NewTLS(ctx context.Context, h *helper.Helper, namespace string, service *Service, ca *Ca) (*TLS, error) {
func NewTLS(ctx context.Context, h *helper.Helper, namespace string, service *Service, typedSecretNames map[service.Endpoint]string, ca *Ca) (*TLS, error) {

// Ensure service SecretName exists or return an error
if service != nil && service.SecretName != "" {
Expand All @@ -72,6 +77,21 @@ func NewTLS(ctx context.Context, h *helper.Helper, namespace string, service *Se
}
}

// Ensure the typed secret exists or return an error
if typedSecretNames != nil {
for endpoint, secretName := range typedSecretNames {
secretData, _, err := secret.GetSecret(ctx, h, secretName, namespace)
if err != nil {
return nil, fmt.Errorf("error ensuring secret %s for endpoint %v exists: %w", secretName, endpoint, err)
}
_, keyOk := secretData.Data["tls.key"]
_, certOk := secretData.Data["tls.crt"]
if !keyOk || !certOk {
return nil, fmt.Errorf("typed secret %s for endpoint %v does not contain both tls.key and tls.crt", secretName, endpoint)
}
}
}

return &TLS{
Service: service,
Ca: ca,
Expand All @@ -97,6 +117,21 @@ func (t *TLS) CreateVolumeMounts() []corev1.VolumeMount {
})
}

for endpoint := range t.Service.TypedSecretName {
// Use secretName to construct unique volume names and mount paths
volumeMounts = append(volumeMounts, corev1.VolumeMount{
Name: fmt.Sprintf("%s-tls-cert", endpoint),
MountPath: fmt.Sprintf("/etc/tls/%s/tls.crt", endpoint),
SubPath: "tls.crt",
ReadOnly: true,
}, corev1.VolumeMount{
Name: fmt.Sprintf("%s-tls-key", endpoint),
MountPath: fmt.Sprintf("/etc/tls/%s/tls.key", endpoint),
SubPath: "tls.key",
ReadOnly: true,
})
}

if t.Ca != nil && t.Ca.CaSecretName != "" {
volumeMounts = append(volumeMounts, corev1.VolumeMount{
Name: "ca-certs",
Expand Down Expand Up @@ -124,6 +159,18 @@ func (t *TLS) CreateVolumes() []corev1.Volume {
})
}

for endpoint, secretName := range t.Service.TypedSecretName {
volumes = append(volumes, corev1.Volume{
Name: fmt.Sprintf("%s-tls-certs", endpoint),
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: secretName,
DefaultMode: ptr.To[int32](0440),
},
},
})
}

if t.Ca != nil && t.Ca.CaSecretName != "" {
volumes = append(volumes, corev1.Volume{
Name: "ca-certs",
Expand Down Expand Up @@ -151,6 +198,19 @@ func (t *TLS) CreateDatabaseClientConfig() string {
"ssl-cert=/etc/pki/tls/certs/tls.crt",
"ssl-key=/etc/pki/tls/private/tls.key")
}

if len(t.Service.TypedSecretName) > 0 {
for endpoint := range t.Service.TypedSecretName {
tlsCertPath := fmt.Sprintf("/etc/tls/%s/tls.crt", endpoint)
tlsKeyPath := fmt.Sprintf("/etc/tls/%s/tls.key", endpoint)

conn = append(conn,
fmt.Sprintf("ssl-cert=%s", tlsCertPath),
fmt.Sprintf("ssl-key=%s", tlsKeyPath),
)
}
}

// Client uses a CA certificate that gets merged
// into the pod's CA bundle by kolla_start
if t.Ca.CaSecretName != "" {
Expand Down
44 changes: 44 additions & 0 deletions modules/common/tls/tls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,14 @@ package tls
import (
"strings"
"testing"

"github.com/openstack-k8s-operators/lib-common/modules/common/service"
)

type SecretType service.Endpoint

const TLSSecret SecretType = "TLSSecret"

func TestCreateVolumeMounts(t *testing.T) {
tests := []struct {
name string
Expand All @@ -40,6 +46,12 @@ func TestCreateVolumeMounts(t *testing.T) {
ca: &Ca{},
wantMountsLen: 2,
},
{
name: "Only Typed TLS Secret",
service: &Service{TypedSecretName: map[service.Endpoint]string{service.Endpoint(TLSSecret): "typed-test-tls-secret"}},
ca: &Ca{},
wantMountsLen: 2,
},
{
name: "Only CA Secret",
service: &Service{},
Expand All @@ -52,6 +64,12 @@ func TestCreateVolumeMounts(t *testing.T) {
ca: &Ca{CaSecretName: "test-ca1"},
wantMountsLen: 3,
},
{
name: "Typed TLS and CA Secrets",
service: &Service{TypedSecretName: map[service.Endpoint]string{service.Endpoint(TLSSecret): "typed-test-tls-secret"}},
ca: &Ca{CaSecretName: "test-ca1"},
wantMountsLen: 3,
},
}

for _, tt := range tests {
Expand Down Expand Up @@ -84,6 +102,12 @@ func TestCreateVolumes(t *testing.T) {
ca: &Ca{},
wantVolLen: 1,
},
{
name: "Only Typed TLS Secret",
service: &Service{TypedSecretName: map[service.Endpoint]string{service.Endpoint(TLSSecret): "typed-test-tls-secret"}},
ca: &Ca{},
wantVolLen: 1,
},
{
name: "Only CA Secret",
service: &Service{},
Expand All @@ -96,6 +120,12 @@ func TestCreateVolumes(t *testing.T) {
ca: &Ca{CaSecretName: "test-ca1"},
wantVolLen: 2,
},
{
name: "Typed TLS and CA Secrets",
service: &Service{TypedSecretName: map[service.Endpoint]string{service.Endpoint(TLSSecret): "typed-test-tls-secret"}},
ca: &Ca{CaSecretName: "test-ca1"},
wantVolLen: 2,
},
}

for _, tt := range tests {
Expand Down Expand Up @@ -131,6 +161,13 @@ func TestGenerateTLSConnectionConfig(t *testing.T) {
wantStmts: []string{"ssl=1", "ssl-cert=", "ssl-key="},
excludeStmts: []string{"ssl-ca="},
},
{
name: "Only Typed TLS Secret",
service: &Service{TypedSecretName: map[service.Endpoint]string{service.Endpoint(TLSSecret): "typed-test-tls-secret"}},
ca: &Ca{},
wantStmts: []string{"ssl=1", "ssl-cert=", "ssl-key="},
excludeStmts: []string{"ssl-ca="},
},
{
name: "Only CA Secret",
service: &Service{},
Expand All @@ -145,6 +182,13 @@ func TestGenerateTLSConnectionConfig(t *testing.T) {
wantStmts: []string{"ssl=1", "ssl-cert=", "ssl-key=", "ssl-ca="},
excludeStmts: []string{},
},
{
name: "Typed TLS and CA Secrets",
service: &Service{TypedSecretName: map[service.Endpoint]string{service.Endpoint(TLSSecret): "typed-test-tls-secret"}},
ca: &Ca{CaSecretName: "test-ca1"},
wantStmts: []string{"ssl=1", "ssl-cert=", "ssl-key=", "ssl-ca="},
excludeStmts: []string{},
},
}

for _, tt := range tests {
Expand Down

0 comments on commit aae9cda

Please sign in to comment.