Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 106 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,13 @@ kubectl get secret,configmap dapr-trust-bundle -n dapr-system

The operator supports the following configuration flags:

| Flag | Default | Description |
|------|---------|-------------|
| `--source-secret-name` | `dapr-trust-bundle-from-cert-manager` | Name of the source secret to monitor |
| `--target-namespace` | `dapr-system` | Namespace to monitor and create resources in |
| `--leader-elect` | `false` | Enable leader election for high availability |
| `--metrics-bind-address` | `:8443` | Address for the metrics endpoint |
| `--health-probe-bind-address` | `:8081` | Address for health and readiness probes |
| Flag | Default | Description |
| ----------------------------- | ------------------------------------- | -------------------------------------------- |
| `--source-secret-name` | `dapr-trust-bundle-from-cert-manager` | Name of the source secret to monitor |
| `--target-namespace` | `dapr-system` | Namespace to monitor and create resources in |
| `--leader-elect` | `false` | Enable leader election for high availability |
| `--metrics-bind-address` | `:8443` | Address for the metrics endpoint |
| `--health-probe-bind-address` | `:8081` | Address for health and readiness probes |

### Helm Configuration

Expand All @@ -103,45 +103,71 @@ controller:
sourceSecretName: "my-cert-secret"
targetNamespace: "production"

# Use namespace-scoped RBAC for enhanced security
rbac:
useClusterRole: false

# Enable monitoring
metrics:
serviceMonitor:
enabled: true
useClusterRole: false # Use namespace-scoped permissions
```

### RBAC Modes

The operator supports two RBAC modes depending on your deployment method:

#### Cluster-wide RBAC (Kustomize Default)

- **Used by**: `make deploy` (kustomize)
- Grants cluster-wide permissions to manage secrets and configmaps
- Suitable for monitoring multiple namespaces
- Uses ClusterRole and ClusterRoleBinding

#### Namespace-scoped RBAC (Helm Default - Enhanced Security)

- **Used by**: Helm chart with `rbac.useClusterRole: false` (default)
- Restricts permissions to the target namespace only
- Uses specific resource names for fine-grained access control
- Automatically configures namespace-scoped caching to prevent cluster-wide resource listing
- Recommended for production environments monitoring a single namespace

## RBAC Permissions

The operator requires different permissions based on the deployment mode:

### Cluster-wide RBAC (default)

- `get`, `list`, `watch` on secrets (to monitor source secrets in any namespace)
- `create`, `update`, `patch`, `delete` on secrets and configmaps (to manage target resources)

### Namespace-scoped RBAC (enhanced security)

- `get`, `list`, `watch` on specific source secret by name (e.g., `dapr-trust-bundle-from-cert-manager`)
- `create`, `delete`, `patch`, `update` on secrets and configmaps (for resource creation)
- `get`, `list`, `watch`, `patch`, `update` on `dapr-trust-bundle` secret and configmap specifically
- `update` on finalizers and status for specific secrets only

### RBAC Modes

#### Cluster-wide RBAC

- Grants cluster-wide permissions to manage secrets and configmaps
- Suitable for monitoring multiple namespaces

#### Namespace-scoped RBAC (Default for Enhanced Security)

- Restricts permissions to the target namespace only
- Uses specific resource names for fine-grained access control
- Automatically configures namespace-scoped caching to prevent cluster-wide resource listing
- Recommended for production environments monitoring a single namespace

```yaml
rbac:
useClusterRole: false # Set true to move to Cluster-wide RBAC
controller:
targetNamespace: "my-namespace"
```

## Installation Methods

### Helm Chart

**Basic Installation:**

```bash
helm install dapr-trustbundle deploy/helm/dapr-trustbundle
```

**Production Installation:**

```bash
helm install dapr-trustbundle deploy/helm/dapr-trustbundle \
--set replicaCount=2 \
Expand All @@ -151,6 +177,7 @@ helm install dapr-trustbundle deploy/helm/dapr-trustbundle \
```

**Custom Configuration:**

```bash
helm install dapr-trustbundle deploy/helm/dapr-trustbundle \
--set controller.sourceSecretName="custom-cert-secret" \
Expand Down Expand Up @@ -183,6 +210,7 @@ curl -sSL https://raw.githubusercontent.com/elenpay/dapr-trustbundle/main/script
### Basic Usage with cert-manager

