Skip to content

Commit

Permalink
Merge pull request #60 from alexandrevilain/feat/mtls
Browse files Browse the repository at this point in the history
Add internode & frontend mTLS using cert-manager
  • Loading branch information
alexandrevilain authored Jul 22, 2022
2 parents 4b6bebe + db11933 commit 2c03a07
Show file tree
Hide file tree
Showing 54 changed files with 3,799 additions and 74 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ out
*.swo
*~
.vscode
.DS_Store
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ test-e2e: artifacts ## Run end2end tests.
test-e2e-dev: artifacts ## Run end2end tests on dev computer using kind.
docker build -t temporal-operator .
docker save temporal-operator > /tmp/temporal-operator.tar
OPERATOR_IMAGE_PATH=/tmp/temporal-operator.tar go test ./tests/e2e -v
OPERATOR_IMAGE_PATH=/tmp/temporal-operator.tar go test ./tests/e2e -v -args "--v=4"

.PHONY: ensure-license
ensure-license: go-licenser
Expand Down
9 changes: 9 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,13 @@ resources:
kind: TemporalCluster
path: github.com/alexandrevilain/temporal-operator/api/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: alexandrevilain.dev
group: apps
kind: TemporalClusterClient
path: github.com/alexandrevilain/temporal-operator/api/v1alpha1
version: v1alpha1
version: "3"
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ Current Status: Work in Progress. The operator can create a basic cluster. Many
- [x] Deploy admin tools.
- [x] Support for Elastisearch.
- [x] Support for Cassandra datastore.
- [x] Automatic mTLS certificates management (using cert-manager).
- [ ] Support for integration in meshes (linkerd & istio).
- [ ] Cluster version upgrades.
- [ ] Automatic mTLS certificates management (using istio, linkerd or cert-manager).
- [ ] Cluster monitoring.
- [ ] Auto scaling.
- [ ] Multi cluster replication.
Expand Down Expand Up @@ -82,6 +83,7 @@ Few examples are available to help you get started:
- [Demo cluster with PostgreSQL](https://github.com/alexandrevilain/temporal-operator/blob/main/examples/cluster-postgres)
- [Demo cluster with PostgreSQL & advanced visibility using ElasticSearch](https://github.com/alexandrevilain/temporal-operator/blob/main/examples/cluster-postgres-es)
- [Demo cluster with Cassandra](https://github.com/alexandrevilain/temporal-operator/blob/main/examples/cluster-cassandra)
- [Demo cluster with mTLS using cert-manager & PostgreSQL as datastore](https://github.com/alexandrevilain/temporal-operator/blob/main/examples/cluster-mtls)
## License
Expand Down
124 changes: 124 additions & 0 deletions api/v1alpha1/temporalcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,117 @@ type TemporalAdminToolsSpec struct {
Image string `json:"image"`
}

// MTLSProvider is the enum for support mTLS provider.
type MTLSProvider string

const (
// CertManagerMTLSProvider uses cert-manager to manage mTLS certificate.
CertManagerMTLSProvider MTLSProvider = "cert-manager"
)

// InternodeMTLSSpec defines parameters for the temporal encryption in transit with mTLS.
type FrontendMTLSSpec struct {
// Enabled defines if the operator should enable mTLS for cluster's public endpoints.
// +optional
Enabled bool `json:"enabled"`
}

// ServerName returns frontend servername for mTLS certificates.
func (FrontendMTLSSpec) ServerName(serverName string) string {
return fmt.Sprintf("frontend.%s", serverName)
}

// GetIntermediateCACertificateMountPath returns the mount path for intermediate CA certificates.
func (FrontendMTLSSpec) GetIntermediateCACertificateMountPath() string {
return "/etc/temporal/config/certs/client/ca"
}

// GetCertificateMountPath returns the mount path for the frontend certificate.
func (FrontendMTLSSpec) GetCertificateMountPath() string {
return "/etc/temporal/config/certs/cluster/frontend"
}

// GetWorkerCertificateMountPath returns the mount path for the worker certificate.
func (FrontendMTLSSpec) GetWorkerCertificateMountPath() string {
return "/etc/temporal/config/certs/cluster/worker"
}

// InternodeMTLSSpec defines parameters for the temporal encryption in transit with mTLS.
type InternodeMTLSSpec struct {
// Enabled defines if the operator should enable mTLS for network between cluster nodes.
// +optional
Enabled bool `json:"enabled"`
}

// ServerName returns internode servername for mTLS certificates.
func (InternodeMTLSSpec) ServerName(serverName string) string {
return fmt.Sprintf("internode.%s", serverName)
}

// GetIntermediateCACertificateMountPath returns the mount path for intermediate CA certificates.
func (InternodeMTLSSpec) GetIntermediateCACertificateMountPath() string {
return "/etc/temporal/config/certs/cluster/ca"
}

// GetCertificateMountPath returns the mount path for the internode certificate.
func (InternodeMTLSSpec) GetCertificateMountPath() string {
return "/etc/temporal/config/certs/cluster/internode"
}

// CertificatesDurationSpec defines parameters for the temporal mTLS certificates duration.
type CertificatesDurationSpec struct {
// RootCACertificate is the 'duration' (i.e. lifetime) of the Root CA Certificate.
// It defaults to 10 years.
// +optional
RootCACertificate *metav1.Duration `json:"rootCACertificate"`
// IntermediateCACertificates is the 'duration' (i.e. lifetime) of the intermediate CAs Certificates.
// It defaults to 5 years.
// +optional
IntermediateCAsCertificates *metav1.Duration `json:"intermediateCAsCertificates"`
// ClientCertificates is the 'duration' (i.e. lifetime) of the client certificates.
// It defaults to 1 year.
// +optional
ClientCertificates *metav1.Duration `json:"clientCertificates"`
// FrontendCertificate is the 'duration' (i.e. lifetime) of the frontend certificate.
// It defaults to 1 year.
// +optional
FrontendCertificate *metav1.Duration `json:"frontendCertificate"`
// InternodeCertificate is the 'duration' (i.e. lifetime) of the internode certificate.
// It defaults to 1 year.
// +optional
InternodeCertificate *metav1.Duration `json:"internodeCertificate"`
}

// MTLSSpec defines parameters for the temporal encryption in transit with mTLS.
type MTLSSpec struct {
// Provider defines the tool used to manage mTLS certificates.
// +kubebuilder:default=cert-manager
// +kubebuilder:validation:Enum=cert-manager
// +optional
Provider MTLSProvider `json:"provider"`
// Internode allows configuration of the internode traffic encryption.
// +optional
Internode *InternodeMTLSSpec `json:"internode"`
// Frontend allows configuration of the frontend's public endpoint traffic encryption.
// +optional
Frontend *FrontendMTLSSpec `json:"frontend"`
// CertificatesDuration allows configuration of maximum certificates lifetime.
// +optional
CertificatesDuration *CertificatesDurationSpec `json:"certificatesDuration,omitempty"`
// RefreshInterval defines interval between refreshes of certificates in the cluster components.
// Defaults to 1 hour.
// +optional
RefreshInterval *metav1.Duration `json:"refreshInterval"`
}

func (m *MTLSSpec) InternodeEnabled() bool {
return m.Internode != nil && m.Internode.Enabled
}

func (m *MTLSSpec) FrontendEnabled() bool {
return m.Frontend != nil && m.Frontend.Enabled
}

// TemporalClusterSpec defines the desired state of TemporalCluster.
type TemporalClusterSpec struct {
// Image defines the temporal server docker image the cluster should use for each services.
Expand Down Expand Up @@ -391,6 +502,9 @@ type TemporalClusterSpec struct {
// AdminTools allows configuration of the optional admin tool pod deployed alongside the cluster.
// +optional
AdminTools *TemporalAdminToolsSpec `json:"admintools,omitempty"`
// MTLS allows configuration of the network traffic encryption for the cluster.
// +optional
MTLS *MTLSSpec `json:"mTLS,omitempty"`
}

// ServiceStatus reports a service status.
Expand Down Expand Up @@ -459,6 +573,16 @@ type TemporalCluster struct {
Status TemporalClusterStatus `json:"status,omitempty"`
}

// ServerName returns cluster's server name.
func (c *TemporalCluster) ServerName() string {
return fmt.Sprintf("%s.%s.svc.cluster.local", c.Name, c.Namespace)
}

// MTLSEnabled returns true if mTLS is enabled for internode or frontend.
func (c *TemporalCluster) MTLSEnabled() bool {
return c.Spec.MTLS != nil && (c.Spec.MTLS.InternodeEnabled() || c.Spec.MTLS.FrontendEnabled())
}

func (c *TemporalCluster) getDatastoreByName(name string) (*TemporalDatastoreSpec, bool) {
for _, datastore := range c.Spec.Datastores {
if datastore.Name == name {
Expand Down
62 changes: 62 additions & 0 deletions api/v1alpha1/temporalclusterclient_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Licensed to Alexandre VILAIN under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Alexandre VILAIN licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package v1alpha1

import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// TemporalClusterClientSpec defines the desired state of TemporalClusterClient
type TemporalClusterClientSpec struct {
// Reference to the temporal cluster the client will get access to.
TemporalClusterRef corev1.LocalObjectReference `json:"temporalClusterRef"`
}

// TemporalClusterClientStatus defines the observed state of TemporalClusterClient
type TemporalClusterClientStatus struct {
// ServerName is the hostname returned by the certificate.
ServerName string `json:"serverName"`
// Reference to the Kubernetes Secret containing the certificate for the client.
SecretRef corev1.LocalObjectReference `json:"secretRef"`
}

//+kubebuilder:object:root=true
//+kubebuilder:subresource:status

// TemporalClusterClient is the Schema for the temporalclusterclients API
type TemporalClusterClient struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec TemporalClusterClientSpec `json:"spec,omitempty"`
Status TemporalClusterClientStatus `json:"status,omitempty"`
}

//+kubebuilder:object:root=true

// TemporalClusterClientList contains a list of TemporalClusterClient
type TemporalClusterClientList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []TemporalClusterClient `json:"items"`
}

func init() {
SchemeBuilder.Register(&TemporalClusterClient{}, &TemporalClusterClientList{})
}
Loading

0 comments on commit 2c03a07

Please sign in to comment.