Skip to content

Commit

Permalink
Add default domain name mechanism (#95)
Browse files Browse the repository at this point in the history
- implement inserting default domain name to the hostname if it does not contain a domain name
- fix a bug with the positive validation of not whitelisted domain when it contains a whitelisted domain
- bump builder image version to be the same as used in CI job (1.13.4)
  • Loading branch information
kubadz authored Apr 23, 2020
1 parent 0c4d7ae commit 978664d
Show file tree
Hide file tree
Showing 12 changed files with 305 additions and 90 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build the manager binary
FROM golang:1.12.5 as builder
FROM golang:1.13.4 as builder

WORKDIR /workspace
# Copy the Go Modules manifests
Expand Down
13 changes: 10 additions & 3 deletions controllers/api_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@ type APIReconciler struct {
OathkeeperSvc string
OathkeeperSvcPort uint32
JWKSURI string
Validator APIRuleValidator
CorsConfig *processing.CorsConfig
GeneratedObjectsLabels map[string]string
ServiceBlackList map[string][]string
DomainWhiteList []string
DefaultDomainName string
}

//APIRuleValidator allows to validate APIRule instances created by the user.
Expand Down Expand Up @@ -84,14 +86,19 @@ func (r *APIReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
}

//1.2) Validate input including host
validationFailures := r.Validator.Validate(api, vsList)
validator := validation.APIRule{
ServiceBlackList: r.ServiceBlackList,
DomainWhiteList: r.DomainWhiteList,
DefaultDomainName: r.DefaultDomainName,
}
validationFailures := validator.Validate(api, vsList)
if len(validationFailures) > 0 {
r.Log.Info(fmt.Sprintf(`Validation failure {"controller": "Api", "request": "%s/%s"}`, api.Namespace, api.Name))
return r.setStatus(ctx, api, generateValidationStatus(validationFailures), gatewayv1alpha1.StatusSkipped)
}

//2) Compute list of required objects (the set of objects required to satisfy our contract on apiRule.Spec, not yet applied)
factory := processing.NewFactory(r.Client, r.Log, r.OathkeeperSvc, r.OathkeeperSvcPort, r.JWKSURI, r.CorsConfig, r.GeneratedObjectsLabels)
factory := processing.NewFactory(r.Client, r.Log, r.OathkeeperSvc, r.OathkeeperSvcPort, r.JWKSURI, r.CorsConfig, r.GeneratedObjectsLabels, r.DefaultDomainName)
requiredObjects := factory.CalculateRequiredState(api)

//3.1 Fetch all existing objects related to _this_ apiRule from the cluster (VS, Rules)
Expand Down
9 changes: 3 additions & 6 deletions controllers/api_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

gatewayv1alpha1 "github.com/kyma-incubator/api-gateway/api/v1alpha1"
"github.com/kyma-incubator/api-gateway/controllers"
"github.com/kyma-incubator/api-gateway/internal/validation"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
rulev1alpha1 "github.com/ory/oathkeeper-maester/api/v1alpha1"
Expand Down Expand Up @@ -100,11 +99,9 @@ func fixAPI() *gatewayv1alpha1.APIRule {

func getAPIReconciler(mgr manager.Manager) reconcile.Reconciler {
return &controllers.APIReconciler{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("Api"),
Validator: &validation.APIRule{
DomainWhiteList: []string{"bar", "kyma.local"},
},
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("Api"),
DomainWhiteList: []string{"bar", "kyma.local"},
CorsConfig: &processing.CorsConfig{
AllowOrigin: TestAllowOrigins,
AllowMethods: TestAllowMethods,
Expand Down
5 changes: 1 addition & 4 deletions controllers/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

gatewayv1alpha1 "github.com/kyma-incubator/api-gateway/api/v1alpha1"
"github.com/kyma-incubator/api-gateway/controllers"
"github.com/kyma-incubator/api-gateway/internal/validation"
rulev1alpha1 "github.com/ory/oathkeeper-maester/api/v1alpha1"
"k8s.io/apimachinery/pkg/runtime"
networkingv1alpha3 "knative.dev/pkg/apis/istio/v1alpha3"
Expand Down Expand Up @@ -88,9 +87,7 @@ var _ = BeforeSuite(func(done Done) {
Log: ctrl.Log.WithName("controllers").WithName("Api"),
OathkeeperSvc: testOathkeeperSvcURL,
OathkeeperSvcPort: testOathkeeperPort,
Validator: &validation.APIRule{
DomainWhiteList: []string{"bar", "kyma.local"},
},
DomainWhiteList: []string{"bar", "kyma.local"},
CorsConfig: &processing.CorsConfig{
AllowOrigin: TestAllowOrigins,
AllowMethods: TestAllowMethods,
Expand Down
9 changes: 1 addition & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
Expand Down Expand Up @@ -86,7 +85,6 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
Expand Down Expand Up @@ -114,7 +112,6 @@ github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273 h1:agujYaXJSxSo1
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
Expand All @@ -133,7 +130,6 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
Expand All @@ -143,7 +139,6 @@ golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190514140710-3ec191127204/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190918130420-a8b05e9114ab h1:h5tBRKZ1aY/bo6GNqe/4zWC8GkaLOFQ5wPKIOQ0i2sA=
golang.org/x/net v0.0.0-20190918130420-a8b05e9114ab/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
Expand All @@ -158,7 +153,6 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872 h1:cGjJzUd8RgBw428LXP65YXni0aiGNA4Bl+ls8SmLOm8=
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190919044723-0c1ff786ef13 h1:/zi0zzlPHWXYXrO1LjNRByFu8sdGgCkj2JLDdBIB84k=
golang.org/x/sys v0.0.0-20190919044723-0c1ff786ef13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand All @@ -171,9 +165,8 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190501045030-23463209683d h1:D7DVZUZEUgsSIDTivnUtVeGfN5AvhDIKtdIZAqx0ieE=
golang.org/x/tools v0.0.0-20190501045030-23463209683d/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
gomodules.xyz/jsonpatch/v2 v2.0.0 h1:OyHbl+7IOECpPKfVK42oFr6N7+Y2dR+Jsb/IiDV3hOo=
gomodules.xyz/jsonpatch/v2 v2.0.0 h1:lHNQverf0+Gm1TbSbVIDWVXOhZ2FpZopxRqpr2uIjs4=
gomodules.xyz/jsonpatch/v2 v2.0.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
Expand Down
21 changes: 21 additions & 0 deletions internal/helpers/default_domain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package helpers

import (
"fmt"
"strings"
)

func GetHostWithDomain(host, defaultDomainName string) string {
if !HostIncludesDomain(host) {
return GetHostWithDefaultDomain(host, defaultDomainName)
}
return host
}

func HostIncludesDomain(host string) bool {
return strings.Contains(host, ".")
}

func GetHostWithDefaultDomain(host, defaultDomainName string) string {
return fmt.Sprintf("%s.%s", host, defaultDomainName)
}
9 changes: 5 additions & 4 deletions internal/processing/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package processing

import (
"fmt"
"github.com/kyma-incubator/api-gateway/internal/helpers"

gatewayv1alpha1 "github.com/kyma-incubator/api-gateway/api/v1alpha1"
"github.com/kyma-incubator/api-gateway/internal/builders"
Expand All @@ -13,7 +14,7 @@ func modifyAccessRule(existing, required *rulev1alpha1.Rule) {
existing.Spec = required.Spec
}

func generateAccessRule(api *gatewayv1alpha1.APIRule, rule gatewayv1alpha1.Rule, accessStrategies []*rulev1alpha1.Authenticator, additionalLabels map[string]string) *rulev1alpha1.Rule {
func generateAccessRule(api *gatewayv1alpha1.APIRule, rule gatewayv1alpha1.Rule, accessStrategies []*rulev1alpha1.Authenticator, additionalLabels map[string]string, defaultDomainName string) *rulev1alpha1.Rule {
namePrefix := fmt.Sprintf("%s-", api.ObjectMeta.Name)
namespace := api.ObjectMeta.Namespace
ownerRef := generateOwnerRef(api)
Expand All @@ -22,7 +23,7 @@ func generateAccessRule(api *gatewayv1alpha1.APIRule, rule gatewayv1alpha1.Rule,
GenerateName(namePrefix).
Namespace(namespace).
Owner(builders.OwnerReference().From(&ownerRef)).
Spec(builders.AccessRuleSpec().From(generateAccessRuleSpec(api, rule, accessStrategies))).
Spec(builders.AccessRuleSpec().From(generateAccessRuleSpec(api, rule, accessStrategies, defaultDomainName))).
Label(OwnerLabel, fmt.Sprintf("%s.%s", api.ObjectMeta.Name, api.ObjectMeta.Namespace))

for k, v := range additionalLabels {
Expand All @@ -32,12 +33,12 @@ func generateAccessRule(api *gatewayv1alpha1.APIRule, rule gatewayv1alpha1.Rule,
return arBuilder.Get()
}

func generateAccessRuleSpec(api *gatewayv1alpha1.APIRule, rule gatewayv1alpha1.Rule, accessStrategies []*rulev1alpha1.Authenticator) *rulev1alpha1.RuleSpec {
func generateAccessRuleSpec(api *gatewayv1alpha1.APIRule, rule gatewayv1alpha1.Rule, accessStrategies []*rulev1alpha1.Authenticator, defaultDomainName string) *rulev1alpha1.RuleSpec {
return builders.AccessRuleSpec().
Upstream(builders.Upstream().
URL(fmt.Sprintf("http://%s.%s.svc.cluster.local:%d", *api.Spec.Service.Name, api.ObjectMeta.Namespace, int(*api.Spec.Service.Port)))).
Match(builders.Match().
URL(fmt.Sprintf("<http|https>://%s<%s>", *api.Spec.Service.Host, rule.Path)).
URL(fmt.Sprintf("<http|https>://%s<%s>", helpers.GetHostWithDomain(*api.Spec.Service.Host, defaultDomainName), rule.Path)).
Methods(rule.Methods)).
Authorizer(builders.Authorizer().Handler(builders.Handler().
Name("allow"))).
Expand Down
9 changes: 6 additions & 3 deletions internal/processing/processing.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package processing
import (
"context"
"fmt"
"github.com/kyma-incubator/api-gateway/internal/helpers"

"github.com/kyma-incubator/api-gateway/internal/builders"
"k8s.io/apimachinery/pkg/runtime"
Expand All @@ -28,10 +29,11 @@ type Factory struct {
JWKSURI string
corsConfig *CorsConfig
additionalLabels map[string]string
defaultDomainName string
}

//NewFactory .
func NewFactory(client client.Client, logger logr.Logger, oathkeeperSvc string, oathkeeperSvcPort uint32, jwksURI string, corsConfig *CorsConfig, additionalLabels map[string]string) *Factory {
func NewFactory(client client.Client, logger logr.Logger, oathkeeperSvc string, oathkeeperSvcPort uint32, jwksURI string, corsConfig *CorsConfig, additionalLabels map[string]string, defaultDomainName string) *Factory {
return &Factory{
client: client,
Log: logger,
Expand All @@ -40,6 +42,7 @@ func NewFactory(client client.Client, logger logr.Logger, oathkeeperSvc string,
JWKSURI: jwksURI,
corsConfig: corsConfig,
additionalLabels: additionalLabels,
defaultDomainName: defaultDomainName,
}
}

Expand All @@ -58,7 +61,7 @@ func (f *Factory) CalculateRequiredState(api *gatewayv1alpha1.APIRule) *State {

for _, rule := range api.Spec.Rules {
if isSecured(rule) {
ar := generateAccessRule(api, rule, rule.AccessStrategies, f.additionalLabels)
ar := generateAccessRule(api, rule, rule.AccessStrategies, f.additionalLabels, f.defaultDomainName)
res.accessRules[ar.Spec.Match.URL] = ar
}
}
Expand Down Expand Up @@ -205,7 +208,7 @@ func (f *Factory) generateVirtualService(api *gatewayv1alpha1.APIRule) *networki
ownerRef := generateOwnerRef(api)

vsSpecBuilder := builders.VirtualServiceSpec()
vsSpecBuilder.Host(*api.Spec.Service.Host)
vsSpecBuilder.Host(helpers.GetHostWithDomain(*api.Spec.Service.Host, f.defaultDomainName))
vsSpecBuilder.Gateway(*api.Spec.Gateway)

for _, rule := range api.Spec.Rules {
Expand Down
Loading

0 comments on commit 978664d

Please sign in to comment.