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
14 changes: 14 additions & 0 deletions pkg/api/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,20 @@ type S3Credentials struct {
// +optional
SessionToken *machineryapi.SecretKeySelector `json:"sessionToken,omitempty"`

// The reference to the secret containing the key for
// Server-Side Encryption with Customer-provided keys (SSE-C).
// When set, every object barman-cloud uploads to and downloads from
// S3 is encrypted with this key using the AWS SSE-C protocol
// (the `--sse-customer-key` barman-cloud option).
// The referenced value must be a base64-encoded 256-bit (32-byte)
// AES key. This is orthogonal to the bucket-managed `encryption`
// field (SSE-S3/SSE-KMS) and is meant for S3-compatible providers
// that only support customer-provided keys (e.g. Hetzner Object
// Storage). It can be combined with any authentication method,
// including inheritFromIAMRole.
// +optional
SSECustomerKey *machineryapi.SecretKeySelector `json:"sseCustomerKey,omitempty"`

// Use the role based authentication without providing explicitly the keys.
// +optional
InheritFromIAMRole bool `json:"inheritFromIAMRole,omitempty"`
Expand Down
5 changes: 5 additions & 0 deletions pkg/api/zz_generated.deepcopy.go

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

11 changes: 11 additions & 0 deletions pkg/command/commandbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"context"

barmanApi "github.com/cloudnative-pg/barman-cloud/pkg/api"
"github.com/cloudnative-pg/barman-cloud/pkg/utils"
)

// CloudWalRestoreOptions returns the options needed to execute the barman command successfully
Expand Down Expand Up @@ -87,6 +88,16 @@ func appendCloudProviderOptions(
options,
"--cloud-provider",
"aws-s3")

// When Server-Side Encryption with Customer-provided keys (SSE-C)
// is configured, point barman-cloud at the key file that the
// credentials package materializes from the referenced secret.
if credentials.AWS.SSECustomerKey != nil {
options = append(
options,
"--sse-customer-key",
"file://"+utils.SSECustomerKeyFileLocation)
}
case credentials.Azure != nil:
options = append(
options,
Expand Down
43 changes: 43 additions & 0 deletions pkg/command/commandbuilder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
machineryapi "github.com/cloudnative-pg/machinery/pkg/api"

barmanApi "github.com/cloudnative-pg/barman-cloud/pkg/api"
"github.com/cloudnative-pg/barman-cloud/pkg/utils"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
Expand Down Expand Up @@ -172,3 +173,45 @@ var _ = Describe("AppendCloudProviderOptions with Azure credentials", func() {
))
})
})

var _ = Describe("AppendCloudProviderOptions with AWS credentials", func() {
var options []string

BeforeEach(func() {
options = []string{}
})

It("should not add the SSE-C option when no customer key is set", func(ctx SpecContext) {
credentials := barmanApi.BarmanCredentials{
AWS: &barmanApi.S3Credentials{
InheritFromIAMRole: true,
},
}
result, err := appendCloudProviderOptions(ctx, options, credentials)
Expect(err).ToNot(HaveOccurred())
Expect(result).To(Equal([]string{
"--cloud-provider", "aws-s3",
}))
Expect(result).ToNot(ContainElement("--sse-customer-key"))
})

It("should add the SSE-C option pointing at the key file when a customer key is set", func(ctx SpecContext) {
credentials := barmanApi.BarmanCredentials{
AWS: &barmanApi.S3Credentials{
InheritFromIAMRole: true,
SSECustomerKey: &machineryapi.SecretKeySelector{
LocalObjectReference: machineryapi.LocalObjectReference{
Name: "sse-c-key",
},
Key: "key",
},
},
}
result, err := appendCloudProviderOptions(ctx, options, credentials)
Expect(err).ToNot(HaveOccurred())
Expect(result).To(Equal([]string{
"--cloud-provider", "aws-s3",
"--sse-customer-key", "file://" + utils.SSECustomerKeyFileLocation,
}))
})
})
34 changes: 34 additions & 0 deletions pkg/credentials/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"

barmanApi "github.com/cloudnative-pg/barman-cloud/pkg/api"
"github.com/cloudnative-pg/barman-cloud/pkg/utils"
)

const (
Expand Down Expand Up @@ -142,6 +143,13 @@ func envSetAWSCredentials(
return nil, fmt.Errorf("missing S3 credentials")
}

// Materialize the SSE-C customer key, if any, before the auth-method
// handling below: SSE-C is orthogonal to authentication and must be
// available for every method, including inheritFromIAMRole.
if err := reconcileAWSSSECustomerKey(ctx, client, namespace, s3credentials); err != nil {
return nil, err
}

if s3credentials.InheritFromIAMRole {
return env, nil
}
Expand Down Expand Up @@ -207,6 +215,32 @@ func envSetAWSCredentials(
return env, nil
}

// reconcileAWSSSECustomerKey materializes (or removes) the S3 SSE-C customer
// key file referenced by the S3 credentials. barman-cloud consumes it through
// the '--sse-customer-key file://' option, so the key must exist on disk next
// to the process that runs the barman-cloud commands. The referenced secret is
// expected to contain a base64-encoded 256-bit AES key, which barman-cloud
// validates when it reads the file.
func reconcileAWSSSECustomerKey(
ctx context.Context,
c client.Client,
namespace string,
s3credentials *barmanApi.S3Credentials,
) error {
if s3credentials.SSECustomerKey == nil {
return fileutils.RemoveFile(utils.SSECustomerKeyFileLocation)
}

key, err := extractValueFromSecret(ctx, c, s3credentials.SSECustomerKey, namespace)
if err != nil {
return err
}

_, err = fileutils.WriteFileAtomic(utils.SSECustomerKeyFileLocation, key, 0o600)

return err
}

// envSetAzureCredentials sets the Azure environment variables given the configuration
// inside the cluster
func envSetAzureCredentials(
Expand Down
5 changes: 5 additions & 0 deletions pkg/utils/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,9 @@ const (

// BarmanCloudCheckWalArchive is the command name for 'barman-cloud-check-wal-archive'
BarmanCloudCheckWalArchive = "barman-cloud-check-wal-archive"

// SSECustomerKeyFileLocation is the path where the S3 SSE-C customer key is
// materialized from its secret so that it can be passed to the barman-cloud
// commands via the '--sse-customer-key file://' option.
SSECustomerKeyFileLocation = "/controller/.sse-customer-key"
)