Skip to content
Open
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
54 changes: 54 additions & 0 deletions api/v1/backend.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package v1

import (
"context"
"fmt"
"reflect"
"strings"

corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/k8up-io/k8up/v2/operator/cfg"
)
Expand Down Expand Up @@ -71,6 +73,14 @@ func (in *Backend) String() string {
return ""
}

// ResolveSecretRefs resolves Secret-backed repository fields in place.
func (in *Backend) ResolveSecretRefs(ctx context.Context, reader client.Reader, namespace, secretName string) error {
if in == nil || in.S3 == nil {
return nil
}
return in.S3.ResolveSecretRefs(ctx, reader, namespace, secretName)
}

// IsBackendEqualTo returns true if the restic repository string is equal to the other's string.
// If other is nil, it returns false.
func (in *Backend) IsBackendEqualTo(other *Backend) bool {
Expand Down Expand Up @@ -98,6 +108,14 @@ func addEnvVarFromSecret(vars map[string]*corev1.EnvVarSource, key string, ref *
}
}

func secretValue(secret *corev1.Secret, key, field string) (string, error) {
value, ok := secret.Data[key]
if !ok {
return "", fmt.Errorf("secret %s/%s has no key %q for %s", secret.Namespace, secret.Name, key, field)
}
return string(value), nil
}

type LocalSpec struct {
MountPath string `json:"mountPath,omitempty"`
}
Expand All @@ -114,11 +132,47 @@ func (in *LocalSpec) String() string {

type S3Spec struct {
Endpoint string `json:"endpoint,omitempty"`
EndpointSecretKey string `json:"endpointSecretKey,omitempty"`
Bucket string `json:"bucket,omitempty"`
BucketSecretKey string `json:"bucketSecretKey,omitempty"`
AccessKeyIDSecretRef *corev1.SecretKeySelector `json:"accessKeyIDSecretRef,omitempty"`
SecretAccessKeySecretRef *corev1.SecretKeySelector `json:"secretAccessKeySecretRef,omitempty"`
}

// ResolveSecretRefs replaces configured endpoint and bucket Secret references
// with their values before the repository string is used to create a Job.
func (in *S3Spec) ResolveSecretRefs(ctx context.Context, reader client.Reader, namespace, secretName string) error {
if in == nil || (in.EndpointSecretKey == "" && in.BucketSecretKey == "") {
return nil
}

secret := &corev1.Secret{}
if err := reader.Get(ctx, client.ObjectKey{Namespace: namespace, Name: secretName}, secret); err != nil {
return fmt.Errorf("get repository Secret %s/%s: %w", namespace, secretName, err)
}

endpoint := in.Endpoint
if in.EndpointSecretKey != "" {
var err error
endpoint, err = secretValue(secret, in.EndpointSecretKey, "S3 endpoint")
if err != nil {
return err
}
}
bucket := in.Bucket
if in.BucketSecretKey != "" {
var err error
bucket, err = secretValue(secret, in.BucketSecretKey, "S3 bucket")
if err != nil {
return err
}
}

in.Endpoint = endpoint
in.Bucket = bucket
return nil
}

// EnvVars returns the env vars for this backend.
func (in *S3Spec) EnvVars(vars map[string]*corev1.EnvVarSource) map[string]*corev1.EnvVarSource {
addEnvVarFromSecret(vars, cfg.AwsAccessKeyIDEnvName, in.AccessKeyIDSecretRef)
Expand Down
31 changes: 31 additions & 0 deletions api/v1/backend_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package v1

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client/fake"

"github.com/k8up-io/k8up/v2/operator/cfg"
)
Expand Down Expand Up @@ -155,6 +160,32 @@ func Test_Backend_GetCredentialEnv(t *testing.T) {
}
}

func TestBackend_ResolveSecretRefs(t *testing.T) {
const (
namespace = "backup"
secretName = "k8up-repo"
)
scheme := runtime.NewScheme()
require.NoError(t, corev1.AddToScheme(scheme))
reader := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: secretName},
Data: map[string][]byte{
"endpoint": []byte("https://endpoint"),
"bucket": []byte("bucket"),
},
}).Build()

backend := &Backend{S3: &S3Spec{
EndpointSecretKey: "endpoint",
BucketSecretKey: "bucket",
}}

err := backend.ResolveSecretRefs(context.Background(), reader, namespace, secretName)

