github.com/argoproj/argo-cd/v3@v3.2.1/test/e2e/sync_with_impersonate_test.go (about) 1 package e2e 2 3 import ( 4 "fmt" 5 "testing" 6 "time" 7 8 "github.com/argoproj/argo-cd/v3/test/e2e/fixture/project" 9 10 "github.com/stretchr/testify/require" 11 rbacv1 "k8s.io/api/rbac/v1" 12 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 13 "k8s.io/apimachinery/pkg/types" 14 15 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" 16 "github.com/argoproj/argo-cd/v3/test/e2e/fixture" 17 . "github.com/argoproj/argo-cd/v3/test/e2e/fixture/app" 18 ) 19 20 const ( 21 WaitDuration = time.Second 22 TimeoutDuration = time.Second * 3 23 ) 24 25 func TestSyncWithFeatureDisabled(t *testing.T) { 26 Given(t). 27 Path("guestbook"). 28 When(). 29 WithImpersonationDisabled(). 30 CreateFromFile(func(app *v1alpha1.Application) { 31 app.Spec.SyncPolicy = &v1alpha1.SyncPolicy{Automated: &v1alpha1.SyncPolicyAutomated{}} 32 }). 33 Then(). 34 // With the impersonation feature disabled, Application sync should continue to use 35 // the control plane service account for the sync operation and the sync should succeed. 36 ExpectConsistently(SyncStatusIs(v1alpha1.SyncStatusCodeSynced), WaitDuration, TimeoutDuration). 37 Expect(OperationMessageContains("successfully synced")) 38 } 39 40 func TestSyncWithNoDestinationServiceAccountsInProject(t *testing.T) { 41 Given(t). 42 Path("guestbook"). 43 When(). 44 CreateFromFile(func(app *v1alpha1.Application) { 45 app.Spec.SyncPolicy = &v1alpha1.SyncPolicy{Automated: &v1alpha1.SyncPolicyAutomated{}} 46 }). 47 WithImpersonationEnabled("", nil). 48 Then(). 49 // With the impersonation feature enabled, Application sync must fail 50 // when there are no destination service accounts configured in AppProject 51 ExpectConsistently(SyncStatusIs(v1alpha1.SyncStatusCodeOutOfSync), WaitDuration, TimeoutDuration). 52 Expect(OperationMessageContains("failed to find a matching service account to impersonate")) 53 } 54 55 func TestSyncWithImpersonateWithSyncServiceAccount(t *testing.T) { 56 projectName := "sync-test-project" 57 serviceAccountName := "test-account" 58 59 projectCtx := project.Given(t) 60 appCtx := Given(t) 61 62 projectCtx. 63 Name(projectName). 64 SourceNamespaces([]string{"*"}). 65 SourceRepositories([]string{"*"}). 66 Destination("*,*"). 67 DestinationServiceAccounts( 68 []string{ 69 fmt.Sprintf("%s,%s,%s", "*", fixture.DeploymentNamespace(), serviceAccountName), 70 fmt.Sprintf("%s,%s,%s", v1alpha1.KubernetesInternalAPIServerAddr, fixture.DeploymentNamespace(), "missing-serviceAccount"), 71 }). 72 When(). 73 Create(). 74 Then(). 75 Expect() 76 77 appCtx. 78 SetTrackingMethod("annotation"). 79 Path("guestbook"). 80 When(). 81 WithImpersonationEnabled(serviceAccountName, []rbacv1.PolicyRule{ 82 { 83 APIGroups: []string{"apps", ""}, 84 Resources: []string{"deployments"}, 85 Verbs: []string{"*"}, 86 }, 87 { 88 APIGroups: []string{""}, 89 Resources: []string{"services"}, 90 Verbs: []string{"*"}, 91 }, 92 }). 93 CreateFromFile(func(app *v1alpha1.Application) { 94 app.Spec.SyncPolicy = &v1alpha1.SyncPolicy{Automated: &v1alpha1.SyncPolicyAutomated{}} 95 app.Spec.Project = projectName 96 }). 97 Then(). 98 // With the impersonation feature enabled, Application sync should succeed 99 // as there is a valid match found in the available destination service accounts configured in AppProject 100 ExpectConsistently(SyncStatusIs(v1alpha1.SyncStatusCodeSynced), WaitDuration, TimeoutDuration). 101 Expect(OperationMessageContains("successfully synced")) 102 } 103 104 func TestSyncWithMissingServiceAccount(t *testing.T) { 105 projectName := "false-test-project" 106 serviceAccountName := "test-account" 107 108 projectCtx := project.Given(t) 109 appCtx := Given(t) 110 111 projectCtx. 112 Name(projectName). 113 SourceNamespaces([]string{"*"}). 114 SourceRepositories([]string{"*"}). 115 Destination("*,*"). 116 DestinationServiceAccounts( 117 []string{ 118 fmt.Sprintf("%s,%s,%s", v1alpha1.KubernetesInternalAPIServerAddr, fixture.DeploymentNamespace(), "missing-serviceAccount"), 119 fmt.Sprintf("%s,%s,%s", "*", fixture.DeploymentNamespace(), serviceAccountName), 120 }). 121 When(). 122 Create(). 123 Then(). 124 Expect() 125 126 appCtx. 127 SetTrackingMethod("annotation"). 128 Path("guestbook"). 129 When(). 130 WithImpersonationEnabled(serviceAccountName, []rbacv1.PolicyRule{ 131 { 132 APIGroups: []string{"apps", ""}, 133 Resources: []string{"deployments"}, 134 Verbs: []string{"*"}, 135 }, 136 { 137 APIGroups: []string{""}, 138 Resources: []string{"services"}, 139 Verbs: []string{"*"}, 140 }, 141 }). 142 CreateFromFile(func(app *v1alpha1.Application) { 143 app.Spec.SyncPolicy = &v1alpha1.SyncPolicy{Automated: &v1alpha1.SyncPolicyAutomated{}} 144 app.Spec.Project = projectName 145 }). 146 Then(). 147 // With the impersonation feature enabled, Application sync must fail 148 // when there is a valid match found in the available destination service accounts configured in AppProject, 149 // but the matching service account is missing. 150 ExpectConsistently(SyncStatusIs(v1alpha1.SyncStatusCodeOutOfSync), WaitDuration, TimeoutDuration). 151 Expect(OperationMessageContains("one or more objects failed to apply")) 152 } 153 154 func TestSyncWithValidSAButDisallowedDestination(t *testing.T) { 155 projectName := "negation-test-project" 156 serviceAccountName := "test-account" 157 158 projectCtx := project.Given(t) 159 appCtx := Given(t) 160 161 projectCtx. 162 Name(projectName). 163 SourceNamespaces([]string{"*"}). 164 SourceRepositories([]string{"*"}). 165 Destination("*,*"). 166 DestinationServiceAccounts( 167 []string{ 168 fmt.Sprintf("%s,%s,%s", "*", fixture.DeploymentNamespace(), serviceAccountName), 169 }). 170 When(). 171 Create(). 172 Then(). 173 Expect() 174 175 appCtx. 176 SetTrackingMethod("annotation"). 177 Path("guestbook"). 178 When(). 179 WithImpersonationEnabled(serviceAccountName, []rbacv1.PolicyRule{ 180 { 181 APIGroups: []string{"apps", ""}, 182 Resources: []string{"deployments"}, 183 Verbs: []string{"*"}, 184 }, 185 { 186 APIGroups: []string{""}, 187 Resources: []string{"services"}, 188 Verbs: []string{"*"}, 189 }, 190 }). 191 CreateFromFile(func(app *v1alpha1.Application) { 192 app.Spec.SyncPolicy = &v1alpha1.SyncPolicy{Automated: &v1alpha1.SyncPolicyAutomated{}} 193 app.Spec.Project = projectName 194 }). 195 Then(). 196 Expect(SyncStatusIs(v1alpha1.SyncStatusCodeSynced)). 197 When(). 198 And(func() { 199 // Patch destination to disallow target destination namespace 200 patch := []byte(fmt.Sprintf(`{"spec": {"destinations": [{"namespace": %q}]}}`, "!"+fixture.DeploymentNamespace())) 201 202 _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Patch(t.Context(), projectName, types.MergePatchType, patch, metav1.PatchOptions{}) 203 require.NoError(t, err) 204 }). 205 Refresh(v1alpha1.RefreshTypeNormal). 206 Then(). 207 // With the impersonation feature enabled, Application sync must fail 208 // as there is a valid match found in the available destination service accounts configured in AppProject 209 // but the destination namespace is now disallowed. 210 ExpectConsistently(SyncStatusIs(v1alpha1.SyncStatusCodeUnknown), WaitDuration, TimeoutDuration) 211 }