Skip to content

Commit

Permalink
Basic Authentication - #399
Browse files Browse the repository at this point in the history
* `pkg/options/auth.go`: Struct definition of the `auth` section.
* `pkg/options/auth_test.go`: Tests that unmarshaling the `auth` section YAML works as expected.
* `internal/controllers/auth.go`: This is where the configuration of envoy will take place, perhaps using an approach similar to the one defined here <envoyproxy/go-control-plane#184>.
* `pkg/spec/extension_test.go`: use `require.EqualError` to match the error message.
* `pkg/spec/extension.go`: Print out the input when we fail to parse `x-kusk` extension.
* `Makefile`: Run `docker build` with out cache, which I'll revert in the future.
* `examples/auth-basic/`: Basic auth samples.

Example `auth` YAML:

```yaml
x-kusk:
  ...
  auth:
    scheme: basic
    path_prefix: /login #optional
    auth-upstream:
      host:
        hostname: example.com
        port: 80
```

See <#399> for further information.
  • Loading branch information
Mohamed Bana committed May 26, 2022
1 parent e994778 commit 9ecf030
Show file tree
Hide file tree
Showing 12 changed files with 387 additions and 9 deletions.
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ LD_FLAGS += -X github.com/kubeshop/kusk-gateway/pkg/analytics.KuskGAMeasurementI
LD_FLAGS += -X github.com/kubeshop/kusk-gateway/pkg/analytics.KuskGAApiSecret=$(GA_SECRET)
LD_FLAGS += -X github.com/kubeshop/kusk-gateway/pkg/build.Version=$(VERSION)

export DOCKER_BUILDKIT ?= 1
export DOCKER_BUILDKIT ?= 1

.PHONY: all
all: build
Expand Down Expand Up @@ -122,14 +122,14 @@ run: $(KTUNNEL) install-local generate fmt vet ## Run a controller from your hos

.PHONY: docker-build-manager
docker-build-manager: ## Build docker image with the manager.
@eval $$(minikube docker-env --profile kgw); docker build -t ${MANAGER_IMG} --build-arg GOPROXY=${GOPROXY} -f ./build/manager/Dockerfile .
@eval $$(minikube docker-env --profile kgw); echo; set -x; docker build --no-cache -t ${MANAGER_IMG} --build-arg GOPROXY=${GOPROXY} -f ./build/manager/Dockerfile .

.PHONY: docker-build
docker-build: docker-build-manager ## Build docker images for all apps

.PHONY: docker-build-manager-debug
docker-build-manager-debug: ## Build docker image with the manager and debugger.
@eval $$(minikube docker-env --profile kgw); docker build -t "${MANAGER_IMG}-debug" --build-arg GOPROXY=${GOPROXY} -f ./build/manager/Dockerfile-debug .
@eval $$(minikube docker-env --profile kgw); echo; set -x; docker build --no-cache -t "${MANAGER_IMG}-debug" --build-arg GOPROXY=${GOPROXY} -f ./build/manager/Dockerfile-debug .

##@ Deployment

