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