Skip to content

Commit

Permalink
Merge pull request #4 from ssttehrani/feat/http-authz
Browse files Browse the repository at this point in the history
feat: add http support to authz filter
  • Loading branch information
ssttehrani authored Feb 7, 2024
2 parents 0118dbe + 8aeb83f commit c0005e5
Show file tree
Hide file tree
Showing 10 changed files with 656 additions and 11 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ container: ## Build the Contour container image
--build-arg "BUILD_GOEXPERIMENT=$(BUILD_GOEXPERIMENT)" \
$(DOCKER_BUILD_LABELS) \
$(shell pwd) \
--platform linux/amd64 \
--tag $(IMAGE):$(VERSION)

push: ## Push the Contour container image to the Docker registry
Expand Down
91 changes: 91 additions & 0 deletions apis/projectcontour/v1/httpproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,14 @@ type ExtensionServiceReference struct {
Name string `json:"name,omitempty" protobuf:"bytes,3,opt,name=name"`
}

// AuthorizationServiceType is an alias to enforce validation
type AuthorizationServiceAPIType string

const (
AuthorizationGRPCService AuthorizationServiceAPIType = "grpc"
AuthorizationHTTPService AuthorizationServiceAPIType = "http"
)

// AuthorizationServer configures an external server to authenticate
// client requests. The external server must implement the v3 Envoy
// external authorization GRPC protocol (https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/auth/v3/external_auth.proto).
Expand All @@ -237,6 +245,20 @@ type AuthorizationServer struct {
// +optional
ExtensionServiceRef ExtensionServiceReference `json:"extensionRef,omitempty"`

// ServiceAPIType defines the external authorization service API type.
// It indicates the protocol implemented by the external server, specifying whether it's a raw HTTP authorization server
// or a gRPC authorization server.
//
// +optional
// +kubebuilder:validation:Enum=http;grpc
// +kubebuilder:default=grpc
ServiceAPIType AuthorizationServiceAPIType `json:"serviceAPIType,omitempty"`

// HttpAuthorizationServerSettings defines configurations for interacting with an external HTTP authorization server.
//
// +optional
HttpServerSettings *HttpAuthorizationServerSettings `json:"httpSettings,omitempty"`

Check warning on line 260 in apis/projectcontour/v1/httpproxy.go

View workflow job for this annotation

GitHub Actions / lint

var-naming: struct field HttpServerSettings should be HTTPServerSettings (revive)

// AuthPolicy sets a default authorization policy for client requests.
// This policy will be used unless overridden by individual routes.
//
Expand Down Expand Up @@ -265,6 +287,75 @@ type AuthorizationServer struct {
WithRequestBody *AuthorizationServerBufferSettings `json:"withRequestBody,omitempty"`
}

// HttpAuthorizationServerSettings defines configurations for interacting with an external HTTP authorization server.
type HttpAuthorizationServerSettings struct {

Check warning on line 291 in apis/projectcontour/v1/httpproxy.go

View workflow job for this annotation

GitHub Actions / lint

var-naming: type HttpAuthorizationServerSettings should be HTTPAuthorizationServerSettings (revive)
// PathPrefix Sets a prefix to the value of authorization request header Path.
//
// +optional
PathPrefix string `json:"pathPrefix,omitempty"`

// Note: This field is not used by Envoy
// https://github.com/envoyproxy/envoy/issues/5357
//
// ServerURI sets the URI of the external HTTP authorization server to which authorization requests must be sent.
//
// // +required
// // +kubebuilder:validation:Pattern=`^https?://[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*(\/[^\s]*)?$`
// ServerURI string `json:"serverURI"`

// AllowedAuthorizationHeaders specifies client request headers that will be sent to the authorization server.
// Note that in addition to the the user’s supplied matchers, Host, Method, Path, Content-Length, and Authorization are additionally included in the list.
//
// +optional
AllowedAuthorizationHeaders []HttpAuthorizationServerAllowedHeaders `json:"allowedAuthorizationHeaders,omitempty"`

// AllowedUpstreamHeaders specifies authorization response headers that will be added to the original client request.
// Note that coexistent headers will be overridden.
//
// +optional
AllowedUpstreamHeaders []HttpAuthorizationServerAllowedHeaders `json:"allowedUpstreamHeaders,omitempty"`
}

// HttpAuthorizationServerAllowedHeaders specifies how to conditionally match against allowed headers
// in the context of HTTP authorization. It includes options such as Exact, Prefix, Suffix,
// Contains, and IgnoreCase to customize header matching criteria. However, regex support
// is intentionally excluded to simplify the user experience and prevent potential issues.
// One of Prefix, Exact, Suffix or Contains must be provided.
type HttpAuthorizationServerAllowedHeaders struct {

Check warning on line 324 in apis/projectcontour/v1/httpproxy.go

View workflow job for this annotation

GitHub Actions / lint

var-naming: type HttpAuthorizationServerAllowedHeaders should be HTTPAuthorizationServerAllowedHeaders (revive)
// Exact specifies a string that the header name must be equal to.
//
// +optional
Exact string `json:"exact,omitempty"`

// Prefix defines a prefix match for the header name.
//
// +optional
Prefix string `json:"prefix,omitempty"`

// Suffix defines a suffix match for a header name.
//
// +optional
Suffix string `json:"suffix,omitempty"`

// To streamline user experience and mitigate potential issues, we do not support regex.
// Additionally, it's essential to ensure that any regex patterns adhere to the configured runtime key, re2.max_program_size.error_level
// by verifying that the program size is smaller than the specified value.
// This necessitates thorough validation of user input.
//
// Regex string `json:"regex,omitempty"`

// Contains specifies a substring that must be present in the header name.
//
// +optional
Contains string `json:"contains,omitempty"`

// IgnoreCase specifies that string matching should be case insensitive.
// Note that this has no effect on the Regex parameter.
//
// +optional
IgnoreCase bool `json:"ignoreCase,omitempty"`
}

// AuthorizationServerBufferSettings enables ExtAuthz filter to buffer client request data and send it as part of authorization request
type AuthorizationServerBufferSettings struct {
// MaxRequestBytes sets the maximum size of message body ExtAuthz filter will hold in-memory.
Expand Down
2 changes: 1 addition & 1 deletion apis/projectcontour/v1alpha1/extensionservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ type ExtensionServiceSpec struct {
// Values may be h2 or h2c. If omitted, protocol-selection falls back on Service annotations.
//
// +optional
// +kubebuilder:validation:Enum=h2;h2c
// +kubebuilder:validation:Enum=h1;h2;h2c
Protocol *string `json:"protocol,omitempty"`

// The policy for load balancing GRPC service requests. Note that the
Expand Down
39 changes: 39 additions & 0 deletions cmd/contour/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -861,12 +861,51 @@ func (s *Server) setupGlobalExternalAuthentication(contourConfiguration contour_
context = contourConfiguration.GlobalExternalAuthorization.AuthPolicy.Context
}

if contourConfiguration.GlobalExternalAuthorization.ServiceAPIType == contour_api_v1.AuthorizationHTTPService && contourConfiguration.GlobalExternalAuthorization.HttpServerSettings == nil {
return nil, fmt.Errorf("Spec.globalExtAuth.HttpServerSettings is not set and it is required for http type")
}

// Not required due to Kubernetes API server validation.
//
// if auth.ServiceAPIType == contour_api_v1.AuthorizationHTTPService && auth.HttpServerSettings.ServerURI == "" {
// validCond.AddErrorf(contour_api_v1.ConditionTypeAuthError, "AuthBadServerURI",
// "Spec.Virtualhost.Authorization.HttpServerSettings.ServerURI is not set or it's empty and it is required for http type")

// return nil
// }

globalExternalAuthConfig := &xdscache_v3.GlobalExternalAuthConfig{
ExtensionServiceConfig: extensionSvcConfig,
FailOpen: contourConfiguration.GlobalExternalAuthorization.FailOpen,
Context: context,
}

switch contourConfiguration.GlobalExternalAuthorization.ServiceAPIType {
case contour_api_v1.AuthorizationGRPCService:
globalExternalAuthConfig.ServiceAPIType = contour_api_v1.AuthorizationGRPCService
case contour_api_v1.AuthorizationHTTPService:
globalExternalAuthConfig.ServiceAPIType = contour_api_v1.AuthorizationHTTPService
globalExternalAuthConfig.HttpPathPrefix = contourConfiguration.GlobalExternalAuthorization.HttpServerSettings.PathPrefix
// globalExternalAuthConfig.HttpServerURI = contourConfiguration.GlobalExternalAuthorization.HttpServerSettings.ServerURI

if contourConfiguration.GlobalExternalAuthorization.HttpServerSettings.AllowedAuthorizationHeaders != nil {
if err := dag.ExternalAuthAllowedHeadersValid(contourConfiguration.GlobalExternalAuthorization.HttpServerSettings.AllowedAuthorizationHeaders); err != nil {
return nil, err
}

globalExternalAuthConfig.HttpAllowedAuthorizationHeaders = contourConfiguration.GlobalExternalAuthorization.HttpServerSettings.AllowedAuthorizationHeaders
}

if contourConfiguration.GlobalExternalAuthorization.HttpServerSettings.AllowedUpstreamHeaders != nil {
if err := dag.ExternalAuthAllowedHeadersValid(contourConfiguration.GlobalExternalAuthorization.HttpServerSettings.AllowedUpstreamHeaders); err != nil {

return nil, err
}

globalExternalAuthConfig.HttpAllowedUpstreamHeaders = contourConfiguration.GlobalExternalAuthorization.HttpServerSettings.AllowedUpstreamHeaders
}
}

if contourConfiguration.GlobalExternalAuthorization.WithRequestBody != nil {
globalExternalAuthConfig.WithRequestBody = &dag.AuthorizationServerBufferSettings{
PackAsBytes: contourConfiguration.GlobalExternalAuthorization.WithRequestBody.PackAsBytes,
Expand Down
Loading

0 comments on commit c0005e5

Please sign in to comment.