ArgoCD ExternalSecret Namespace Permission Error
SkillCloud & infraFix 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.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the ArgoCD ExternalSecret Namespace Permission Error skill
What this skill tells your AI
The instructions your AI receives, as published by divinevideo/divine-mobile in .agents/skills/argocd-externalsecret-namespace-permission/SKILL.md and read by ahel’s review.
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
- ArgoCD application shows
OutOfSyncstatus but doesn't sync - Checking application resources shows:
message: namespace gorse is not permitted in project 'infrastructure' - ExternalSecret is in a shared ApplicationSet (e.g.,
external-secrets-resources) - Target namespace belongs to a different application (e.g.,
gorseapp indefaultproject) - Using apps-of-apps pattern with project-based isolation
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
# k8s/applications/gorse/base/external-secret.yaml
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
# k8s/applications/gorse/base/kustomization.yaml
resources:
- namespace.yaml
- external-secret.yaml # Add here
- deployment.yaml
Step 3: Add environment-specific patches in overlays
# k8s/applications/gorse/overlays/staging/kustomization.yaml
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
Signals
- GitHub stars
- 264
- Forks
- 55
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
argocd-externalsecret-namespace-permission- Source
- github.com/divinevideo/divine-mobile