Skip to content

External-secret OutOfSync

Sometimes we can get an argocd Application OutOfSync because an external-secret is OutOfSync with some differences in this places:

  • conversionStrategy
  • decodingStrategy
  • decodingStrategy

... and we did not define that values.

The root cause is that External Secrets Operator acts as a mutating admission controller, modifying resources after they're applied. It adds default values for conversionStrategy, decodingStrategy, and metadataPolicy fields when they're not explicitly specified in the ExternalSecret manifest. This creates a drift between your Git source (without these fields) and the live cluster state (with default values added), causing ArgoCD to show the resources as OutOfSync

Solution 1: ignoreDifferences

We can ignore that fields at controller level. This is not the best option because we are ignoring some fields in the resource.

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
data:
  resource.customizations.ignoreDifferences.external-secrets.io_ExternalSecret: |
      jqPathExpressions:
      - '.spec.data[]?.remoteRef.conversionStrategy'
      - '.spec.data[]?.remoteRef.decodingStrategy'
      - '.spec.data[]?.remoteRef.metadataPolicy'
      - '.spec.dataFrom[]?.extract.conversionStrategy'
      - '.spec.dataFrom[]?.extract.decodingStrategy'
      - '.spec.dataFrom[]?.extract.metadataPolicy'
      - '.spec.dataFrom[]?.find.conversionStrategy'
      - '.spec.dataFrom[]?.find.decodingStrategy'
      - '.spec.dataFrom[]?.find.metadataPolicy'

This can also be configured at Application level with spec.ignoreDifferences. It must be configured in all drifted Applications

We also neeed to ignore that differences when syncing

apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
  annotations:
    argocd.argoproj.io/sync-options: RespectIgnoreDifferences=true

Solution 2: add default values

Another option is to add to the external-secret the default values the external secret operator adds. For example

apiVersion: external-secrets.io/v1
kind: ExternalSecret
spec:
  data:
  - secretKey: mykey
    remoteRef:
      key: mykey
      conversionStrategy: Default
      decodingStrategy: None
      metadataPolicy: None

Solution 3: use Server Side Apply

Another option is to use Server Side Apply. With this:

  • ArgoCD declares ownership of only the fields it manages
  • Other controllers can own and modify their own fields (like external secrets operator)
  • Kubernetes merges changes from multiple sources without conflicts
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  annotations:
    argocd.argoproj.io/sync-options: ServerSideApply=true
spec:
  ...

Note: I did not make this work for now.