Skip to content
Draft
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 config/crd/bases/pgbackrest.dalibo.com_stanzas.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,60 @@ spec:
pattern: ^(0B|[0-9]+(KiB|MiB|GiB|TiB)|([0-4])PiB)$
type: string
type: object
azureRepositories:
items:
properties:
account:
description: Azure repository account.
minLength: 1
type: string
container:
description: Azure container used to store the repository.
minLength: 1
type: string
endpoint:
default: blob.core.windows.net
description: Azure repository endpoint.
minLength: 1
type: string
keyType:
default: shared
description: Azure repository key type.
enum:
- shared
- sas
- auto
minLength: 1
type: string
secretRef:
description: Reference to a Kubernetes Secret containing
the Azure repository key.
properties:
keyReference:
description: The reference to the Azure key.
properties:
key:
description: The key to select.
type: string
name:
description: Name of the referent.
type: string
required:
- key
- name
type: object
type: object
uriStyle:
description: Azure URI Style.
enum:
- host
- path
type: string
required:
- account
- container
type: object
type: array
compressConfig:
description: Define compression settings for file compression.
properties:
Expand Down
95 changes: 77 additions & 18 deletions internal/operator/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/cloudnative-pg/machinery/pkg/stringset"
apipgbackrest "github.com/dalibo/cnpg-i-pgbackrest/api/v1"
"github.com/dalibo/cnpg-i-pgbackrest/internal/metadata"
pgbackrestapi "github.com/dalibo/cnpg-i-pgbackrest/internal/pgbackrest/api"
"github.com/dalibo/cnpg-i-pgbackrest/internal/utils"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -175,51 +176,109 @@ func (c *PluginConfiguration) GetReferredPgBackrestObjectKey() []types.Namespace
return res
}

// helper to decode secret values
func decodeSecretVal(
ctx context.Context,
c client.Client,
ns string,
ref *machineryapi.SecretKeySelector,
) (string, error) {
raw, err := utils.GetValueFromSecret(ctx, c, ns, ref)
if err != nil {
return "", err
}
return string(raw), nil
}

