> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/argoproj/argo-cd/llms.txt
> Use this file to discover all available pages before exploring further.

# ApplicationSet Security

> Security considerations and best practices for Argo CD ApplicationSets

<Warning>
  ApplicationSet is a powerful tool. It is **crucial** to understand its security implications before using it.
</Warning>

## Only Admins May Create ApplicationSets

ApplicationSets are privileged resources that should only be managed by cluster administrators.

### Why Admin-Only Access?

ApplicationSets have significant privileges:

1. **Arbitrary Project Access**
   * ApplicationSets can create Applications under any Project
   * Many Argo CD setups include Projects (like `default`) with high permissions
   * These Projects often have permissions to manage Argo CD's own resources (RBAC ConfigMap, Secrets, etc.)

2. **Rapid Resource Creation/Deletion**
   * ApplicationSets can quickly create an arbitrary number of Applications
   * They can delete them just as quickly
   * This could overwhelm clusters or disrupt services

3. **Secret Access**
   * Some generators (like Git generator) can read Secrets in the Argo CD namespace
   * These Secrets could be sent to arbitrary URLs as auth headers
   * Example: Using the `api` field to send credentials to attacker-controlled endpoints

<Note>
  **Recommendation:** Use Kubernetes RBAC to restrict ApplicationSet create/update/delete permissions to admin users only.
</Note>

### RBAC Configuration Example

```yaml theme={null}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: applicationset-admin
  namespace: argocd
rules:
- apiGroups:
  - argoproj.io
  resources:
  - applicationsets
  verbs:
  - create
  - update
  - delete
  - patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: applicationset-admin-binding
  namespace: argocd
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: applicationset-admin
subjects:
- kind: User
  name: admin@example.com
  apiGroup: rbac.authorization.k8s.io
```

## Control ApplicationSet Sources of Truth

Even if non-admins cannot create ApplicationSet resources, they may still affect ApplicationSet behavior through generator sources.

### Git Generator Risks

<Warning>
  If an ApplicationSet uses a Git generator, anyone with push access to the source repository can affect the ApplicationSet's behavior.
</Warning>

#### Potential Attacks

**Excessive Application Creation:**

```yaml theme={null}
# Malicious user adds many directories or config files
apps/
├── app1/
├── app2/
├── app3/
# ... hundreds more directories
├── app999/
```

This could:

* Strain the ApplicationSet controller
* Strain the Application controller
* Trigger SCM provider rate limiting
* Degrade service for legitimate Applications

**Resource Exhaustion:**

* Creating Applications that consume excessive cluster resources
* Deploying resource-intensive workloads to multiple clusters simultaneously

#### Mitigation Strategies

<AccordionGroup>
  <Accordion title="Restrict Git Repository Access">
    * Limit push access to the source Git repository
    * Require pull request reviews for changes
    * Use branch protection rules
    * Implement approval workflows
  </Accordion>

  <Accordion title="Use Resource Quotas">
    Set limits in Argo CD AppProjects:

    ```yaml theme={null}
    apiVersion: argoproj.io/v1alpha1
    kind: AppProject
    metadata:
      name: team-project
    spec:
      resourceQuotas:
      - applications: 50
      - cpu: 100
      - memory: 200Gi
    ```
  </Accordion>

  <Accordion title="Monitor ApplicationSet Activity">
    * Set up alerts for unusual Application creation patterns
    * Monitor for rapid increases in Application count
    * Track resource consumption by Applications
  </Accordion>

  <Accordion title="Validate Configuration Files">
    Use CI/CD to validate config files before merge:

    ```yaml theme={null}
    # .github/workflows/validate.yml
    name: Validate Config
    on: [pull_request]
    jobs:
      validate:
        runs-on: ubuntu-latest
        steps:
        - uses: actions/checkout@v2
        - name: Validate JSON
          run: |
            for file in apps/**/config.json; do
              jq empty "$file" || exit 1
            done
        - name: Check limits
          run: |
            count=$(find apps -name config.json | wc -l)
            if [ $count -gt 50 ]; then
              echo "Too many applications: $count"
              exit 1
            fi
    ```
  </Accordion>
</AccordionGroup>

## Templated Project Field

The `project` field deserves special attention when templated.

### The Risk

