Files
headlamp-sealed-secrets-plugin/docs/user-guide/scopes-explained.md
T
Chris Farhood 282025ca24 docs: implement Phase 3 - user tutorials and guides
Create comprehensive tutorials and user guides for common workflows
and core concepts.

New tutorials:
- tutorials/ci-cd-integration.md (8KB) - Complete CI/CD guide
  - GitHub Actions, GitLab CI, and Jenkins examples
  - Certificate management and kubeseal CLI usage
  - Bulk secret creation and environment-specific patterns
  - Troubleshooting and best practices

New user guides:
- user-guide/scopes-explained.md (12KB) - Deep dive into scopes
  - Detailed explanation of strict/namespace-wide/cluster-wide
  - Security implications and use cases
  - Decision tree for scope selection
  - Common mistakes and how to avoid them
  - Scope comparison table

- user-guide/rbac-permissions.md (10KB) - RBAC configuration
  - Required permissions for different access levels
  - Example RBAC configurations (viewer, creator, admin)
  - Service account setup for CI/CD
  - Plugin UI behavior based on permissions
  - Troubleshooting permission issues
  - Security best practices

Benefits:
- Real-world examples for GitHub Actions, GitLab CI, Jenkins
- Clear security guidance with decision trees
- Copy-paste RBAC manifests for common scenarios
- Troubleshooting sections for each guide
- Cross-referenced with other documentation

Phase 3 deliverables (3-4 days estimated, completed in 1 session):
 CI/CD integration tutorial with 3 platform examples
 Scopes explained with security best practices
 RBAC permissions guide with example manifests
 Decision trees and comparison tables
 Troubleshooting sections for each guide

Total documentation:
- 30KB of new tutorial/guide content
- 3 comprehensive guides
- 20+ code examples
- Cross-referenced with API docs and other guides

Next: Phase 4 - Troubleshooting guides and ADRs

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-11 23:31:34 -05:00

397 lines
10 KiB
Markdown

