Skip to content

Commit

Permalink
feat: Add support for Global External Authorization
Browse files Browse the repository at this point in the history
Closes #4954.

Signed-off-by: claytonig <claytonivorgonsalves@gmail.com>
  • Loading branch information
claytonig committed Feb 14, 2023
1 parent d044dbd commit 8b98559
Show file tree
Hide file tree
Showing 21 changed files with 2,364 additions and 105 deletions.
8 changes: 8 additions & 0 deletions apis/projectcontour/v1/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ func (v *VirtualHost) AuthorizationContext() map[string]string {
return nil
}

// DisableGlobalAuthorization returns true if this virtual host disables
// global authorization. If a global authorization config present, the default
// policy is to not disable.
func (v *VirtualHost) DisableGlobalAuthorization() bool {
return v.Authorization != nil && v.Authorization.GlobalExternalAuthorizationDisabled

}

// GetPrefixReplacements returns replacement prefixes from the path
// rewrite policy (if any).
func (r *Route) GetPrefixReplacements() []ReplacePrefix {
Expand Down
5 changes: 4 additions & 1 deletion apis/projectcontour/v1/httpproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ type AuthorizationServer struct {
// ExtensionServiceRef specifies the extension resource that will authorize client requests.
//
// +required
ExtensionServiceRef ExtensionServiceReference `json:"extensionRef"`
ExtensionServiceRef ExtensionServiceReference `json:"extensionRef,,omitempty"`

// AuthPolicy sets a default authorization policy for client requests.
// This policy will be used unless overridden by individual routes.
Expand Down Expand Up @@ -223,6 +223,9 @@ type AuthorizationServer struct {
// WithRequestBody specifies configuration for sending the client request's body to authorization server.
// +optional
WithRequestBody *AuthorizationServerBufferSettings `json:"withRequestBody,omitempty"`

// GlobalExternalAuthorizationDisabled optionally disables the global external authorization on the virtual host.
GlobalExternalAuthorizationDisabled bool `json:"globalExtAuthDisabled,omitempty"`
}

// AuthorizationServerBufferSettings enables ExtAuthz filter to buffer client request data and send it as part of authorization request
Expand Down
66 changes: 66 additions & 0 deletions apis/projectcontour/v1alpha1/contourconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ type ContourConfigurationSpec struct {
// +optional
EnableExternalNameService *bool `json:"enableExternalNameService,omitempty"`

// GlobalExternalAuthorization allows envoys external authorization filter
// to be enabled for all HTTP requests.
// +optional
GlobalExternalAuthorization *GlobalExternalAuthorizationConfig `json:"globalExtAuth,omitempty"`

// RateLimitService optionally holds properties of the Rate Limit Service
// to be used for global rate limiting.
// +optional
Expand Down Expand Up @@ -623,6 +628,67 @@ type NetworkParameters struct {
EnvoyAdminPort *int `json:"adminPort,omitempty"`
}

// GlobalExternalAuthorizationConfig defines properties of global HTTP external authorization.
type GlobalExternalAuthorizationConfig struct {
// ExtensionService identifies the extension service responsible for the authorization.
// formatted as <namespace>/<name>.
ExtensionService string `json:"extensionService,omitempty"`
// AuthPolicy sets a default authorization policy for client requests.
// This policy will be used unless overridden by individual routes.
//
// +optional
AuthPolicy *GlobalAuthorizationPolicy `json:"globalAuthPolicy,omitempty"`
// ResponseTimeout configures maximum time to wait for a check response from the authorization server.
// Timeout durations are expressed in the Go [Duration format](https://godoc.org/time#ParseDuration).
// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
// The string "infinity" is also a valid input and specifies no timeout.
//
// +optional
ResponseTimeout string `json:"responseTimeout,omitempty"`
// If FailOpen is true, the client request is forwarded to the upstream service
// even if the authorization server fails to respond. This field should not be
// set in most cases. It is intended for use only while migrating applications
// from internal authorization to Contour external authorization.
//
// +optional
FailOpen *bool `json:"failOpen,omitempty"`
// WithRequestBody specifies configuration for sending the client request's body to authorization server.
// +optional
WithRequestBody *GlobalAuthorizationServerBufferSettings `json:"withRequestBody,omitempty"`
}

// GlobalAuthorizationServerBufferSettings enables ExtAuthz filter to buffer client request data and send it as part of authorization request
type GlobalAuthorizationServerBufferSettings struct {
// MaxRequestBytes sets the maximum size of message body ExtAuthz filter will hold in-memory.
// +optional
// +kubebuilder:validation:Minimum=1
// +kubebuilder:default=1024
MaxRequestBytes uint32 `json:"maxRequestBytes,omitempty"`
// If AllowPartialMessage is true, then Envoy will buffer the body until MaxRequestBytes are reached.
// +optional
AllowPartialMessage *bool `json:"allowPartialMessage,omitempty"`
// If PackAsBytes is true, the body sent to Authorization Server is in raw bytes.
// +optional
PackAsBytes *bool `json:"packAsBytes,omitempty"`
}

// GlobalAuthorizationPolicy modifies how client requests are authenticated.
type GlobalAuthorizationPolicy struct {
// When true, this field disables client request authentication
// for the scope of the policy.
//
// +optional
Disabled *bool `json:"disabled,omitempty"`
// Context is a set of key/value pairs that are sent to the
// authentication server in the check request. If a context
// is provided at an enclosing scope, the entries are merged
// such that the inner scope overrides matching keys from the
// outer scope.
//
// +optional
Context map[string]string `json:"context,omitempty"`
}

// RateLimitServiceConfig defines properties of a global Rate Limit Service.
type RateLimitServiceConfig struct {
// ExtensionService identifies the extension service defining the RLS.
Expand Down
87 changes: 87 additions & 0 deletions apis/projectcontour/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

119 changes: 85 additions & 34 deletions cmd/contour/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,10 @@ func (s *Server) doServe() error {
return err
}

if listenerConfig.GlobalExternalAuthConfig, err = s.setupGlobalExternalAuthentication(contourConfiguration); err != nil {
return err
}

contourMetrics := metrics.NewMetrics(s.registry)

// Endpoints updates are handled directly by the EndpointsTranslator
Expand Down Expand Up @@ -434,19 +438,20 @@ func (s *Server) doServe() error {
}

builder := s.getDAGBuilder(dagBuilderConfig{
ingressClassNames: ingressClassNames,
rootNamespaces: contourConfiguration.HTTPProxy.RootNamespaces,
gatewayControllerName: gatewayControllerName,
gatewayRef: gatewayRef,
disablePermitInsecure: *contourConfiguration.HTTPProxy.DisablePermitInsecure,
enableExternalNameService: *contourConfiguration.EnableExternalNameService,
dnsLookupFamily: contourConfiguration.Envoy.Cluster.DNSLookupFamily,
headersPolicy: contourConfiguration.Policy,
clientCert: clientCert,
fallbackCert: fallbackCert,
connectTimeout: timeouts.ConnectTimeout,
client: s.mgr.GetClient(),
metrics: contourMetrics,
ingressClassNames: ingressClassNames,
rootNamespaces: contourConfiguration.HTTPProxy.RootNamespaces,
gatewayControllerName: gatewayControllerName,
gatewayRef: gatewayRef,
disablePermitInsecure: *contourConfiguration.HTTPProxy.DisablePermitInsecure,
enableExternalNameService: *contourConfiguration.EnableExternalNameService,
dnsLookupFamily: contourConfiguration.Envoy.Cluster.DNSLookupFamily,
headersPolicy: contourConfiguration.Policy,
clientCert: clientCert,
fallbackCert: fallbackCert,
connectTimeout: timeouts.ConnectTimeout,
client: s.mgr.GetClient(),
metrics: contourMetrics,
globalExternalAuthorizationService: contourConfiguration.GlobalExternalAuthorization,
})

// Build the core Kubernetes event handler.
Expand Down Expand Up @@ -636,6 +641,50 @@ func (s *Server) setupRateLimitService(contourConfiguration contour_api_v1alpha1
}, nil
}

func (s *Server) setupGlobalExternalAuthentication(contourConfiguration contour_api_v1alpha1.ContourConfigurationSpec) (*xdscache_v3.GlobalExternalAuthConfig, error) {
if contourConfiguration.GlobalExternalAuthorization == nil {
return nil, nil
}

// ensure the specified ExtensionService exists
extensionSvc := &contour_api_v1alpha1.ExtensionService{}
namespaceName := k8s.NamespacedNameFrom(contourConfiguration.GlobalExternalAuthorization.ExtensionService)
key := client.ObjectKey{
Namespace: namespaceName.Namespace,
Name: namespaceName.Name,
}

// Using GetAPIReader() here because the manager's caches won't be started yet,
// so reads from the manager's client (which uses the caches for reads) will fail.
if err := s.mgr.GetAPIReader().Get(context.Background(), key, extensionSvc); err != nil {
return nil, fmt.Errorf("error getting global external authorization extension service %s: %v", key, err)
}

// get the response timeout from the ExtensionService
var responseTimeout timeout.Setting
var err error

if tp := extensionSvc.Spec.TimeoutPolicy; tp != nil {
responseTimeout, err = timeout.Parse(tp.Response)
if err != nil {
return nil, fmt.Errorf("error parsing global http ext auth extension service %s response timeout: %v", key, err)
}
}

var sni string
if extensionSvc.Spec.UpstreamValidation != nil {
sni = extensionSvc.Spec.UpstreamValidation.SubjectName
}

return &xdscache_v3.GlobalExternalAuthConfig{
ExtensionService: key,
SNI: sni,
Timeout: responseTimeout,
FailOpen: ref.Val(contourConfiguration.GlobalExternalAuthorization.FailOpen, false),
Context: contourConfiguration.GlobalExternalAuthorization.AuthPolicy.Context,
}, nil
}

func (s *Server) setupDebugService(debugConfig contour_api_v1alpha1.DebugConfig, builder *dag.Builder) error {
debugsvc := &debug.Service{
Service: httpsvc.Service{
Expand Down Expand Up @@ -836,19 +885,20 @@ func (s *Server) setupGatewayAPI(contourConfiguration contour_api_v1alpha1.Conto
}

type dagBuilderConfig struct {
ingressClassNames []string
rootNamespaces []string
gatewayControllerName string
gatewayRef *types.NamespacedName
disablePermitInsecure bool
enableExternalNameService bool
dnsLookupFamily contour_api_v1alpha1.ClusterDNSFamilyType
headersPolicy *contour_api_v1alpha1.PolicyConfig
clientCert *types.NamespacedName
fallbackCert *types.NamespacedName
connectTimeout time.Duration
client client.Client
metrics *metrics.Metrics
ingressClassNames []string
rootNamespaces []string
gatewayControllerName string
gatewayRef *types.NamespacedName
disablePermitInsecure bool
enableExternalNameService bool
dnsLookupFamily contour_api_v1alpha1.ClusterDNSFamilyType
headersPolicy *contour_api_v1alpha1.PolicyConfig
clientCert *types.NamespacedName
fallbackCert *types.NamespacedName
connectTimeout time.Duration
client client.Client
metrics *metrics.Metrics
globalExternalAuthorizationService *contour_api_v1alpha1.GlobalExternalAuthorizationConfig
}

func (s *Server) getDAGBuilder(dbc dagBuilderConfig) *dag.Builder {
Expand Down Expand Up @@ -917,14 +967,15 @@ func (s *Server) getDAGBuilder(dbc dagBuilderConfig) *dag.Builder {
ConnectTimeout: dbc.connectTimeout,
},
&dag.HTTPProxyProcessor{
EnableExternalNameService: dbc.enableExternalNameService,
DisablePermitInsecure: dbc.disablePermitInsecure,
FallbackCertificate: dbc.fallbackCert,
DNSLookupFamily: dbc.dnsLookupFamily,
ClientCertificate: dbc.clientCert,
RequestHeadersPolicy: &requestHeadersPolicy,
ResponseHeadersPolicy: &responseHeadersPolicy,
ConnectTimeout: dbc.connectTimeout,
EnableExternalNameService: dbc.enableExternalNameService,
DisablePermitInsecure: dbc.disablePermitInsecure,
FallbackCertificate: dbc.fallbackCert,
DNSLookupFamily: dbc.dnsLookupFamily,
ClientCertificate: dbc.clientCert,
RequestHeadersPolicy: &requestHeadersPolicy,
ResponseHeadersPolicy: &responseHeadersPolicy,
ConnectTimeout: dbc.connectTimeout,
GlobalExternalAuthorization: dbc.globalExternalAuthorizationService,
},
}

Expand Down
Loading

0 comments on commit 8b98559

Please sign in to comment.