require.NoError(t, err)
assert.Equal(t, "s3:https://endpoint/bucket", backend.String())
}

func newSecretRef(name string) *corev1.SecretKeySelector {
return &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Expand Down
1 change: 1 addition & 0 deletions charts/k8up/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ $(rbac_gen_tgt):
@yq -i e '.metadata.name="{{ include \"k8up.fullname\" . }}-manager", del(.metadata.creationTimestamp)' $@
@yq -i e '.metadata.labels.replace="LABELS"' $@
@$(sed) -e 's/replace: LABELS/{{- include "k8up.labels" . | nindent 4 }}/g' $@
@$(sed) -e 's/- k8up-repo/- {{ .Values.k8up.repositorySecretName | default "k8up-repo" }}/g' $@
@$(sed) -e '1s/^/{{- if .Values.rbac.create -}}\n/' $@
@$(sed) -e '$$a{{- end -}}' $@

Expand Down
1 change: 1 addition & 0 deletions charts/k8up/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Document your changes in values.yaml and let `make docs:helm` generate this sect
| k8up.globalResources.requests.cpu | string | `""` | Global CPU resource requests applied to jobs. See [supported units][resource-units]. |
| k8up.globalResources.requests.memory | string | `""` | Global Memory resource requests applied to jobs. See [supported units][resource-units]. |
| k8up.operatorNamespace | string | `""` | Specifies the namespace in which K8up's `EffectiveSchedules` are stored. Defaults to release namespace if left empty. |
| k8up.repositorySecretName | string | `""` | Specifies the name of the Secret that contains repository configuration values (e.g. S3 endpoint and bucket). Defaults to `k8up-repo` if left empty. |
| k8up.skipSnapshotSync | bool | `false` | Specifies whether K8up should skip synchronizing Snapshot custom resources to the cluster after backup or prune operations. When enabled, the operator passes `BACKUP_SKIP_SNAPSHOT_SYNC=true` to backup and prune job pods. Webhook notifications are still sent. |
| k8up.skipWithoutAnnotation | bool | `false` | Specifies whether K8up should ignore PVCs without the backup annotation (by default, `k8up.io/backup`) |
| k8up.timezone | string | `""` | Specifies the timezone K8up is using for scheduling. Empty value defaults to the timezone in which Kubernetes is deployed. Accepts `tz database` compatible entries, e.g. `Europe/Zurich` |
Expand Down
8 changes: 8 additions & 0 deletions charts/k8up/crds/k8up.io_archives.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -383,8 +383,12 @@ spec:
x-kubernetes-map-type: atomic
bucket:
type: string
bucketSecretKey:
type: string
endpoint:
type: string
endpointSecretKey:
type: string
secretAccessKeySecretRef:
description: SecretKeySelector selects a key of a Secret.
properties:
Expand Down Expand Up @@ -873,8 +877,12 @@ spec:
x-kubernetes-map-type: atomic
bucket:
type: string
bucketSecretKey:
type: string
endpoint:
type: string
endpointSecretKey:
type: string
secretAccessKeySecretRef:
description: SecretKeySelector selects a key of a Secret.
properties:
Expand Down
4 changes: 4 additions & 0 deletions charts/k8up/crds/k8up.io_backups.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -390,8 +390,12 @@ spec:
x-kubernetes-map-type: atomic
bucket:
type: string
bucketSecretKey:
type: string
endpoint:
type: string
endpointSecretKey:
type: string
secretAccessKeySecretRef:
description: SecretKeySelector selects a key of a Secret.
properties:
Expand Down
4 changes: 4 additions & 0 deletions charts/k8up/crds/k8up.io_checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,12 @@ spec:
x-kubernetes-map-type: atomic
bucket:
type: string
bucketSecretKey:
type: string
endpoint:
type: string
endpointSecretKey:
type: string
secretAccessKeySecretRef:
description: SecretKeySelector selects a key of a Secret.
properties:
Expand Down
4 changes: 4 additions & 0 deletions charts/k8up/crds/k8up.io_prunes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,12 @@ spec:
x-kubernetes-map-type: atomic
bucket:
type: string
bucketSecretKey:
type: string
endpoint:
type: string
endpointSecretKey:
type: string
secretAccessKeySecretRef:
description: SecretKeySelector selects a key of a Secret.
properties:
Expand Down
8 changes: 8 additions & 0 deletions charts/k8up/crds/k8up.io_restores.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,12 @@ spec:
x-kubernetes-map-type: atomic
bucket:
type: string
bucketSecretKey:
type: string
endpoint:
type: string
endpointSecretKey:
type: string
secretAccessKeySecretRef:
description: SecretKeySelector selects a key of a Secret.
properties:
Expand Down Expand Up @@ -875,8 +879,12 @@ spec:
x-kubernetes-map-type: atomic
bucket:
type: string
bucketSecretKey:
type: string
endpoint:
type: string
endpointSecretKey:
type: string
secretAccessKeySecretRef:
description: SecretKeySelector selects a key of a Secret.
properties:
Expand Down
32 changes: 32 additions & 0 deletions charts/k8up/crds/k8up.io_schedules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -376,8 +376,12 @@ spec:
x-kubernetes-map-type: atomic
bucket:
type: string
bucketSecretKey:
type: string
endpoint:
type: string
endpointSecretKey:
type: string
secretAccessKeySecretRef:
description: SecretKeySelector selects a key of a Secret.
properties:
Expand Down Expand Up @@ -868,8 +872,12 @@ spec:
x-kubernetes-map-type: atomic
bucket:
type: string
bucketSecretKey:
type: string
endpoint:
type: string
endpointSecretKey:
type: string
secretAccessKeySecretRef:
description: SecretKeySelector selects a key of a Secret.
properties:
Expand Down Expand Up @@ -1486,8 +1494,12 @@ spec:
x-kubernetes-map-type: atomic
bucket:
type: string
bucketSecretKey:
type: string
endpoint:
type: string
endpointSecretKey:
type: string
secretAccessKeySecretRef:
description: SecretKeySelector selects a key of a Secret.
properties:
Expand Down Expand Up @@ -1930,8 +1942,12 @@ spec:
x-kubernetes-map-type: atomic
bucket:
type: string
bucketSecretKey:
type: string
endpoint:
type: string
endpointSecretKey:
type: string
secretAccessKeySecretRef:
description: SecretKeySelector selects a key of a Secret.
properties:
Expand Down Expand Up @@ -2950,8 +2966,12 @@ spec:
x-kubernetes-map-type: atomic
bucket:
type: string
bucketSecretKey:
type: string
endpoint:
type: string
endpointSecretKey:
type: string
secretAccessKeySecretRef:
description: SecretKeySelector selects a key of a Secret.
properties:
Expand Down Expand Up @@ -4164,8 +4184,12 @@ spec:
x-kubernetes-map-type: atomic
bucket:
type: string
bucketSecretKey:
type: string
endpoint:
type: string
endpointSecretKey:
type: string
secretAccessKeySecretRef:
description: SecretKeySelector selects a key of a Secret.
properties:
Expand Down Expand Up @@ -5204,8 +5228,12 @@ spec:
x-kubernetes-map-type: atomic
bucket:
type: string
bucketSecretKey:
type: string
endpoint:
type: string
endpointSecretKey:
type: string
secretAccessKeySecretRef:
description: SecretKeySelector selects a key of a Secret.
properties:
Expand Down Expand Up @@ -5696,8 +5724,12 @@ spec:
x-kubernetes-map-type: atomic
bucket:
type: string
bucketSecretKey:
type: string
endpoint:
type: string
endpointSecretKey:
type: string
secretAccessKeySecretRef:
description: SecretKeySelector selects a key of a Secret.
properties:
Expand Down
2 changes: 2 additions & 0 deletions charts/k8up/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ spec:
value: "{{ .Values.k8up.skipWithoutAnnotation }}"
- name: BACKUP_GLOBAL_SKIP_SNAPSHOT_SYNC
value: "{{ .Values.k8up.skipSnapshotSync }}"
- name: BACKUP_REPOSITORY_SECRET_NAME
value: "{{ .Values.k8up.repositorySecretName | default "k8up-repo" }}"
- name: BACKUP_OPERATOR_NAMESPACE
{{- if .Values.k8up.operatorNamespace }}
value: "{{ .Values.k8up.operatorNamespace }}"
Expand Down
8 changes: 8 additions & 0 deletions charts/k8up/templates/operator-clusterrole.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ rules:
- get
- list
- watch
- apiGroups:
- ""
resourceNames:
- {{ .Values.k8up.repositorySecretName | default "k8up-repo" }}
resources:
- secrets
verbs:
- get
- apiGroups:
- ""
resources:
Expand Down
Loading
Loading