# Scopes Explained
Understanding SealedSecret scopes and when to use each one.
## What are Scopes?
Scopes determine **where** a SealedSecret can be unsealed. They control the binding between the encrypted data and its Kubernetes resource identity (namespace and/or name).
Think of scopes as **security levels** for your encrypted secrets:
- **Strict** = Locked to specific name + namespace (most secure)
- **Namespace-wide** = Locked to namespace (can rename)
- **Cluster-wide** = Can move anywhere (least secure)
## The Three Scopes
### Strict Scope (Recommended)
**Binding**: Namespace + Name + Key
The sealed secret can ONLY be unsealed if all three match:
- ✅ Same namespace
- ✅ Same secret name
- ✅ Same key name
**Example:**
```yaml
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: db-credentials
namespace: production
spec:
encryptedData:
password: AgB... # Can ONLY be unsealed as:
# - name: db-credentials
# - namespace: production
# - key: password
```
**Use when:**
- Production secrets
- Database credentials
- API keys
- Any sensitive data
**Advantages:**
- ✅ Maximum security
- ✅ Prevents accidental leaks from renaming
- ✅ Prevents cross-namespace access
**Limitations:**
- ❌ Cannot rename the secret
- ❌ Cannot move to different namespace
- ❌ Must re-encrypt if name/namespace changes
**Creating with Headlamp:**
1. Click "Create Sealed Secret"
2. Select **"strict"** scope (default)
3. Fill in name, namespace, and secret data
4. Click "Create"
**Creating with kubeseal:**
```bash
kubectl create secret generic db-credentials \
--namespace production \
--from-literal=password=mysecret \
--dry-run=client -o yaml | \
kubeseal --cert cert.pem --scope strict --format yaml
```
### Namespace-Wide Scope
**Binding**: Namespace + Key
The sealed secret can be unsealed if:
- ✅ Same namespace
- ✅ Same key name
- ⚠️ Any secret name (can rename)
**Example:**
```yaml
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: app-config
namespace: staging
spec:
encryptedData:
api-url: AgB... # Can be unsealed as:
# - name: app-config (or ANY name)
# - namespace: staging (must match)
# - key: api-url (must match)
```
**Use when:**
- Shared configuration across multiple apps in a namespace
- Secrets that might be renamed
- Non-critical secrets
**Advantages:**
- ✅ Flexible naming
- ✅ Can rename secret without re-encryption
- ✅ Still namespace-isolated
**Limitations:**
- ❌ Less secure than strict
- ❌ Cannot move to different namespace
- ❌ Anyone in namespace can unseal by creating correctly-named secret
**Creating with Headlamp:**
1. Click "Create Sealed Secret"
2. Select **"namespace-wide"** scope
3. Fill in namespace and secret data
4. Name can be changed later
**Creating with kubeseal:**
```bash
kubectl create secret generic temp-name \
--namespace staging \
--from-literal=api-url=https://api.staging.example.com \
--dry-run=client -o yaml | \
kubeseal --cert cert.pem --scope namespace-wide --format yaml
```
### Cluster-Wide Scope
**Binding**: Key only
The sealed secret can be unsealed if:
- ⚠️ Any namespace
- ⚠️ Any secret name
- ✅ Same key name
**Example:**
```yaml
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: global-config
namespace: default
spec:
encryptedData:
license-key: AgB... # Can be unsealed as:
# - name: ANY
# - namespace: ANY
# - key: license-key (must match)
```
**Use when:**
- Truly global configuration
- License keys used across all namespaces
- Public URLs or non-sensitive config
**Advantages:**
- ✅ Maximum flexibility
- ✅ Can move anywhere in cluster
- ✅ Can rename freely
**Limitations:**
- ❌ Least secure
- ❌ Anyone in cluster can unseal
- ❌ Easy to accidentally expose
**Creating with Headlamp:**
1. Click "Create Sealed Secret"
2. Select **"cluster-wide"** scope
3. Fill in secret data
4. Can deploy to any namespace
**Creating with kubeseal:**
```bash
kubectl create secret generic temp \
--from-literal=license-key=ABC123 \
--dry-run=client -o yaml | \
kubeseal --cert cert.pem --scope cluster-wide --format yaml
```
## Scope Comparison
| Feature | Strict | Namespace-Wide | Cluster-Wide |
|---------|--------|----------------|--------------|
| **Security** | 🔒🔒🔒 High | 🔒🔒 Medium | 🔒 Low |
| **Can rename** | ❌ No | ✅ Yes | ✅ Yes |
| **Can move namespace** | ❌ No | ❌ No | ✅ Yes |
| **Binding** | Name+NS+Key | NS+Key | Key only |
| **Use case** | Production secrets | Shared namespace config | Global config |
| **Recommended for** | Credentials, API keys | App config | Public URLs |
## Decision Tree
```
┌─────────────────────────────────┐
│ Is this a sensitive credential? │
│ (password, API key, token, etc) │
└─────────┬──────────────┬────────┘
│ │
YES NO
│ │
v v
┌─────────┐ ┌──────────────────┐
│ strict │ │ Could this value │
│ scope │ │ be shared across │
└─────────┘ │ your cluster? │
└────┬────────┬────┘
│ │
YES NO
│ │
v v
┌──────────┐ ┌──────────────┐
│cluster- │ │namespace- │
│wide scope│ │wide scope │
└──────────┘ └──────────────┘
```
## Examples by Use Case
### Database Credentials (Strict)
```yaml
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: postgres-credentials
namespace: production
spec:
encryptedData:
username: AgB...
password: AgB...
host: AgB...
```
**Why strict?** Credentials must not leak to other namespaces or be accessible via renaming.
### Application Config (Namespace-Wide)
```yaml
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: app-config
namespace: staging
spec:
encryptedData:
api-url: AgB...
timeout: AgB...
log-level: AgB...
```
**Why namespace-wide?** Config is specific to staging but might be used by multiple apps (with different names).
### License Key (Cluster-Wide)
```yaml
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: company-license
namespace: default
spec:
encryptedData:
license-key: AgB...
```
**Why cluster-wide?** The same license applies to all namespaces and environments.
## Changing Scopes
You **cannot** change a scope after encryption. To change scope:
1. **Delete the old sealed secret**:
```bash
kubectl delete sealedsecret old-secret -n production
```
2. **Re-encrypt with new scope**:
```bash
kubectl create secret generic old-secret \
--namespace production \
--from-literal=password=value \
--dry-run=client -o yaml | \
kubeseal --cert cert.pem --scope namespace-wide --format yaml > new-sealed-secret.yaml
```
3. **Apply new sealed secret**:
```bash
kubectl apply -f new-sealed-secret.yaml
```
## Security Best Practices
### 1. Default to Strict
Always use **strict scope** unless you have a specific reason not to:
✅ **Good:**
```bash
# Explicit strict scope
kubeseal --scope strict
```
❌ **Risky:**
```bash
# Using cluster-wide for credentials
kubeseal --scope cluster-wide # Don't do this for secrets!
```
### 2. Audit Your Scopes
List all sealed secrets and their scopes:
```bash
kubectl get sealedsecrets --all-namespaces -o json | \
jq -r '.items[] | "\(.metadata.namespace)/\(.metadata.name): \(.spec.template.type // "strict")"'
```
### 3. Separate Sensitive from Non-Sensitive
```bash
# Sensitive → strict
kubectl create secret generic db-creds --from-literal=password=... | \
kubeseal --scope strict
# Non-sensitive → namespace-wide or cluster-wide
kubectl create secret generic app-urls --from-literal=api=https://... | \
kubeseal --scope namespace-wide
```
### 4. Document Scope Choices
Add annotations to explain why a scope was chosen:
```yaml
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: db-credentials
namespace: production
annotations:
sealedsecrets.scope: "strict"
sealedsecrets.reason: "Database credentials must not be accessible outside production namespace"
spec:
encryptedData:
password: AgB...
```
## Common Mistakes
### ❌ Using Cluster-Wide for Everything
```bash
# DON'T: Encrypting passwords with cluster-wide scope
kubeseal --scope cluster-wide < secret-with-passwords.yaml
```
**Problem**: Anyone in any namespace can create a secret with the same key name and unseal it.
**Solution**: Use strict scope for credentials.
### ❌ Renaming Strict-Scoped Secrets
```bash
# Create strict-scoped secret
kubectl apply -f db-secret.yaml # name: db-credentials
# Later, try to rename
kubectl apply -f db-secret.yaml # name: database-creds (DIFFERENT NAME)
```
**Problem**: Sealed secret won't unseal because name changed.
**Solution**: Re-encrypt with new name or use namespace-wide scope.
### ❌ Moving Secrets Between Namespaces
```bash
# Seal for production
kubectl create secret generic app-secret --namespace production | kubeseal
# Try to use in staging
kubectl apply -f sealed-secret.yaml --namespace staging
```
**Problem**: Won't unseal (namespace mismatch with strict or namespace-wide scope).
**Solution**: Re-encrypt for the target namespace or use cluster-wide (if appropriate).
## Next Steps
- **[RBAC Permissions](rbac-permissions.md)** - Control who can create/view sealed secrets
- **[Creating Secrets](creating-secrets.md)** - Complete guide to secret creation
- **[Secret Rotation](../tutorials/secret-rotation.md)** - Rotate secrets and keys
## Resources
- [Sealed Secrets Scopes Documentation](https://github.com/bitnami-labs/sealed-secrets#scopes)
- [Security Best Practices](../deployment/security-hardening.md)