github.com/argoproj/argo-cd/v3@v3.2.1/docs/proposals/config-management-plugin-v2.md (about)

     1  ---
     2  title: Config-Management-Plugin-Enhancement
     3  authors:
     4    - "@kshamajain99" # Authors' github accounts here.
     5  sponsors:
     6    - TBD        # List all interested parties here.
     7  reviewers:
     8    - TBD
     9  approvers:
    10    - TBD
    11  
    12  creation-date: 2021-03-29
    13  last-updated: 2021-03-29
    14  ---
    15  
    16  # Config Management Plugin Enhancement
    17  
    18  We want to enhance config management plugin in order to improve Argo CD operator and end-user experience 
    19  for using additional tools such as cdk8s, Tanka, jkcfg, QBEC, Dhall, pulumi, etc. 
    20  
    21  ## Summary
    22  
    23  Currently, Argo CD provides first-class support for Helm, Kustomize and Jsonnet/YAML. The support includes:
    24  
    25  - Bundled binaries (maintainers periodically upgrade binaries)
    26  - An ability to override parameters using UI/CLI
    27  - The applications are discovered in Git repository and auto-suggested during application creation in UI
    28  - Performance optimizations. Argo CD "knows" when it is safe to generate manifests concurrently and takes advantage of it.
    29  
    30  We want to enhance the configuration management plugin so that it can provide similar first-class support for additional 
    31  tools such as cdk8s, Tanka, jkcfg, QBEC, Dhall, pulumi, etc.
    32  
    33  ## Motivation
    34  
    35  The config management plugin feature should be improved to provide the same level of user experience as 
    36  for the natively supported tools to the additional tools such as  cdk8s, Tanka, jkcfg, QBEC, Dhall, pulumi, etc., 
    37  including Argo CD operators as well as end-user experience.
    38  
    39  ### Goals
    40  
    41  The goals for config management plugin enhancement are,
    42  
    43  #### Improve Installation Experience
    44  The current Config Management plugin installation experience requires two changes:
    45  
    46  - An entry in configManagementPlugins in the Argo CD configmap (i.e.  argocd-cm)
    47  - Either an init container with a volume mount that adds a new binary into Argo CD repo server pod, or a rebuild of the argocd image, which contains the necessary tooling
    48  
    49  The problem with this approach is that the process is error-prone, manual, and requires learning from each and every Argo CD administrator. 
    50  
    51  The goal is to make additional tools easily accessible for installation to Argo CD operators.
    52  
    53  #### Provide Discovery (Auto-selection of Tool)
    54  For Argo CD’s natively supported config management plugins (Helm, Kustomize, Jsonnet), Argo CD auto-detects 
    55  and selects the appropriate tool given only the path in the Git repository. 
    56  This selection is based on the recognition of well-known files in the directory (e.g. Chart.yaml, kustomization.yaml, etc...). 
    57  
    58  Currently, unlike natively supported tools, when a plugin is used, a user needs to explicitly specify the plugin 
    59  that should be used to render the manifests. As part of the improvements to config management plugins, 
    60  
    61  We want to provide the same ability to auto-select the plugin based on recognized files in the path of the git repository.
    62  
    63  #### Parameters support in UI/CLI
    64  Currently, configuration management plugins allow specifying only a list of environment variables via UI/CLI. 
    65  
    66  We want to extend its functionality to provide a similar experience as for existing natively supported tools 
    67  to additional config management tools. 
    68  
    69  ### Non-Goals
    70  
    71  - We aren't planning on changing the existing support for native plugins as of now. 
    72  
    73  ## Proposal
    74  
    75  We have drafted the solution to the problem statement as **running configuration management plugin tools as sidecar in the argocd-repo-server**. 
    76  
    77  All it means that Argo CD Config Management Plugin 2.0 will be,
    78  
    79  - A user-supplied container image with all the necessary tooling installed in it. 
    80  - It will run as a sidecar in the repo server deployment and will have shared access to the git repositories.
    81  - It will contain a CMP YAML specification file describing how to render manifests.
    82  - Its entrypoint will be a lightweight CMP API server that receives requests by the main repo-server to render manifests, 
    83  based on the CMP specification file.
    84  
    85  This mechanism will provide the following benefits over the existing solution,
    86  
    87  - Plugin owners control their execution environment, packaging whatever dependent binaries required.
    88  - An  Argo CD user who wants to use additional config management tools does not have to go through the hassle of building 
    89  a customized argocd-repo-server in order to install required dependencies. 
    90  - The plugin image will be running in a container separate from the main repo-server.
    91  
    92  ### Use cases
    93  
    94  - UC1: As an Argo CD user, I would like to use first-class support provided for additional tools to generate and manage deployable kubernetes manifests
    95  - UC2: As an Argo CD operator, I want to have smooth experience while installing additional tools such as  cdk8s, Tanka, jkcfg, QBEC, Dhall, pulumi, etc.
    96  - UC3: As a plugin owner, I want to have some control over the execution environment as I want to package whatever dependent binaries required. 
    97  
    98  ### Implementation Details
    99  
   100  Config Management Plugin v2.0 implementation and experience will be as,
   101  
   102  #### Installation
   103  
   104  To install a plugin, an operator will simply patch argocd-repo-server to run config management plugin container as a sidecar, 
   105  with argocd-cmp-server as it’s entrypoint. Operator can use either off-the-shelf or custom built plugin image as sidecar image. 
   106  
   107  ```bash
   108  # A plugin is a container image which runs as a sidecar, with the execution environment
   109  # necessary to render manifests. To install a plugin, 
   110  containers:
   111  - name: cdk8s
   112    command: [/var/run/argocd/argocd-cmp-server]
   113    image: docker.ui/cdk8s/cdk8s:latest
   114    volumeMounts:
   115    - mountPath: /var/run/argocd
   116      name: var-files
   117  ```
   118  
   119  The argocd-cmp-server binary will be populated inside the plugin container via an init container in the argocd-repo-server, 
   120  which will pre-populate a volume shared between plugins and the repo-server.
   121  
   122  ```bash
   123  # An init container will copy the argocd static binary into the shared volume
   124  # so that the CMP server can become the entrypoint
   125  initContainers:
   126  - command:
   127    - cp
   128    - -n
   129    - /usr/local/bin/argocd
   130    - /var/run/argocd/argocd-cmp-server
   131    image: quay.io/argoproj/argocd:latest
   132    name: copyutil
   133    volumeMounts:
   134    - mountPath: /var/run/argocd
   135      name: var-files
   136   
   137  # var-files is a shared volume between repo-server and cmp-server which holds:
   138  # 1) socket files that repo-server uses to communicate to each plugin
   139  # 2) git repositories cloned by repo-server
   140  volumes:
   141  - emptyDir: {}
   142    name: var-files
   143  ```
   144  
   145  #### Configuration
   146  
   147  Plugins will be configured via a ConfigManagementPlugin manifest located inside the plugin container, placed at a 
   148  well-known location (e.g. /home/argocd/plugins/plugin.yaml). Argo CD is agnostic to the mechanism of how the plugin.yaml would be placed, 
   149  but various options can be used on how to place this file, including: 
   150  
   151  - Baking the file into the plugin image as part of docker build
   152  - Volume mapping the file through a configmap.
   153  
   154  Note that, while the ConfigManagementPlugin looks like a Kubernetes object, it is not actually a custom resource. 
   155  It only follows kubernetes-style spec conventions.
   156  
   157  ```bash
   158  # metadata file is in the root and shell executor knows about it
   159  apiVersion: argoproj.io/v1alpha1
   160  kind: ConfigManagementPlugin
   161  metadata:
   162    name: cdk8s
   163  spec:
   164    version: v1.0
   165    init:
   166      command: [cdk8s, init]
   167    generate:
   168      command: [sh, -c, "cdk8s synth && cat dist/*.yaml"]
   169    discovery:
   170      find:
   171      - command: [find . -name main.ts]
   172        glob: "**/*/main.ts"
   173      check:
   174      - command: [-f ./main.ts]
   175        glob: "main.ts"
   176  ```
   177  
   178  #### Config Management Plugin API Server (cmp-server)
   179  The Config Management Plugin API Server (cmp-server) will be a new Argo CD component whose sole responsibility will be 
   180  to execute `generate` commands inside the plugin environment (the sidecar container), at the request of the repo-server.
   181  
   182  The cmp-server will expose the following APIs to the repo-server,
   183  
   184  - GenerateManifests(path) - returns YAML output using plugin tooling
   185  - IsSupported(path) - returns whether or not the given path is supported by the plugin
   186  
   187  At startup, cmp-server looks at the /home/argocd/cmp-server/plugin.yaml ConfigManagementPlugin specification file to understand how to perform the requests.
   188  
   189  #### Registration & Communication
   190  The repo-server needs to understand what all plugins are available to render manifests. To do this, the cmp-server 
   191  sidecars will register themselves as available plugins to the argocd-repo-server by populating named socket files in the 
   192  shared volume between repo-server and cmp-server. e.g.:
   193  
   194  ```bash
   195  /home/argocd/plugins/
   196                          cdk8s.sock
   197                          jkcfg.sock
   198                          pulumi.sock
   199  ```
   200  
   201  The name of the socket file will indicate the plugin name. To discover the available plugins, the repo-server will list 
   202  the shared plugins directory to discover the available plugins.
   203  
   204  To communicate with a plugin, the repo-server will simply need to connect to the socket and make gRPC calls against the 
   205  cmp-server listening on the other side. 
   206  
   207  #### Discovery (Auto-selection of Tool)
   208  
   209  - The plugin discovery will run in the main repo-server container.
   210  - Argo CD repo-server lists the shared plugins directory and runs `discover` command from the specification file, 
   211  whichever plugin provides a positive response first will be selected.
   212  
   213  #### Versioning
   214  There will be one sidecar container per version. Hence, for two different versions users will have to configure two different sidecars.
   215  
   216  ### Security Considerations
   217  
   218  The use of the plugin as sidecars separate from the repo-server is already a security improvement over the current v1.8 
   219  config management plugin mechanism, since the plugin tooling will no longer have access to the files of the argocd-repo-server image. 
   220  However additional improvements can be made to increase security.
   221  
   222  ### Risks and Mitigations
   223  
   224  One issue is that currently when repositories are cloned, the repo is cloned using the same UID of the repo-server user, 
   225  and so all repository files are created using that UID. This means that a command which executes in the git repository path, 
   226  could traverse upwards and see/write files which are outside of the repository tree.
   227  
   228  One proposal to prevent out-of-tree access to files, is that each git repository could be cloned with unique UIDs, 
   229  different from the repo-server’s UID. When the cmp-server executes the tooling command to generate manifests, 
   230  the command could be executed using the UID of the git repository files. e.g.:
   231  
   232  ```
   233  cmd := exec.Command(command, args...)
   234  cmd.SysProcAttr = &syscall.SysProcAttr{}
   235  cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid}
   236  ```
   237  
   238  This would ensure that the command could not read or write anything out-of-tree from the repository directory.
   239  
   240  ### Upgrade / Downgrade Strategy
   241  
   242  The argocd-repo-server manifest will change in order to populate the argocd-cmp-server binary inside the plugin container 
   243  via an init container.
   244  
   245  ```bash
   246  # An init container will copy the argocd static binary into the shared volume
   247  # so that the CMP server can become the entrypoint
   248  initContainers:
   249  - command:
   250    - cp
   251    - -n
   252    - /usr/local/bin/argocd
   253    - /var/run/argocd/argocd-cmp-server
   254    image: quay.io/argoproj/argocd:latest
   255    name: copyutil
   256    volumeMounts:
   257    - mountPath: /var/run/argocd
   258      name: var-files
   259   
   260  # var-files is a shared volume between repo-server and cmp-server which holds:
   261  # 1) socket files that repo-server uses to communicate to each plugin
   262  # 2) git repositories cloned by repo-server
   263  volumes:
   264  - emptyDir: {}
   265    name: var-files
   266  ```
   267    
   268  After upgrading to CMP v2, an Argo CD operator will have to make following changes,
   269  
   270  - In order to install a plugin, an Argo CD operator will simply have to patch argocd-repo-server 
   271  to run config management plugin container as a sidecar, with argocd-cmp-server as it’s entrypoint:
   272  
   273      ```bash
   274      # A plugin is a container image which runs as a sidecar, with the execution environment
   275      # necessary to render manifests. To install a plugin, 
   276      containers:
   277      - name: cdk8s
   278        command: [/var/run/argocd/argocd-cmp-server]
   279        image: docker.ui/cdk8s/cdk8s:latest
   280        volumeMounts:
   281        - mountPath: /var/run/argocd
   282          name: var-files
   283      ```
   284  
   285  - Plugins will be configured via a ConfigManagementPlugin manifest located inside the plugin container, placed at a 
   286  well-known location (e.g. /plugin.yaml). Argo CD is agnostic to the mechanism of how the plugin.yaml would be placed, 
   287  but various options can be used on how to place this file, including: 
   288      - Baking the file into the plugin image as part of docker build
   289      - Volume mapping the file through a configmap.
   290  
   291  (For more details please refer to [implementation details](#configuration))
   292  
   293  ## Drawbacks
   294  
   295  There aren't any major drawbacks to this proposal. Also, the advantages supersede the minor learning curve of the new way of managing plugins.
   296  
   297  However following are few minor drawbacks,
   298  
   299  - With addition of plugin.yaml, there will be more yamls to manage
   300  - Operators need to be aware of the modified Kubernetes manifests in the subsequent version.
   301  - The format of the CMP manifest is a new "contract" that would need to adhere the usual Argo CD compatibility promises in future.
   302  
   303  ## Alternatives
   304  
   305  1. ConfigManagementPlugin as CRD. Have a CR which the human operator creates:
   306  
   307      ```bash
   308      apiVersion: argoproj.io/v1alpha1
   309      kind: ConfigManagementPlugin
   310      metadata:
   311        name: cdk8s
   312      spec:
   313        name: cdk8s
   314        image: docker.ui/cdk8s/cdk8s:latest
   315        version: v1.0
   316        init:
   317          command: [cdk8s, init]
   318        generate:
   319          command: [sh, -c, "cdk8s synth && cat dist/*.yaml"]
   320          discovery:
   321          find:
   322          - command: [find . -name main.ts]
   323            glob: "**/*/main.ts"
   324            check:
   325          - command: [-f ./main.ts]
   326            glob: "main.ts"
   327      ```
   328  
   329  2. Something magically patches the relevant manifest to add the sidecar.