Skip to content

Commit

Permalink
observe router secrets for servingInfo - named certificates
Browse files Browse the repository at this point in the history
  • Loading branch information
stlaz committed Jan 14, 2020
1 parent 37cc2e0 commit f5778ac
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import (

"github.com/openshift/cluster-authentication-operator/pkg/operator2/configobservation"
"github.com/openshift/cluster-authentication-operator/pkg/operator2/configobservation/apiserver"
consoleObserver "github.com/openshift/cluster-authentication-operator/pkg/operator2/configobservation/console"
"github.com/openshift/cluster-authentication-operator/pkg/operator2/configobservation/infrastructure"
"github.com/openshift/cluster-authentication-operator/pkg/operator2/configobservation/oauth"
"github.com/openshift/cluster-authentication-operator/pkg/operator2/configobservation/routersecret"
)

type ConfigObserver struct {
Expand All @@ -38,6 +40,7 @@ func NewConfigObserver(
for _, ns := range interestingNamespaces {
preRunCacheSynced = append(preRunCacheSynced,
kubeInformersForNamespaces.InformersFor(ns).Core().V1().ConfigMaps().Informer().HasSynced,
kubeInformersForNamespaces.InformersFor(ns).Core().V1().Secrets().Informer().HasSynced,
)
}

Expand All @@ -46,42 +49,46 @@ func NewConfigObserver(
operatorClient,
eventRecorder,
configobservation.Listers{
ConfigMapLister: kubeInformersForNamespaces.ConfigMapLister(),
SecretsLister: kubeInformersForNamespaces.SecretLister(),

APIServerLister_: configInformer.Config().V1().APIServers().Lister(),
ConsoleLister: configInformer.Config().V1().Consoles().Lister(),
ConfigMapLister: kubeInformersForNamespaces.ConfigMapLister(),
InfrastructureLister: configInformer.Config().V1().Infrastructures().Lister(),
OAuthLister: configInformer.Config().V1().OAuths().Lister(),
ResourceSync: resourceSyncer,
PreRunCachesSynced: append(preRunCacheSynced,
operatorClient.Informer().HasSynced,

kubeInformersForNamespaces.InformersFor("openshift-authentication").Core().V1().Secrets().Informer().HasSynced,

configInformer.Config().V1().APIServers().Informer().HasSynced,
configInformer.Config().V1().Consoles().Informer().HasSynced,
configInformer.Config().V1().Infrastructures().Informer().HasSynced,
configInformer.Config().V1().OAuths().Informer().HasSynced,
),
},
apiserver.ObserveAdditionalCORSAllowedOrigins,
consoleObserver.ObserveConsoleURL,
infrastructure.ObserveAPIServerURL,
libgoapiserver.ObserveTLSSecurityProfile,
oauth.ObserveIdentityProviders,
oauth.ObserveTemplates,
oauth.ObserveTokenConfig,
routersecret.ObserveRouterSecret,
),
}

operatorClient.Informer().AddEventHandler(c.EventHandler())

for _, ns := range interestingNamespaces {
kubeInformersForNamespaces.InformersFor(ns).Core().V1().ConfigMaps().Informer().AddEventHandler(c.EventHandler())
kubeInformersForNamespaces.InformersFor(ns).Core().V1().Secrets().Informer().AddEventHandler(c.EventHandler())
}

configInformer.Config().V1().APIServers().Informer().AddEventHandler(c.EventHandler())
configInformer.Config().V1().Consoles().Informer().AddEventHandler(c.EventHandler())
configInformer.Config().V1().Infrastructures().Informer().AddEventHandler(c.EventHandler())
configInformer.Config().V1().OAuths().Informer().AddEventHandler(c.EventHandler())
configInformer.Config().V1().Proxies().Informer().AddEventHandler(c.EventHandler())

return c
}
1 change: 1 addition & 0 deletions pkg/operator2/configobservation/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ var _ configobserver.Listers = Listers{}