<Warning>
  If the `project` field is templated, a malicious user with write access to the generator's source could create Applications under Projects with insufficient restrictions.
</Warning>

**Example vulnerable ApplicationSet:**

```yaml theme={null}
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: team-apps
spec:
  goTemplate: true
  generators:
  - git:
      repoURL: https://github.com/org/app-configs.git
      revision: main
      files:
      - path: "apps/**/config.json"
  template:
    metadata:
      name: '{{.appName}}'
    spec:
      project: '{{.projectName}}' # DANGEROUS: templated project
      source:
        repoURL: '{{.source}}'
        targetRevision: '{{.revision}}'
        path: '{{.path}}'
      destination:
        server: '{{.server}}'
        namespace: '{{.namespace}}'
```

**Malicious config.json:**

```json theme={null}
{
  "appName": "malicious-app",
  "projectName": "default",
  "source": "https://github.com/attacker/malicious-manifests",
  "revision": "main",
  "path": "k8s",
  "server": "https://kubernetes.default.svc",
  "namespace": "argocd"
}
```

This could:

* Create an Application in the `default` Project (which may have admin permissions)
* Deploy to the `argocd` namespace
* Modify Argo CD's RBAC ConfigMap
* Escalate privileges

### Secure Pattern

<Check>
  **Safe ApplicationSet with hard-coded project:**
</Check>

```yaml theme={null}
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: team-apps
spec:
  goTemplate: true
  generators:
  - git:
      repoURL: https://github.com/org/app-configs.git
      revision: main
      files:
      - path: "apps/team-a/**/config.json" # Scoped to team folder
  template:
    metadata:
      name: 'team-a-{{.appName}}'
    spec:
      project: team-a-project # SAFE: hard-coded project
      source:
        repoURL: '{{.source}}' # Can be templated
        targetRevision: '{{.revision}}' # Can be templated
        path: '{{.path}}' # Can be templated
      destination:
        server: https://kubernetes.default.svc # SAFE: hard-coded cluster
        namespace: team-a # SAFE: hard-coded namespace
```

### Requirements for Templated Projects

<Warning>
  If the `project` field is templated, admins **MUST** control all sources of truth for the ApplicationSet's generators.
</Warning>

For Git generators:

* PRs **must** require admin approval
* Implement mandatory code review
* Use branch protection
* Consider using CODEOWNERS files

**Example CODEOWNERS:**

```
# All ApplicationSet source repos require admin review
* @platform-team-admins

# Specific team folders can be managed by team leads
apps/team-a/** @team-a-leads @platform-team-admins
apps/team-b/** @team-b-leads @platform-team-admins
```

## Repository Credentials for ApplicationSets

<Warning>
  If your ApplicationSet uses a repository requiring credentials **and** the project field is templated, you must add the repository as "non project scoped".
</Warning>

### Configuring Non-Scoped Repositories

**Via UI:**

1. Navigate to Settings → Repositories
2. Add repository
3. Set Project field to **blank** in the dropdown

**Via CLI:**

```bash theme={null}
# Do NOT supply the --project parameter
argocd repo add https://github.com/org/app-configs.git \
  --username git \
  --password $GITHUB_TOKEN
```

**Declaratively:**

```yaml theme={null}
apiVersion: v1
kind: Secret
metadata:
  name: repo-credentials
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: repository
type: Opaque
stringData:
  url: https://github.com/org/app-configs.git
  username: git
  password: ghp_xxxxxxxxxxxxxxxxxxxx
  # DO NOT include project: field here
```

### Why Non-Scoped?

Project-scoped repositories restrict which Projects can use them. If the ApplicationSet's `project` field is templated, the ApplicationSet doesn't know in advance which Projects will be used, so it needs access to a non-scoped repository.

## Git Generator Specific Concerns

### No Signature Verification

<Warning>
  Git generators do not support Git commit signature verification for ApplicationSets with templated project fields.
</Warning>

This means:

* Cannot verify commit signatures
* Cannot guarantee commits are from trusted sources
* Must rely on Git provider access controls

**Mitigation:**

* Use GitHub/GitLab branch protection with required reviews
* Enable signed commits at the repository level
* Monitor for unexpected changes
* Use audit logs to track who made changes

### SCM Provider Authentication

The Git generator can use Secrets for SCM provider authentication:

```yaml theme={null}
generators:
- git:
    repoURL: https://github.com/org/private-repo.git
    revision: main
    files:
    - path: "apps/**/config.json"
    tokenRef:
      secretName: github-token
      key: token
```

<Warning>
  A malicious ApplicationSet creator could reference any Secret in the Argo CD namespace and potentially exfiltrate credentials.
</Warning>

**Protection:**

* Restrict ApplicationSet create/update to admins only
* Use Secret scanning tools
* Audit ApplicationSet resources regularly

## Best Practices

<CardGroup cols={2}>
  <Card title="Principle of Least Privilege" icon="shield-halved">
    * Only admins can manage ApplicationSets
    * Hard-code sensitive fields (project, cluster, namespace)
    * Scope generators to specific paths or labels
    * Use restricted AppProjects
  </Card>

  <Card title="Git Access Control" icon="git">
    * Require PR reviews for generator sources
    * Use branch protection rules
    * Implement CODEOWNERS
    * Enable audit logging
  </Card>

  <Card title="Monitoring & Alerting" icon="bell">
    * Alert on rapid Application creation
    * Monitor resource consumption
    * Track ApplicationSet changes
    * Review audit logs regularly
  </Card>

  <Card title="Resource Limits" icon="gauge">
    * Set AppProject resource quotas
    * Limit Applications per ApplicationSet
    * Use namespace ResourceQuotas
    * Implement rate limiting
  </Card>
</CardGroup>

## Security Checklist

Before deploying ApplicationSets in production:

<Steps>
  <Step title="RBAC Configuration">
    * [ ] ApplicationSet create/update/delete restricted to admins
    * [ ] Kubernetes RBAC rules in place
    * [ ] Argo CD RBAC configured appropriately
  </Step>

  <Step title="ApplicationSet Review">
    * [ ] Project field hard-coded (or admin-controlled source)
    * [ ] Destination cluster hard-coded or restricted
    * [ ] Destination namespace hard-coded or restricted
    * [ ] Generator sources controlled by admins
  </Step>

  <Step title="Git Repository Security">
    * [ ] Branch protection enabled
    * [ ] Required reviews configured
    * [ ] CODEOWNERS file in place
    * [ ] Audit logging enabled
  </Step>

  <Step title="AppProject Configuration">
    * [ ] Resource quotas set
    * [ ] Destination restrictions configured
    * [ ] Source repositories restricted
    * [ ] Cluster resource deny list configured
  </Step>

  <Step title="Monitoring">
    * [ ] Alerts for unusual Application creation
    * [ ] Resource consumption monitoring
    * [ ] Audit log review process
    * [ ] Incident response plan
  </Step>
</Steps>

## Example Secure Configuration

Here's a complete example of a secure self-service ApplicationSet:

```yaml theme={null}
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: team-a-project
  namespace: argocd
spec:
  description: Team A applications
  
  # Restrict source repositories
  sourceRepos:
  - 'https://github.com/team-a/*'
  
  # Restrict destination clusters and namespaces
  destinations:
  - namespace: 'team-a-*'
    server: https://kubernetes.default.svc
  
  # Resource quotas
  resourceQuotas:
  - applications: 25
  
  # Deny dangerous resources
  clusterResourceBlacklist:
  - group: ''
    kind: Namespace
  - group: rbac.authorization.k8s.io
    kind: ClusterRole
  - group: rbac.authorization.k8s.io
    kind: ClusterRoleBinding
---
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: team-a-apps
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - git:
      repoURL: https://github.com/org/app-configs.git
      revision: main
      files:
      - path: "apps/team-a/**/config.json" # Scoped to team
  template:
    metadata:
      name: 'team-a-{{.appName}}'
    spec:
      project: team-a-project # Hard-coded project
      source:
        repoURL: '{{.source}}' # Team can customize
        targetRevision: '{{.revision}}' # Team can customize
        path: '{{.path}}' # Team can customize
      destination:
        server: https://kubernetes.default.svc # Hard-coded cluster
        namespace: 'team-a-{{.appName}}' # Scoped namespace
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
        - CreateNamespace=true
```

## Next Steps

<Card title="Overview" icon="book" href="/applicationset/overview">
  Learn more about ApplicationSet fundamentals and capabilities
</Card>