1. **Create a cert-manager Certificate:**

```yaml
apiVersion: cert-manager.io/v1
kind: Certificate
Expand All @@ -196,10 +224,11 @@ spec:
kind: ClusterIssuer
commonName: dapr-trust-bundle
dnsNames:
- dapr-trust-bundle
- dapr-trust-bundle
```

2. **The operator automatically creates:**

- `Secret/dapr-trust-bundle` with transformed keys
- `ConfigMap/dapr-trust-bundle` with CA certificate only

Expand Down Expand Up @@ -250,8 +279,16 @@ kubectl cluster-info --context kind-dapr-trustbundle
make docker-build
kind load docker-image dapr-trustbundle-operator:latest --name dapr-trustbundle

# Deploy the operator
make deploy
# Deploy the operator (choose one method)

# Option 1: Deploy with Helm (Recommended - namespace-scoped RBAC by default)
helm install dapr-trustbundle deploy/helm/dapr-trustbundle \
--set image.repository=dapr-trustbundle-operator \
--set image.tag=latest \
--set image.pullPolicy=Never

# Option 2: Deploy with kustomize (cluster-wide RBAC)
make kind-deploy

# Run tests
make test
Expand All @@ -261,19 +298,47 @@ make test

```bash
# Apply example secret in the dapr-system namespace
kubectl apply -n dapr-system -f examples/test-secret.yaml
kubectl apply -n dapr-system -f examples/test-secret.yaml

# Check operator logs
kubectl logs -n dapr-system -l control-plane=operator -f

# Clean up
make undeploy

# Clean up when done
make undeploy
kind delete cluster --name dapr-trustbundle
```

For more details take a look to [./examples/README.md](./examples/README.md)

### CI/CD Pipeline

This project includes GitHub Actions workflows for automated building and releasing:

- **Linting** (`.github/workflows/lint.yml`):

- Runs `golangci-lint` to check Go code for style and correctness issues

- **Testing** (`.github/workflows/test.yml`):

- Runs unit tests and integration tests
- Ensures code changes do not break existing functionality

- **End-to-End Testing** (`.github/workflows/test-e2e.yml`):

- Deploys the operator to a test cluster
- Runs end-to-end tests against the deployed operator

- **Docker Build & Push** (`.github/workflows/docker-build-push.yml`):
- Triggers on pushes to `main` branch and tag creation
- Builds multi-platform Docker images (linux/amd64, linux/arm64)
- Pushes to GitHub Container Registry (`ghcr.io`)
- Generates deployment manifests as artifacts

**Image Tagging Strategy:**

- `main` - Latest development version from main branch
- `v1.0.0` - Stable release versions
- `pr-123` - Pull request builds for testing

### Project Structure

```
Expand All @@ -296,14 +361,17 @@ kind delete cluster --name dapr-trustbundle

### Common Issues

| Issue | Cause | Solution |
|-------|-------|----------|
| `ERROR: no nodes found for cluster "kind"` | Using named Kind cluster but make targets expect default cluster | Either use default cluster name (`kind create cluster`) or manually load image (`kind load docker-image dapr-trustbundle-operator:latest --name your-cluster-name`) |
| `ImagePullBackOff` | Image not available in cluster | Run `make kind-load` for Kind clusters |
| RBAC errors | Insufficient permissions | Run `make manifests deploy` to update RBAC |
| `configmaps is forbidden at cluster scope` | Using namespace RBAC but operator tries cluster-wide access | Ensure `rbac.useClusterRole: false` and operator will auto-configure namespace caching |
| Secret not syncing | Source secret name mismatch | Verify `--source-secret-name` flag matches actual secret |
| Operator not starting | Configuration errors | Check operator logs and verify flags |
1. **ImagePullBackOff**: Ensure you send the newly built image to your cluster, we use `make kind-load` that takes care of this
2. **RBAC errors**: Run `make manifests` and `make deploy` to update permissions
3. # **Secret not syncing**: Check operator logs and verify the source secret name matches exactly
| Issue | Cause | Solution |
| ------------------------------------------ | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ERROR: no nodes found for cluster "kind"` | Using named Kind cluster but make targets expect default cluster | Either use default cluster name (`kind create cluster`) or manually load image (`kind load docker-image dapr-trustbundle-operator:latest --name your-cluster-name`) |
| `ImagePullBackOff` | Image not available in cluster | Run `make kind-load` for Kind clusters |
| RBAC errors | Insufficient permissions | Run `make manifests deploy` to update RBAC |
| `configmaps is forbidden at cluster scope` | Using namespace RBAC but operator tries cluster-wide access | Ensure `rbac.useClusterRole: false` and operator will auto-configure namespace caching |
| Secret not syncing | Source secret name mismatch | Verify `--source-secret-name` flag matches actual secret |
| Operator not starting | Configuration errors | Check operator logs and verify flags |

