| name | argocd-externalsecret-namespace-permission |
| description | Fix ArgoCD ExternalSecret deployment failing with "namespace X is not permitted in project Y".
Use when: (1) ExternalSecret shows OutOfSync in ArgoCD but won't sync, (2) ArgoCD application
status shows "namespace X is not permitted in project 'infrastructure'", (3) ExternalSecret
targets a namespace managed by a different ArgoCD project, (4) Using apps-of-apps pattern
with separate infrastructure and application projects.
|
| author | Claude Code |
| version | 1.0.0 |
| date | "2026-01-29T00:00:00.000Z" |
ArgoCD ExternalSecret Namespace Permission Error
Problem
ExternalSecrets defined in a shared "external-secrets-resources" ApplicationSet fail to
deploy to namespaces that aren't in the ArgoCD project's allowed destinations. The sync
shows OutOfSync but refuses to apply.
Context / Trigger Conditions
Root Cause
ArgoCD projects define allowed destination namespaces. When ExternalSecrets are deployed
via a centralized "infrastructure" project but target namespaces managed by application-specific
projects, the infrastructure project doesn't have permission to deploy to those namespaces.
Solution
Move the ExternalSecret from the shared external-secrets-resources to the application itself.
Step 1: Create ExternalSecret in the application
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: gorse-secrets
namespace: gorse
spec:
refreshInterval: 1h
secretStoreRef:
name: gcp-secret-manager
kind: ClusterSecretStore
target:
name: gorse-secrets
creationPolicy: Owner
data:
- secretKey: api_key
remoteRef:
key: gorse-api-key-ENVIRONMENT
Step 2: Add to application kustomization
resources:
- namespace.yaml
- external-secret.yaml
- deployment.yaml
Step 3: Add environment-specific patches in overlays
patches:
- target:
kind: ExternalSecret
name: gorse-secrets
patch: |-
- op: replace
path: /spec/data/0/remoteRef/key
value: gorse-api-key-staging
Step 4: Remove from external-secrets-resources
Remove the ExternalSecret from k8s/external-secrets/base/ and all overlay patches.
Verification
- Sync the application:
argocd app sync gorse
- Check ExternalSecret status:
kubectl get externalsecrets -n gorse
- Verify secret created:
kubectl get secrets -n gorse
Alternative Solutions
Option 1: Expand project destinations
Add the namespace to the infrastructure project's allowed destinations in ArgoCD.
Not recommended as it breaks project isolation.
Option 2: Use ClusterSecretStore
If using ClusterSecretStore, the secret can be referenced from any namespace.
The ExternalSecret itself still needs to be in an allowed namespace.
Notes
- This pattern is common when migrating from monolithic to modular ArgoCD setups
- Each application should own its secret definitions for better isolation
- ClusterSecretStore remains shared; only ExternalSecret moves
- The "infrastructure" project typically manages cluster-wide resources, not app-specific secrets