Skip to content

Commit e11ba0e

Browse files
authored
feat: Ability to toggle resource proxy per agent (#489)
Signed-off-by: jannfis <[email protected]>
1 parent 4d15d33 commit e11ba0e

File tree

9 files changed

+140
-49
lines changed

9 files changed

+140
-49
lines changed

agent/agent.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ type Agent struct {
9090

9191
// redisProxyMsgHandler manages redis connection state for agent
9292
redisProxyMsgHandler *redisProxyMsgHandler
93+
94+
// enableResourceProxy determines if the agent should proxy resources to the principal
95+
enableResourceProxy bool
9396
}
9497

9598
const defaultQueueName = "default"
@@ -121,6 +124,8 @@ func NewAgent(ctx context.Context, client *kube.KubernetesClient, namespace stri
121124
a.namespace = namespace
122125
a.mode = types.AgentModeAutonomous
123126
a.redisProxyMsgHandler = &redisProxyMsgHandler{}
127+
// Resource proxy is enabled by default.
128+
a.enableResourceProxy = true
124129

125130
for _, o := range opts {
126131
err := o(a)

agent/options.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,10 @@ func WithRedisPassword(password string) AgentOption {
9292
return nil
9393
}
9494
}
95+
96+
func WithEnableResourceProxy(enable bool) AgentOption {
97+
return func(o *Agent) error {
98+
o.enableResourceProxy = enable
99+
return nil
100+
}
101+
}

agent/resource.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ var ErrUnmanaged = errors.New("resource not managed by app")
3333
// scoped.
3434
// - Request for a list of available APIs
3535
func (a *Agent) processIncomingResourceRequest(ev *event.Event) error {
36+
// If resource proxy is disabled, we return an error immediately.
37+
if !a.enableResourceProxy {
38+
return fmt.Errorf("resource proxy is disabled in agent configuration")
39+
}
40+
3641
rreq, err := ev.ResourceRequest()
3742
if err != nil {
3843
return err

agent/resource_test.go

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -317,10 +317,11 @@ func Test_processIncomingResourceRequest(t *testing.T) {
317317
// Setup test environment
318318
kubeClient := kube.NewDynamicFakeClient(pod)
319319
agent := &Agent{
320-
context: context.Background(),
321-
kubeClient: kubeClient,
322-
queues: queue.NewSendRecvQueues(),
323-
emitter: event.NewEventSource("test-agent"),
320+
context: context.Background(),
321+
kubeClient: kubeClient,
322+
queues: queue.NewSendRecvQueues(),
323+
emitter: event.NewEventSource("test-agent"),
324+
enableResourceProxy: true,
324325
}
325326
require.NoError(t, agent.queues.Create(defaultQueueName))
326327

@@ -381,10 +382,11 @@ func Test_processIncomingResourceRequest(t *testing.T) {
381382
// Setup test environment
382383
kubeClient := kube.NewDynamicFakeClient(pod)
383384
agent := &Agent{
384-
context: context.Background(),
385-
kubeClient: kubeClient,
386-
queues: queue.NewSendRecvQueues(),
387-
emitter: event.NewEventSource("test-agent"),
385+
context: context.Background(),
386+
kubeClient: kubeClient,
387+
queues: queue.NewSendRecvQueues(),
388+
emitter: event.NewEventSource("test-agent"),
389+
enableResourceProxy: true,
388390
}
389391
require.NoError(t, agent.queues.Create(defaultQueueName))
390392

@@ -429,10 +431,11 @@ func Test_processIncomingResourceRequest(t *testing.T) {
429431
// Setup test environment with empty client
430432
kubeClient := kube.NewDynamicFakeClient()
431433
agent := &Agent{
432-
context: context.Background(),
433-
kubeClient: kubeClient,
434-
queues: queue.NewSendRecvQueues(),
435-
emitter: event.NewEventSource("test-agent"),
434+
context: context.Background(),
435+
kubeClient: kubeClient,
436+
queues: queue.NewSendRecvQueues(),
437+
emitter: event.NewEventSource("test-agent"),
438+
enableResourceProxy: true,
436439
}
437440
require.NoError(t, agent.queues.Create(defaultQueueName))
438441

@@ -475,10 +478,11 @@ func Test_processIncomingResourceRequest(t *testing.T) {
475478

476479
t.Run("Invalid request returns error", func(t *testing.T) {
477480
agent := &Agent{
478-
context: context.Background(),
479-
kubeClient: kube.NewDynamicFakeClient(),
480-
queues: queue.NewSendRecvQueues(),
481-
emitter: event.NewEventSource("test-agent"),
481+
context: context.Background(),
482+
kubeClient: kube.NewDynamicFakeClient(),
483+
queues: queue.NewSendRecvQueues(),
484+
emitter: event.NewEventSource("test-agent"),
485+
enableResourceProxy: true,
482486
}
483487
require.NoError(t, agent.queues.Create(defaultQueueName))
484488

@@ -495,8 +499,9 @@ func Test_processIncomingResourceRequest(t *testing.T) {
495499
func Test_getAvailableResources(t *testing.T) {
496500
t.Run("Error when resource is specified", func(t *testing.T) {
497501
agent := &Agent{
498-
context: context.Background(),
499-
kubeClient: kube.NewDynamicFakeClient(),
502+
context: context.Background(),
503+
kubeClient: kube.NewDynamicFakeClient(),
504+
enableResourceProxy: true,
500505
}
501506

502507
gvr := schema.GroupVersionResource{
@@ -526,8 +531,9 @@ func Test_getAvailableResources(t *testing.T) {
526531
}
527532

528533
agent := &Agent{
529-
context: context.Background(),
530-
kubeClient: kube.NewDynamicFakeClient(pod1, pod2),
534+
context: context.Background(),
535+
kubeClient: kube.NewDynamicFakeClient(pod1, pod2),
536+
enableResourceProxy: true,
531537
}
532538

533539
gvr := schema.GroupVersionResource{
@@ -555,8 +561,9 @@ func Test_getAvailableResources(t *testing.T) {
555561
}
556562

557563
agent := &Agent{
558-
context: context.Background(),
559-
kubeClient: kube.NewDynamicFakeClient(node1, node2),
564+
context: context.Background(),
565+
kubeClient: kube.NewDynamicFakeClient(node1, node2),
566+
enableResourceProxy: true,
560567
}
561568

562569
gvr := schema.GroupVersionResource{

cmd/argocd-agent/agent.go

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -39,29 +39,30 @@ import (
3939
// NewAgentRunCommand returns a new agent run command.
4040
func NewAgentRunCommand() *cobra.Command {
4141
var (
42-
serverAddress string
43-
serverPort int
44-
logLevel string
45-
logFormat string
46-
insecure bool
47-
rootCASecretName string
48-
rootCAPath string
49-
kubeConfig string
50-
kubeContext string
51-
namespace string
52-
agentMode string
53-
creds string
54-
tlsSecretName string
55-
tlsClientCrt string
56-
tlsClientKey string
57-
enableWebSocket bool
58-
metricsPort int
59-
healthzPort int
60-
enableCompression bool
61-
pprofPort int
62-
redisAddr string
63-
redisUsername string
64-
redisPassword string
42+
serverAddress string
43+
serverPort int
44+
logLevel string
45+
logFormat string
46+
insecure bool
47+
rootCASecretName string
48+
rootCAPath string
49+
kubeConfig string
50+
kubeContext string
51+
namespace string
52+
agentMode string
53+
creds string
54+
tlsSecretName string
55+
tlsClientCrt string
56+
tlsClientKey string
57+
enableWebSocket bool
58+
metricsPort int
59+
healthzPort int
60+
enableCompression bool
61+
pprofPort int
62+
redisAddr string
63+
redisUsername string
64+
redisPassword string
65+
enableResourceProxy bool
6566

6667
// Time interval for agent to principal ping
6768
// Ex: "30m", "1h" or "1h20m10s". Valid time units are "s", "m", "h".
@@ -172,6 +173,8 @@ func NewAgentRunCommand() *cobra.Command {
172173
agentOpts = append(agentOpts, agent.WithRedisUsername(redisUsername))
173174
agentOpts = append(agentOpts, agent.WithRedisPassword(redisPassword))
174175

176+
agentOpts = append(agentOpts, agent.WithEnableResourceProxy(enableResourceProxy))
177+
175178
if metricsPort > 0 {
176179
agentOpts = append(agentOpts, agent.WithMetricsPort(metricsPort))
177180
}
@@ -257,6 +260,9 @@ func NewAgentRunCommand() *cobra.Command {
257260
command.Flags().IntVar(&pprofPort, "pprof-port",
258261
env.NumWithDefault("ARGOCD_AGENT_PPROF_PORT", cmdutil.ValidPort, 0),
259262
"Port the pprof server will listen on")
263+
command.Flags().BoolVar(&enableResourceProxy, "enable-resource-proxy",
264+
env.BoolWithDefault("ARGOCD_AGENT_ENABLE_RESOURCE_PROXY", true),
265+
"Enable resource proxy")
260266

261267
command.Flags().StringVar(&kubeConfig, "kubeconfig", "", "Path to a kubeconfig file to use")
262268
command.Flags().StringVar(&kubeContext, "kubecontext", "", "Override the default kube context")

docs/configuration/agent/configuration.md

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,21 @@ The recommended approach for production deployments is to use ConfigMap entries
241241
- **Default**: `""` (empty)
242242
- **Example**: `"redis-password"`
243243

244+
### Resource Proxy Configuration
245+
246+
#### Enable Resource Proxy
247+
- **Command Line Flag**: `--enable-resource-proxy`
248+
- **Environment Variable**: `ARGOCD_AGENT_ENABLE_RESOURCE_PROXY`
249+
- **ConfigMap Entry**: `agent.resource-proxy.enable`
250+
- **Description**: Enable the resource proxy to allow access to live resources on this agent cluster from the principal
251+
- **Type**: Boolean
252+
- **Default**: `true`
253+
- **Example**: `"true"`
254+
- **Use Cases for Disabling**:
255+
- Security policies that require restricted resource access
256+
- Performance optimization when live resource viewing is not needed
257+
- Troubleshooting resource proxy related issues
258+
244259
### Kubernetes Configuration
245260

246261
#### Kubeconfig
@@ -272,7 +287,8 @@ argocd-agent agent \
272287
--server-port=8443 \
273288
--agent-mode=autonomous \
274289
--namespace=argocd \
275-
--log-level=info
290+
--log-level=info \
291+
--enable-resource-proxy=true
276292
```
277293

278294
### Using Environment Variables
@@ -282,6 +298,7 @@ export ARGOCD_AGENT_REMOTE_PORT=8443
282298
export ARGOCD_AGENT_MODE=autonomous
283299
export ARGOCD_AGENT_NAMESPACE=argocd
284300
export ARGOCD_AGENT_LOG_LEVEL=info
301+
export ARGOCD_AGENT_ENABLE_RESOURCE_PROXY=true
285302
argocd-agent agent
286303
```
287304

@@ -313,4 +330,20 @@ The ConfigMap should be mounted to the agent container and the parameters will b
313330
- Store sensitive configuration like credentials in Kubernetes Secrets, not ConfigMaps
314331
- Use mutual TLS (`mtls`) authentication when possible for enhanced security
315332
- Regularly rotate TLS certificates and authentication credentials
316-
- Restrict network access to the agent's metrics and health endpoints
333+
- Restrict network access to the agent's metrics and health endpoints
334+
- Consider disabling resource proxy (`--enable-resource-proxy=false`) if live resource access is not required for enhanced security isolation
335+
336+
## Resource Proxy Considerations
337+
338+
When the resource proxy is **enabled** (default):
339+
- Users can view live resources for applications on this agent cluster through the Argo CD UI
340+
- The agent processes resource requests from the principal and proxies them to the local Kubernetes API
341+
- All resource access is limited to resources managed by Argo CD applications
342+
343+
When the resource proxy is **disabled**:
344+
- Live resource viewing will not work for applications on this agent cluster
345+
- The Argo CD UI will show application status but not allow inspection of individual resources
346+
- Application synchronization and management operations continue to work normally
347+
- Reduces attack surface and network communication between principal and agent
348+
349+
For detailed information about how the resource proxy works and additional configuration options, see the [Live Resources](../../user-guide/live-resources.md) user guide.

docs/user-guide/live-resources.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,25 @@ argocd-agent principal \
6868

6969
### Agent Configuration
7070

71-
**No additional configuration is required on the agent side.** The agent automatically processes resource requests received from the principal through the standard event queue mechanism.
71+
The resource proxy is **enabled by default** on the agent and requires no additional configuration in most cases. However, it can be disabled if live resource access is not needed.
72+
73+
#### Environment Variables
74+
75+
| Variable | Default | Description |
76+
|----------|---------|-------------|
77+
| `ARGOCD_AGENT_ENABLE_RESOURCE_PROXY` | `true` | Enable/disable resource proxy processing on the agent |
78+
79+
#### Command Line Options
80+
81+
```bash
82+
# Disable resource proxy on the agent
83+
argocd-agent agent --enable-resource-proxy=false
84+
85+
# Enable resource proxy (default behavior)
86+
argocd-agent agent --enable-resource-proxy=true
87+
```
88+
89+
**Note**: When disabled, the agent will not process resource requests from the principal, making live resource viewing unavailable for applications on this agent cluster.
7290

7391
## RBAC Requirements
7492

@@ -496,6 +514,8 @@ curl -k --cert client.crt --key client.key \
496514

497515
## Related Documentation
498516

517+
- [Agent Configuration](../configuration/agent/configuration.md#resource-proxy-configuration) - Agent resource proxy configuration options
518+
- [Principal Configuration](../configuration/principal/configuration.md#resource-proxy-configuration) - Principal resource proxy configuration options
499519
- [Application Synchronization](./applications.md) - How Applications are managed
500520
- [Agent Modes](../concepts/agent-modes/) - Understanding managed vs autonomous modes
501521
- [Architecture](../concepts/architecture.md) - Overall system architecture

install/kubernetes/agent/agent-deployment.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ spec:
140140
secretKeyRef:
141141
name: argocd-redis
142142
key: auth
143+
- name: ARGOCD_AGENT_ENABLE_RESOURCE_PROXY
144+
valueFrom:
145+
configMapKeyRef:
146+
name: argocd-agent-params
147+
key: agent.resource-proxy.enable
148+
optional: true
143149
image: argocd-agent
144150
imagePullPolicy: Always
145151
name: argocd-agent-agent

install/kubernetes/agent/agent-params-cm.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,6 @@ data:
8080
# agent.pprof.port: The port the pprof server should listen on.
8181
# Default: 0
8282
agent.pprof.port: "0"
83-
83+
# agent.resource-proxy.enable: Whether to enable the resource proxy.
84+
# Default: true
85+
agent.resource-proxy.enable: "true"

0 commit comments

Comments
 (0)