github.com/argoproj/argo-cd/v3@v3.2.1/docs/user-guide/source-hydrator.md (about)

     1  # Source Hydrator
     2  
     3  **Current feature state**: Alpha
     4  
     5  Tools like Helm and Kustomize allow users to express their Kubernetes manifests in a more concise and reusable way
     6  (keeping it DRY - Don't Repeat Yourself). However, these tools can obscure the actual Kubernetes manifests that are
     7  applied to the cluster.
     8  
     9  The "rendered manifest pattern" is a feature of Argo CD that allows users to push the hydrated manifests to git before syncing them to the cluster. This
    10  allows users to see the actual Kubernetes manifests that are applied to the cluster.
    11  
    12  ## Enabling the Source Hydrator
    13  
    14  The source hydrator is disabled by default.
    15  
    16  To enable the source hydrator, you need to enable the "commit server" component and set the `hydrator.enabled` field in
    17  argocd-cmd-params-cm ConfigMap to `"true"`.
    18  
    19  ```yaml
    20  apiVersion: v1
    21  kind: ConfigMap
    22  metadata:
    23    name: argocd-cmd-params-cm
    24    namespace: argocd
    25  data:
    26    hydrator.enabled: "true"
    27  ```
    28  
    29  !!! important
    30      After updating the ConfigMap, you must restart the Argo CD controller and API server for the changes to take effect.
    31  
    32  If you are using one of the `*-install.yaml` manifests to install Argo CD, you can use the 
    33  `*-install-with-hydrator.yaml` version of that file instead.
    34  
    35  For example,
    36  
    37  ```
    38  Without hydrator: https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
    39  With hydrator:    https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install-with-hydrator.yaml
    40  ```
    41  
    42  !!! important
    43      The `*-with-hydrator-install.yaml` manifests will eventually be removed when the source hydrator is either enabled
    44      by default or removed. The upgrade guide will note if the `install-with-hydrator.yaml` manifests are no longer
    45      available.
    46  
    47  ## Using the Source Hydrator
    48  
    49  To use the source hydrator, you must first install a push and a pull secret. This example uses a GitHub App for authentication, but
    50  you can use [any authentication method that Argo CD supports for repository access](../operator-manual/declarative-setup.md#repositories).
    51  
    52  ```yaml
    53  apiVersion: v1
    54  kind: Secret
    55  metadata:
    56    name: my-push-secret
    57    namespace: argocd
    58    labels:
    59      argocd.argoproj.io/secret-type: repository-write
    60  type: Opaque
    61  stringData:
    62    url: "https://github.com"
    63    type: "git"
    64    githubAppID: "<your app ID here>"
    65    githubAppInstallationID: "<your installation ID here>"
    66    githubAppPrivateKey: |
    67      <your private key here>
    68  ---
    69  apiVersion: v1
    70  kind: Secret
    71  metadata:
    72    name: my-pull-secret
    73    namespace: argocd
    74    labels:
    75      argocd.argoproj.io/secret-type: repository
    76  type: Opaque
    77  stringData:
    78    url: "https://github.com"
    79    type: "git"
    80    githubAppID: "<your app ID here>"
    81    githubAppInstallationID: "<your installation ID here>"
    82    githubAppPrivateKey: |
    83      <your private key here>
    84  ```
    85  
    86  The only difference between the secrets above, besides the resource name, is that the push secret contains the label
    87  `argocd.argoproj.io/secret-type: repository-write`, which causes the Secret to be used for pushing manifests to git
    88  instead of pulling from git. Argo CD requires different secrets for pushing and pulling to provide better isolation.
    89  
    90  Once your secrets are installed, set the `spec.sourceHydrator` field of the Application. For example:
    91  
    92  ```yaml
    93  apiVersion: argoproj.io/v1alpha1
    94  kind: Application
    95  metadata:
    96    name: my-app
    97  spec:
    98    sourceHydrator:
    99      drySource:
   100        repoURL: https://github.com/argoproj/argocd-example-apps
   101        path: helm-guestbook
   102        targetRevision: HEAD
   103      syncSource:
   104        targetBranch: environments/dev
   105        path: helm-guestbook
   106  ```
   107  
   108  In this example, the hydrated manifests will be pushed to the `environments/dev` branch of the `argocd-example-apps`
   109  repository.
   110  
   111  When using source hydration, the `syncSource.path` field is required and must always point to a non-root
   112  directory in the repository. Setting the path to the repository root (for eg. `"."` or `""`) is not
   113  supported. This ensures that hydration is always scoped to a dedicated subdirectory, which avoids unintentionally overwriting or removing files that may exist in the repository root.
   114  
   115  During each hydration run, Argo CD cleans the application's configured path before writing out newly generated manifests. This guarantees that old or stale files from previous hydration do not linger in the output directory. However, the repository root is never cleaned, so files such as CI/CD configuration, README files, or other root-level assets remain untouched.
   116  
   117  It is important to note that hydration only cleans the currently configured application path. If an application’s path changes, the old directory is not removed automatically. Likewise, if an application is deleted, its output path remains in the repository and must be cleaned up manually by the repository owner if desired. This design is intentional: it prevents accidental deletion of files when applications are restructured or removed, and it protects critical files like CI pipelines that may coexist in the repository.
   118  
   119  !!! important "Project-Scoped Repositories"
   120  
   121      Repository Secrets may contain a `project` field, making the secret only usable by Applications in that project.
   122      The source hydrator only supports project-scoped repositories if all Applications writing to the same repository and
   123      branch are in the same project. If Applications in different projects write to the same repository and branch, the
   124      source hydrator will not be able to use a project-scoped repository secret and will require a global repository 
   125      secret. This behavior may change in the future.
   126  
   127  If there are multiple repository-write Secrets available for a repo, the source hydrator will non-deterministically
   128  select one of the matching Secrets and log a warning saying "Found multiple credentials for repoURL".
   129  
   130  ## Pushing to a "Staging" Branch
   131  
   132  The source hydrator can be used to push hydrated manifests to a "staging" branch instead of the `syncSource` branch.
   133  This provides a way to prevent the hydrated manifests from being applied to the cluster until some prerequisite
   134  conditions are met (in effect providing a way to handle environment promotion via Pull Requests).
   135  
   136  To use the source hydrator to push to a "staging" branch, set the `spec.sourceHydrator.hydrateTo` field of the
   137  Application. For example:
   138  
   139  ```yaml
   140  apiVersion: argoproj.io/v1alpha1
   141  kind: Application
   142  metadata:
   143    name: my-app
   144  spec:
   145    project: my-project
   146    destination:
   147      server: https://kubernetes.default.svc
   148      namespace: default
   149    sourceHydrator:
   150      drySource:
   151        repoURL: https://github.com/argoproj/argocd-example-apps
   152        path: helm-guestbook
   153        targetRevision: HEAD
   154      syncSource:
   155        targetBranch: environments/dev
   156        path: helm-guestbook
   157      hydrateTo:
   158        targetBranch: environments/dev-next
   159  ```
   160  
   161  In this example, the hydrated manifests will be pushed to the `environments/dev-next` branch, and Argo CD will not sync
   162  the changes until something moves them to the `environments/dev` branch.
   163  
   164  You could use a CI action to move the hydrated manifests from the `hydrateTo` branch to the `syncSource` branch. To
   165  introduce a gating mechanism, you could require a Pull Request to be opened to merge the changes from the `hydrateTo`
   166  branch to the `syncSource` branch.
   167  
   168  Argo CD will only push changes to the `hydrateTo` branch, it will not create a PR or otherwise facilitate moving those 
   169  changes to the `syncSource` branch. You will need to use your own tooling to move the changes from the `hydrateTo` 
   170  branch to the `syncSource` branch.
   171  
   172  ## Commit Tracing
   173  
   174  It's common for CI or other tooling to push DRY manifest changes after a code change. It's important for users to be
   175  able to trace the hydrated commits back to the original code change that caused the hydration.
   176  
   177  Source Hydrator makes use of some custom git commit trailers to facilitate this tracing. A CI job that builds an image
   178  and pushes an image bump to DRY manifests can use the following commit trailers to link the hydrated commit to the
   179  code commit.
   180  
   181  ```shell
   182  git commit -m "Bump image to v1.2.3" \
   183    # Must be an RFC 5322 name
   184    --trailer "Argocd-reference-commit-author: Author Name <author@example.com>" \
   185    # Must be a hex string 5-40 characters long
   186    --trailer "Argocd-reference-commit-sha: <code-commit-sha>" \
   187    # The subject is the first line of the commit message. It cannot contain newlines.
   188    --trailer "Argocd-reference-commit-subject: Commit message of the code commit" \
   189     # The body must be a valid JSON string, including opening and closing quotes
   190    --trailer 'Argocd-reference-commit-body: "Commit message of the code commit\n\nSigned-off-by: Author Name <author@example.com>"' \
   191     # The repo URL must be a valid URL
   192    --trailer "Argocd-reference-commit-repourl: https://git.example.com/owner/repo" \
   193    # The date must by in ISO 8601 format
   194    --trailer "Argocd-reference-commit-date: 2025-06-09T13:50:18-04:00" 
   195  ```
   196  
   197  !!!note Newlines are not allowed
   198      The commit trailers must not contain newlines. 
   199  
   200  So the full CI script might look something like this:
   201  
   202  ```shell
   203  # Clone code repo
   204  git clone https://git.example.com/owner/repo.git
   205  cd repo
   206  
   207  # Build the image and get the new image tag
   208  # <cusom build logic here>
   209  
   210  # Get the commit information
   211  author=$(git show -s --format="%an <%ae>")
   212  sha=$(git rev-parse HEAD)
   213  subject=$(git show -s --format='%s')
   214  body=$(git show -s --format='%b')
   215  jsonbody=$(jq -n --arg body "$body" '$body')
   216  repourl=$(git remote get-url origin)
   217  date=$(git show -s --format='%aI')
   218  
   219  # Clone the dry source repo
   220  git clone https://git.example.com/owner/deployment-repo.git
   221  cd deployment-repo
   222  
   223  # Bump the image in the dry manifests
   224  # <custom bump logic here, e.g. `kustomize edit`>
   225  
   226  # Commit the changes with the commit trailers
   227  git commit -m "Bump image to v1.2.3" \
   228    --trailer "Argocd-reference-commit-author: $author" \
   229    --trailer "Argocd-reference-commit-sha: $sha" \
   230    --trailer "Argocd-reference-commit-subject: $subject" \
   231    --trailer "Argocd-reference-commit-body: $jsonbody" \
   232    --trailer "Argocd-reference-commit-repourl: $repourl" \
   233    --trailer "Argocd-reference-commit-date: $date"
   234  ```
   235  
   236  The commit metadata will appear in the hydrated commit's root hydrator.metadata file:
   237  
   238  ```json
   239  {
   240    "author": "CI <ci@example.com>",
   241    "subject": "chore: bump image to b82add2",
   242    "date": "2025-06-09T13:50:08-04:00",
   243    "body": "Signed-off-by: CI <ci@example.com>\n",
   244    "drySha": "6cb951525937865dced818bbdd78c89b2d2b3045",
   245    "repoURL": "https://git.example.com/owner/manifests-repo",
   246    "references": [
   247      {
   248        "commit": {
   249          "author": {
   250            "name": "Author Name",
   251            "email": "author@example.com"
   252          },
   253          "sha": "b82add298aa045d3672880802d5305c5a8aaa46e",
   254          "subject": "chore: make a change",
   255          "body": "make a change\n\nSigned-off-by: Author Name <author@example.com>",
   256          "repoURL": "https://git.example.com/owner/repo",
   257          "date": "2025-06-09T13:50:18-04:00"
   258        }
   259      }
   260    ]
   261  }
   262  ```
   263  
   264  The top-level "body" field contains the commit message of the DRY commit minus the subject line and any 
   265  `Argocd-reference-commit-*` trailers that were used in `references`. Unrecognized or invalid trailers are preserved in
   266  the body.
   267  
   268  Although `references` is an array, the source hydrator currently only supports a single related commit. If a trailer is
   269  specified more than once, the last one will be used.
   270  
   271  All trailers are optional. If a trailer is not specified, the corresponding field in the metadata will be omitted.
   272  
   273  ## Commit Message Template
   274  
   275  The commit message is generated using a [Go text/template](https://pkg.go.dev/text/template), optionally configured by the user via the argocd-cm ConfigMap. The template is rendered using the values from `hydrator.metadata`. The template can be multi-line, allowing users to define a subject line, body and optional trailers. To define the commit message template, you need to set the `sourceHydrator.commitMessageTemplate` field in argocd-cm ConfigMap.
   276  
   277  The template may functions from the [Sprig function library](https://github.com/Masterminds/sprig).
   278  
   279  ```yaml
   280  apiVersion: v1
   281  kind: ConfigMap
   282  metadata:
   283    name: argocd-cm
   284    namespace: argocd
   285  data:
   286    sourceHydrator.commitMessageTemplate: |
   287      {{.metadata.drySha | trunc 7}}: {{ .metadata.subject }}
   288      {{- if .metadata.body }}
   289      
   290      {{ .metadata.body }}
   291      {{- end }}
   292      {{ range $ref := .metadata.references }}
   293      {{- if and $ref.commit $ref.commit.author }}
   294      Co-authored-by: {{ $ref.commit.author }}
   295      {{- end }}
   296      {{- end }}
   297      {{- if .metadata.author }}
   298      Co-authored-by: {{ .metadata.author }}
   299      {{- end }}
   300  ```
   301  
   302  ### Credential Templates
   303  
   304  Credential templates allow a single credential to be used for multiple repositories. The source hydrator supports credential templates. For example, if you setup credential templates for the URL prefix `https://github.com/argoproj`, these credentials will be used for all repositories with this URL as prefix (e.g. `https://github.com/argoproj/argocd-example-apps`) that do not have their own credentials configured.
   305  For more information please refer [credential-template](private-repositories.md#credential-templates). 
   306  An example of repo-write-creds secret.
   307  
   308  ```yaml
   309  apiVersion: v1
   310  kind: Secret
   311  metadata:
   312    name: private-repo
   313    namespace: argocd
   314    labels:
   315      argocd.argoproj.io/secret-type: repo-write-creds
   316  stringData:
   317    type: git
   318    url: https://github.com/argoproj
   319    password: my-password
   320    username: my-username
   321  ```
   322  
   323  ## Limitations
   324  
   325  ### Signature Verification
   326  
   327  The source hydrator **does not currently support signature verification of the DRY sources it hydrates/commits**. It
   328  also does not sign the commits it pushes to git, so if signature verification is enabled, the commits will fail
   329  verification when Argo CD attempts to sync the hydrated manifests.
   330  
   331  ### Project-Scoped Push Secrets
   332  
   333  If all the Applications for a given destination repo/branch are under the same project, then the hydrator will use any
   334  available project-scoped push secrets. If two Applications for a given repo/branch are in different projects, then the
   335  hydrator will not be able to use a project-scoped push secret and will require a global push secret.
   336  
   337  ### `manifest-generate-paths` Annotation Support
   338  
   339  The source hydrator does not currently support the [manifest-generate-paths annotation](../operator-manual/high_availability.md#manifest-paths-annotation) 
   340  for work avoidance on hydration of dry commits. In other words, the source hydrator is not able to skip hydration of dry 
   341  commits that have not changed relevant files.
   342  
   343  The application controller _does_ honor the `manifest-generate-paths` annotation when syncing the hydrated manifests.
   344  So if your application hydrates to the `foo` directory, and the `manifest-generate-paths` annotation is set to `foo`, 
   345  then the application controller will not re-hydrate the manifests after a commit that only affects files in the `bar`
   346  directory.
   347  
   348  ## Prerequisites
   349  
   350  ### Handle Secrets on the Destination Cluster
   351  
   352  Do not use the source hydrator with any tool that injects secrets into your manifests as part of the hydration process
   353  (for example, Helm with SOPS or the Argo CD Vault Plugin). These secrets would be committed to git. Instead, use a
   354  secrets operator that populates the secret values on the destination cluster.
   355  
   356  ## Best Practices
   357  
   358  ### Make Hydration Deterministic
   359  
   360  The source hydrator should be deterministic. For a given dry source commit, the hydrator should always produce the same
   361  hydrated manifests. This means that the hydrator should not rely on external state or configuration that is not stored
   362  in git.
   363  
   364  Examples of non-deterministic hydration:
   365  
   366  * A Helm chart using unpinned dependencies
   367  * A Helm chart is using a non-deterministic template function such as `randAlphaNum` or `lookup`
   368  * [Config Management Plugins](../operator-manual/config-management-plugins.md) which retrieve non-git state, such as secrets
   369  * Kustomize manifests referencing unpinned remote bases
   370  
   371  ### Enable Branch Protection
   372  
   373  Argo CD should be the only thing pushing hydrated manifests to the hydrated branches. To prevent other tools or users
   374  from pushing to the hydrated branches, enable branch protection in your SCM.
   375  
   376  It is best practice to prefix the hydrated branches with a common prefix, such as `environments/`. This makes it easier
   377  to configure branch protection rules on the destination repository.
   378  
   379  !!! note
   380      To maintain reproducibility and determinism in the Hydrator’s output,
   381      Argo CD-specific metadata (such as `argocd.argoproj.io/tracking-id`) is
   382      not written to Git during hydration. These annotations are added dynamically
   383      during application sync and comparison.