Skip to content

Commit fbefb26

Browse files
committed
coroot: project API keys from a Secret (#14)
1 parent 7291ba9 commit fbefb26

File tree

7 files changed

+89
-53
lines changed

7 files changed

+89
-53
lines changed

api/v1/coroot_types.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,9 +251,10 @@ type ProjectSpec struct {
251251
}
252252

253253
type ApiKeySpec struct {
254-
// Random string or UUID (must be unique; required).
255-
// +kubebuilder:validation:Required
254+
// Plain-text API key. Must be unique. Prefer using KeySecret for better security.
256255
Key string `json:"key,omitempty"`
256+
// Secret with the API key. Created automatically if missing.
257+
KeySecret *corev1.SecretKeySelector `json:"keySecret,omitempty"`
257258
// API key description (optional).
258259
Description string `json:"description,omitempty"`
259260
}

api/v1/zz_generated.deepcopy.go

Lines changed: 8 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/coroot.com_coroots.yaml

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6168,10 +6168,34 @@ spec:
61686168
description: API key description (optional).
61696169
type: string
61706170
key:
6171-
description: Random string or UUID (must be unique; required).
6171+
description: Plain-text API key. Must be unique. Prefer
6172+
using KeySecret for better security.
61726173
type: string
6173-
required:
6174-
- key
6174+
keySecret:
6175+
description: Secret with the API key. Created automatically
6176+
if missing.
6177+
properties:
6178+
key:
6179+
description: The key of the secret to select from. Must
6180+
be a valid secret key.
6181+
type: string
6182+
name:
6183+
default: ""
6184+
description: |-
6185+
Name of the referent.
6186+
This field is effectively required, but due to backwards compatibility is
6187+
allowed to be empty. Instances of this type with an empty value here are
6188+
almost certainly wrong.
6189+
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
6190+
type: string
6191+
optional:
6192+
description: Specify whether the Secret or its key
6193+
must be defined
6194+
type: boolean
6195+
required:
6196+
- key
6197+
type: object
6198+
x-kubernetes-map-type: atomic
61756199
type: object
61766200
minItems: 1
61776201
type: array

config/rbac/role.yaml

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ rules:
2727
- ""
2828
resources:
2929
- persistentvolumeclaims
30+
- secrets
3031
- serviceaccounts
3132
- services
3233
verbs:
@@ -37,15 +38,6 @@ rules:
3738
- patch
3839
- update
3940
- watch
40-
- apiGroups:
41-
- ""
42-
resources:
43-
- secrets
44-
verbs:
45-
- create
46-
- get
47-
- list
48-
- watch
4941
- apiGroups:
5042
- apps
5143
resources:

controller/clickhouse.go

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,6 @@ import (
1313
"k8s.io/apimachinery/pkg/util/intstr"
1414
)
1515

16-
func (r *CorootReconciler) clickhouseSecret(cr *corootv1.Coroot) *corev1.Secret {
17-
ls := Labels(cr, "clickhouse")
18-
s := &corev1.Secret{
19-
ObjectMeta: metav1.ObjectMeta{
20-
Name: fmt.Sprintf("%s-clickhouse", cr.Name),
21-
Namespace: cr.Namespace,
22-
Labels: ls,
23-
},
24-
Data: map[string][]byte{"password": []byte(RandomString(16))},
25-
}
26-
return s
27-
}
28-
2916
func (r *CorootReconciler) clickhouseService(cr *corootv1.Coroot) *corev1.Service {
3017
ls := Labels(cr, "clickhouse")
3118
s := &corev1.Service{
@@ -218,12 +205,7 @@ func (r *CorootReconciler) clickhouseStatefulSets(cr *corootv1.Coroot) []*appsv1
218205
},
219206
}},
220207
{Name: "CLICKHOUSE_PASSWORD", ValueFrom: &corev1.EnvVarSource{
221-
SecretKeyRef: &corev1.SecretKeySelector{
222-
LocalObjectReference: corev1.LocalObjectReference{
223-
Name: fmt.Sprintf("%s-clickhouse", cr.Name),
224-
},
225-
Key: "password",
226-
},
208+
SecretKeyRef: secretKeySelector(fmt.Sprintf("%s-clickhouse", cr.Name), "password"),
227209
}},
228210
},
229211
ReadinessProbe: &corev1.Probe{
@@ -241,14 +223,6 @@ func (r *CorootReconciler) clickhouseStatefulSets(cr *corootv1.Coroot) []*appsv1
241223
EmptyDir: &corev1.EmptyDirVolumeSource{},
242224
},
243225
},
244-
//{
245-
// Name: "data",
246-
// VolumeSource: corev1.VolumeSource{
247-
// PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
248-
// ClaimName: fmt.Sprintf("data-%s-clickhouse-shard-%d", cr.Name, shard),
249-
// },
250-
// },
251-
//},
252226
},
253227
},
254228
},

