Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic Authentication #399

Closed
Tracked by #170
jasmingacic opened this issue May 12, 2022 · 8 comments
Closed
Tracked by #170

Basic Authentication #399

jasmingacic opened this issue May 12, 2022 · 8 comments

Comments

@jasmingacic
Copy link
Contributor

jasmingacic commented May 12, 2022

Use this a guide
https://medium.com/@ricklee_10931/envoy-external-authorization-a-simple-example-d50ef2ede631

@crjones crjones added this to the 1.1.0 milestone May 12, 2022
@crjones crjones added the ready label May 12, 2022
@crjones crjones changed the title basic auth Basic Authentication May 13, 2022
@crjones
Copy link
Contributor

crjones commented May 13, 2022

For basic auth OpenAPI only seems to concern itself with the type of authentication how credentials are transmitted.

  1. We should validate that the specified method is present in the request and auto reject the request if not met.
  2. We need to know whether to pass through the request to the upstream service or a dedicated authentication service to verify credentials. This will likely require special extension markup to specify. As recommended by Ole, LDAP could be one of these options along with the option to pass the request to a URL or an upstream host or service.

@crjones
Copy link
Contributor

crjones commented May 18, 2022

components:
  securitySchemes:
    basicAuth:
      type: "http"
      description: "HTTP Basic Authentication."
      scheme: "basic"
      x-kusk:
        path_prefix: /login #optional
        auth-upstream: # upstream and redirect are mutually exclusive
          host: # host and service are mutually exclusive
            hostname: example.com
            port: 80
          service: # host and service are mutually exclusive
            namespace: default
            name: petstore
            port: 8000

@crjones
Copy link
Contributor

crjones commented May 18, 2022

Could we start with not specifying any extensions for now and just validate that requests have the desired authentication?

GIVEN a basic auth scheme is specified
WHEN basic auth headers are found in the request
THEN forward the request to the upstream

GIVEN a basic auth scheme is specified
WHEN basic auth headers are NOT found in the request
THEN respond 401 and add WW-Authenticate header

@jasmingacic
Copy link
Contributor Author

jasmingacic commented May 19, 2022

@kylehodgetts I'm going to leave the snippet here so we don't lose it

package main

import (
	"context"
	"encoding/json"
	"fmt"

	v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
	auth "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/ext_authz/v3"
	"github.com/getkin/kin-openapi/openapi3"
)

func main() {
	options := &BasicAuth{}

	ctx := context.Background()
	loader := openapi3.Loader{Context: ctx}
	spec, _ := loader.LoadFromFile("out.yaml")
	for name, val := range spec.Components.SecuritySchemes {
		fmt.Println(name, val.Value.Type, val.Value.Scheme)
		if ok, err := getAuthOptions(val.Value.ExtensionProps, options); ok {
			fmt.Println(options)
		} else {
			fmt.Println(err)
			break
		}
	}
	var uri string
	var cluster string
	if options.Upstream.Host != nil {
		uri = fmt.Sprintf("s%:d%", options.Upstream.Host.Hostname, options.Upstream.Host.Port)
	} else if options.Upstream.Service != nil {
		// <service-name>.<namespace>.svc.cluster.local:<service-port>
		cluster = fmt.Sprintf("%s.%s.svc.cluster.local:%d", options.Upstream.Service.Name, options.Upstream.Service.Namespace, options.Upstream.Service.Port)
	}

	extauthz := auth.ExtAuthz{
		Services: &auth.ExtAuthz_HttpService{
			HttpService: &auth.HttpService{
				ServerUri: &v3.HttpUri{
					Uri: uri,
					HttpUpstreamType: &v3.HttpUri_Cluster{
						Cluster: "upstream_cluster",
					},
				},
			},
		},
	}

	fmt.Println(extauthz)
}

const kuskExtensionKey = "x-kusk"

func getAuthOptions(extensionProps openapi3.ExtensionProps, options *BasicAuth) (bool, error) {
	if extension, ok := extensionProps.Extensions[kuskExtensionKey]; ok {
		if kuskExtension, ok := extension.(json.RawMessage); ok {
			fmt.Println(string(kuskExtension))
			err := json.Unmarshal(kuskExtension, options)
			if err != nil {
				return false, fmt.Errorf("failed to parse extension: %w", err)
			}
			return true, nil
		}
	}
	return false, nil

}

type BasicAuth struct {
	Upstream   AuthService `json:"auth-upstream,omitempty"`
	PathPrefix string      `json:"path_prefix"`
}

