Skip to content

Commit

Permalink
Merge pull request #430 from awgreene/custom-routes
Browse files Browse the repository at this point in the history
Custom Certs for OAuth Route
  • Loading branch information
openshift-merge-robot committed Jul 12, 2021
2 parents 4eda0f5 + 7c29d66 commit 65cd3f0
Show file tree
Hide file tree
Showing 19 changed files with 1,425 additions and 194 deletions.
21 changes: 21 additions & 0 deletions bindata/oauth-openshift/route.yaml
@@ -0,0 +1,21 @@
# emulates server-side defaulting as in https://github.com/openshift/openshift-apiserver/blob/master/pkg/route/apis/route/configv1listers/defaults.go
# TODO: replace with server-side apply
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: oauth-openshift
namespace: openshift-authentication
labels:
app: oauth-openshift
spec:
host: ""
port:
targetPort: 6443
tls:
insecureEdgeTerminationPolicy: Redirect
termination: passthrough
to:
kind: Service
name: oauth-openshift
weight: 100
wildcardPolicy: None
82 changes: 82 additions & 0 deletions pkg/controllers/common/ingress_config.go
Expand Up @@ -3,6 +3,10 @@ package common
import (
"fmt"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
corev1listers "k8s.io/client-go/listers/core/v1"

configv1 "github.com/openshift/api/config/v1"
operatorv1 "github.com/openshift/api/operator/v1"
configv1lister "github.com/openshift/client-go/config/listers/config/v1"
Expand All @@ -28,3 +32,81 @@ func GetIngressConfig(ingressLister configv1lister.IngressLister, conditionPrefi
}
return ingress, nil
}

// GetComponentRouteSpec searches the entries of the ingress.spec.componentRoutes array for a componentRoute with a matching namespace and name.
// If a matching componentRoute is found a pointer to it is returned, otherwise nil is returned.
func GetComponentRouteSpec(ingress *configv1.Ingress, namespace string, name string) *configv1.ComponentRouteSpec {
componentRoutes := ingress.Spec.ComponentRoutes
for i := range componentRoutes {
if componentRoutes[i].Namespace == namespace &&
componentRoutes[i].Name == name {
return &componentRoutes[i]
}
}
return nil
}

// GetComponentRouteStatus searches the entries of the ingress.status.componentRoutes array for a componentRoute with a matching namespace and name.
// If a matching componentRoute is found a pointer to it is returned, otherwise nil is returned.
func GetComponentRouteStatus(ingress *configv1.Ingress, namespace string, name string) *configv1.ComponentRouteStatus {
componentRoutes := ingress.Status.ComponentRoutes
for i := range componentRoutes {
if componentRoutes[i].Namespace == namespace &&
componentRoutes[i].Name == name {
return &componentRoutes[i]
}
}
return nil
}

// GetCustomRouteHostname searches the entries of the ingress.spec.componentRoutes array for a componentRoute with a matching namespace and name.
// If a matching componentRoute is found, the hostname defined in the entry if found, otherwise an empty string is returned.
func GetCustomRouteHostname(ingress *configv1.Ingress, namespace string, name string) string {
if componentRoute := GetComponentRouteSpec(ingress, namespace, name); componentRoute != nil {
return string(componentRoute.Hostname)
}
return ""
}

// GetActiveRouterCertKeyBytes returns a byte array containing the server certificates, a byte array containing the private key,
// a boolean representing if the default openshift-authentication/v4-0-config-system-router-certs secret is being used, and
// any errors retrieving the active router secret.
func GetActiveRouterCertKeyBytes(secretLister corev1listers.SecretLister, ingressConfig *configv1.Ingress, namespace string, defaultSecretName string, customSecretName string) ([]byte, []byte, bool, error) {
secret, err := GetActiveRouterSecret(secretLister, namespace, defaultSecretName, customSecretName)
if err != nil {
return nil, nil, false, err
}

tlsCertKey := corev1.TLSCertKey
tlsPrivateKeyKey := corev1.TLSPrivateKeyKey
isDefault := secret.GetName() == defaultSecretName
if isDefault {
tlsCertKey = ingressConfig.Spec.Domain
tlsPrivateKeyKey = ingressConfig.Spec.Domain
}

cert := secret.Data[tlsCertKey]
privateKey := secret.Data[tlsPrivateKeyKey]

return cert, privateKey, isDefault, nil
}