Expand Down
2 changes: 1 addition & 1 deletion cmd/manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ func main() {
analytics.SendAnonymousInfo("kusk-gateway manager bootstrapping")
logger, err := initLogger(false, config.LogLevel)
if err != nil {
_ = fmt.Errorf("unable to init logger: %w", err)
fmt.Fprintln(os.Stderr, fmt.Errorf("kusk-gateway-manager: unable to init logger: %w", err))
os.Exit(1)
}
ctrl.SetLogger(logger)
Expand Down
36 changes: 36 additions & 0 deletions examples/auth-basic/auth-basic-api.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
apiVersion: gateway.kusk.io/v1alpha1
kind: API
metadata:
name: envoy-auth-basic-http-service-sample
spec:
fleet:
name: default
namespace: default
# service name and port should be specified inside x-kusk annotation
spec: |
openapi: 3.0.0
info:
title: envoy-auth-basic-http-service
description: envoy-auth-basic-http-service
version: '0.0.1'
schemes:
- http
- https
x-kusk:
auth:
scheme: basic
auth-upstream:
host:
hostname: envoy-auth-basic-http-service.svc.cluster.local
port: 9092
upstream:
service:
name: httpbin
namespace: default
port: 8080
paths:
"/":
get:
description: Returns GET data.
operationId: "/get"
responses: {}
76 changes: 76 additions & 0 deletions examples/auth-basic/auth-basic-manifest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: envoy-auth-basic-http-service
name: envoy-auth-basic-http-service
spec:
replicas: 1
selector:
matchLabels:
app: envoy-auth-basic-http-service
template:
metadata:
labels:
app: envoy-auth-basic-http-service
spec:
containers:
- image: banaioltd/envoy-auth-basic-http-service:latest
name: envoy-auth-basic-http-service
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 9092
---
apiVersion: v1
kind: Service
metadata:
labels:
app: envoy-auth-basic-http-service
name: envoy-auth-basic-http-service
spec:
ports:
- port: 9092
targetPort: 9092
selector:
app: envoy-auth-basic-http-service
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: httpbin
name: httpbin
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
template:
metadata:
labels:
app: httpbin
spec:
containers:
- image: kennethreitz/httpbin
name: httpbin
resources:
limits:
memory: "128Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
labels:
app: httpbin
name: httpbin
spec:
ports:
- port: 8080
targetPort: 80
selector:
app: httpbin
43 changes: 43 additions & 0 deletions examples/auth-basic/auth-basic-staticroute.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
apiVersion: gateway.kusk.io/v1alpha1
kind: StaticRoute
metadata:
name: httpbin-sample
spec:
# should work with localhost, example.org
hosts: [ "localhost", "*"]
paths:
# Root goes to httpbin
/:
get: &root_route
route:
upstream:
host:
hostname: httpbin.default.svc.cluster.local
port: 8080
rewrite:
pattern: "^/$"
substitution: "/get"
# copying for all methods
post: *root_route
put: *root_route
head: *root_route
# /static -> /
/static:
get:
redirect:
path_redirect: "/"
response_code: 308
# /get2 routed to k8s service httpbin in default namespace with rewrite to /get
/get2:
get:
route:
upstream:
service:
name: httpbin
namespace: default
port: 8080
rewrite:
pattern: "^/get2$"
substitution: "/get"


75 changes: 75 additions & 0 deletions internal/controllers/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
MIT License
Copyright (c) 2022 Kubeshop
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package controllers

import (
"fmt"

envoy_config_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
auth_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/ext_authz/v3"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/durationpb"

"github.com/kubeshop/kusk-gateway/pkg/options"
)

var _ = auth_v3.AuthorizationRequest{}

func convertAuthOptions(auth *options.Auth) *auth_v3.HttpService {
uri := fmt.Sprintf("http://%s:%d", auth.AuthUpstream.Host.Hostname, auth.AuthUpstream.Host.Port)
httpUpstreamType := &envoy_config_core_v3.HttpUri_Cluster{}

pathPrefix := ""
if auth.PathPrefix != nil {
pathPrefix = *auth.PathPrefix
}

return &auth_v3.HttpService{
ServerUri: &envoy_config_core_v3.HttpUri{
// https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/http_uri.proto#envoy-v3-api-msg-config-core-v3-httpuri
Uri: uri,
HttpUpstreamType: httpUpstreamType,
Timeout: &durationpb.Duration{
Seconds: 60,
},
},
PathPrefix: pathPrefix,
}
}

func configureAuthz(filterConf map[string]*anypb.Any, authOptions *options.Auth) error {
// Do nothing for now.
return nil

// if authOptions != nil {
// httpService := convertAuthOptions(authOptions)
// anyHTTPService, err := anypb.New(httpService)
// if err != nil {
// return fmt.Errorf("configureAuthz: failure marshalling `auth` configuration: %w ", err)
// }

// filterConf["envoy.filters.http.ext_authz.v3.HttpService"] = anyHTTPService
// }
}
10 changes: 10 additions & 0 deletions internal/controllers/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,16 @@ func UpdateConfigFromAPIOpts(envoyConfiguration *config.EnvoyConfiguration, prox
if err := envoyConfiguration.AddRouteToVHost(string(vh), rt); err != nil {
return fmt.Errorf("failure adding the route to vhost %s: %w ", string(vh), err)
}

if err := configureAuthz(filterConf, finalOpts.Auth); err != nil {
return err
}

rt.TypedPerFilterConfig = filterConf
}

if err := envoyConfiguration.AddRouteToVHost(string(vh), rt); err != nil {
return fmt.Errorf("failure adding the route to vhost %s: %w ", string(vh), err)
}
}
}
Expand Down
63 changes: 63 additions & 0 deletions pkg/options/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
MIT License
Copyright (c) 2022 Kubeshop
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package options

// x-kusk:
// ...
// auth:
// scheme: basic
// path_prefix: /login #optional
// auth-upstream:
// host:
// hostname: example.com
// port: 80

type Auth struct {
Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"`
PathPrefix *string `json:"path_prefix,omitempty" yaml:"path_prefix,omitempty"`
AuthUpstream AuthUpstream `json:"auth-upstream,omitempty" yaml:"auth-upstream,omitempty"`
}

type AuthUpstream struct {
Host *AuthUpstreamHost `json:"host,omitempty" yaml:"host,omitempty"`
}

type AuthUpstreamHost struct {
Hostname Host `json:"hostname,omitempty" yaml:"hostname,omitempty"`
Port uint32 `json:"port,omitempty" yaml:"port,omitempty"`
}

func (a *Auth) Validate() error {
return nil

// return v.ValidateStruct(&a,
// v.Field(&a.Scheme, v.In("http", "https")),
// v.Field(&a.Scheme, v.In("basic")),
// v.Field(&a.PathPrefix, is.),
// v.Field(&a.AuthUpstream.Host.Hostname, is.Host),
// v.Field(&a.AuthUpstream.Host.Port, is.Port),
// v.Field(&o.PathRedirect, v.By(o.MutuallyExlusivePathRedirectCheck)),
// )
}
Loading

0 comments on commit 9ecf030

Please sign in to comment.