controller/controller.go

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func NewCorootReconciler(mgr ctrl.Manager) *CorootReconciler {
6969
// +kubebuilder:rbac:groups=coroot.com,resources=coroots/status,verbs=get;update;patch
7070
// +kubebuilder:rbac:groups=coroot.com,resources=coroots/finalizers,verbs=update
7171
// +kubebuilder:rbac:groups="",resources=events,verbs=create;patch
72-
// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create
72+
// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch;delete
7373
// +kubebuilder:rbac:groups="",resources=namespaces;nodes;pods;endpoints;persistentvolumes,verbs=get;list;watch
7474
// +kubebuilder:rbac:groups="",resources=services;persistentvolumeclaims;serviceaccounts,verbs=get;list;watch;create;update;patch;delete
7575
// +kubebuilder:rbac:groups=apps,resources=deployments;replicasets;daemonsets;statefulsets;cronjobs,verbs=get;list;watch;create;update;patch;delete
@@ -123,10 +123,8 @@ func (r *CorootReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
123123
return ctrl.Result{}, nil
124124
}
125125

126-
if cr.Spec.Replicas > 1 && cr.Spec.Postgres == nil {
127-
logger.Error(fmt.Errorf("postgres not configured"), "Coroot requires Postgres to run multiple replicas (will run only one replica)")
128-
cr.Spec.Replicas = 1
129-
}
126+
r.corootValidate(ctx, cr)
127+
130128
r.CreateOrUpdateServiceAccount(ctx, cr, "coroot", sccNonroot)
131129
for _, pvc := range r.corootPVCs(cr) {
132130
r.CreateOrUpdatePVC(ctx, cr, pvc, cr.Spec.Storage.ReclaimPolicy)
@@ -149,7 +147,7 @@ func (r *CorootReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
149147
}
150148

151149
if cr.Spec.ExternalClickhouse == nil {
152-
r.CreateSecret(ctx, cr, r.clickhouseSecret(cr))
150+
r.CreateOrUpdateSecret(ctx, cr, "clickhouse", fmt.Sprintf("%s-clickhouse", cr.Name), "password", 16)
153151

154152
r.CreateOrUpdateServiceAccount(ctx, cr, "clickhouse-keeper", sccNonroot)
155153
r.CreateOrUpdateService(ctx, cr, r.clickhouseKeeperServiceHeadless(cr))
@@ -204,8 +202,28 @@ func (r *CorootReconciler) CreateOrUpdate(ctx context.Context, cr *corootv1.Coro
204202
}
205203
}
206204

207-
func (r *CorootReconciler) CreateSecret(ctx context.Context, cr *corootv1.Coroot, s *corev1.Secret) {
208-
r.CreateOrUpdate(ctx, cr, s, false, false, nil)
205+
func (r *CorootReconciler) CreateOrUpdateSecret(ctx context.Context, cr *corootv1.Coroot, component, name, key string, length int) string {
206+
s := &corev1.Secret{
207+
ObjectMeta: metav1.ObjectMeta{
208+
Name: name,
209+
Namespace: cr.Namespace,
210+
Labels: Labels(cr, component),
211+
},
212+
}
213+
var data string
214+
r.CreateOrUpdate(ctx, cr, s, false, false, func() error {
215+
if s.Data == nil {
216+
s.Data = map[string][]byte{}
217+
}
218+
if d, ok := s.Data[key]; ok {
219+
data = string(d)
220+
} else {
221+
data = RandomString(length)
222+
s.Data[key] = []byte(data)
223+
}
224+
return nil
225+
})
226+
return data
209227
}
210228

211229
func (r *CorootReconciler) CreateOrUpdateDeployment(ctx context.Context, cr *corootv1.Coroot, d *appsv1.Deployment) {

controller/coroot.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package controller
33
import (
44
"bytes"
55
"cmp"
6+
"context"
67
"fmt"
78
"strings"
89
"text/template"
@@ -15,8 +16,26 @@ import (
1516
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1617
"k8s.io/apimachinery/pkg/util/intstr"
1718
"k8s.io/utils/ptr"
19+
ctrl "sigs.k8s.io/controller-runtime"
1820
)
1921

22+
func (r *CorootReconciler) corootValidate(ctx context.Context, cr *corootv1.Coroot) {
23+
logger := ctrl.Log.WithValues("namespace", cr.Namespace, "name", cr.Name)
24+
25+
if cr.Spec.Replicas > 1 && cr.Spec.Postgres == nil {
26+
logger.Error(fmt.Errorf("postgres not configured"), "Coroot requires Postgres to run multiple replicas (will run only one replica)")
27+
cr.Spec.Replicas = 1
28+
}
29+
30+
for _, p := range cr.Spec.Projects {
31+
for i, k := range p.ApiKeys {
32+
if k.KeySecret != nil {
33+
p.ApiKeys[i].Key = r.CreateOrUpdateSecret(ctx, cr, "coroot", k.KeySecret.Name, k.KeySecret.Key, 32)
34+
}
35+
}
36+
}
37+
}
38+
2039
func (r *CorootReconciler) corootService(cr *corootv1.Coroot) *corev1.Service {
2140
ls := Labels(cr, "coroot")
2241

@@ -175,9 +194,6 @@ func (r *CorootReconciler) corootStatefulSet(cr *corootv1.Coroot) *appsv1.Statef
175194
if cr.Spec.AuthBootstrapAdminPassword != "" {
176195
env = append(env, corev1.EnvVar{Name: "AUTH_BOOTSTRAP_ADMIN_PASSWORD", Value: cr.Spec.AuthBootstrapAdminPassword})
177196
}
178-
for _, e := range cr.Spec.Env {
179-
env = append(env, e)
180-
}
181197

182198
image := r.getAppImage(cr, AppCorootCE)
183199
if cr.Spec.EnterpriseEdition != nil {
@@ -259,6 +275,10 @@ func (r *CorootReconciler) corootStatefulSet(cr *corootv1.Coroot) *appsv1.Statef
259275
env = append(env, corev1.EnvVar{Name: "URL_BASE_PATH", Value: cr.Spec.Ingress.Path})
260276
}
261277

278+
for _, e := range cr.Spec.Env {
279+
env = append(env, e)
280+
}
281+
262282
replicas := int32(cr.Spec.Replicas)
263283
if replicas <= 0 {
264284
replicas = 1

0 commit comments

Comments
 (0)