diff --git a/internal/cnpgi/operator/specs/role.go b/internal/cnpgi/operator/specs/role.go index a53278d6..6abe1175 100644 --- a/internal/cnpgi/operator/specs/role.go +++ b/internal/cnpgi/operator/specs/role.go @@ -60,7 +60,7 @@ func BuildRoleRules(barmanObjects []barmancloudv1.ObjectStore) []rbacv1.PolicyRu } } - return []rbacv1.PolicyRule{ + rules := []rbacv1.PolicyRule{ { APIGroups: []string{ barmancloudv1.GroupVersion.Group, @@ -87,7 +87,11 @@ func BuildRoleRules(barmanObjects []barmancloudv1.ObjectStore) []rbacv1.PolicyRu }, ResourceNames: barmanObjectsSet.ToSortedList(), }, - { + } + + secrets := secretsSet.ToSortedList() + if len(secrets) > 0 { + rules = append(rules, rbacv1.PolicyRule{ APIGroups: []string{ "", }, @@ -99,9 +103,11 @@ func BuildRoleRules(barmanObjects []barmancloudv1.ObjectStore) []rbacv1.PolicyRu "watch", "list", }, - ResourceNames: secretsSet.ToSortedList(), - }, + ResourceNames: secrets, + }) } + + return rules } // ObjectStoreNamesFromRole extracts the ObjectStore names referenced diff --git a/internal/cnpgi/operator/specs/role_test.go b/internal/cnpgi/operator/specs/role_test.go index bb5c9a13..33bcc470 100644 --- a/internal/cnpgi/operator/specs/role_test.go +++ b/internal/cnpgi/operator/specs/role_test.go @@ -78,13 +78,12 @@ var _ = Describe("BuildRoleRules", func() { Expect(rules[2].ResourceNames).To(ConsistOf("secret-a", "secret-b")) }) - It("should produce rules with empty ResourceNames for empty input", func() { + It("should not produce a secrets rule for empty input", func() { rules := BuildRoleRules(nil) - Expect(rules).To(HaveLen(3)) + Expect(rules).To(HaveLen(2)) Expect(rules[0].ResourceNames).To(BeEmpty()) Expect(rules[0].ResourceNames).NotTo(BeNil()) Expect(rules[1].ResourceNames).To(BeEmpty()) - Expect(rules[2].ResourceNames).To(BeEmpty()) }) It("should deduplicate secret names across ObjectStores", func() { @@ -95,6 +94,31 @@ var _ = Describe("BuildRoleRules", func() { rules := BuildRoleRules(objects) Expect(rules[2].ResourceNames).To(Equal([]string{"shared-secret"})) }) + + It("should not produce a secrets rule when ObjectStores use IAM role inheritance", func() { + objects := []barmancloudv1.ObjectStore{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "store-a", + Namespace: "default", + }, + Spec: barmancloudv1.ObjectStoreSpec{ + Configuration: barmanapi.BarmanObjectStoreConfiguration{ + DestinationPath: "s3://bucket/path", + BarmanCredentials: barmanapi.BarmanCredentials{ + AWS: &barmanapi.S3Credentials{ + InheritFromIAMRole: true, + }, + }, + }, + }, + }, + } + rules := BuildRoleRules(objects) + Expect(rules).To(HaveLen(2)) + Expect(rules[0].ResourceNames).To(Equal([]string{"store-a"})) + Expect(rules[1].ResourceNames).To(Equal([]string{"store-a"})) + }) }) var _ = Describe("BuildRole", func() { diff --git a/internal/cnpgi/operator/specs/secrets.go b/internal/cnpgi/operator/specs/secrets.go index 89811ad2..4f365c1f 100644 --- a/internal/cnpgi/operator/specs/secrets.go +++ b/internal/cnpgi/operator/specs/secrets.go @@ -28,13 +28,17 @@ import ( func CollectSecretNamesFromCredentials(barmanCredentials *barmanapi.BarmanCredentials) []string { var references []*machineryapi.SecretKeySelector if barmanCredentials.AWS != nil { - references = append( - references, - barmanCredentials.AWS.AccessKeyIDReference, - barmanCredentials.AWS.SecretAccessKeyReference, - barmanCredentials.AWS.RegionReference, - barmanCredentials.AWS.SessionToken, - ) + // When using IAM role inheritance, barman-cloud uses the pod + // environment credential chain and does not read credential Secrets. + if !barmanCredentials.AWS.InheritFromIAMRole { + references = append( + references, + barmanCredentials.AWS.AccessKeyIDReference, + barmanCredentials.AWS.SecretAccessKeyReference, + barmanCredentials.AWS.RegionReference, + barmanCredentials.AWS.SessionToken, + ) + } } if barmanCredentials.Azure != nil { // When using default Azure credentials or managed identity, no secrets are required diff --git a/internal/cnpgi/operator/specs/secrets_test.go b/internal/cnpgi/operator/specs/secrets_test.go index d6fa706b..52cb4ba9 100644 --- a/internal/cnpgi/operator/specs/secrets_test.go +++ b/internal/cnpgi/operator/specs/secrets_test.go @@ -57,6 +57,29 @@ var _ = Describe("CollectSecretNamesFromCredentials", func() { secrets := CollectSecretNamesFromCredentials(credentials) Expect(secrets).To(BeEmpty()) }) + + It("should return empty list when using InheritFromIAMRole", func() { + credentials := &barmanapi.BarmanCredentials{ + AWS: &barmanapi.S3Credentials{ + InheritFromIAMRole: true, + AccessKeyIDReference: &machineryapi.SecretKeySelector{ + LocalObjectReference: machineryapi.LocalObjectReference{ + Name: "aws-secret", + }, + Key: "access-key-id", + }, + RegionReference: &machineryapi.SecretKeySelector{ + LocalObjectReference: machineryapi.LocalObjectReference{ + Name: "aws-region", + }, + Key: "region", + }, + }, + } + + secrets := CollectSecretNamesFromCredentials(credentials) + Expect(secrets).To(BeEmpty()) + }) }) Context("when collecting secrets from Azure credentials", func() { diff --git a/internal/controller/objectstore_controller_test.go b/internal/controller/objectstore_controller_test.go index 0f64ac52..8c4360bd 100644 --- a/internal/controller/objectstore_controller_test.go +++ b/internal/controller/objectstore_controller_test.go @@ -31,8 +31,8 @@ import ( apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/types" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/client/interceptor" @@ -261,7 +261,7 @@ var _ = Describe("ObjectStoreReconciler", func() { Expect(result).To(Equal(reconcile.Result{})) }) - It("should produce empty ResourceNames when all ObjectStores are deleted", func() { + It("should omit the secrets rule when all ObjectStores are deleted", func() { store := newTestObjectStore("my-store", "default", "aws-creds") role := newLabeledRole("my-cluster", "default", []barmancloudv1.ObjectStore{*store}) @@ -291,10 +291,11 @@ var _ = Describe("ObjectStoreReconciler", func() { Name: "my-cluster-barman-cloud", }, &updatedRole)).To(Succeed()) - // All rules should have empty ResourceNames Expect(updatedRole.Rules[0].ResourceNames).To(BeEmpty()) Expect(updatedRole.Rules[1].ResourceNames).To(BeEmpty()) - Expect(updatedRole.Rules[2].ResourceNames).To(BeEmpty()) + for _, rule := range updatedRole.Rules { + Expect(rule.Resources).NotTo(Equal([]string{"secrets"})) + } }) It("should return an error when listing Roles fails", func() {