type AuthService struct {
	Host    *Host    `json:"host,omitempty"`
	Service *Service `json:"service,omitempty"`
}
type Service struct {
	Name      string `json:"name"`
	Namespace string `json:"namespace"`
	Port      int    `json:"port"`
}

type Host struct {
	Hostname string `json:"hostname"`
	Port     int    `json:"port"`
}

Sample API I used https://pastebin.com/eMtgqEYa

@jasmingacic
Copy link
Contributor Author

The next bit is to pass the config to the fleet.
We already have auth options and we should be good (I think)

@mbana mbana self-assigned this May 24, 2022
mbana pushed a commit that referenced this issue May 26, 2022
* `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.
mbana pushed a commit that referenced this issue May 26, 2022
* `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.
mbana pushed a commit that referenced this issue May 26, 2022
* `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.
mbana pushed a commit that referenced this issue May 26, 2022
* `internal/envoy/config/hcm.go`: Hardcode filters in `NewHCMBuilder` just for testing purposes.
* Add `prototypes/auth-basic/ext_authz` that contains an envoy sample that proxies auth to an upstream service. See: <https://github.com/envoyproxy/envoy/tree/main/examples/ext_authz>.

See <#399> for further information.
mbana pushed a commit that referenced this issue May 27, 2022
**WIP:** Still debugging.

See <#399> for further information.
mbana pushed a commit that referenced this issue May 27, 2022
**WIP:** Still debugging.

See <#399> for further information.
mbana pushed a commit that referenced this issue May 27, 2022
**WIP:** Still debugging.

See <#399> for further information.
mbana pushed a commit that referenced this issue May 31, 2022
First cut at basic auth with hardcoded values and static configuration. These hardcoded values and static configuration will be removed later on.

`pkg/options/options.go`, `pkg/options/auth.go` and `pkg/options/auth_test.go`
------------------------------------------------------------------------------

* Add `AuthOptions` as an optional in `SubOptions`.
* Add the authentication option themselves and tests.

`internal/controllers/envoyfleet_resources.go`
----------------------------------------------

* Turn on `envoy` logging - `filter:trace,ext_authz:trace` - to help tracing `ext_authz` and `filter` log lines.
* Add note and commented out code on how to configure different logging levels.

`internal/envoy/config/hcm.go`
------------------------------

* Create a new function called `makeHTTPExternalAuthorization` that creates the filter.
* In `NewHCMBuilder` create the `HTTPExternalAuthorization` filter and add it to `httpConnectionManager.HttpFilters`.
* Copy `generateClusterName` from `internal/controllers/parser.go`.

See <#399> for further information.
@jasmingacic
Copy link
Contributor Author

@mbana Can you add some update here?

@mbana
Copy link
Contributor

mbana commented Jun 1, 2022

The work exists in this, https://github.com/kubeshop/kusk-gateway/tree/mbana-basic-auth-prototype, branch. It works for a statically configured authentication server, i.e., if I hardcode the authentication server and cluster in the code.

The last hurdle that I'm working on is to make the static configuration of the authentication server, e.g., ext-authz-http-service, in https://github.com/kubeshop/kusk-gateway/blob/mbana-basic-auth-prototype/internal/envoy/config/hcm.go#L153, dynamic, that is, read it from:

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

So that in it proxies to example.com as defined in the configuration instead of always to ext-authz-http-service. This is a bit tricky because:

  1. The place where authentication is configured is https://github.com/kubeshop/kusk-gateway/blob/mbana-basic-auth-prototype/internal/controllers/parser.go#L298 (called from https://github.com/kubeshop/kusk-gateway/blob/mbana-basic-auth-prototype/internal/controllers/config_manager.go#L110). That is, the adding of the cluster takes place first.
  2. The httpConnectionManagerBuilder, where the HTTPExternalAuthorization filter is added, is created further down in https://github.com/kubeshop/kusk-gateway/blob/mbana-basic-auth-prototype/internal/controllers/config_manager.go#L153.

How to run it. Checkout the branch above and

git pull
git checkout mbana-basic-auth-prototype
make create-env
kubectl port-forward service/default 8080:80
kubectl apply -f protoypes/manifests/ext-authz-http-service-api.yaml
kubectl apply -f protoypes/manifests/auth-basic-staticroute.yaml
kubectl apply -f protoypes/manifests/ext-authz-http-service.yaml

Run the commands below. Notice the first one contains invalid credentials (Unauthorized - hint: credentials are kubeshop:kubeshop) causing a 401 Unauthorized, then we try again with valid credentials, kubeshop:kubeshop, and then it works.

$ curl -L -X GET -v --user kubeshop:kubeshopx http://localhost:8080/get2
Note: Unnecessary use of -X or --request, GET is already inferred.
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
* Server auth using Basic with user 'kubeshop'
> GET /get2 HTTP/1.1
> Host: localhost:8080
> Authorization: Basic a3ViZXNob3A6a3ViZXNob3B4
> User-Agent: curl/7.83.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 401 Unauthorized
< x-powered-by: Express
< date: Wed, 01 Jun 2022 12:56:11 GMT
< content-length: 54
< x-envoy-upstream-service-time: 761
< content-type: text/plain
< server: envoy
<
* Connection #0 to host localhost left intact
Unauthorized - hint: credentials are kubeshop:kubeshop%
$ curl -L -X GET -v --user kubeshop:kubeshop http://localhost:8080/get2
Note: Unnecessary use of -X or --request, GET is already inferred.
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
* Server auth using Basic with user 'kubeshop'
> GET /get2 HTTP/1.1
> Host: localhost:8080
> Authorization: Basic a3ViZXNob3A6a3ViZXNob3A=
> User-Agent: curl/7.83.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< server: envoy
< date: Wed, 01 Jun 2022 12:56:17 GMT
< content-type: application/json
< content-length: 367
< access-control-allow-origin: *
< access-control-allow-credentials: true
< x-envoy-upstream-service-time: 32
<
{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Authorization": "Basic a3ViZXNob3A6a3ViZXNob3A=",
    "Host": "localhost:8080",
    "User-Agent": "curl/7.83.0",
    "X-Current-User": "kubeshop",
    "X-Envoy-Expected-Rq-Timeout-Ms": "15000",
    "X-Envoy-Original-Path": "/get2"
  },
  "origin": "172.17.0.1",
  "url": "http://localhost:8080/get"
}
* Connection #0 to host localhost left intact

mbana pushed a commit that referenced this issue Jun 1, 2022
Make the configuration dynamic.

See <#399> for further information.
@aabedraba
Copy link

Trying to figure out some issues with Validation of the manifest.

mbana pushed a commit that referenced this issue Jun 6, 2022
Code review points part #4.

Fix validation logic.

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 6, 2022
Code review points part #5.

Remove unused from `examples/ext_authz/ext-authz-staticroute.yaml`.

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 8, 2022
Code review points.

Add `Dockerfile`

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 9, 2022
First cut at basic auth with hardcoded values and static configuration. These hardcoded values and static configuration will be removed later on.

`pkg/options/options.go`, `pkg/options/auth.go` and `pkg/options/auth_test.go`
------------------------------------------------------------------------------

* Add `AuthOptions` as an optional in `SubOptions`.
* Add the authentication option themselves and tests.

`internal/controllers/envoyfleet_resources.go`
----------------------------------------------

* Turn on `envoy` logging - `filter:trace,ext_authz:trace` - to help tracing `ext_authz` and `filter` log lines.
* Add note and commented out code on how to configure different logging levels.

`internal/envoy/config/hcm.go`
------------------------------

* Create a new function called `makeHTTPExternalAuthorization` that creates the filter.
* In `NewHCMBuilder` create the `HTTPExternalAuthorization` filter and add it to `httpConnectionManager.HttpFilters`.
* Copy `generateClusterName` from `internal/controllers/parser.go`.

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 9, 2022
Make the configuration dynamic.

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 9, 2022
Code review points part #1.

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 9, 2022
Code review points part #2.

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 9, 2022
Code review points part #4.

Fix validation logic.

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 9, 2022
Code review points part #5.

Remove unused from `examples/ext_authz/ext-authz-staticroute.yaml`.

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 9, 2022
Code review points.

Add `Dockerfile`

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 9, 2022
Code review points.

Fix `MIT License` comment style so it does not appear in `godoc` when previewing the docs for the repository.

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 9, 2022
Code review points.

Run `go mod tidy` and `go mod verify`

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 9, 2022
Code review points.

Push `docker.io/kubeshop/kusk-ext-authz-http-service` image.

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 15, 2022
First cut at basic auth with hardcoded values and static configuration. These hardcoded values and static configuration will be removed later on.

`pkg/options/options.go`, `pkg/options/auth.go` and `pkg/options/auth_test.go`
------------------------------------------------------------------------------

* Add `AuthOptions` as an optional in `SubOptions`.
* Add the authentication option themselves and tests.

`internal/controllers/envoyfleet_resources.go`
----------------------------------------------

* Turn on `envoy` logging - `filter:trace,ext_authz:trace` - to help tracing `ext_authz` and `filter` log lines.
* Add note and commented out code on how to configure different logging levels.

`internal/envoy/config/hcm.go`
------------------------------

* Create a new function called `makeHTTPExternalAuthorization` that creates the filter.
* In `NewHCMBuilder` create the `HTTPExternalAuthorization` filter and add it to `httpConnectionManager.HttpFilters`.
* Copy `generateClusterName` from `internal/controllers/parser.go`.

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 15, 2022
Make the configuration dynamic.

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 15, 2022
Code review points part #1.

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 15, 2022
Code review points part #2.

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 15, 2022
Code review points part #4.

Fix validation logic.

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 15, 2022
Code review points part #5.

Remove unused from `examples/ext_authz/ext-authz-staticroute.yaml`.

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 15, 2022
Code review points.

Add `Dockerfile`

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 15, 2022
Code review points.

Fix `MIT License` comment style so it does not appear in `godoc` when previewing the docs for the repository.

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 15, 2022
Code review points.

Run `go mod tidy` and `go mod verify`

See <#399> for further information.
mbana pushed a commit that referenced this issue Jun 15, 2022
Code review points.

Push `docker.io/kubeshop/kusk-ext-authz-http-service` image.

See <#399> for further information.
mbana added a commit that referenced this issue Jun 16, 2022
`pkg/options/options.go`, `pkg/options/auth.go` and `pkg/options/auth_test.go`
------------------------------------------------------------------------------

* Add `AuthOptions` as an optional in `SubOptions`.
* Add the authentication option themselves and tests.

`internal/controllers/envoyfleet_resources.go`
----------------------------------------------

* Turn on `envoy` logging - `filter:trace,ext_authz:trace` - to help tracing `ext_authz` and `filter` log lines.
* Add note and commented out code on how to configure different logging levels.

`internal/envoy/config/hcm.go`
------------------------------

* Create a new function called `makeHTTPExternalAuthorization` that creates the filter.
* In `NewHCMBuilder` create the `HTTPExternalAuthorization` filter and add it to `httpConnectionManager.HttpFilters`.
* Copy `generateClusterName` from `internal/controllers/parser.go`.

See <#399> for further information.

Signed-off-by: Mohamed Bana <mohamed@bana.io>
jasmingacic added a commit that referenced this issue Jun 20, 2022
* Basic Authentication - #399

`pkg/options/options.go`, `pkg/options/auth.go` and `pkg/options/auth_test.go`
------------------------------------------------------------------------------

* Add `AuthOptions` as an optional in `SubOptions`.
* Add the authentication option themselves and tests.

`internal/controllers/envoyfleet_resources.go`
----------------------------------------------

* Turn on `envoy` logging - `filter:trace,ext_authz:trace` - to help tracing `ext_authz` and `filter` log lines.
* Add note and commented out code on how to configure different logging levels.

`internal/envoy/config/hcm.go`
------------------------------

* Create a new function called `makeHTTPExternalAuthorization` that creates the filter.
* In `NewHCMBuilder` create the `HTTPExternalAuthorization` filter and add it to `httpConnectionManager.HttpFilters`.
* Copy `generateClusterName` from `internal/controllers/parser.go`.

See <#399> for further information.

Signed-off-by: Mohamed Bana <mohamed@bana.io>

* basic auth smokes

Signed-off-by: jasmingacic <jasmin.gacic@gmail.com>

* a little bit of optimization

Signed-off-by: jasmingacic <jasmin.gacic@gmail.com>

* removed upstream from mocked apis

Signed-off-by: jasmingacic <jasmin.gacic@gmail.com>

* fixing  global auth  disable

Signed-off-by: jasmingacic <jasmin.gacic@gmail.com>

* re-enabled teeardown for basic auth smokes

Signed-off-by: jasmingacic <jasmin.gacic@gmail.com>

* removed commented code from auth service

Signed-off-by: jasmingacic <jasmin.gacic@gmail.com>

Co-authored-by: Mohamed Bana <mohamed@bana.io>
@crjones crjones moved this from Ready to Done in Kusk Gateway Product Backlog Jun 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

4 participants