Commit cb593265 authored by Claudio Gonçalves's avatar Claudio Gonçalves Committed by Claudio Netto

change TLSSecret to support many certificates

parent be7b7da7
......@@ -16,9 +16,10 @@ type NginxSpec struct {
Image string `json:"image"`
// Reference to the nginx config object.
Config *ConfigRef `json:"configRef"`
// References to a secret containing tls certificate and key pairs.
// Certificates refers to a Secret containing one or more certificate-key
// pairs.
// +optional
TLSSecret *TLSSecret `json:"tlsSecret,omitempty"`
Certificates *TLSSecret `json:"certificates,omitempty"`
// Template used to configure the nginx pod.
// +optional
PodTemplate NginxPodTemplateSpec `json:"podTemplate,omitempty"`
......@@ -105,28 +106,30 @@ const (
ConfigKindInline = ConfigKind("Inline")
)
// TLSSecret is a reference to tls certificate and key pairs stored in a secret.
// TLSSecret is a reference to TLS certificate and key pairs stored in a Secret.
type TLSSecret struct {
// Name of the Secret holding the certificate and key.
// SecretName refers to the Secret holding the certificates and keys pairs.
SecretName string `json:"secretName"`
// Secret field that contains the key.
// Defaults to tls.key
// +optional
KeyField string `json:"keyField,omitempty"`
// Secret field that contains the certificate.
// Defaults to tls.crt
// Items maps the key and path where the certificate-key pairs should be
// mounted on nginx container.
Items []TLSSecretItem `json:"items"`
}
// TLSSecretItem maps each certificate and key pair against a key-value data
// from a Secret object.
type TLSSecretItem struct {
// CertificateField is the field name that contains the certificate.
CertificateField string `json:"certificateField"`
// CertificatePath holds the path where the certificate should be stored
// inside the nginx container. Defaults to same as CertificatedField.
// +optional
CertificateField string `json:"certificateField,omitempty"`
// Path where the key should be stored inside the nginx container.
// Relative to /etc/nginx/certs/.
// Defaults to <KeyName>
CertificatePath string `json:"certificatePath,omitempty"`
// KeyField is the field name that contains the key.
KeyField string `json:"keyField"`
// KeyPath holds the path where the key should be store inside the nginx
// container. Defaults to same as KeyField.
// +optional
KeyPath string `json:"keyPath,omitempty"`
// Path where the certificate should be stored inside the nginx container.
// Relative to /etc/nginx/certs/.
// Defaults to <CertificateName>
// +optional
CertificatePath string `json:"certificatePath,omitempty"`
}
// FilesRef is a reference to arbitrary files stored into a ConfigMap in the
......
......@@ -174,10 +174,10 @@ func (in *NginxSpec) DeepCopyInto(out *NginxSpec) {
*out = new(ConfigRef)
**out = **in
}
if in.TLSSecret != nil {
in, out := &in.TLSSecret, &out.TLSSecret
if in.Certificates != nil {
in, out := &in.Certificates, &out.Certificates
*out = new(TLSSecret)
**out = **in
(*in).DeepCopyInto(*out)
}
in.PodTemplate.DeepCopyInto(&out.PodTemplate)
if in.Service != nil {
......@@ -264,6 +264,11 @@ func (in *ServiceStatus) DeepCopy() *ServiceStatus {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TLSSecret) DeepCopyInto(out *TLSSecret) {
*out = *in
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]TLSSecretItem, len(*in))
copy(*out, *in)
}
return
}
......@@ -276,3 +281,19 @@ func (in *TLSSecret) DeepCopy() *TLSSecret {
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TLSSecretItem) DeepCopyInto(out *TLSSecretItem) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSSecretItem.
func (in *TLSSecretItem) DeepCopy() *TLSSecretItem {
if in == nil {
return nil
}
out := new(TLSSecretItem)
in.DeepCopyInto(out)
return out
}
......@@ -67,7 +67,7 @@ func TestReconcileNginx_reconcileService(t *testing.T) {
Namespace: "default",
},
Spec: v1alpha1.NginxSpec{
TLSSecret: &v1alpha1.TLSSecret{},
Certificates: &v1alpha1.TLSSecret{},
},
Status: v1alpha1.NginxStatus{},
},
......
......@@ -99,7 +99,7 @@ func NewDeployment(n *v1alpha1.Nginx) (*appv1.Deployment, error) {
},
}
setupConfig(n.Spec.Config, &deployment)
setupTLS(n.Spec.TLSSecret, &deployment)
setupTLS(n.Spec.Certificates, &deployment)
setupExtraFiles(n.Spec.ExtraFiles, &deployment)
// This is done on the last step because n.Spec may have mutated during these methods
......@@ -161,7 +161,7 @@ func NewService(n *v1alpha1.Nginx) *corev1.Service {
Type: nginxService(n),
},
}
if n.Spec.TLSSecret != nil {
if n.Spec.Certificates != nil {
service.Spec.Ports = append(service.Spec.Ports, corev1.ServicePort{
Name: defaultHTTPSPortName,
Protocol: corev1.ProtocolTCP,
......@@ -283,20 +283,23 @@ func setupTLS(secret *v1alpha1.TLSSecret, dep *appv1.Deployment) {
MountPath: certMountPath,
})
secret.KeyField = valueOrDefault(secret.KeyField, "tls.key")
secret.CertificateField = valueOrDefault(secret.CertificateField, "tls.crt")
secret.KeyPath = valueOrDefault(secret.KeyPath, secret.KeyField)
secret.CertificatePath = valueOrDefault(secret.CertificatePath, secret.CertificateField)
var items []corev1.KeyToPath
for _, item := range secret.Items {
items = append(items, corev1.KeyToPath{
Key: item.CertificateField,
Path: valueOrDefault(item.CertificatePath, item.CertificateField),
}, corev1.KeyToPath{
Key: item.KeyField,
Path: valueOrDefault(item.KeyPath, item.KeyField),
})
}
dep.Spec.Template.Spec.Volumes = append(dep.Spec.Template.Spec.Volumes, corev1.Volume{
Name: "nginx-certs",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: secret.SecretName,
Items: []corev1.KeyToPath{
{Key: secret.KeyField, Path: secret.KeyPath},
{Key: secret.CertificateField, Path: secret.CertificatePath},
},
Items: items,
},
},
})
......
......@@ -34,14 +34,18 @@ func nginxWithService() v1alpha1.Nginx {
return n
}
func nginxWithTLSSecret() v1alpha1.Nginx {
func nginxWithCertificate() v1alpha1.Nginx {
n := baseNginx()
n.Spec.TLSSecret = &v1alpha1.TLSSecret{
n.Spec.Certificates = &v1alpha1.TLSSecret{
SecretName: "my-secret",
KeyField: "key-field",
KeyPath: "key-path",
CertificateField: "cert-field",
CertificatePath: "cert-path",
Items: []v1alpha1.TLSSecretItem{
{
KeyField: "key-field",
KeyPath: "key-path",
CertificateField: "cert-field",
CertificatePath: "cert-path",
},
},
}
return n
}
......@@ -217,12 +221,16 @@ func Test_NewDeployment(t *testing.T) {
{
name: "with-tls",
nginxFn: func(n v1alpha1.Nginx) v1alpha1.Nginx {
n.Spec.TLSSecret = &v1alpha1.TLSSecret{
n.Spec.Certificates = &v1alpha1.TLSSecret{
SecretName: "my-secret",
KeyField: "key-field",
KeyPath: "key-path",
CertificateField: "cert-field",
CertificatePath: "cert-path",
Items: []v1alpha1.TLSSecretItem{
{
CertificateField: "cert-field",
CertificatePath: "cert-path",
KeyField: "key-field",
KeyPath: "key-path",
},
},
}
return n
},
......@@ -258,8 +266,8 @@ func Test_NewDeployment(t *testing.T) {
Secret: &corev1.SecretVolumeSource{
SecretName: "my-secret",
Items: []corev1.KeyToPath{
{Key: "key-field", Path: "key-path"},
{Key: "cert-field", Path: "cert-path"},
{Key: "key-field", Path: "key-path"},
},
},
},
......@@ -271,8 +279,74 @@ func Test_NewDeployment(t *testing.T) {
{
name: "with-tls-default-values",
nginxFn: func(n v1alpha1.Nginx) v1alpha1.Nginx {
n.Spec.TLSSecret = &v1alpha1.TLSSecret{
n.Spec.Certificates = &v1alpha1.TLSSecret{
SecretName: "my-secret",
Items: []v1alpha1.TLSSecretItem{
{
CertificateField: "cert.crt",
KeyField: "cert.key",
},
},
}
return n
},
deployFn: func(d appv1.Deployment) appv1.Deployment {
d.Spec.Template.Spec.Containers[0].Ports = []corev1.ContainerPort{
{
Name: defaultHTTPPortName,
ContainerPort: defaultHTTPPort,
Protocol: corev1.ProtocolTCP,
},
{
Name: defaultHTTPSPortName,
ContainerPort: defaultHTTPSPort,
Protocol: corev1.ProtocolTCP,
},
}
d.Spec.Template.Spec.Containers[0].VolumeMounts = []corev1.VolumeMount{
{Name: "nginx-certs", MountPath: "/etc/nginx/certs"},
}
d.Spec.Template.Spec.Containers[0].ReadinessProbe = &corev1.Probe{
Handler: corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/",
Port: intstr.FromString(defaultHTTPSPortName),
Scheme: corev1.URISchemeHTTPS,
},
},
}
d.Spec.Template.Spec.Volumes = []corev1.Volume{
{
Name: "nginx-certs",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: "my-secret",
Items: []corev1.KeyToPath{
{Key: "cert.crt", Path: "cert.crt"},
{Key: "cert.key", Path: "cert.key"},
},
},
},
},
}
return d
},
},
{
name: "with-two-certificates",
nginxFn: func(n v1alpha1.Nginx) v1alpha1.Nginx {
n.Spec.Certificates = &v1alpha1.TLSSecret{
SecretName: "my-secret",
Items: []v1alpha1.TLSSecretItem{
{
CertificateField: "rsa.crt.pem",
KeyField: "rsa.key.pem",
},
{
CertificateField: "ecdsa.crt.pem",
KeyField: "ecdsa.key.pem",
},
},
}
return n
},
......@@ -308,8 +382,10 @@ func Test_NewDeployment(t *testing.T) {
Secret: &corev1.SecretVolumeSource{
SecretName: "my-secret",
Items: []corev1.KeyToPath{
{Key: "tls.key", Path: "tls.key"},
{Key: "tls.crt", Path: "tls.crt"},
{Key: "rsa.crt.pem", Path: "rsa.crt.pem"},
{Key: "rsa.key.pem", Path: "rsa.key.pem"},
{Key: "ecdsa.crt.pem", Path: "ecdsa.crt.pem"},
{Key: "ecdsa.key.pem", Path: "ecdsa.key.pem"},
},
},
},
......@@ -542,7 +618,7 @@ func TestNewService(t *testing.T) {
},
{
name: "with-tls",
nginx: nginxWithTLSSecret(),
nginx: nginxWithCertificate(),
want: &corev1.Service{
TypeMeta: metav1.TypeMeta{
Kind: "Service",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment