Skip to content

Commit 8858332

Browse files
committed
Add ProxySecretRef field to Provider API
Introduce spec.proxySecretRef to enable secure proxy configuration through dedicated Secrets. This provides a more secure alternative to the deprecated spec.proxy field and secret proxy key. The new field integrates with runtime/secrets for unified proxy handling and maintains backward compatibility. Deprecation warnings are implemented for existing proxy configuration methods. Proxy priority: ProxySecretRef > secret proxy key > spec.proxy Signed-off-by: cappyzawa <[email protected]>
1 parent 2503bda commit 8858332

File tree

9 files changed

+188
-19
lines changed

9 files changed

+188
-19
lines changed

api/v1beta3/provider_types.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,20 @@ type ProviderSpec struct {
9797
Timeout *metav1.Duration `json:"timeout,omitempty"`
9898

9999
// Proxy the HTTP/S address of the proxy server.
100+
// Deprecated: Use ProxySecretRef instead. Will be removed in v1.
100101
// +kubebuilder:validation:Pattern="^(http|https)://.*$"
101102
// +kubebuilder:validation:MaxLength:=2048
102103
// +kubebuilder:validation:Optional
103104
// +optional
104105
Proxy string `json:"proxy,omitempty"`
105106

107+
// ProxySecretRef specifies the Secret containing the proxy configuration
108+
// for this Provider. The Secret should contain an 'address' key with the
109+
// HTTP/S address of the proxy server. Optional 'username' and 'password'
110+
// keys can be provided for proxy authentication.
111+
// +optional
112+
ProxySecretRef *meta.LocalObjectReference `json:"proxySecretRef,omitempty"`
113+
106114
// SecretRef specifies the Secret containing the authentication
107115
// credentials for this Provider.
108116
// +optional

api/v1beta3/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/notification.toolkit.fluxcd.io_providers.yaml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,10 +475,25 @@ spec:
475475
pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
476476
type: string
477477
proxy:
478-
description: Proxy the HTTP/S address of the proxy server.
478+
description: |-
479+
Proxy the HTTP/S address of the proxy server.
480+
Deprecated: Use ProxySecretRef instead. Will be removed in v1.
479481
maxLength: 2048
480482
pattern: ^(http|https)://.*$
481483
type: string
484+
proxySecretRef:
485+
description: |-
486+
ProxySecretRef specifies the Secret containing the proxy configuration
487+
for this Provider. The Secret should contain an 'address' key with the
488+
HTTP/S address of the proxy server. Optional 'username' and 'password'
489+
keys can be provided for proxy authentication.
490+
properties:
491+
name:
492+
description: Name of the referent.
493+
type: string
494+
required:
495+
- name
496+
type: object
482497
secretRef:
483498
description: |-
484499
SecretRef specifies the Secret containing the authentication

docs/api/v1beta3/notification.md

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,25 @@ string
330330
</td>
331331
<td>
332332
<em>(Optional)</em>
333-
<p>Proxy the HTTP/S address of the proxy server.</p>
333+
<p>Proxy the HTTP/S address of the proxy server.
334+
Deprecated: Use ProxySecretRef instead. Will be removed in v1.</p>
335+
</td>
336+
</tr>
337+
<tr>
338+
<td>
339+
<code>proxySecretRef</code><br>
340+
<em>
341+
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
342+
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
343+
</a>
344+
</em>
345+
</td>
346+
<td>
347+
<em>(Optional)</em>
348+
<p>ProxySecretRef specifies the Secret containing the proxy configuration
349+
for this Provider. The Secret should contain an &lsquo;address&rsquo; key with the
350+
HTTP/S address of the proxy server. Optional &lsquo;username&rsquo; and &lsquo;password&rsquo;
351+
keys can be provided for proxy authentication.</p>
334352
</td>
335353
</tr>
336354
<tr>
@@ -650,7 +668,25 @@ string
650668
</td>
651669
<td>
652670
<em>(Optional)</em>
653-
<p>Proxy the HTTP/S address of the proxy server.</p>
671+
<p>Proxy the HTTP/S address of the proxy server.
672+
Deprecated: Use ProxySecretRef instead. Will be removed in v1.</p>
673+
</td>
674+
</tr>
675+
<tr>
676+
<td>
677+
<code>proxySecretRef</code><br>
678+
<em>
679+
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
680+
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
681+
</a>
682+
</em>
683+
</td>
684+
<td>
685+
<em>(Optional)</em>
686+
<p>ProxySecretRef specifies the Secret containing the proxy configuration
687+
for this Provider. The Secret should contain an &lsquo;address&rsquo; key with the
688+
HTTP/S address of the proxy server. Optional &lsquo;username&rsquo; and &lsquo;password&rsquo;
689+
keys can be provided for proxy authentication.</p>
654690
</td>
655691
</tr>
656692
<tr>

docs/spec/v1beta3/providers.md

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,7 +1097,7 @@ credentials for the provider API.
10971097
The Kubernetes secret can have any of the following keys:
10981098

10991099
- `address` - overrides `.spec.address`
1100-
- `proxy` - overrides `.spec.proxy`
1100+
- `proxy` - overrides `.spec.proxy` (deprecated, use `.spec.proxySecretRef` instead. **Support for this key will be removed in v1**)
11011101
- `token` - used for authentication
11021102
- `username` - overrides `.spec.username`
11031103
- `headers` - HTTP headers values included in the POST request
@@ -1155,7 +1155,7 @@ stringData:
11551155
#### Proxy auth example
11561156

11571157
Some networks need to use an authenticated proxy to access external services.
1158-
Therefore, the proxy address can be stored as a secret to hide parameters like the username and password:
1158+
The recommended approach is to use `.spec.proxySecretRef` with a dedicated Secret:
11591159

11601160
```yaml
11611161
---
@@ -1164,6 +1164,22 @@ kind: Secret
11641164
metadata:
11651165
name: my-provider-proxy
11661166
namespace: default
1167+
stringData:
1168+
address: "http://proxy_url:proxy_port"
1169+
username: "proxy_username"
1170+
password: "proxy_password"
1171+
```
1172+
1173+
**Legacy approach (deprecated):**
1174+
The proxy address can also be stored in the main secret to hide parameters like the username and password:
1175+
1176+
```yaml
1177+
---
1178+
apiVersion: v1
1179+
kind: Secret
1180+
metadata:
1181+
name: my-provider-proxy-legacy
1182+
namespace: default
11671183
stringData:
11681184
proxy: "http://username:password@proxy_url:proxy_port"
11691185
```
@@ -1210,10 +1226,17 @@ the controller will log a deprecation warning.
12101226
### HTTP/S proxy
12111227

12121228
`.spec.proxy` is an optional field to specify an HTTP/S proxy address.
1229+
**Warning:** This field is deprecated, use `.spec.proxySecretRef` instead. **Support for this field will be removed in v1.**
1230+
1231+
`.spec.proxySecretRef` is an optional field to specify a name reference to a
1232+
Secret in the same namespace as the Provider, containing the proxy configuration.
1233+
The Secret should contain an `address` key with the HTTP/S address of the proxy server.
1234+
Optional `username` and `password` keys can be provided for proxy authentication.
12131235

12141236
If the proxy address contains sensitive information such as basic auth credentials, it is
1215-
recommended to store the proxy in the Kubernetes secret referenced by `.spec.secretRef.name`.
1216-
When the referenced Secret contains a `proxy` key, the `.spec.proxy` value is ignored.
1237+
recommended to use `.spec.proxySecretRef` instead of `.spec.proxy`.
1238+
When `.spec.proxySecretRef` is specified, both `.spec.proxy` and the `proxy` key from
1239+
`.spec.secretRef` are ignored.
12171240

12181241
### Timeout
12191242

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ require (
2424
github.com/fluxcd/pkg/cache v0.9.0
2525
github.com/fluxcd/pkg/git v0.31.0
2626
github.com/fluxcd/pkg/masktoken v0.7.0
27-
github.com/fluxcd/pkg/runtime v0.60.0
27+
github.com/fluxcd/pkg/runtime v0.61.0
2828
github.com/fluxcd/pkg/ssa v0.48.0
2929
github.com/fluxcd/pkg/ssh v0.18.0
3030
github.com/getsentry/sentry-go v0.32.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,8 @@ github.com/fluxcd/pkg/git v0.31.0 h1:hVUJcRujNa+GA5zrjrMpuVcgHbCBjfq0CZIZJqJl22I
168168
github.com/fluxcd/pkg/git v0.31.0/go.mod h1:rUgLXVQGBkBggHOLVMhHMHaweQ8Oc6HwZiN2Zm08Zxs=
169169
github.com/fluxcd/pkg/masktoken v0.7.0 h1:pitmyOg2pUVdW+nn2Lk/xqm2TaA08uxvOC0ns3sz6bM=
170170
github.com/fluxcd/pkg/masktoken v0.7.0/go.mod h1:Lc1uoDjO1GY6+YdkK+ZqqBIBWquyV58nlSJ5S1N1IYU=
171-
github.com/fluxcd/pkg/runtime v0.60.0 h1:d++EkV3FlycB+bzakB5NumwY4J8xts8i7lbvD6jBLeU=
172-
github.com/fluxcd/pkg/runtime v0.60.0/go.mod h1:UeU0/eZLErYC/1bTmgzBfNXhiHy9fuQzjfLK0HxRgxY=
171+
github.com/fluxcd/pkg/runtime v0.61.0 h1:63OCvVoJd3RbmAl7UBUzOeNtaY5V1iVL+SaaqiNMM74=
172+
github.com/fluxcd/pkg/runtime v0.61.0/go.mod h1:UeU0/eZLErYC/1bTmgzBfNXhiHy9fuQzjfLK0HxRgxY=
173173
github.com/fluxcd/pkg/ssa v0.48.0 h1:DW+4DG8L/yZEi30UltOEXPB1d/ZFn4HfVhpJQp5oc2o=
174174
github.com/fluxcd/pkg/ssa v0.48.0/go.mod h1:T50TO0U2obLodZnrFgOrxollfBEy4V673OkM2aTUF1c=
175175
github.com/fluxcd/pkg/ssh v0.18.0 h1:SB0RrZ/YZIla3chTUulsfVmiCzJv5pEWfHM3dHMC8AU=

internal/server/event_handlers.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import (
4040
"github.com/fluxcd/pkg/auth"
4141
pkgcache "github.com/fluxcd/pkg/cache"
4242
"github.com/fluxcd/pkg/masktoken"
43+
"github.com/fluxcd/pkg/runtime/secrets"
4344

4445
apiv1 "github.com/fluxcd/notification-controller/api/v1"
4546
apiv1beta3 "github.com/fluxcd/notification-controller/api/v1beta3"
@@ -311,7 +312,11 @@ func createNotifier(ctx context.Context, kubeClient client.Client, provider *api
311312

312313
webhook := provider.Spec.Address
313314
username := provider.Spec.Username
314-
proxy := provider.Spec.Proxy
315+
// TODO: Remove deprecated proxy handling when Provider v1 is released.
316+
deprecatedProxy := provider.Spec.Proxy
317+
if deprecatedProxy != "" {
318+
log.FromContext(ctx).Error(nil, "warning: spec.proxy is deprecated, please use spec.proxySecretRef instead. Support for this field will be removed in v1.")
319+
}
315320
token := ""
316321
password := ""
317322
headers := make(map[string]string)
@@ -336,11 +341,12 @@ func createNotifier(ctx context.Context, kubeClient client.Client, provider *api
336341
}
337342

338343
if val, ok := secret.Data["proxy"]; ok {
339-
proxy = strings.TrimSpace(string(val))
340-
_, err := url.Parse(proxy)
344+
deprecatedProxy = strings.TrimSpace(string(val))
345+
_, err := url.Parse(deprecatedProxy)
341346
if err != nil {
342347
return nil, "", fmt.Errorf("invalid 'proxy' in secret '%s/%s'", secret.Namespace, secret.Name)
343348
}
349+
log.FromContext(ctx).Error(nil, "warning: specifying proxy with 'proxy' key in the referenced secret is deprecated, use spec.proxySecretRef with 'address' key instead. Support for the 'proxy' key will be removed in v1.")
344350
}
345351

346352
if val, ok := secret.Data["token"]; ok {
@@ -359,6 +365,17 @@ func createNotifier(ctx context.Context, kubeClient client.Client, provider *api
359365
}
360366
}
361367

368+
var proxy string
369+
if provider.Spec.ProxySecretRef != nil {
370+
proxyURL, err := secrets.ProxyURLFromSecret(ctx, kubeClient, provider.Spec.ProxySecretRef.Name, provider.Namespace)
371+
if err != nil {
372+
return nil, "", fmt.Errorf("failed to get proxy URL from secret: %w", err)
373+
}
374+
proxy = proxyURL.String()
375+
} else {
376+
proxy = deprecatedProxy
377+
}
378+
362379
var certPool *x509.CertPool
363380
if provider.Spec.CertSecretRef != nil {
364381
var secret corev1.Secret

internal/server/event_handlers_test.go

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -548,13 +548,15 @@ func TestGetNotificationParams(t *testing.T) {
548548
func TestCreateNotifier(t *testing.T) {
549549
secretName := "foo-secret"
550550
certSecretName := "cert-secret"
551+
proxySecretName := "proxy-secret"
551552
tests := []struct {
552-
name string
553-
providerSpec *apiv1beta3.ProviderSpec
554-
secretType corev1.SecretType
555-
secretData map[string][]byte
556-
certSecretData map[string][]byte
557-
wantErr bool
553+
name string
554+
providerSpec *apiv1beta3.ProviderSpec
555+
secretType corev1.SecretType
556+
secretData map[string][]byte
557+
certSecretData map[string][]byte
558+
proxySecretData map[string][]byte
559+
wantErr bool
558560
}{
559561
{
560562
name: "no address, no secret ref",
@@ -578,6 +580,7 @@ func TestCreateNotifier(t *testing.T) {
578580
},
579581
wantErr: true,
580582
},
583+
// TODO: Remove deprecated secret proxy key tests when Provider v1 is released.
581584
{
582585
name: "reference to secret with valid address, proxy, headers",
583586
providerSpec: &apiv1beta3.ProviderSpec{
@@ -625,6 +628,7 @@ func TestCreateNotifier(t *testing.T) {
625628
"address": []byte("https://example.com"),
626629
},
627630
},
631+
// TODO: Remove deprecated spec.proxy field tests when Provider v1 is released.
628632
{
629633
name: "invalid spec proxy overridden by valid secret ref proxy",
630634
providerSpec: &apiv1beta3.ProviderSpec{
@@ -780,6 +784,60 @@ Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc
780784
},
781785
wantErr: false,
782786
},
787+
{
788+
name: "proxy from ProxySecretRef",
789+
providerSpec: &apiv1beta3.ProviderSpec{
790+
Type: "generic",
791+
Address: "https://example.com",
792+
ProxySecretRef: &meta.LocalObjectReference{Name: proxySecretName},
793+
},
794+
proxySecretData: map[string][]byte{
795+
"address": []byte("http://proxy.example.com:8080"),
796+
},
797+
},
798+
{
799+
name: "proxy from ProxySecretRef with authentication",
800+
providerSpec: &apiv1beta3.ProviderSpec{
801+
Type: "generic",
802+
Address: "https://example.com",
803+
ProxySecretRef: &meta.LocalObjectReference{Name: proxySecretName},
804+
},
805+
proxySecretData: map[string][]byte{
806+
"address": []byte("http://proxy.example.com:8080"),
807+
"username": []byte("proxyuser"),
808+
"password": []byte("proxypass"),
809+
},
810+
},
811+
{
812+
name: "ProxySecretRef reference to non-existing secret",
813+
providerSpec: &apiv1beta3.ProviderSpec{
814+
Type: "generic",
815+
Address: "https://example.com",
816+
ProxySecretRef: &meta.LocalObjectReference{Name: "non-existing"},
817+
},
818+
wantErr: true,
819+
},
820+
{
821+
name: "ProxySecretRef missing address field",
822+
providerSpec: &apiv1beta3.ProviderSpec{
823+
Type: "generic",
824+
Address: "https://example.com",
825+
ProxySecretRef: &meta.LocalObjectReference{Name: proxySecretName},
826+
},
827+
proxySecretData: map[string][]byte{
828+
"username": []byte("proxyuser"),
829+
},
830+
wantErr: true,
831+
},
832+
// TODO: Remove deprecated spec.proxy field tests when Provider v1 is released.
833+
{
834+
name: "deprecated spec.proxy field",
835+
providerSpec: &apiv1beta3.ProviderSpec{
836+
Type: "generic",
837+
Address: "https://example.com",
838+
Proxy: "http://proxy.example.com:8080",
839+
},
840+
},
783841
}
784842

785843
for _, tt := range tests {
@@ -806,6 +864,13 @@ Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc
806864
}
807865
builder.WithObjects(secret)
808866
}
867+
if tt.proxySecretData != nil {
868+
secret := &corev1.Secret{
869+
ObjectMeta: metav1.ObjectMeta{Name: proxySecretName},
870+
Data: tt.proxySecretData,
871+
}
872+
builder.WithObjects(secret)
873+
}
809874
provider := apiv1beta3.Provider{Spec: *tt.providerSpec}
810875

811876
_, _, err := createNotifier(context.TODO(), builder.Build(), &provider, "", nil)

0 commit comments

Comments
 (0)