Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions charts/k3k/crds/k3k.io_clusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ spec:
certificates.
properties:
enabled:
default: true
description: Enabled toggles this feature on or off.
type: boolean
sources:
Expand All @@ -244,6 +245,8 @@ spec:
- For TLS pairs (e.g., ServerCA): 'tls.crt' and 'tls.key'.
- For ServiceAccountTokenKey: 'tls.key'.
type: string
required:
- secretName
type: object
etcdPeerCA:
description: ETCDPeerCA specifies the etcd-peer-ca cert/key
Expand All @@ -256,6 +259,8 @@ spec:
- For TLS pairs (e.g., ServerCA): 'tls.crt' and 'tls.key'.
- For ServiceAccountTokenKey: 'tls.key'.
type: string
required:
- secretName
type: object
etcdServerCA:
description: ETCDServerCA specifies the etcd-server-ca cert/key
Expand All @@ -268,6 +273,8 @@ spec:
- For TLS pairs (e.g., ServerCA): 'tls.crt' and 'tls.key'.
- For ServiceAccountTokenKey: 'tls.key'.
type: string
required:
- secretName
type: object
requestHeaderCA:
description: RequestHeaderCA specifies the request-header-ca
Expand All @@ -280,6 +287,8 @@ spec:
- For TLS pairs (e.g., ServerCA): 'tls.crt' and 'tls.key'.
- For ServiceAccountTokenKey: 'tls.key'.
type: string
required:
- secretName
type: object
serverCA:
description: ServerCA specifies the server-ca cert/key pair.
Expand All @@ -291,6 +300,8 @@ spec:
- For TLS pairs (e.g., ServerCA): 'tls.crt' and 'tls.key'.
- For ServiceAccountTokenKey: 'tls.key'.
type: string
required:
- secretName
type: object
serviceAccountToken:
description: ServiceAccountToken specifies the service-account-token
Expand All @@ -303,8 +314,20 @@ spec:
- For TLS pairs (e.g., ServerCA): 'tls.crt' and 'tls.key'.
- For ServiceAccountTokenKey: 'tls.key'.
type: string
required:
- secretName
type: object
required:
- clientCA
- etcdPeerCA
- etcdServerCA
- requestHeaderCA
- serverCA
- serviceAccountToken
type: object
required:
- enabled
- sources
type: object
expose:
description: |-
Expand Down
2 changes: 1 addition & 1 deletion cli/cmds/cluster_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ func newCluster(name, namespace string, config *CreateConfig) *v1beta1.Cluster {
}

