Skip to content

Commit

Permalink
kap remove hosts from authscheme
Browse files Browse the repository at this point in the history
  • Loading branch information
eguzki committed Nov 8, 2022
1 parent 4212ed3 commit d7ab64b
Show file tree
Hide file tree
Showing 9 changed files with 492 additions and 68 deletions.
37 changes: 33 additions & 4 deletions api/v1beta1/authpolicy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,44 @@ package v1beta1
import (
"fmt"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/go-logr/logr"
"github.com/google/go-cmp/cmp"
authorinov1beta1 "github.com/kuadrant/authorino/api/v1beta1"
"github.com/kuadrant/kuadrant-operator/pkg/common"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
gatewayapiv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"

"github.com/kuadrant/kuadrant-operator/pkg/common"
)

type AuthSchemeSpec struct {
// Named sets of JSON patterns that can be referred in `when` conditionals and in JSON-pattern matching policy rules.
Patterns map[string]authorinov1beta1.JSONPatternExpressions `json:"patterns,omitempty"`

// Conditions for the AuthConfig to be enforced.
// If omitted, the AuthConfig will be enforced for all requests.
// If present, all conditions must match for the AuthConfig to be enforced; otherwise, Authorino skips the AuthConfig and returns immediately with status OK.
Conditions []authorinov1beta1.JSONPattern `json:"when,omitempty"`

// List of identity sources/authentication modes.
// At least one config of this list MUST evaluate to a valid identity for a request to be successful in the identity verification phase.
Identity []*authorinov1beta1.Identity `json:"identity,omitempty"`

// List of metadata source configs.
// Authorino fetches JSON content from sources on this list on every request.
Metadata []*authorinov1beta1.Metadata `json:"metadata,omitempty"`

// Authorization is the list of authorization policies.
// All policies in this list MUST evaluate to "true" for a request be successful in the authorization phase.
Authorization []*authorinov1beta1.Authorization `json:"authorization,omitempty"`

// List of response configs.
// Authorino gathers data from the auth pipeline to build custom responses for the client.
Response []*authorinov1beta1.Response `json:"response,omitempty"`

// Custom denial response codes, statuses and headers to override default 40x's.
DenyWith *authorinov1beta1.DenyWith `json:"denyWith,omitempty"`
}

