Skip to content

Commit 3eed3b8

Browse files
authored
feat: Support oauth2 service in proxy mode (#1561)
1 parent 52ff61b commit 3eed3b8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+3498
-3002
lines changed

.vscode/launch.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@
153153
"RADIX_CONTAINER_REGISTRY": "radixdev.azurecr.io",
154154
"RADIX_APP_CONTAINER_REGISTRY": "radixdevapp.azurecr.io",
155155
"RADIX_OAUTH_PROXY_DEFAULT_OIDC_ISSUER_URL": "https://login.microsoftonline.com/3aa4a235-b6e2-48d5-9195-7fcf05b459b0/v2.0",
156-
"RADIX_OAUTH_PROXY_IMAGE": "quay.io/oauth2-proxy/oauth2-proxy:v7.9.0",
157-
"RADIX_OAUTH_REDIS_IMAGE": "docker.io/library/redis:8.0",
156+
"RADIX_OAUTH_PROXY_IMAGE": "quay.io/oauth2-proxy/oauth2-proxy:v7.12.0",
157+
"RADIX_OAUTH_REDIS_IMAGE": "docker.io/library/redis:8.2.2-alpine3.22",
158158
"RADIXOPERATOR_TENANT_ID": "3aa4a235-b6e2-48d5-9195-7fcf05b459b0",
159159
"KUBERNETES_SERVICE_PORT": "443",
160160
"REGISTRATION_CONTROLLER_THREADS": "10",
@@ -168,10 +168,10 @@
168168
"RADIXOPERATOR_PODSECURITYSTANDARD_ENFORCE_LEVEL": "baseline",
169169
"RADIXOPERATOR_PODSECURITYSTANDARD_APP_NAMESPACE_ENFORCE_LEVEL": "privileged",
170170
"RADIXOPERATOR_PODSECURITYSTANDARD_ENFORCE_VERSION": "v1.23",
171-
"RADIXOPERATOR_PODSECURITYSTANDARD_AUDIT_LEVEL": "restricted",
172-
"RADIXOPERATOR_PODSECURITYSTANDARD_AUDIT_VERSION": "v1.23",
173-
"RADIXOPERATOR_PODSECURITYSTANDARD_WARN_LEVEL": "restricted",
174-
"RADIXOPERATOR_PODSECURITYSTANDARD_WARN_VERSION": "v1.23",
171+
"RADIXOPERATOR_PODSECURITYSTANDARD_AUDIT_LEVEL": "",
172+
"RADIXOPERATOR_PODSECURITYSTANDARD_AUDIT_VERSION": "",
173+
"RADIXOPERATOR_PODSECURITYSTANDARD_WARN_LEVEL": "",
174+
"RADIXOPERATOR_PODSECURITYSTANDARD_WARN_VERSION": "",
175175
"RADIX_ZONE": "dev",
176176
"RADIX_DEPLOYMENTS_PER_ENVIRONMENT_HISTORY_LIMIT": "10",
177177
"RADIX_PIPELINE_JOBS_HISTORY_LIMIT": "5",
@@ -186,7 +186,7 @@
186186
"RADIXOPERATOR_ORPHANED_ENVIRONMENTS_CLEANUP_CRON": "0 0 * * *",
187187
"LOG_LEVEL": "info",
188188
"LOG_PRETTY": "true",
189-
"RADIXOPERATOR_PIPELINE_IMAGE": "ghcr.io/equinor/radix/pipeline:1.104.1",
189+
"RADIXOPERATOR_PIPELINE_IMAGE": "ghcr.io/equinor/radix/pipeline:1.107.1",
190190
"RADIX_PIPELINE_GIT_CLONE_GIT_IMAGE": "docker.io/alpine/git:2.45.2"
191191
},
192192
"args": ["--useOutClusterClient=false"]