if config.customCertsPath != "" {
cluster.Spec.CustomCAs = v1beta1.CustomCAs{
cluster.Spec.CustomCAs = &v1beta1.CustomCAs{
Enabled: true,
Sources: v1beta1.CredentialSources{
ClientCA: v1beta1.CredentialSource{
Expand Down
2 changes: 1 addition & 1 deletion docs/crds/crd-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ _Appears in:_

| Field | Description | Default | Validation |
| --- | --- | --- | --- |
| `enabled` _boolean_ | Enabled toggles this feature on or off. | | |
| `enabled` _boolean_ | Enabled toggles this feature on or off. | true | |
| `sources` _[CredentialSources](#credentialsources)_ | Sources defines the sources for all required custom CA certificates. | | |


Expand Down
23 changes: 12 additions & 11 deletions pkg/apis/k3k.io/v1beta1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ type ClusterSpec struct {
// CustomCAs specifies the cert/key pairs for custom CA certificates.
//
// +optional
CustomCAs CustomCAs `json:"customCAs,omitempty"`
CustomCAs *CustomCAs `json:"customCAs,omitempty"`

// Sync specifies the resources types that will be synced from virtual cluster to host cluster.
//
Expand Down Expand Up @@ -416,32 +416,34 @@ type NodePortConfig struct {
// CustomCAs specifies the cert/key pairs for custom CA certificates.
type CustomCAs struct {
// Enabled toggles this feature on or off.
Enabled bool `json:"enabled,omitempty"`
//
// +kubebuilder:default=true
Enabled bool `json:"enabled"`

// Sources defines the sources for all required custom CA certificates.
Sources CredentialSources `json:"sources,omitempty"`
Sources CredentialSources `json:"sources"`
}

// CredentialSources lists all the required credentials, including both
// TLS key pairs and single signing keys.
type CredentialSources struct {
// ServerCA specifies the server-ca cert/key pair.
ServerCA CredentialSource `json:"serverCA,omitempty"`
ServerCA CredentialSource `json:"serverCA"`

// ClientCA specifies the client-ca cert/key pair.
ClientCA CredentialSource `json:"clientCA,omitempty"`
ClientCA CredentialSource `json:"clientCA"`

// RequestHeaderCA specifies the request-header-ca cert/key pair.
RequestHeaderCA CredentialSource `json:"requestHeaderCA,omitempty"`
RequestHeaderCA CredentialSource `json:"requestHeaderCA"`

// ETCDServerCA specifies the etcd-server-ca cert/key pair.
ETCDServerCA CredentialSource `json:"etcdServerCA,omitempty"`
ETCDServerCA CredentialSource `json:"etcdServerCA"`

// ETCDPeerCA specifies the etcd-peer-ca cert/key pair.
ETCDPeerCA CredentialSource `json:"etcdPeerCA,omitempty"`
ETCDPeerCA CredentialSource `json:"etcdPeerCA"`

// ServiceAccountToken specifies the service-account-token key.
ServiceAccountToken CredentialSource `json:"serviceAccountToken,omitempty"`
ServiceAccountToken CredentialSource `json:"serviceAccountToken"`
}

// CredentialSource defines where to get a credential from.
Expand All @@ -451,8 +453,7 @@ type CredentialSource struct {
// The controller expects specific keys inside based on the credential type:
// - For TLS pairs (e.g., ServerCA): 'tls.crt' and 'tls.key'.
// - For ServiceAccountTokenKey: 'tls.key'.
// +optional
SecretName string `json:"secretName,omitempty"`
SecretName string `json:"secretName"`
}

// ClusterStatus reflects the observed state of a Cluster.
Expand Down
6 changes: 5 additions & 1 deletion pkg/apis/k3k.io/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 3 additions & 4 deletions pkg/controller/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -736,8 +736,8 @@ func (c *ClusterReconciler) validate(cluster *v1beta1.Cluster, policy v1beta1.Vi
return fmt.Errorf("%w: mode %q is not allowed by the policy %q", ErrClusterValidation, cluster.Spec.Mode, policy.Name)
}

if cluster.Spec.CustomCAs.Enabled {
if err := c.validateCustomCACerts(cluster); err != nil {
if cluster.Spec.CustomCAs != nil && cluster.Spec.CustomCAs.Enabled {
if err := c.validateCustomCACerts(cluster.Spec.CustomCAs.Sources); err != nil {
return fmt.Errorf("%w: %w", ErrClusterValidation, err)
}
}
Expand Down Expand Up @@ -828,8 +828,7 @@ func (c *ClusterReconciler) lookupServiceCIDR(ctx context.Context) (string, erro
}

// validateCustomCACerts will make sure that all the cert secrets exists
func (c *ClusterReconciler) validateCustomCACerts(cluster *v1beta1.Cluster) error {
credentialSources := cluster.Spec.CustomCAs.Sources
func (c *ClusterReconciler) validateCustomCACerts(credentialSources v1beta1.CredentialSources) error {
if credentialSources.ClientCA.SecretName == "" ||
credentialSources.ServerCA.SecretName == "" ||
credentialSources.ETCDPeerCA.SecretName == "" ||
Expand Down
2 changes: 2 additions & 0 deletions pkg/controller/cluster/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ var _ = Describe("Cluster Controller", Label("controller"), Label("Cluster"), fu
Expect(cluster.Spec.Servers).To(Equal(ptr.To[int32](1)))
Expect(cluster.Spec.Version).To(BeEmpty())

Expect(cluster.Spec.CustomCAs).To(BeNil())

Expect(cluster.Spec.Persistence.Type).To(Equal(v1beta1.DynamicPersistenceMode))
Expect(cluster.Spec.Persistence.StorageRequestSize).To(Equal("2G"))

Expand Down
6 changes: 5 additions & 1 deletion pkg/controller/cluster/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ func (s *Server) StatefulServer(ctx context.Context) (*apps.StatefulSet, error)
volumeMounts = append(volumeMounts, volumeMount)
}

if s.cluster.Spec.CustomCAs.Enabled {
if s.cluster.Spec.CustomCAs != nil && s.cluster.Spec.CustomCAs.Enabled {
vols, mounts, err := s.loadCACertBundle(ctx)
if err != nil {
return nil, err
Expand Down Expand Up @@ -434,6 +434,10 @@ func (s *Server) setupStartCommand() (string, error) {
}

func (s *Server) loadCACertBundle(ctx context.Context) ([]v1.Volume, []v1.VolumeMount, error) {
if s.cluster.Spec.CustomCAs == nil {
return nil, nil, fmt.Errorf("customCAs not found")
}
Comment on lines +437 to +439

Choose a reason for hiding this comment

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

Seems to be unnecessary given the conditional on L333.

Copy link
Collaborator Author

@enrichman enrichman Oct 23, 2025

Choose a reason for hiding this comment

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

Yes, that's true. I just wanted to be extra safe in case someone calls this method and forgets to check that. :)


customCerts := s.cluster.Spec.CustomCAs.Sources
caCertMap := map[string]string{
"server-ca": customCerts.ServerCA.SecretName,
Expand Down
2 changes: 1 addition & 1 deletion tests/cluster_certs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ var _ = When("a cluster with custom certificates is installed with individual ce

cluster := NewCluster(namespace.Name)

cluster.Spec.CustomCAs = v1beta1.CustomCAs{
cluster.Spec.CustomCAs = &v1beta1.CustomCAs{
Enabled: true,
Sources: v1beta1.CredentialSources{
ServerCA: v1beta1.CredentialSource{
Expand Down
Loading