type AuthPolicySpec struct {
// TargetRef identifies an API object to apply policy to.
TargetRef gatewayapiv1alpha2.PolicyTargetReference `json:"targetRef"`
Expand All @@ -20,7 +49,7 @@ type AuthPolicySpec struct {
AuthRules []*AuthRule `json:"rules,omitempty"`

// AuthSchemes are embedded Authorino's AuthConfigs
AuthScheme *authorinov1beta1.AuthConfigSpec `json:"authScheme,omitempty"`
AuthScheme AuthSchemeSpec `json:"authScheme,omitempty"`
}

type AuthRule struct {
Expand Down
90 changes: 85 additions & 5 deletions api/v1beta1/zz_generated.deepcopy.go

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

10 changes: 0 additions & 10 deletions config/crd/bases/kuadrant.io_authpolicies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -669,14 +669,6 @@ spec:
type: object
type: object
type: object
hosts:
description: The list of public host names of the services protected
by this authentication/authorization scheme. Authorino uses
the requested host to lookup for the corresponding authentication/authorization
configs to enforce.
items:
type: string
type: array
identity:
description: List of identity sources/authentication modes. At
least one config of this list MUST evaluate to a valid identity
Expand Down Expand Up @@ -1671,8 +1663,6 @@ spec:
type: string
type: object
type: array
required:
- hosts
type: object
rules:
description: Rule describe the requests that will be routed to external
Expand Down
6 changes: 3 additions & 3 deletions config/samples/kuadrant_v1beta1_authpolicy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ spec:
methods: ["DELETE", "POST"]
paths: ["/admin*"]
authScheme:
hosts: ["api.toystore.com"]
identity:
- name: friends
apiKey:
labelSelectors:
group: friends
selector:
matchLabels:
group: friends
credentials:
in: authorization_header
keySelector: APIKEY
112 changes: 90 additions & 22 deletions controllers/authpolicy_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ func (r *AuthPolicyReconciler) reconcileSpec(ctx context.Context, ap *kuadrantv1
return ctrl.Result{}, err
}

if err := r.reconcileAuthRules(ctx, ap); err != nil {
if err := r.reconcileIstioAuthorizationPolicies(ctx, ap); err != nil {
return ctrl.Result{}, err
}

Expand All @@ -152,42 +152,49 @@ func (r *AuthPolicyReconciler) enforceHierarchicalConstraints(ctx context.Contex
return fmt.Errorf("rule host (%s) does not follow any hierarchical constraints", invalidHost)
}

if valid, invalidHost := common.ValidSubdomains(targetHostnames, ap.Spec.AuthScheme.Hosts); !valid {
return fmt.Errorf("host defined in authscheme (%s) does not follow any hierarchical constraints", invalidHost)
}

return nil
}

func (r *AuthPolicyReconciler) reconcileAuthSchemes(ctx context.Context, ap *kuadrantv1beta1.AuthPolicy) error {
logger, _ := logr.FromContext(ctx)
logger, err := logr.FromContext(ctx)
if err != nil {
return err
}

apKey := client.ObjectKeyFromObject(ap)
authConfig := &authorinov1beta1.AuthConfig{
ObjectMeta: metav1.ObjectMeta{
Name: authConfigName(apKey),
Namespace: common.KuadrantNamespace,
},
Spec: *ap.Spec.AuthScheme,
authConfig, err := r.desiredAuthConfig(ctx, ap)
if err != nil {
return err
}
err := r.ReconcileResource(ctx, &authorinov1beta1.AuthConfig{}, authConfig, alwaysUpdateAuthConfig)

err = r.ReconcileResource(ctx, &authorinov1beta1.AuthConfig{}, authConfig, alwaysUpdateAuthConfig)
if err != nil && !apierrors.IsAlreadyExists(err) {
logger.Error(err, "ReconcileResource failed to create/update AuthConfig resource")
return err
}

return nil
}

// reconcileAuthRules translates and reconciles `AuthRules` into an Istio AuthorizationPoilcy containing them.
func (r *AuthPolicyReconciler) reconcileAuthRules(ctx context.Context, ap *kuadrantv1beta1.AuthPolicy) error {
logger, _ := logr.FromContext(ctx)
// reconcileIstioAuthorizationPolicies translates and reconciles `AuthRules` into an Istio AuthorizationPoilcy containing them.
func (r *AuthPolicyReconciler) reconcileIstioAuthorizationPolicies(ctx context.Context, ap *kuadrantv1beta1.AuthPolicy) error {
logger, err := logr.FromContext(ctx)
if err != nil {
return err
}

targetHostnames, err := r.TargetHostnames(ctx, ap.Spec.TargetRef, ap.Namespace)
if err != nil {
return err
}

toRules := []*secv1beta1types.Rule_To{}
for _, rule := range ap.Spec.AuthRules {
hosts := rule.Hosts
if len(rule.Hosts) == 0 {
hosts = targetHostnames
}
toRules = append(toRules, &secv1beta1types.Rule_To{
Operation: &secv1beta1types.Operation{
Hosts: rule.Hosts,
Hosts: hosts,
Methods: rule.Methods,
Paths: rule.Paths,
},
Expand Down Expand Up @@ -220,7 +227,7 @@ func (r *AuthPolicyReconciler) reconcileAuthRules(ctx context.Context, ap *kuadr

gwKeys, err := r.TargetedGatewayKeys(ctx, ap.Spec.TargetRef, ap.Namespace)
if err != nil {
return nil
return err
}

targetObjectKind := "Gateway"
Expand Down Expand Up @@ -268,18 +275,26 @@ func (r *AuthPolicyReconciler) reconcileNetworkResourceBackReference(ctx context
}

func (r *AuthPolicyReconciler) removeAuthSchemes(ctx context.Context, ap *kuadrantv1beta1.AuthPolicy) error {
logger, _ := logr.FromContext(ctx)
logger, err := logr.FromContext(ctx)
if err != nil {
return err
}

logger.Info("Removing Authorino's AuthConfigs")

apKey := client.ObjectKeyFromObject(ap)
authConfig := &authorinov1beta1.AuthConfig{
TypeMeta: metav1.TypeMeta{
Kind: "AuthConfig",
APIVersion: authorinov1beta1.GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: authConfigName(apKey),
Namespace: common.KuadrantNamespace,
},
}

err := r.DeleteResource(ctx, authConfig)
err = r.DeleteResource(ctx, authConfig)
if err != nil {
if apierrors.IsNotFound(err) {
return nil
Expand All @@ -290,6 +305,59 @@ func (r *AuthPolicyReconciler) removeAuthSchemes(ctx context.Context, ap *kuadra
return nil
}

func (r *AuthPolicyReconciler) desiredAuthConfig(ctx context.Context, ap *kuadrantv1beta1.AuthPolicy) (*authorinov1beta1.AuthConfig, error) {
hosts, err := r.policyHosts(ctx, ap)
if err != nil {
return nil, err
}

return &authorinov1beta1.AuthConfig{
TypeMeta: metav1.TypeMeta{
Kind: "AuthConfig",
APIVersion: authorinov1beta1.GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: authConfigName(client.ObjectKeyFromObject(ap)),
Namespace: common.KuadrantNamespace,
},
Spec: authorinov1beta1.AuthConfigSpec{
Hosts: hosts,
Patterns: ap.Spec.AuthScheme.Patterns,
Conditions: ap.Spec.AuthScheme.Conditions,
Identity: ap.Spec.AuthScheme.Identity,
Metadata: ap.Spec.AuthScheme.Metadata,
Authorization: ap.Spec.AuthScheme.Authorization,
Response: ap.Spec.AuthScheme.Response,
DenyWith: ap.Spec.AuthScheme.DenyWith,
},
}, nil
}

func (r *AuthPolicyReconciler) policyHosts(ctx context.Context, ap *kuadrantv1beta1.AuthPolicy) ([]string, error) {
if len(ap.Spec.AuthRules) == 0 {
return r.TargetHostnames(ctx, ap.Spec.TargetRef, ap.Namespace)
}

uniqueHostnamesMap := make(map[string]interface{})
for idx := range ap.Spec.AuthRules {
if len(ap.Spec.AuthRules[idx].Hosts) == 0 {
// When one of the rules does not have hosts, just return target hostnames
return r.TargetHostnames(ctx, ap.Spec.TargetRef, ap.Namespace)
}

for _, hostname := range ap.Spec.AuthRules[idx].Hosts {
uniqueHostnamesMap[hostname] = nil
}
}

hostnames := make([]string, 0, len(uniqueHostnamesMap))
for k := range uniqueHostnamesMap {
hostnames = append(hostnames, k)
}

return hostnames, nil
}

func (r *AuthPolicyReconciler) removeIstioAuthPolicy(ctx context.Context, ap *kuadrantv1beta1.AuthPolicy) error {
logger, _ := logr.FromContext(ctx)
logger.Info("Removing Istio's AuthorizationPolicy")
Expand Down
Loading

0 comments on commit d7ab64b

Please sign in to comment.