func GetEnvVarConfig(
ctx context.Context,
r apipgbackrest.Stanza,
stanza apipgbackrest.Stanza,
c client.Client,
) ([]string, error) {
conf := r.Spec.Configuration
conf := stanza.Spec.Configuration
ns := stanza.Namespace
env, err := conf.ToEnv()
if err != nil {
return nil, err
}
// helper to fetch secret values
secretVal := func(ref *machineryapi.SecretKeySelector) (string, error) {
raw, err := utils.GetValueFromSecret(ctx, c, r.Namespace, ref)
if err != nil {
return "", err
}
return string(raw), nil
s3env, err := getEnvVarForS3(ctx, c, ns, conf.S3Repositories, 1)
if err != nil {
return nil, err
}
env = append(env, s3env...)
azureEnv, err := getEnvVarForAzure(
ctx,
c,
ns,
conf.AzureRepositories,
len(conf.S3Repositories)+1,
)
if err != nil {
return nil, err
}
for i, r := range conf.S3Repositories {
env = append(env, azureEnv...)
return env, nil
}

func getEnvVarForS3(
ctx context.Context,
c client.Client,
ns string,
repositories []pgbackrestapi.S3Repository,
startId int,
) ([]string, error) {
s3env := make([]string, 0, len(repositories))
for i, r := range repositories {
sRef := r.SecretRef
aKey, err := secretVal(sRef.AccessKeyIDReference)
aKey, err := decodeSecretVal(ctx, c, ns, sRef.AccessKeyIDReference)
if err != nil {
return nil, err
}
sKey, err := secretVal(sRef.SecretAccessKeyReference)
sKey, err := decodeSecretVal(ctx, c, ns, sRef.SecretAccessKeyReference)
if err != nil {
return nil, err
}
prefix := fmt.Sprintf("PGBACKREST_REPO%d_", i+1)
prefix := fmt.Sprintf("PGBACKREST_REPO%d_", startId+i)
if r.Cipher != nil {
encKey, err := secretVal(r.Cipher.PassReference)
encKey, err := decodeSecretVal(ctx, c, ns, r.Cipher.PassReference)
if err != nil {
return nil, err
}
env = append(env, fmt.Sprintf("%sCIPHER_PASS=%s", prefix, encKey))
s3env = append(s3env, fmt.Sprintf("%sCIPHER_PASS=%s", prefix, encKey))
}
// build env var names
env = append(
env,
s3env = append(
s3env,
fmt.Sprintf("%sS3_KEY=%s", prefix, aKey),
fmt.Sprintf("%sS3_KEY_SECRET=%s", prefix, sKey),
fmt.Sprintf("%sTYPE=%s", prefix, "s3"),
)
}
return env, nil
return s3env, nil
}

func getEnvVarForAzure(
ctx context.Context,
c client.Client,
ns string,
repositories []pgbackrestapi.AzureRepository,
startId int,
) ([]string, error) {
azureEnv := make([]string, 0, len(repositories))
for i, r := range repositories {
sRef := r.SecretRef
sKey, err := decodeSecretVal(ctx, c, ns, sRef.KeyReference)
if err != nil {
return nil, err
}
prefix := fmt.Sprintf("PGBACKREST_REPO%d_", (startId + i))
azureEnv = append(
azureEnv,
fmt.Sprintf("%sAZURE_KEY=%s", prefix, sKey),
fmt.Sprintf("%sTYPE=%s", prefix, "azure"),
)
}
return azureEnv, nil
}

type ClusterDefinitionGetter interface {
Expand Down
31 changes: 29 additions & 2 deletions internal/operator/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,18 @@ func buildFakeClient() client.Client {
"key": []byte("SECRET123"),
},
}
azureKey := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "azure-key-secret",
Namespace: "default",
},
Data: map[string][]byte{
"key": []byte("MYAZURESECRET123"),
},
}
return fake.NewClientBuilder().
WithScheme(scheme).
WithObjects(aKey, sKey).
WithObjects(aKey, sKey, azureKey).
Build()
}
func buildRepo() *apipgbackrest.Stanza {
Expand All @@ -61,7 +70,7 @@ func buildRepo() *apipgbackrest.Stanza {
Endpoint: "https://s3.example.com",
Region: "us-east-1",
RepoPath: "/backups",
SecretRef: &pgbackrest.SecretRef{
SecretRef: &pgbackrest.S3SecretRef{
AccessKeyIDReference: &machineryapi.SecretKeySelector{
LocalObjectReference: machineryapi.LocalObjectReference{
Name: "access-key-secret",
Expand All @@ -77,6 +86,20 @@ func buildRepo() *apipgbackrest.Stanza {
},
},
},
AzureRepositories: []pgbackrest.AzureRepository{
{
Account: "my_account",
Container: "my_container",
SecretRef: &pgbackrest.AzureSecretRef{
KeyReference: &machineryapi.SecretKeySelector{
LocalObjectReference: machineryapi.LocalObjectReference{
Name: "azure-key-secret",
},
Key: "key",
},
},
},
},
},
},
}
Expand All @@ -94,6 +117,10 @@ func TestGetEnvVarConfig(t *testing.T) {
"PGBACKREST_REPO1_S3_KEY=AKIA123",
"PGBACKREST_REPO1_S3_KEY_SECRET=SECRET123",
"PGBACKREST_REPO1_TYPE=s3",
"PGBACKREST_REPO2_TYPE=azure",
"PGBACKREST_REPO2_AZURE_ACCOUNT=my_account",
"PGBACKREST_REPO2_AZURE_CONTAINER=my_container",
"PGBACKREST_REPO2_AZURE_KEY=MYAZURESECRET123",
}
for _, e := range expected {
if !slices.Contains(env, e) {
Expand Down
48 changes: 45 additions & 3 deletions internal/pgbackrest/api/stanza.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ type Retention struct {
History int32 `json:"history,omitempty" ENV:"HISTORY"`
}

// SecretRef defines a reference to a Kubernetes Secret
type SecretRef struct {
// S3SecretRef defines a reference to a Kubernetes Secret
type S3SecretRef struct {
// The reference to the access key ID
// +optional
AccessKeyIDReference *machineryapi.SecretKeySelector `json:"accessKeyId,omitempty"`
Expand Down Expand Up @@ -151,7 +151,7 @@ type S3Repository struct {

// Reference to a Kubernetes Secret containing S3 credentials.
// +optional
SecretRef *SecretRef `json:"secretRef,omitempty"`
SecretRef *S3SecretRef `json:"secretRef,omitempty"`

// Path where backups and archive are stored.
// +kubebuilder:validation:MinLength=1
Expand All @@ -163,6 +163,45 @@ type S3Repository struct {
// +optional
Cipher *CipherConfig `json:"cipherConfig" nestedEnvPrefix:"_CIPHER_"`
}

// AzureSecretRef defines a reference to a Kubernetes Secret
type AzureSecretRef struct {
// The reference to the Azure key
// +optional
KeyReference *machineryapi.SecretKeySelector `json:"keyReference,omitempty"`
}

type AzureRepository struct {

// Azure repository account.
// +kubebuilder:validation:MinLength=1
Account string `json:"account" env:"_AZURE_ACCOUNT"`

// Azure container used to store the repository.
// +kubebuilder:validation:MinLength=1
Container string `json:"container" env:"_AZURE_CONTAINER"`

// Azure repository endpoint.
// +kubebuilder:validation:MinLength=1
// +optional
// +kubebuilder:default=blob.core.windows.net
Endpoint string `json:"endpoint" env:"_AZURE_ENDPOINT"`

// Reference to a Kubernetes Secret containing the Azure repository key.
SecretRef *AzureSecretRef `json:"secretRef,omitempty"`

// Azure repository key type.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Enum=shared;sas;auto
// +kubebuilder:default=shared
// +optional
KeyType string `json:"keyType" env:"_AZURE_KEY_TYPE"`

// Azure URI Style.
// +kubebuilder:validation:Enum=host;path
// +optional
UriStyle string `json:"uriStyle" env:"_AZURE_URI_STYLE"`
}
type ArchiveOption struct {

// +kubebuilder:default=false
Expand Down Expand Up @@ -198,6 +237,9 @@ type Stanza struct {
// +optional
S3Repositories []S3Repository `json:"s3Repositories" nestedEnvPrefix:"REPO"`

// +optional
AzureRepositories []AzureRepository `json:"azureRepositories" nestedEnvPrefix:"REPO"`

// +kubebuilder:validation:MinLength=1
Name string `json:"name" env:"STANZA"`

Expand Down
8 changes: 8 additions & 0 deletions internal/pgbackrest/api/stanza_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ func TestStanzaToEnv(t *testing.T) {
"PGBACKREST_LOG_LEVEL_FILE=off",
"PGBACKREST_DELTA=y",
"PGBACKREST_LOG_LEVEL_CONSOLE=trace",
"PGBACKREST_REPO3_AZURE_ACCOUNT=myaccount",
"PGBACKREST_REPO3_AZURE_CONTAINER=mycontainer",
"machin=truc",
}
b := false
Expand All @@ -59,6 +61,12 @@ func TestStanzaToEnv(t *testing.T) {
},
},
},
AzureRepositories: []AzureRepository{
{
Account: "myaccount",
Container: "mycontainer",
},
},
Archive: ArchiveOption{
Async: true,
},
Expand Down
Loading
Loading