### Debug Commands

Expand Down Expand Up @@ -349,7 +417,7 @@ curl -k https://localhost:8443/metrics
### Image Tagging Strategy

- `main` - Latest development version
- `v1.0.0` - Stable release versions
- `v1.0.0` - Stable release versions

### Available Images

Expand Down Expand Up @@ -384,4 +452,3 @@ Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for detai
---

For more detailed examples and advanced configuration, see the [`examples/`](examples/) directory and [Helm chart documentation](deploy/helm/dapr-trustbundle/README.md).

11 changes: 0 additions & 11 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import (
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
Expand Down Expand Up @@ -208,16 +207,6 @@ func main() {
// LeaderElectionReleaseOnCancel: true,
}

// Check if we should use namespace-scoped caching based on environment variable
// This should be set when using namespace-scoped RBAC (Role instead of ClusterRole)
if useNamespaceCache := os.Getenv("USE_NAMESPACE_CACHE"); useNamespaceCache == "true" {
setupLog.Info("Using namespace-scoped cache for enhanced security", "namespace", targetNamespace)
// Limit the cache to only watch the target namespace
managerOptions.Cache.DefaultNamespaces = map[string]cache.Config{
targetNamespace: {},
}
}

mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), managerOptions)
if err != nil {
setupLog.Error(err, "unable to start manager")
Expand Down
15 changes: 9 additions & 6 deletions config/rbac/role-namespaced.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,22 @@ metadata:
name: manager-role-namespaced
namespace: dapr-system # This would be replaced with actual target namespace
rules:
# Permission to read the source secret
# Permission to list secrets and configmaps in namespace (required for controller-runtime cache)
- apiGroups:
- ""
resources:
- secrets
- configmaps
verbs:
- get
- list
- watch
# Permission to read the source secret by name
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
resourceNames:
- dapr-trust-bundle-from-cert-manager # This would be replaced with actual source secret name
# Permission to create secrets and configmaps (no resourceNames needed for create)
Expand All @@ -32,8 +39,6 @@ rules:
- secrets
verbs:
- get
- list
- watch
- patch
- update
resourceNames:
Expand All @@ -44,8 +49,6 @@ rules:
- configmaps
verbs:
- get
- list
- watch
- patch
- update
resourceNames:
Expand Down
6 changes: 1 addition & 5 deletions deploy/helm/dapr-trustbundle/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,8 @@ spec:
{{- end }}
- --source-secret-name={{ .Values.controller.sourceSecretName }}
- --target-namespace={{ .Values.controller.targetNamespace }}
env:
{{- if not .Values.rbac.useClusterRole }}
- name: USE_NAMESPACE_CACHE
value: "true"
{{- end }}
{{- with .Values.env }}
env:
{{- toYaml . | nindent 10 }}
{{- end }}
ports:
Expand Down
11 changes: 9 additions & 2 deletions deploy/helm/dapr-trustbundle/templates/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,22 @@ metadata:
labels:
{{- include "dapr-trustbundle.labels" . | nindent 4 }}
rules:
# Permission to read the source secret
# Permission to list secrets and configmaps in namespace (required for controller-runtime cache)
- apiGroups:
- ""
resources:
- secrets
- configmaps
verbs:
- get
- list
- watch
# Permission to read the source secret by name
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
resourceNames:
- {{ .Values.controller.sourceSecretName }}
# Permission to create secrets and configmaps (no resourceNames needed for create)
Expand Down