// GetActiveRouterSecret returns the secret that contains the serving certificates for the openshift-authentication/oauth-openshift
// route, a boolean representing if the default openshift-authentication/v4-0-config-system-router-certs secret is being used, and
// any errors in retrieving the active secret.
func GetActiveRouterSecret(secretLister corev1listers.SecretLister, namespace string, defaultSecretName string, customSecretName string) (*corev1.Secret, error) {
secret, err := secretLister.Secrets(namespace).Get(customSecretName)
if err != nil {
if !errors.IsNotFound(err) {
return nil, err
}

// Custom serving certificate secret does not exist, use default secret instead
secret, err = secretLister.Secrets(namespace).Get(defaultSecretName)
if err != nil {
return nil, err
}
}

return secret, nil
}
209 changes: 209 additions & 0 deletions pkg/controllers/common/ingress_config_test.go
@@ -0,0 +1,209 @@
package common

import (
"reflect"
"testing"

configv1 "github.com/openshift/api/config/v1"
)

func TestGetCustomRouteHostname(t *testing.T) {
tests := []struct {
name string
componentRouteNamespace string
componentRouteName string
ingress *configv1.Ingress
want string
}{
{
name: "Return an empty string if componentRoute list is empty",
componentRouteNamespace: "foo",
componentRouteName: "bar",
ingress: &configv1.Ingress{},
want: "",
},
{
name: "Return an empty string if componentRoute is not present",
componentRouteNamespace: "foo",
componentRouteName: "bar",
ingress: &configv1.Ingress{
Spec: configv1.IngressSpec{
ComponentRoutes: []configv1.ComponentRouteSpec{
{
Namespace: "notFoo",
Name: "notBar",
Hostname: "shouldNotBeUsed",
},
},
},
},
want: "",
}, {
name: "Use provided hostname if componentRoute is present",
componentRouteNamespace: "foo",
componentRouteName: "bar",
ingress: &configv1.Ingress{
Spec: configv1.IngressSpec{
ComponentRoutes: []configv1.ComponentRouteSpec{
{
Namespace: "notFoo",
Name: "notBar",
Hostname: "shouldNotBeUsed",
},
{
Namespace: "foo",
Name: "bar",
Hostname: "expected.com",
},
},
},
},
want: "expected.com",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetCustomRouteHostname(tt.ingress, tt.componentRouteNamespace, tt.componentRouteName); !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetCustomRouteHostname() = %v, want %v", got, tt.want)
}
})
}
}

func TestGetComponentRouteSpec(t *testing.T) {
tests := []struct {
name string
componentRouteNamespace string
componentRouteName string
ingress *configv1.Ingress
want *configv1.ComponentRouteSpec
}{
{
name: "Return nil if ingress.Spec.ComponentRoutes list is empty",
componentRouteNamespace: "foo",
componentRouteName: "bar",
ingress: &configv1.Ingress{},
want: nil,
},
{
name: "Return nil if the componentRoute is not in the ingress.Spec.ComponentRoutes list",
componentRouteNamespace: "foo",
componentRouteName: "bar",
ingress: &configv1.Ingress{
Spec: configv1.IngressSpec{
ComponentRoutes: []configv1.ComponentRouteSpec{
{
Namespace: "notFoo",
Name: "notBar",
},
},
},
},
want: nil,
},
{
name: "If the componentRoute is found its pointer is returned",
componentRouteNamespace: "foo",
componentRouteName: "bar",
ingress: &configv1.Ingress{
Spec: configv1.IngressSpec{
ComponentRoutes: []configv1.ComponentRouteSpec{
{
Namespace: "notFoo",
Name: "notBar",
},
{
Namespace: "foo",
Name: "bar",
Hostname: "hostname",
ServingCertKeyPairSecret: configv1.SecretNameReference{
Name: "secretName",
},
},
},
},
},
want: &configv1.ComponentRouteSpec{
Namespace: "foo",
Name: "bar",
Hostname: "hostname",
ServingCertKeyPairSecret: configv1.SecretNameReference{
Name: "secretName",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetComponentRouteSpec(tt.ingress, tt.componentRouteNamespace, tt.componentRouteName); !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetComponentRouteSpec() = %v, want %v", got, tt.want)
}
})
}
}