operator/deployment/controller.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/equinor/radix-operator/pkg/apis/kube"
1111
"github.com/equinor/radix-operator/pkg/apis/metrics"
1212
v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1"
13+
"github.com/equinor/radix-operator/pkg/apis/utils/annotations"
1314
radixclient "github.com/equinor/radix-operator/pkg/client/clientset/versioned"
1415
informers "github.com/equinor/radix-operator/pkg/client/informers/externalversions"
1516
"github.com/rs/zerolog/log"
@@ -130,7 +131,8 @@ func NewController(ctx context.Context,
130131
if radixutils.ArrayEqualElements(newRr.Spec.AdGroups, oldRr.Spec.AdGroups) &&
131132
radixutils.ArrayEqualElements(newRr.Spec.AdUsers, oldRr.Spec.AdUsers) &&
132133
radixutils.ArrayEqualElements(newRr.Spec.ReaderAdGroups, oldRr.Spec.ReaderAdGroups) &&
133-
radixutils.ArrayEqualElements(newRr.Spec.ReaderAdUsers, oldRr.Spec.ReaderAdUsers) {
134+
radixutils.ArrayEqualElements(newRr.Spec.ReaderAdUsers, oldRr.Spec.ReaderAdUsers) &&
135+
oldRr.Annotations[annotations.PreviewOAuth2ProxyModeAnnotation] == newRr.Annotations[annotations.PreviewOAuth2ProxyModeAnnotation] {
134136
return
135137
}
136138

operator/deployment/controller_test.go

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import (
55
"testing"
66

77
"github.com/equinor/radix-operator/operator/common"
8+
"github.com/equinor/radix-operator/pkg/apis/kube"
89
radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1"
10+
"github.com/equinor/radix-operator/pkg/apis/utils/annotations"
911
"github.com/golang/mock/gomock"
1012
"github.com/stretchr/testify/suite"
1113
corev1 "k8s.io/api/core/v1"
@@ -21,7 +23,7 @@ func TestControllerSuite(t *testing.T) {
2123
}
2224

2325
func (s *controllerTestSuite) Test_Controller_Calls_Handler() {
24-
rdName, namespace := "any-rd", "any-ns"
26+
appName, rdName, namespace := "any-app", "any-rd", "any-ns"
2527

2628
sut := NewController(context.Background(), s.KubeClient, s.RadixClient, s.Handler, s.KubeInformerFactory, s.RadixInformerFactory)
2729
s.RadixInformerFactory.Start(s.Ctx.Done())
@@ -30,18 +32,22 @@ func (s *controllerTestSuite) Test_Controller_Calls_Handler() {
3032
err := sut.Run(s.Ctx, 5)
3133
s.Require().NoError(err)
3234
}()
35+
rr, err := s.RadixClient.RadixV1().RadixRegistrations().Create(context.Background(), &radixv1.RadixRegistration{
36+
ObjectMeta: metav1.ObjectMeta{Name: appName, Annotations: map[string]string{}}},
37+
metav1.CreateOptions{})
38+
s.Require().NoError(err)
3339

3440
// Create RD should sync
3541
rd := &radixv1.RadixDeployment{
36-
ObjectMeta: metav1.ObjectMeta{Name: rdName, Namespace: namespace},
42+
ObjectMeta: metav1.ObjectMeta{Name: rdName, Namespace: namespace, Labels: map[string]string{kube.RadixAppLabel: appName}},
3743
Spec: radixv1.RadixDeploymentSpec{
3844
Components: []radixv1.RadixDeployComponent{
3945
{Name: "any", PublicPort: "http"},
4046
},
4147
},
4248
}
4349
s.Handler.EXPECT().Sync(gomock.Any(), namespace, rdName).Times(1).DoAndReturn(s.SyncedChannelCallback())
44-
rd, err := s.RadixClient.RadixV1().RadixDeployments(rd.Namespace).Create(s.Ctx, rd, metav1.CreateOptions{})
50+
rd, err = s.RadixClient.RadixV1().RadixDeployments(rd.Namespace).Create(s.Ctx, rd, metav1.CreateOptions{})
4551
s.Require().NoError(err)
4652
s.WaitForSynced("Sync should be called")
4753

@@ -54,7 +60,7 @@ func (s *controllerTestSuite) Test_Controller_Calls_Handler() {
5460

5561
// Update RD labels should sync.
5662
s.Handler.EXPECT().Sync(gomock.Any(), namespace, rdName).Times(1).DoAndReturn(s.SyncedChannelCallback())
57-
rd.Labels = map[string]string{"key": "value"}
63+
rd.Labels["key"] = "val"
5864
rd, err = s.RadixClient.RadixV1().RadixDeployments(rd.ObjectMeta.Namespace).Update(s.Ctx, rd, metav1.UpdateOptions{})
5965
s.Require().NoError(err)
6066
s.WaitForSynced("Sync should be called")
@@ -107,4 +113,38 @@ func (s *controllerTestSuite) Test_Controller_Calls_Handler() {
107113
s.Require().NoError(err)
108114
s.WaitForSynced("Sync should be called")
109115

116+
// Sync should trigger when annotation radix.equinor.com/preview-oauth2-proxy-mode changes on RR
117+
s.Handler.EXPECT().Sync(gomock.Any(), namespace, rdName).Times(1).DoAndReturn(s.SyncedChannelCallback())
118+
rr.Annotations[annotations.PreviewOAuth2ProxyModeAnnotation] = "any"
119+
rr, err = s.RadixClient.RadixV1().RadixRegistrations().Update(context.Background(), rr, metav1.UpdateOptions{})
120+
s.Require().NoError(err)
121+
s.WaitForSynced("Sync should be called")
122+
123+
// Sync should trigger when AdGroups changes on RR
124+
s.Handler.EXPECT().Sync(gomock.Any(), namespace, rdName).Times(1).DoAndReturn(s.SyncedChannelCallback())
125+
rr.Spec.AdGroups = []string{"new-admin-group"}
126+
rr, err = s.RadixClient.RadixV1().RadixRegistrations().Update(context.Background(), rr, metav1.UpdateOptions{})
127+
s.Require().NoError(err)
128+
s.WaitForSynced("Sync should be called")
129+
130+
// Sync should trigger when AdUsers changes on RR
131+
s.Handler.EXPECT().Sync(gomock.Any(), namespace, rdName).Times(1).DoAndReturn(s.SyncedChannelCallback())
132+
rr.Spec.AdUsers = []string{"new-admin-user"}
133+
rr, err = s.RadixClient.RadixV1().RadixRegistrations().Update(context.Background(), rr, metav1.UpdateOptions{})
134+
s.Require().NoError(err)
135+
s.WaitForSynced("Sync should be called")
136+
137+
// Sync should trigger when ReaderAdGroups changes on RR
138+
s.Handler.EXPECT().Sync(gomock.Any(), namespace, rdName).Times(1).DoAndReturn(s.SyncedChannelCallback())
139+
rr.Spec.ReaderAdGroups = []string{"new-reader-group"}
140+
rr, err = s.RadixClient.RadixV1().RadixRegistrations().Update(context.Background(), rr, metav1.UpdateOptions{})
141+
s.Require().NoError(err)
142+
s.WaitForSynced("Sync should be called")
143+
144+
// Sync should trigger when ReaderAdUsers changes on RR
145+
s.Handler.EXPECT().Sync(gomock.Any(), namespace, rdName).Times(1).DoAndReturn(s.SyncedChannelCallback())
146+
rr.Spec.ReaderAdUsers = []string{"new-reader-user"}
147+
_, err = s.RadixClient.RadixV1().RadixRegistrations().Update(context.Background(), rr, metav1.UpdateOptions{})
148+
s.Require().NoError(err)
149+
s.WaitForSynced("Sync should be called")
110150
}

operator/deployment/handler.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,13 +135,12 @@ func (t *handler) Sync(ctx context.Context, namespace, name string) error {
135135
return err
136136
}
137137

138-
ingressAnnotations := ingress.GetAnnotationProvider(t.ingressConfiguration, rd.Namespace, t.oauth2DefaultConfig)
139-
140138
auxResourceManagers := []deployment.AuxiliaryResourceManager{
141-
deployment.NewOAuthProxyResourceManager(rd, radixRegistration, t.kubeutil, t.oauth2DefaultConfig, ingress.GetAuxOAuthProxyAnnotationProviders(), t.oauth2ProxyDockerImage, t.config.ContainerRegistryConfig.ExternalRegistryAuthSecret),
139+
deployment.NewOAuthProxyResourceManager(rd, radixRegistration, t.kubeutil, t.oauth2DefaultConfig, ingress.GetOAuthAnnotationProviders(), ingress.GetOAuthProxyModeAnnotationProviders(t.ingressConfiguration, rd.Namespace), t.oauth2ProxyDockerImage, t.config.ContainerRegistryConfig.ExternalRegistryAuthSecret),
142140
deployment.NewOAuthRedisResourceManager(rd, radixRegistration, t.kubeutil, t.oauth2RedisDockerImage, t.config.ContainerRegistryConfig.ExternalRegistryAuthSecret),
143141
}
144142

143+
ingressAnnotations := ingress.GetComponentAnnotationProvider(t.ingressConfiguration, rd.Namespace, t.oauth2DefaultConfig)
145144
syncRD := rd.DeepCopy()
146145
deployment := t.deploymentSyncerFactory.CreateDeploymentSyncer(t.kubeclient, t.kubeutil, t.radixclient, t.prometheusperatorclient, t.certClient, radixRegistration, syncRD, ingressAnnotations, auxResourceManagers, t.config)
147146
err = deployment.OnSync(ctx)

operator/deployment/handler_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,13 +160,13 @@ func (s *handlerSuite) Test_Sync() {
160160
ingress.NewForceSslRedirectAnnotationProvider(),
161161
ingress.NewIngressConfigurationAnnotationProvider(ingressConfig),
162162
ingress.NewClientCertificateAnnotationProvider(activeRd.Namespace),
163-
ingress.NewOAuth2AnnotationProvider(oauthConfig),
163+
ingress.NewOAuth2AnnotationProvider(oauthConfig, activeRd.Namespace),
164164
ingress.NewIngressPublicAllowListAnnotationProvider(),
165165
ingress.NewIngressPublicConfigAnnotationProvider(),
166166
ingress.NewRedirectErrorPageAnnotationProvider(),
167167
}
168168
expectedAuxResources := []deployment.AuxiliaryResourceManager{
169-
deployment.NewOAuthProxyResourceManager(activeRd, rr, s.kubeUtil, oauthConfig, ingress.GetAuxOAuthProxyAnnotationProviders(), oauthProxyImage, s.config.ContainerRegistryConfig.ExternalRegistryAuthSecret),
169+
deployment.NewOAuthProxyResourceManager(activeRd, rr, s.kubeUtil, oauthConfig, ingress.GetOAuthAnnotationProviders(), ingress.GetOAuthProxyModeAnnotationProviders(ingressConfig, activeRd.Namespace), oauthProxyImage, s.config.ContainerRegistryConfig.ExternalRegistryAuthSecret),
170170
deployment.NewOAuthRedisResourceManager(activeRd, rr, s.kubeUtil, oauthRedisImage, s.config.ContainerRegistryConfig.ExternalRegistryAuthSecret),
171171
}
172172
factory.

operator/dnsalias/controller.go

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import (
44
"context"
55
"reflect"
66

7-
radixutils "github.com/equinor/radix-common/utils"
87
"github.com/equinor/radix-operator/operator/common"
98
"github.com/equinor/radix-operator/pkg/apis/metrics"
109
radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1"
10+
"github.com/equinor/radix-operator/pkg/apis/utils/annotations"
1111
radixlabels "github.com/equinor/radix-operator/pkg/apis/utils/labels"
1212
radixclient "github.com/equinor/radix-operator/pkg/client/clientset/versioned"
1313
informers "github.com/equinor/radix-operator/pkg/client/informers/externalversions"
@@ -50,24 +50,21 @@ func NewController(ctx context.Context, kubeClient kubernetes.Interface,
5050
addEventHandlersForRadixDNSAliases(radixDNSAliasInformer, controller, &logger)
5151
addEventHandlersForRadixDeployments(radixInformerFactory, controller, radixClient, &logger)
5252
addEventHandlersForIngresses(ctx, kubeInformerFactory, controller, &logger)
53-
addEventHandlersForRadixRegistrations(radixInformerFactory, controller, radixClient, &logger)
53+
addEventHandlersForRadixRegistrations(ctx, radixInformerFactory, controller, radixClient, &logger)
5454
return controller
5555
}
5656

57-
func addEventHandlersForRadixRegistrations(radixInformerFactory informers.SharedInformerFactory, controller *common.Controller, radixClient radixclient.Interface, logger *zerolog.Logger) {
57+
func addEventHandlersForRadixRegistrations(ctx context.Context, radixInformerFactory informers.SharedInformerFactory, controller *common.Controller, radixClient radixclient.Interface, logger *zerolog.Logger) {
5858
radixRegistrationInformer := radixInformerFactory.Radix().V1().RadixRegistrations()
5959
if _, err := radixRegistrationInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
6060
UpdateFunc: func(oldObj, newObj interface{}) {
6161
oldRR := oldObj.(*radixv1.RadixRegistration)
6262
newRR := newObj.(*radixv1.RadixRegistration)
63-
if oldRR.GetResourceVersion() == newRR.GetResourceVersion() &&
64-
radixutils.ArrayEqualElements(oldRR.Spec.AdGroups, newRR.Spec.AdGroups) &&
65-
radixutils.ArrayEqualElements(oldRR.Spec.AdUsers, newRR.Spec.AdUsers) &&
66-
radixutils.ArrayEqualElements(oldRR.Spec.ReaderAdGroups, newRR.Spec.ReaderAdGroups) &&
67-
radixutils.ArrayEqualElements(oldRR.Spec.ReaderAdUsers, newRR.Spec.ReaderAdUsers) {
63+
64+
if oldRR.Annotations[annotations.PreviewOAuth2ProxyModeAnnotation] == newRR.Annotations[annotations.PreviewOAuth2ProxyModeAnnotation] {
6865
return // updating RadixRegistration has the same resource version. Do nothing.
6966
}
70-
enqueueRadixDNSAliasesForAppName(controller, radixClient, newRR.GetName(), logger)
67+
enqueueRadixDNSAliasesForAppName(ctx, controller, radixClient, newRR.GetName(), logger)
7168
},
7269
}); err != nil {
7370
panic(err)
@@ -175,23 +172,21 @@ func enqueueRadixDNSAliasesForRadixDeployment(controller *common.Controller, rad
175172
return
176173
}
177174
for _, radixDNSAlias := range radixDNSAliases {
178-
radixDNSAlias := radixDNSAlias
179175
logger.Debug().Msgf("re-sync RadixDNSAlias %s", radixDNSAlias.GetName())
180176
if err := controller.Enqueue(&radixDNSAlias); err != nil {
181177
logger.Error().Err(err).Msgf("failed to enqueue RadixDNSAlias %s", radixDNSAlias.GetName())
182178
}
183179
}
184180
}
185181

186-
func enqueueRadixDNSAliasesForAppName(controller *common.Controller, radixClient radixclient.Interface, appName string, logger *zerolog.Logger) {
182+
func enqueueRadixDNSAliasesForAppName(ctx context.Context, controller *common.Controller, radixClient radixclient.Interface, appName string, logger *zerolog.Logger) {
187183
logger.Debug().Msgf("Added or updated an RadixRegistration %s. Enqueue relevant RadixDNSAliases", appName)
188-
radixDNSAliases, err := getRadixDNSAliasForApp(radixClient, appName)
184+
radixDNSAliases, err := getRadixDNSAliasForApp(ctx, radixClient, appName)
189185
if err != nil {
190186
logger.Error().Err(err).Msgf("failed to get list of RadixDNSAliases for the application %s", appName)
191187
return
192188
}
193189
for _, radixDNSAlias := range radixDNSAliases {
194-
radixDNSAlias := radixDNSAlias
195190
logger.Debug().Msgf("Enqueue RadixDNSAlias %s", radixDNSAlias.GetName())
196191
if err := controller.Enqueue(&radixDNSAlias); err != nil {
197192
logger.Error().Err(err).Msgf("failed to enqueue RadixDNSAlias %s", radixDNSAlias.GetName())
@@ -210,8 +205,8 @@ func getRadixDNSAliasForAppAndEnvironment(radixClient radixclient.Interface, app
210205
return radixDNSAliasList.Items, err
211206
}
212207

213-
func getRadixDNSAliasForApp(radixClient radixclient.Interface, appName string) ([]radixv1.RadixDNSAlias, error) {
214-
radixDNSAliasList, err := radixClient.RadixV1().RadixDNSAliases().List(context.Background(), metav1.ListOptions{
208+
func getRadixDNSAliasForApp(ctx context.Context, radixClient radixclient.Interface, appName string) ([]radixv1.RadixDNSAlias, error) {
209+
radixDNSAliasList, err := radixClient.RadixV1().RadixDNSAliases().List(ctx, metav1.ListOptions{
215210
LabelSelector: radixlabels.ForApplicationName(appName).String(),
216211
})
217212
if err != nil {
@@ -222,10 +217,7 @@ func getRadixDNSAliasForApp(radixClient radixclient.Interface, appName string) (
222217

223218
func deepEqual(old, new *radixv1.RadixDNSAlias) bool {
224219
return reflect.DeepEqual(new.Spec, old.Spec) &&
225-
reflect.DeepEqual(new.ObjectMeta.Labels, old.ObjectMeta.Labels) &&
226-
reflect.DeepEqual(new.ObjectMeta.Annotations, old.ObjectMeta.Annotations) &&
227-
reflect.DeepEqual(new.ObjectMeta.Finalizers, old.ObjectMeta.Finalizers) &&
228-
reflect.DeepEqual(new.ObjectMeta.DeletionTimestamp, old.ObjectMeta.DeletionTimestamp)
220+
reflect.DeepEqual(new.ObjectMeta.Labels, old.ObjectMeta.Labels)
229221
}
230222

231223
func getOwner(ctx context.Context, radixClient radixclient.Interface, _, name string) (interface{}, error) {

0 commit comments

Comments
 (0)