type Listers struct {
ConfigMapLister corelistersv1.ConfigMapLister
SecretsLister corelistersv1.SecretLister

APIServerLister_ configlistersv1.APIServerLister
ConsoleLister configlistersv1.ConsoleLister
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package routersecret

import (
"bytes"
"encoding/json"
"fmt"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/sets"

configv1 "github.com/openshift/api/config/v1"
"github.com/openshift/library-go/pkg/operator/configobserver"
"github.com/openshift/library-go/pkg/operator/events"

"github.com/openshift/cluster-authentication-operator/pkg/operator2/configobservation"
)

func ObserveRouterSecret(genericlisters configobserver.Listers, recorder events.Recorder, previouslyObservedConfig map[string]interface{}) (map[string]interface{}, []error) {
namedCertificatesPath := []string{"servingInfo", "namedCertificates"}
listers := genericlisters.(configobservation.Listers)
errs := []error{}

currentNamedCertificates, _, err := unstructured.NestedFieldCopy(previouslyObservedConfig, namedCertificatesPath...)
if err != nil {
return previouslyObservedConfig, append(errs, err)
}

currentNamedCertificatesSlice := []interface{}{}
if currentNamedCertificates != nil {
currentNamedCertificatesSlice = currentNamedCertificates.([]interface{})
}

// TODO: this was previously causing "FailedRouterSecret" degraded condition
routerSecret, err := listers.SecretsLister.Secrets("openshift-authentication").Get("v4-0-config-system-router-certs")
if err != nil {
return previouslyObservedConfig, append(errs, err)
}

// FIXME: treat the error
observedNamedCertificates, err := routerSecretToSNI(routerSecret)

observedConfig := map[string]interface{}{}
if err := unstructured.SetNestedField(
observedConfig,
observedNamedCertificates,
namedCertificatesPath...,
); err != nil {
return previouslyObservedConfig, append(errs, err)
}

if !equality.Semantic.DeepEqual(currentNamedCertificatesSlice, observedNamedCertificates) {
recorder.Eventf("ObserveRouterSecret", "namedCertificates changed to %#v", observedNamedCertificates)
}

return observedConfig, errs
}

func routerSecretToSNI(routerSecret *corev1.Secret) ([]interface{}, error) {
var certs []configv1.NamedCertificate
// make sure the output slice of named certs is sorted by domain so that the generated config is deterministic
for _, domain := range sets.StringKeySet(routerSecret.Data).List() {
certs = append(certs, configv1.NamedCertificate{
Names: []string{"*." + domain}, // ingress domain is always a wildcard
CertInfo: configv1.CertInfo{ // the cert and key are appended together
CertFile: "/var/config/system/secrets/v4-0-config-system-router-certs/" + domain,
KeyFile: "/var/config/system/secrets/v4-0-config-system-router-certs/" + domain,
},
})
}

// TODO: the following is a bit perverted, I wonder if it could be done differently
configBytes, err := json.Marshal(certs)
if err != nil {
return nil, err
}

// TODO: we may want to actually round-trip this to remove the fields that can be omitted
unstructuredCertConfig := []interface{}{}
if err := json.NewDecoder(bytes.NewBuffer(configBytes)).Decode(&unstructuredCertConfig); err != nil {
return nil, fmt.Errorf("decode of observed config failed with error: %v", err)
}

return unstructuredCertConfig, nil
}
4 changes: 1 addition & 3 deletions pkg/operator2/oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ func init() {
func (c *authOperator) handleOAuthConfig(
operatorConfig *operatorv1.Authentication,
route *routev1.Route,
routerSecret *corev1.Secret,
service *corev1.Service,
) (
*corev1.ConfigMap,
Expand All @@ -49,8 +48,7 @@ func (c *authOperator) handleOAuthConfig(
CertFile: "/var/config/system/secrets/v4-0-config-system-serving-cert/tls.crt",
KeyFile: "/var/config/system/secrets/v4-0-config-system-serving-cert/tls.key",
},
ClientCA: "", // I think this can be left unset
NamedCertificates: routerSecretToSNI(routerSecret),
ClientCA: "", // I think this can be left unset
},
MaxRequestsInFlight: 1000, // TODO this is a made up number
RequestTimeoutSeconds: 5 * 60, // 5 minutes
Expand Down
2 changes: 1 addition & 1 deletion pkg/operator2/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ func (c *authOperator) handleSync(operatorConfig *operatorv1.Authentication) err
return fmt.Errorf("failed applying session secret: %v", err)
}

expectedCLIconfig, err := c.handleOAuthConfig(operatorConfig, route, routerSecret, service)
expectedCLIconfig, err := c.handleOAuthConfig(operatorConfig, route, service)
if err != nil {
return fmt.Errorf("failed handling OAuth configuration: %v", err)
}
Expand Down
16 changes: 0 additions & 16 deletions pkg/operator2/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/klog"

configv1 "github.com/openshift/api/config/v1"
Expand Down Expand Up @@ -84,21 +83,6 @@ func defaultRoute(ingress *configv1.Ingress) *routev1.Route {
}
}

func routerSecretToSNI(routerSecret *corev1.Secret) []configv1.NamedCertificate {
var out []configv1.NamedCertificate
// make sure the output slice of named certs is sorted by domain so that the generated config is deterministic
for _, domain := range sets.StringKeySet(routerSecret.Data).List() {
out = append(out, configv1.NamedCertificate{
Names: []string{"*." + domain}, // ingress domain is always a wildcard
CertInfo: configv1.CertInfo{ // the cert and key are appended together
CertFile: "/var/config/system/secrets/v4-0-config-system-router-certs/" + domain,
KeyFile: "/var/config/system/secrets/v4-0-config-system-router-certs/" + domain,
},
})
}
return out
}

func routerSecretToCA(route *routev1.Route, routerSecret *corev1.Secret, ingress *configv1.Ingress) []byte {
var caData []byte

Expand Down

0 comments on commit f5778ac

Please sign in to comment.