func TestGetComponentRouteStatus(t *testing.T) {
tests := []struct {
name string
componentRouteNamespace string
componentRouteName string
ingress *configv1.Ingress
want *configv1.ComponentRouteStatus
}{
{
name: "Return nil if ingress.Status.ComponentRoutes list is empty",
componentRouteNamespace: "foo",
componentRouteName: "bar",
ingress: &configv1.Ingress{},
want: nil,
},
{
name: "Return nil if the componentRoute is not in the ingress.Status.ComponentRoutes list",
componentRouteNamespace: "foo",
componentRouteName: "bar",
ingress: &configv1.Ingress{
Status: configv1.IngressStatus{
ComponentRoutes: []configv1.ComponentRouteStatus{
{
Namespace: "notFoo",
Name: "notBar",
},
},
},
},
want: nil,
},
{
name: "If the componentRoute is found its pointer is returned",
componentRouteNamespace: "foo",
componentRouteName: "bar",
ingress: &configv1.Ingress{
Status: configv1.IngressStatus{
ComponentRoutes: []configv1.ComponentRouteStatus{
{
Namespace: "notFoo",
Name: "notBar",
},
{
Namespace: "foo",
Name: "bar",
DefaultHostname: "expected",
},
},
},
},
want: &configv1.ComponentRouteStatus{
Namespace: "foo",
Name: "bar",
DefaultHostname: "expected",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetComponentRouteStatus(tt.ingress, tt.componentRouteNamespace, tt.componentRouteName); !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetComponentRouteStatus() = %v, want %v", got, tt.want)
}
})
}
}
Expand Up @@ -38,6 +38,7 @@ func NewConfigObserver(
configInformer.Config().V1().Consoles().Informer().HasSynced,
configInformer.Config().V1().Infrastructures().Informer().HasSynced,
configInformer.Config().V1().OAuths().Informer().HasSynced,
configInformer.Config().V1().Ingresses().Informer().HasSynced,
}

informers := []factory.Informer{
Expand All @@ -46,6 +47,7 @@ func NewConfigObserver(
configInformer.Config().V1().Consoles().Informer(),
configInformer.Config().V1().Infrastructures().Informer(),
configInformer.Config().V1().OAuths().Informer(),
configInformer.Config().V1().Ingresses().Informer(),
}

for _, ns := range interestingNamespaces {
Expand Down Expand Up @@ -82,6 +84,7 @@ func NewConfigObserver(
configobservation.Listers{
ConfigMapLister: kubeInformersForNamespaces.ConfigMapLister(),
SecretsLister: kubeInformersForNamespaces.SecretLister(),
IngressLister: configInformer.Config().V1().Ingresses().Lister(),

APIServerLister_: configInformer.Config().V1().APIServers().Lister(),
ConsoleLister: configInformer.Config().V1().Consoles().Lister(),
Expand Down
1 change: 1 addition & 0 deletions pkg/controllers/configobservation/interfaces.go
Expand Up @@ -23,6 +23,7 @@ type Listers struct {
ConsoleLister configlistersv1.ConsoleLister
InfrastructureLister configlistersv1.InfrastructureLister
OAuthLister_ configlistersv1.OAuthLister
IngressLister configlistersv1.IngressLister

ResourceSync resourcesynccontroller.ResourceSyncer
PreRunCachesSynced []cache.InformerSynced
Expand Down

0 comments on commit 65cd3f0

Please sign in to comment.