github.com/argoproj/argo-cd/v3@v3.2.1/docs/proposals/decouple-application-sync-user-using-impersonation.md (about) 1 --- 2 title: Decouple Control plane and Application Sync privileges 3 authors: 4 - "@anandf" 5 sponsors: 6 - Red Hat 7 reviewers: 8 - "@blakepettersson" 9 - "@crenshaw-dev" 10 - "@jannfis" 11 approvers: 12 - "@alexmt" 13 - "@crenshaw-dev" 14 - "@jannfis" 15 16 creation-date: 2023-06-23 17 last-updated: 2024-02-06 18 --- 19 20 # Decouple Application Sync using Impersonation 21 22 Application syncs in Argo CD have the same privileges as the Argo CD control plane. As a consequence, in a multi-tenant setup, the Argo CD control plane privileges needs to match the tenant that needs the highest privileges. As an example, if an Argo CD instance has 10 Applications and only one of them requires admin privileges, then the Argo CD control plane must have admin privileges in order to be able to sync that one Application. Argo CD provides a multi-tenancy model to restrict what each Application can do using `AppProjects`, even though the control plane has higher privileges, however that creates a large attack surface since if Argo CD is compromised, attackers would have cluster-admin access to the cluster. 23 24 The goal of this proposal is to perform the Application sync as a different user using impersonation and use the service account provided in the cluster config purely for control plane operations. 25 26 ### What is Impersonation 27 28 Impersonation is a feature in Kubernetes and enabled in the `kubectl` CLI client, using which, a user can act as another user through impersonation headers. For example, an admin could use this feature to debug an authorization policy by temporarily impersonating another user and seeing if a request was denied. 29 30 Impersonation requests first authenticate as the requesting user, then switch to the impersonated user info. 31 32 ```shell 33 kubectl --as <user-to-impersonate> ... 34 kubectl --as <user-to-impersonate> --as-group <group-to-impersonate> ... 35 ``` 36 37 ## Open Questions [optional] 38 39 - Should the restrictions imposed as part of the `AppProjects` be honored if the impersonation feature is enabled ? 40 >Yes, other restrictions implemented by `AppProject` related to whitelisting/blacklisting resources must continue to be honoured. 41 - Can an Application refer to a service account with elevated privileges like say `cluster-admin`, `admin`, and service accounts used for running the ArgoCD controllers itself ? 42 >Yes, this is possible as long as the ArgoCD admin user explicitly allows it through the `AppProject` configuration. 43 - Among the destinations configured in the `AppProject`, if there are multiple matches for a given destination, which destination option should be used ? 44 >If there are more than one matching destination, either with a glob pattern match or an exact match, then we use the first valid match to determine the service account to be used for the sync operation. 45 - Can the kubernetes audit trail events capture the impersonation. 46 >Yes, kubernetes audit trail events capture both the actual user and the impersonating user details and hence its possible to track who executed the commands and as which user permissions using the audit trails. 47 - Would the Sync hooks be using the impersonation service account. 48 >Yes, if the impersonation feature is enabled and customers use Sync hooks, then impersonation service account would be used for executing the hook jobs as well. 49 - If application resources have hardcoded namespaces in the git repository, would different service accounts be used for each resource during the sync operation ? 50 >The service account to be used for impersonation is determined on a per Application level rather than on per resource level. The value specified in `Application.spec.destination.namespace` would be used to determine the service account to be used for the sync operation of all resources present in the `Application`. 51 52 ## Summary 53 54 In a multi team/multi tenant environment, an application team is typically granted access to a namespace to self-manage their Applications in a declarative way. Current implementation of ArgoCD requires the ArgoCD Administrator to create an `AppProject` with access settings configured to replicate the RBAC resources that are configured for each team. This approach requires duplication of effort and also requires syncing the access between both to maintain the security posture. It would be desirable for users to use the existing RBAC rules without having to revert to Argo CD API to create and manage these Applications. One namespace per team, or even one namespace per application is what we are looking to address as part of this proposal. 55 56 ## Motivation 57 58 This proposal would allow ArgoCD administrators to manage the cluster permissions using kubernetes native RBAC implementation rather than using complex configurations in `AppProjects` to restrict access to individual applications. By decoupling the privileges required for application sync from the privileges required for ArgoCD control plane operations, the security requirement of providing least privileges can be achieved there by improving the security posture of ArgoCD. For implementing multi team/tenant use cases, this decoupling would be greatly beneficial. 59 60 ### Assumptions 61 62 - Namespaces are pre-populated with one or more `ServiceAccounts` that define the permissions for each `AppProject`. 63 - Many users prefer to control access to kubernetes resources through kubernetes RBAC constructs instead of Argo specific constructs. 64 - Each tenant is generally given access to a specific namespace along with a service account, role or cluster role and role binding to control access to that namespace. 65 - `Applications` created by a tenant manage namespaced resources. 66 - An `AppProject` can either be mapped to a single tenant or multiple related tenants and the respective destinations that needs to be managed via the `AppProject`, needs to be configured. 67 68 69 ### Goals 70 - Applications may only impersonate ServiceAccounts that live in the same namespace as the destination namespace configured in the application.If the service account is created in a different namespace, then the user can provide the service account name in the format `<namespace>:<service_account_name>` . ServiceAccount to be used for syncing each application is determined by the target destination configured in the `AppProject` associated with the `Application`. 71 - If impersonation feature is enabled, and no service account name is provided in the associated `AppProject`, then the default service account of the destination namespace of the `Application` should be used. 72 - Access restrictions implemented through properties in AppProject (if done) must have the existing behavior. From a security standpoint, any restrictions that were available before switching to a service account based approach should continue to exist even when the impersonation feature is enabled. 73 - The feature can be enabled/disabled only at the system level. Once enabled/disabled, it is applicable to all Argo CD `Applications`. 74 75 ### Non-Goals 76 77 None 78 79 ## Proposal 80 81 As part of this proposal, it would be possible for an ArgoCD Admin to specify a service account name in `AppProjects` CR for a single or a group of destinations. A destination is uniquely identified by a target cluster and a namespace combined. 82 83 When applications gets synced, based on its destination (target cluster and namespace combination), the `defaultServiceAccount` configured in the `AppProject` will be selected and used for impersonation when executing the kubectl commands for the sync operation. 84 85 We would be introducing a new element `destinationServiceAccounts` in `AppProject.spec`. This element is used for the sole purpose of specifying the impersonation configuration. The `defaultServiceAccount` configured for the `AppProject` would be used for the sync operation for a particular destination cluster and namespace. If impersonation feature is enabled and no specific service account is provided in the `AppProject` CR, then the `default` service account in the destination namespace would be used for impersonation. 86 87 ```yaml 88 apiVersion: argoproj.io/v1alpha1 89 kind: AppProject 90 metadata: 91 name: my-project 92 namespace: argocd 93 finalizers: 94 - resources-finalizer.argocd.argoproj.io 95 spec: 96 description: Example Project 97 # Allow manifests to deploy from any Git repos 98 sourceRepos: 99 - '*' 100 destinations: 101 - '*' 102 destinationServiceAccounts: 103 - server: https://kubernetes.default.svc 104 namespace: guestbook 105 defaultServiceAccount: guestbook-deployer 106 - server: https://kubernetes.default.svc 107 namespace: guestbook-dev 108 defaultServiceAccount: guestbook-dev-deployer 109 - server: https://kubernetes.default.svc 110 namespace: guestbook-stage 111 defaultServiceAccount: guestbook-stage-deployer 112 - server: '*' 113 namespace: '*' 114 defaultServiceAccount: default # catch all service account to be used when all other matches fail. 115 ``` 116 117 ### Structure of DestinationServiceAccount: 118 |Parameter| Type | Required/Optional| Description| 119 | ------ | ------ | ------- | -------- | 120 | server | string | Required | Server specifies the URL of the target cluster's Kubernetes control plane API. Glob patterns are supported. | 121 | namespace | string | Required | Namespace specifies the target namespace for the application's resources. Glob patterns are supported. | 122 | defaultServiceAccount | string | Required| DefaultServiceAccount specifies the service account to be impersonated when performing the `Application` sync operation.| 123 124 **Note:** Only server URL for the target cluster is supported and target cluster name is not supported. 125 126 ### Future enhancements 127 128 In a future release, we plan to support overriding of service accounts at the application level. In that case, we would be adding an element called `allowedServiceAccounts` to `AppProject.spec.destinationServiceAccounts[*]` 129 130 ### Use cases 131 132 #### Use case 1: 133 134 As a user, I would like to use kubernetes security constructs to restrict user access for application sync 135 So that, I can provide granular permissions based on the principle of least privilege required for syncing an application. 136 137 #### Use case 2: 138 139 As a user, I would like to configure a common service account for all applications associated to an AppProject 140 So that, I can use a generic convention of naming service accounts and avoid associating the service account per application. 141 142 ### Design considerations 143 144 - Extending the `destinations` field under `AppProjects` was an option that was considered. But since the intent of it was to restrict the destinations that an associated `Application` can use, it was not used. Also the destination fields allowed negation operator (`!`) which would complicate the service account matching logic. The decision to create a new struct under `AppProject.Spec` for specifying the service account for each destination was considered a better alternative. 145 146 - The field name `defaultServiceAccount` was chosen instead of `serviceAccount` as we wanted to support overriding of the service account at an `Application` at a later point in time and wanted to reserve the name `serviceAccount` for future extension. 147 148 - Not supporting all impersonation options at the moment to keep the initial design to a minimum. Based on the need and feedback, support to impersonate users or groups can be added in future. 149 150 ### Implementation Details/Notes/Constraints 151 152 #### Component : GitOps Engine 153 154 - Fix GitOps Engine code to honor Impersonate configuration set in the Application sync context for all kubectl commands that are being executed. 155 156 #### Component: ArgoCD API 157 158 - Create a new struct type `DestinationServiceAccount` having fields `namespace`, `server` and `defaultServiceAccount` 159 - Create a new field `DestinationServiceAccounts` under a `AppProject.Spec` that takes in a list of `DestinationServiceAccount` objects. 160 - Add Documentation for newly introduced struct and its fields for `DestinationServiceAccount` and `DestinationServiceAccounts` under `AppProject.Spec` 161 162 #### Component: ArgoCD Application Controller 163 164 - Provide a configuration in `argocd-cm` which can be modified to enable the Impersonation feature. Set `applicationcontroller.enable.impersonation: true` in the Argo CD ConfigMap. Default value of `applicationcontroller.enable.impersonation` would be `false` and user has to explicitly override it to use this feature. 165 - Provide an option to override the Impersonation feature using environment variables. 166 Set `ARGOCD_APPLICATION_CONTROLLER_ENABLE_IMPERSONATION=true` in the Application controller environment variables. Default value of the environment variable must be `false` and user has to explicitly set it to `true` to use this feature. 167 - Provide an option to enable this feature using a command line flag `--enable-impersonation`. This new argument option needs to be added to the Application controller args. 168 - Fix Application Controller `sync.go` to set the Impersonate configuration from the AppProject CR to the `SyncContext` Object (rawConfig and restConfig field, need to understand which config is used for the actual sync and if both configs need to be impersonated.) 169 170 #### Component: ArgoCD UI 171 172 - Provide option to create `DestinationServiceAccount` with fields `namespace`, `server` and `defaultServiceAccount`. 173 - Provide option to add multiple `DestinationServiceAccounts` to an `AppProject` created/updated via the web console. 174 - Update the User Guide documentation on how to use these newly added fields from the web console. 175 176 #### Component: ArgoCD CLI 177 178 - Provide option to create `DestinationServiceAccount` with fields `namespace`, `server` and `defaultServiceAccount`. 179 - Provide option to add multiple `DestinationServiceAccounts` to an `AppProject` created/updated via the web console. 180 - Update the User Guide and other documentation where the CLI option usages are explained. 181 182 #### Component: Documentation 183 184 - Add note that this is a Beta feature in the documentation. 185 - Add a separate section for this feature under user-guide section. 186 - Update the ArgoCD CLI command reference documentation. 187 - Update the ArgoCD UI command reference documentation. 188 189 ### Detailed examples 190 191 #### Example 1: Service account for application sync specified at the AppProject level for all namespaces 192 193 In this specific scenario, service account name `generic-deployer` will get used for the application sync as the namespace `guestbook` matches the glob pattern `*`. 194 195 - Install ArgoCD in the `argocd` namespace. 196 ```shell 197 kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/install.yaml -n argocd 198 ``` 199 200 - Enable the impersonation feature in ArgoCD. 201 ```shell 202 kubectl patch cm argocd-cm -n argocd --type json --patch '[{ "op": "add", "path": "/data/application.sync.impersonation.enabled", "value": "true" }]' 203 ``` 204 205 - Create a namespace called `guestbook` and a service account called `guestbook-deployer`. 206 ``` 207 kubectl create namespace guestbook 208 kubectl create serviceaccount guestbook-deployer 209 ``` 210 211 - Create Role and RoleBindings and configure RBAC access for creating `Service` and `Deployment` objects in namespace `guestbook` for service account `guestbook-deployer`. 212 ```shell 213 kubectl create role guestbook-deployer-role --verb get,list,update,delete --resource pods,deployment,service 214 kubectl create rolebinding guestbook-deployer-rb --serviceaccount guestbook-deployer --role guestbook-deployer-role 215 ``` 216 217 - Create the `Application` in the `argocd` namespace and the required `AppProject` as below 218 ```yaml 219 apiVersion: argoproj.io/v1alpha1 220 kind: Application 221 metadata: 222 name: guestbook 223 namespace: argocd 224 spec: 225 project: my-project 226 source: 227 repoURL: https://github.com/argoproj/argocd-example-apps.git 228 targetRevision: HEAD 229 path: guestbook 230 destination: 231 server: https://kubernetes.default.svc 232 namespace: guestbook 233 --- 234 apiVersion: argoproj.io/v1alpha1 235 kind: AppProject 236 metadata: 237 name: my-project 238 namespace: argocd 239 finalizers: 240 - resources-finalizer.argocd.argoproj.io 241 spec: 242 description: Example Project 243 # Allow manifests to deploy from any Git repos 244 sourceRepos: 245 - '*' 246 destinations: 247 - namespace: '*' 248 server: https://kubernetes.default.svc 249 destinationServiceAccounts: 250 - namespace: '*' 251 server: https://kubernetes.default.svc 252 defaultServiceAccount: generic-deployer 253 ``` 254 255 #### Example 2: Service account for application sync specified at the AppProject level for specific namespaces 256 257 In this specific scenario, service account name `guestbook-deployer` will get used for the application sync as the namespace `guestbook` matches the target namespace `guestbook`. 258 259 - Install ArgoCD in the `argocd` namespace. 260 ```shell 261 kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/install.yaml -n argocd 262 ``` 263 264 - Enable the impersonation feature in ArgoCD. 265 ```shell 266 kubectl patch cm argocd-cm -n argocd --type json --patch '[{ "op": "add", "path": "/data/application.sync.impersonation.enabled", "value": "true" }]' 267 ``` 268 269 - Create a namespace called `guestbook` and a service account called `guestbook-deployer`. 270 ```shell 271 kubectl create namespace guestbook 272 kubectl create serviceaccount guestbook-deployer 273 ``` 274 - Create Role and RoleBindings and configure RBAC access for creating `Service` and `Deployment` objects in namespace `guestbook` for service account `guestbook-deployer`. 275 ```shell 276 kubectl create role guestbook-deployer-role --verb get,list,update,delete --resource pods,deployment,service 277 kubectl create rolebinding guestbook-deployer-rb --serviceaccount guestbook-deployer --role guestbook-deployer-role 278 ``` 279 280 In this specific scenario, service account name `guestbook-deployer` will get used as it matches to the specific namespace `guestbook`. 281 ```yaml 282 apiVersion: argoproj.io/v1alpha1 283 kind: Application 284 metadata: 285 name: guestbook 286 namespace: argocd 287 spec: 288 project: my-project 289 source: 290 repoURL: https://github.com/argoproj/argocd-example-apps.git 291 targetRevision: HEAD 292 path: guestbook 293 destination: 294 server: https://kubernetes.default.svc 295 namespace: guestbook 296 --- 297 apiVersion: argoproj.io/v1alpha1 298 kind: AppProject 299 metadata: 300 name: my-project 301 namespace: argocd 302 finalizers: 303 - resources-finalizer.argocd.argoproj.io 304 spec: 305 description: Example Project 306 # Allow manifests to deploy from any Git repos 307 sourceRepos: 308 - '*' 309 destinations: 310 - namespace: guestbook 311 server: https://kubernetes.default.svc 312 - namespace: guestbook-ui 313 server: https://kubernetes.default.svc 314 destinationServiceAccounts: 315 - namespace: guestbook 316 server: https://kubernetes.default.svc 317 defaultServiceAccount: guestbook-deployer 318 - namespace: guestbook-ui 319 server: https://kubernetes.default.svc 320 defaultServiceAccount: guestbook-ui-deployer 321 ``` 322 323 #### Example 3: Remote destination with cluster-admin access and using different service account for the sync operation 324 325 **Note**: In this example, we are relying on the default service account `argocd-manager` with `cluster-admin` privileges which gets created when adding a remote cluster destination using the ArgoCD CLI. 326 327 - Install ArgoCD in the `argocd` namespace. 328 ```shell 329 kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/install.yaml -n argocd 330 ``` 331 332 - Enable the impersonation feature in ArgoCD. 333 ```shell 334 kubectl patch cm argocd-cm -n argocd --type json --patch '[{ "op": "add", "path": "/data/application.sync.impersonation.enabled", "value": "true" }]' 335 ``` 336 337 - Add the remote cluster as a destination to argocd 338 ```shell 339 argocd cluster add remote-cluster --name remote-cluster 340 ``` 341 **Note:** The above command would create a service account named `argocd-manager` in `kube-system` namespace and `ClusterRole` named `argocd-manager-role` with full cluster admin access and a `ClusterRoleBinding` named `argocd-manager-role-binding` mapping the `argocd-manager-role` to the service account `remote-cluster` 342 343 - In the remote cluster, create a namespace called `guestbook` and a service account called `guestbook-deployer`. 344 ```shell 345 kubectl ctx remote-cluster 346 kubectl create namespace guestbook 347 kubectl create serviceaccount guestbook-deployer 348 ``` 349 350 - In the remote cluster, create `Role` and `RoleBindings` and configure RBAC access for creating `Service` and `Deployment` objects in namespace `guestbook` for service account `guestbook-deployer`. 351 352 ```shell 353 kubectl ctx remote-cluster 354 kubectl create role guestbook-deployer-role --verb get,list,update,delete --resource pods,deployment,service 355 kubectl create rolebinding guestbook-deployer-rb --serviceaccount guestbook-deployer --role guestbook-deployer-role 356 ``` 357 358 - Create the `Application` and `AppProject` for the `guestbook` application. 359 ```yaml 360 apiVersion: argoproj.io/v1alpha1 361 kind: Application 362 metadata: 363 name: guestbook 364 namespace: argocd 365 spec: 366 project: my-project 367 source: 368 repoURL: https://github.com/argoproj/argocd-example-apps.git 369 targetRevision: HEAD 370 path: guestbook 371 destination: 372 server: https://kubernetes.default.svc 373 namespace: guestbook 374 --- 375 apiVersion: argoproj.io/v1alpha1 376 kind: AppProject 377 metadata: 378 name: my-project 379 namespace: argocd 380 finalizers: 381 - resources-finalizer.argocd.argoproj.io 382 spec: 383 description: Example Project 384 # Allow manifests to deploy from any Git repos 385 sourceRepos: 386 - '*' 387 destinations: 388 - namespace: guestbook 389 server: https://kubernetes.default.svc 390 destinationServiceAccounts: 391 - namespace: guestbook 392 server: https://kubernetes.default.svc 393 defaultServiceAccount: guestbook-deployer 394 ``` 395 396 #### Example 4: Remote destination with a custom service account for the sync operation 397 398 **Note**: In this example, we are relying on a non default service account `guestbook` created in the target cluster and namespace for the sync operation. This use case is for handling scenarios where the remote cluster is managed by a different administrator and providing a service account with `cluster-admin` level access is not feasible. 399 400 - Install ArgoCD in the `argocd` namespace. 401 ```shell 402 kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/install.yaml -n argocd 403 ``` 404 405 - Enable the impersonation feature in ArgoCD. 406 ```shell 407 kubectl patch cm argocd-cm -n argocd --type json --patch '[{ "op": "add", "path": "/data/application.sync.impersonation.enabled", "value": "true" }]' 408 ``` 409 410 - In the remote cluster, create a service account called `argocd-admin` 411 ```shell 412 kubectl ctx remote-cluster 413 kubectl create serviceaccount argocd-admin 414 kubectl create clusterrole argocd-admin-role --verb=impersonate --resource="users,groups,serviceaccounts" 415 kubectl create clusterrole argocd-admin-role-access-review --verb=create --resource="selfsubjectaccessreviews" 416 kubectl create clusterrolebinding argocd-admin-role-binding --serviceaccount argocd-admin --clusterrole argocd-admin-role 417 kubectl create clusterrolebinding argocd-admin-access-review-role-binding --serviceaccount argocd-admin --clusterrole argocd-admin-role 418 ``` 419 420 - In the remote cluster, create a namespace called `guestbook` and a service account called `guestbook-deployer`. 421 ```shell 422 kubectl ctx remote-cluster 423 kubectl create namespace guestbook 424 kubectl create serviceaccount guestbook-deployer 425 ``` 426 427 - In the remote cluster, create `Role` and `RoleBindings` and configure RBAC access for creating `Service` and `Deployment` objects in namespace `guestbook` for service account `guestbook-deployer`. 428 ```shell 429 kubectl create role guestbook-deployer-role --verb get,list,update,delete --resource pods,deployment,service 430 kubectl create rolebinding guestbook-deployer-rb --serviceaccount guestbook-deployer --role guestbook-deployer-role 431 ``` 432 433 In this specific scenario, service account name `guestbook-deployer` will get used as it matches to the specific namespace `guestbook`. 434 ```yaml 435 apiVersion: argoproj.io/v1alpha1 436 kind: Application 437 metadata: 438 name: guestbook 439 namespace: argocd 440 spec: 441 project: my-project 442 source: 443 repoURL: https://github.com/argoproj/argocd-example-apps.git 444 targetRevision: HEAD 445 path: guestbook 446 destination: 447 server: https://kubernetes.default.svc 448 namespace: guestbook 449 --- 450 apiVersion: argoproj.io/v1alpha1 451 kind: AppProject 452 metadata: 453 name: my-project 454 namespace: argocd 455 finalizers: 456 - resources-finalizer.argocd.argoproj.io 457 spec: 458 description: Example Project 459 # Allow manifests to deploy from any Git repos 460 sourceRepos: 461 - '*' 462 destinations: 463 - namespace: guestbook 464 server: https://kubernetes.default.svc 465 - namespace: guestbook-ui 466 server: https://kubernetes.default.svc 467 destinationServiceAccounts: 468 - namespace: guestbook 469 server: https://kubernetes.default.svc 470 defaultServiceAccount: guestbook-deployer 471 - namespace: guestbook-ui 472 server: https://kubernetes.default.svc 473 defaultServiceAccount: guestbook-ui-deployer 474 ``` 475 476 ### Special cases 477 478 #### Specifying service account in a different namespace 479 480 By default, the service account would be looked up in the Application's destination namespace configured through `Application.Spec.Destination.Namespace` field. If the service account is in a different namespace, then users can provide the namespace of the service account explicitly in the format <namespace>:<service_account_name> 481 eg: 482 ```yaml 483 ... 484 destinationServiceAccounts: 485 - server: https://kubernetes.default.svc 486 namespace: '*' 487 defaultServiceAccount: mynamespace:guestbook-deployer 488 ... 489 ``` 490 491 #### Multiple matches of destinations 492 493 If there are multiple matches for a given destination, the first valid match in the list of `destinationServiceAccounts` would be used. 494 495 eg: 496 Lets assume that the `AppProject` has the below `destinationServiceAccounts` configured. 497 ```yaml 498 ... 499 destinationServiceAccounts: 500 - server: https://kubernetes.default.svc 501 namespace: guestbook-prod 502 defaultServiceAccount: guestbook-prod-deployer 503 - server: https://kubernetes.default.svc 504 namespace: 'guestbook-*' 505 defaultServiceAccount: guestbook-generic-deployer 506 - server: https://kubernetes.default.svc 507 namespace: '*' 508 defaultServiceAccount: generic-deployer 509 ... 510 ``` 511 - If the application destination namespace is `myns`, then the service account `generic-deployer` would be used as the first valid match is the glob pattern `*` and there are no other valid matches in the list. 512 - If the application destination namespace is `guestbook-dev` or `guestbook-stage`, then both glob patterns `*` and `guestbook-*` are valid matches, however `guestbook-*` pattern appears first and hence, the service account `guestbook-generic-deployer` would be used for the impersonation. 513 - If the application destination namespace is `guestbook-prod`, then there are three candidates, however the first valid match in the list is the one with service account `guestbook-prod-deployer` and that would be used for the impersonation. 514 515 #### Application resources referring to multiple namespaces 516 If application resources have hardcoded namespaces in the git repository, would different service accounts be used for each resource during the sync operation ? 517 518 The service account to be used for impersonation is determined on a per Application level rather than on per resource level. The value specified in `Application.spec.destination.namespace` would be used to determine the service account to be used for the sync operation of all resources present in the `Application`. 519 520 #### Application does not have a `spec.destination.namespace` field 521 `spec.destination.namespace` is an optional field in an `Application`. If the user does not specify it, the application controller will use the service account in the Application's namespace for the sync operation. User's also have the option of specifying the service account along with its namespace, in which case the service account in the user specified namespace will be used for the sync operation. 522 523 eg: 524 525 ```yaml 526 apiVersion: argoproj.io/v1alpha1 527 kind: Application 528 metadata: 529 name: guestbook 530 namespace: argocd 531 spec: 532 project: my-project 533 source: 534 repoURL: https://github.com/argoproj/argocd-example-apps.git 535 targetRevision: HEAD 536 path: guestbook 537 destination: 538 server: https://kubernetes.default.svc 539 --- 540 apiVersion: argoproj.io/v1alpha1 541 kind: AppProject 542 metadata: 543 name: my-project 544 namespace: argocd 545 finalizers: 546 - resources-finalizer.argocd.argoproj.io 547 spec: 548 description: Example Project 549 # Allow manifests to deploy from any Git repos 550 sourceRepos: 551 - '*' 552 destinations: 553 - namespace: guestbook 554 server: https://kubernetes.default.svc 555 - namespace: guestbook-ui 556 server: https://kubernetes.default.svc 557 destinationServiceAccounts: 558 - namespace: guestbook 559 server: https://kubernetes.default.svc 560 defaultServiceAccount: guestbook-deployer 561 - namespace: guestbook-ui 562 server: https://kubernetes.default.svc 563 defaultServiceAccount: guestbook-ui-deployer 564 ``` 565 In the above example, since `spec.destination.namespace` is not specified, Application's namespace `argocd` is used for scoping the service account. So the service account `system:serviceaccount:argocd:guestbook-deployer` will be used for the sync operation. 566 567 In the above example, If the matching service account is specified with a namespace, eg: `guestbook:guestbook-deployer`, then the service account `system:serviceaccount:guestbook:guestbook-deployer` will be used for the sync operation. 568 569 ### Security Considerations 570 571 * How does this proposal impact the security aspects of Argo CD workloads ? 572 * Are there any unresolved follow-ups that need to be done to make the enhancement more robust ? 573 574 ### Risks and Mitigations 575 576 #### Privilege Escalation 577 578 There could be an issue of privilege escalation, if we allow users to impersonate without restrictions. This is mitigated by only allowing admin users to configure service account used for the sync operation at the `AppProject` level. 579 580 Instead of allowing users to impersonate all possible users, administrators can restrict the users a particular service account can impersonate using the `resourceNames` field in the RBAC spec. 581 582 583 ### Upgrade / Downgrade Strategy 584 585 If applicable, how will the component be upgraded and downgraded? Make sure this is in the test 586 plan. 587 588 Consider the following in developing an upgrade/downgrade strategy for this enhancement: 589 590 - What changes (in invocations, configurations, API use, etc.) is an existing cluster required to 591 make on upgrade in order to keep previous behavior? 592 - What changes (in invocations, configurations, API use, etc.) is an existing cluster required to 593 make on upgrade in order to make use of the enhancement? 594 595 - This feature would be implemented on an `opt-in` based on a feature flag and disabled by default. 596 - The new struct being added to `AppProject.Spec` would be introduced as an optional field and would be enabled only if the feature is enabled explicitly by a feature flag. If new property is used in the CR, but the feature flag is not enabled, then a warning message would be displayed during reconciliation of such CRs. 597 598 599 ## Drawbacks 600 601 - When using this feature, there is an overhead in creating namespaces, service accounts and the required RBAC policies and mapping the service accounts with the corresponding `AppProject` configuration. 602 603 ## Alternatives 604 605 ### Option 1 606 Allow all options available in the `ImpersonationConfig` available to the user through the `AppProject` CRs. 607 608 ```yaml 609 apiVersion: argoproj.io/v1alpha1 610 kind: AppProject 611 metadata: 612 name: my-project 613 namespace: argocd 614 spec: 615 description: Example Project 616 # Allow manifests to deploy from any Git repos 617 sourceRepos: 618 - '*' 619 destinations: 620 - namespace: '*' 621 server: https://kubernetes.default.svc 622 namespace: guestbook 623 impersonate: 624 user: system:serviceaccount:dev_ns:admin 625 uid: 1234 626 groups: 627 - admin 628 - view 629 - edit 630 ``` 631 632 ### Related issue 633 634 https://github.com/argoproj/argo-cd/issues/7689 635 636 637 ### Related links 638 639 https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation 640 641 ### Prior art 642 643 https://github.com/argoproj/argo-cd/pull/3377 644 https://github.com/argoproj/argo-cd/pull/7651